/*
    This file is part of the KDE system
    Copyright (C)  1999,2000 Boloni Laszlo

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.

    klt_part.cpp
 */

#include "klt_part.h"

#include <sys/stat.h>
#include <stdlib.h>

#include <qfile.h>
#include <qlayout.h>
#include <qwmatrix.h>

#include <kaboutdata.h>
#include <kdebug.h>
#include <kfontdialog.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <klineeditdlg.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <krun.h>
#include <kstdaction.h>

extern "C"
{
  /**
   * This function is the 'main' function of this part.  It takes
   * the form 'void *init_lib<library name>()  It always returns a
   * new factory object
   */
  void *init_libkltpart()
  {
    return new kltFactory;
  }
}

/**
 * We need one static instance of the factory for our C 'main' function
 */
KInstance *kltFactory::s_instance = 0L;
KAboutData *kltFactory::s_aboutData = 0;

kltFactory::kltFactory()
{
}

kltFactory::~kltFactory()
{
  if (s_instance)
    delete s_instance;

  if ( s_aboutData )
    delete s_aboutData;

  s_instance = 0;
  s_aboutData = 0;
}

KParts::Part *kltFactory::createPartObject(QWidget *parentWidget, const char *widgetName,
                                         QObject *parent, const char *name, const char *classname,
                                         const QStringList&)
{
  kdDebug(1211) << "kltFactory::createPart parentWidget=" << parentWidget << " parent=" << parent << endl;
  KParts::Part *obj = new kltPart(parentWidget, widgetName, parent, name, classname);
  return obj;
}

KInstance *kltFactory::instance()
{
  if ( !s_instance )
    {
      s_aboutData = new KAboutData("klt", I18N_NOOP("Klt"), "1.1");
      s_instance = new KInstance( s_aboutData );
    }
  return s_instance;
}

//////////////////////////////////////////////////////////////////////

class KltFontSelectAction : public KSelectAction {
public:
    KltFontSelectAction(const QString &text, int accel,
                            const QObject* receiver, const char* slot,
                            QObject* parent, const char* name = 0 )
        : KSelectAction(text, accel, receiver, slot, parent, name) {}
    KltFontSelectAction( const QString &text, const QIconSet& pix,
                             int accel, const QObject* receiver,
                             const char* slot, QObject* parent,
                             const char* name = 0 )
        : KSelectAction(text, pix, accel, receiver, slot, parent, name) {}

    virtual void slotActivated( int index );
};

void KltFontSelectAction::slotActivated(int index) {
    // emit even if it's already activated
    if (currentItem() == index) {
      KSelectAction::slotActivated();
      return;
    } else {
      KSelectAction::slotActivated(index);
    }
}

//////////////////////////////////////////////////////////////////////

const char *fonts[] = {
 "13",
 "7",   // tiny font, never used
 "10",  // small font
 "13",  // medium
 "15",  // large
 "20", // huge
 "-misc-console-medium-r-normal--16-160-72-72-c-160-iso10646-1", // "Linux"
 "-misc-fixed-medium-r-normal--15-140-75-75-c-90-iso10646-1",    // "Unicode"
 };

#define TOPFONT (sizeof(fonts)/sizeof(char*))
#define DEFAULTFONT TOPFONT

#define DEFAULT_HISTORY_SIZE 1000

kltPart::kltPart(QWidget *_parentWidget, const char *widgetName, QObject *parent, const char *name, const char *classname)
  : KParts::ReadOnlyPart(parent, name)
,te(0)
,se(0)
,colors(0)
,rootxpm(0)
,m_histSize(DEFAULT_HISTORY_SIZE)
{
  parentWidget=_parentWidget;
  setInstance(kltFactory::instance());

  m_extension = new kltBrowserExtension(this);

  // This is needed since only klt.cpp does it
  // Without this -> crash on keypress... (David)
  KeyTrans::loadAll();

  m_streamEnabled = ( classname && strcmp( classname, "TerminalEmulator" ) == 0 );

  QStrList eargs;

fprintf(stderr,"In klt_part bitty\n");

  const char* shell = getenv("SHELL");
  if (shell == NULL || *shell == '\0') shell = "/bin/sh";
  eargs.append(shell);
  te = new TEWidget(parentWidget,widgetName);
  te->setMinimumSize(150,70);    // allow resizing, cause resize in TEWidget

  setWidget(te);
  se = new TESession(te,shell,eargs,"klt");
  connect( se,SIGNAL(done(TESession*)),
           this,SLOT(doneSession(TESession*)) );
  connect( se,SIGNAL(openURLRequest(const QString &)),
           this,SLOT(emitOpenURLRequest(const QString &)) );
  connect( te,SIGNAL(configureRequest(TEWidget*,int,int,int)),
           this,SLOT(configureRequest(TEWidget*,int,int,int)) );
  connect( se, SIGNAL( updateTitle() ),
           this, SLOT( updateTitle() ) );
  connect( se, SIGNAL(restoreAllListenToKeyPress()),
           this, SLOT(restoreAllListenToKeyPress()) );
  // We ignore the following signals
  //connect( se->getEmulation(), SIGNAL(changeColumns(int)),
  //         this, SLOT(changeColumns(int)) );
  //connect( se, SIGNAL(clearAllListenToKeyPress()),
  //        this, SLOT(clearAllListenToKeyPress()) );
  connect( se->getEmulation(),SIGNAL(ImageSizeChanged(int,int)), 
           this,SLOT(notifySize(int,int)));

  rootxpm = new KRootPixmap(te);

  colors = new ColorSchemaList();
  colors->checkSchemas();
  colors->sort();

  readProperties();
  se->setConnect(true);

  makeGUI();

  updateSchemaMenu();

  ColorSchema *sch=colors->find(s_schema);
  if (sch)
    curr_schema=sch->numb();
  else
    curr_schema = 0;
  for (uint i=0; i<m_schema->count(); i++)
    m_schema->setItemChecked(i,false);

  m_schema->setItemChecked(curr_schema,true);
  se->setSchemaNo(curr_schema);

  // insert keymaps into menu
  for (int i = 0; i < KeyTrans::count(); i++) {
    KeyTrans* ktr = KeyTrans::find(i);
    m_keytab->insertItem(ktr->hdr(),ktr->numb());
  }

  applySettingsToGUI();

  // kDebugInfo("Loading successful");
  se->run();

  connect( se, SIGNAL( destroyed() ), this, SLOT( sessionDestroyed() ) );
}

void kltPart::doneSession(TESession*)
{
  // see doneSession in klt.cpp
  if (se)
  {
    kdDebug(1211) << "doneSession - disconnecting done" << endl;;
    disconnect( se,SIGNAL(done(TESession*)),
                this,SLOT(doneSession(TESession*)) );
    se->setConnect(false);
    //QTimer::singleShot(100,se,SLOT(terminate()));
    kdDebug(1211) << "se->terminate()" << endl;;
    se->terminate();
  }
}

void kltPart::sessionDestroyed()
{
  kdDebug(1211) << "sessionDestroyed()" << endl;;
  disconnect( se, SIGNAL( destroyed() ), this, SLOT( sessionDestroyed() ) );
  se = 0;
  delete this;
}

void kltPart::configureRequest(TEWidget*te,int,int x,int y)
{
  m_popupMenu->popup(te->mapToGlobal(QPoint(x,y)));
}

kltPart::~kltPart()
{
  kdDebug(1211) << "kltPart::~kltPart() this=" << this << endl;
  if ( se ) {
    disconnect( se, SIGNAL( destroyed() ), this, SLOT( sessionDestroyed() ) );
    kdDebug(1211) << "Deleting se session" << endl;
    delete se;
    se=0;
  }

  if (colors) delete colors;
  colors=0;

  //te is deleted by the framework
}

bool kltPart::openURL( const KURL & url )
{
  //kdDebug(1211) << "kltPart::openURL " << url.prettyURL() << endl;

  if (currentURL==url) {
    emit completed();
    return true;
  }

  m_url = url;
  emit setWindowCaption( url.prettyURL() );
  kdDebug(1211) << "Set Window Caption to " << url.prettyURL() << "\n";
  emit started( 0 );

  if ( url.isLocalFile() ) {
      struct stat buff;
      stat( QFile::encodeName( url.path() ), &buff );
      QString text = ( S_ISDIR( buff.st_mode ) ? url.path() : url.directory() );
      KRun::shellQuote(text);
      text = QString::fromLatin1("\001\013cd ") + text + '\n';
      te->emitText( text );
  }

  emit completed();
  return true;
}

void kltPart::emitOpenURLRequest(const QString &cwd)
{
  KURL url;
  url.setPath(cwd);
  if (url==currentURL)
    return; 
  currentURL=url;
  m_extension->emitOpenURLRequest(url);
}


void kltPart::makeGUI()
{
  KActionCollection* actions = new KActionCollection(this);

  // Send Signal Menu -------------------------------------------------------------
  m_signals = new KPopupMenu((KMainWindow*)parentWidget);
  m_signals->insertItem( i18n( "&Suspend Task" )   + " (STOP)", SIGSTOP);
  m_signals->insertItem( i18n( "&Continue Task" )  + " (CONT)", SIGCONT);
  m_signals->insertItem( i18n( "&Hangup" )         + " (HUP)",   SIGHUP);
  m_signals->insertItem( i18n( "&Interrupt Task" ) + " (INT)",   SIGINT);
  m_signals->insertItem( i18n( "&Terminate Task" ) + " (TERM)", SIGTERM);
  m_signals->insertItem( i18n( "&Kill Task" )      + " (KILL)",  SIGKILL);
  m_signals->insertItem( i18n( "User Signal &1")   + " (USR1)", SIGUSR1);
  m_signals->insertItem( i18n( "User Signal &2")   + " (USR2)", SIGUSR2);
  connect(m_signals, SIGNAL(activated(int)), SLOT(sendSignal(int)));

  // Settings Menu ----------------------------------------------------------------
  m_options = new KPopupMenu((KMainWindow*)parentWidget);

  // Scrollbar
  selectScrollbar = new KSelectAction(i18n("Sc&rollbar"), 0, this,
                                      SLOT(slotSelectScrollbar()), actions);
  QStringList scrollitems;
  scrollitems << i18n("&Hide") << i18n("&Left") << i18n("&Right");
  selectScrollbar->setItems(scrollitems);
  selectScrollbar->plug(m_options);

  // Select Bell
  m_options->insertSeparator();
  selectBell = new KSelectAction(i18n("&Bell"), SmallIconSet( "bell"), 0 , this,
                                 SLOT(slotSelectBell()), actions);
  QStringList bellitems;
  bellitems << i18n("&None")
            << i18n("&System Notification")
            << i18n("&Visible Bell");
  selectBell->setItems(bellitems);
  selectBell->plug(m_options);

  // Select font
  selectFont = new KltFontSelectAction( i18n( "&Font" ), SmallIconSet( "text" ), 0,
                                            this, SLOT(slotSelectFont()), actions);
  QStringList it;
  it << i18n("&Normal")
     << i18n("&Tiny")
     << i18n("&Small")
     << i18n("&Medium")
     << i18n("&Large")
     << i18n("&Huge")
     << ""
     << i18n("&Linux")
     << i18n("&Unicode")
     << ""
     << i18n("&Custom...");
  selectFont->setItems(it);
  selectFont->plug(m_options);

  // Keyboard Options Menu ---------------------------------------------------
  m_keytab = new KPopupMenu((KMainWindow*)parentWidget);
  m_keytab->setCheckable(true);
  connect(m_keytab, SIGNAL(activated(int)), SLOT(keytab_menu_activated(int)));
  m_options->insertItem( SmallIconSet( "key_bindings" ), i18n( "&Keyboard" ), m_keytab );

  // Schema Options Menu -----------------------------------------------------
  m_schema = new KPopupMenu((KMainWindow*)parentWidget);
  m_schema->setCheckable(true);
  connect(m_schema, SIGNAL(activated(int)), SLOT(schema_menu_activated(int)));
  connect(m_schema, SIGNAL(aboutToShow()), SLOT(schema_menu_check()));
  m_options->insertItem( SmallIconSet( "colorize" ), i18n( "Sch&ema" ), m_schema);

  KAction *historyType = new KAction(i18n("&History..."), "history", 0, this,
                                     SLOT(slotHistoryType()), actions);
  historyType->plug(m_options);
  m_options->insertSeparator();

  // Select line spacing
  selectLineSpacing =
    new KSelectAction
    (
     i18n("Li&ne Spacing"),
     SmallIconSet("leftjust"), // Non-code hack.
     0,
     this,
     SLOT(slotSelectLineSpacing()),
     this
    );

  QStringList lineSpacingList;

  lineSpacingList
    << i18n("&0")
    << i18n("&1")
    << i18n("&2")
    << i18n("&3")
    << i18n("&4")
    << i18n("&5")
    << i18n("&6")
    << i18n("&7")
    << i18n("&8");

  selectLineSpacing->setItems(lineSpacingList);
  selectLineSpacing->plug(m_options);

  // Blinking Cursor
  blinkingCursor = new KToggleAction (i18n("Blinking &Cursor"),
                                      0, this,SLOT(slotBlinkingCursor()), actions);
  blinkingCursor->plug(m_options);

  // Frame on/off
  showFrame = new KToggleAction(i18n("Show Fr&ame"), 0,
                                this, SLOT(slotToggleFrame()), actions);
  showFrame->plug(m_options);

  // Word Connectors
  KAction *WordSeps = new KAction(i18n("Wor&d Connectors..."), 0, this,
                                  SLOT(slotWordSeps()), actions);
  WordSeps->plug(m_options);

  // Save Settings
  m_options->insertSeparator();
  KAction *saveSettings = KStdAction::saveOptions(this, SLOT(saveProperties()), actions);
  saveSettings->plug(m_options);
  if (KGlobalSettings::insertTearOffHandle())
    m_options->insertTearOffHandle();

  // Popup Menu -------------------------------------------------------------------
  m_popupMenu = new KPopupMenu((KMainWindow*)parentWidget);
  KAction *copyClipboard = new KAction(i18n("&Copy"), "editcopy", 0,
                                        te, SLOT(copyClipboard()), actions);
  copyClipboard->plug(m_popupMenu);
  
  KAction *pasteClipboard = new KAction(i18n("&Paste"), "editpaste", 0,
                                        te, SLOT(pasteClipboard()), actions);
  pasteClipboard->plug(m_popupMenu);

  m_popupMenu->insertItem(i18n("&Send Signal"), m_signals);
  m_popupMenu->insertSeparator();

  m_popupMenu->insertItem(i18n("S&ettings"), m_options);
  m_popupMenu->insertSeparator();

  KAction *closeSession = new KAction(i18n("&Close Terminal Emulator"), "fileclose", 0, this,
                                      SLOT(closeCurrentSession()), actions);
  closeSession->plug(m_popupMenu);
  if (KGlobalSettings::insertTearOffHandle())
    m_popupMenu->insertTearOffHandle();
}

void kltPart::applySettingsToGUI()
{
  showFrame->setChecked( b_framevis );
  selectScrollbar->setCurrentItem(n_scroll);
  selectFont->setCurrentItem(n_font);
  updateKeytabMenu();
  selectBell->setCurrentItem(n_bell);
  selectLineSpacing->setCurrentItem(te->lineSpacing());
  blinkingCursor->setChecked(te->blinkingCursor());
  m_schema->setItemChecked(curr_schema,true);
}

void kltPart::readProperties()
{
  KConfig* config = new KConfig("kltpartrc",true);
  config->setDesktopGroup();

  b_framevis = config->readBoolEntry("has frame",false);
  b_histEnabled = config->readBoolEntry("historyenabled",true);
  n_bell = QMIN(config->readUnsignedNumEntry("bellmode",TEWidget::BELLSYSTEM),2);
  n_font = QMIN(config->readUnsignedNumEntry("font",3),TOPFONT);
  n_keytab=config->readNumEntry("keytab",0); // act. the keytab for this session
  n_scroll = QMIN(config->readUnsignedNumEntry("scrollbar",TEWidget::SCRRIGHT),2);
  m_histSize = config->readNumEntry("history",DEFAULT_HISTORY_SIZE);
  s_word_seps= config->readEntry("wordseps",":@-./_~");

  QFont tmpFont("fixed");
  tmpFont.setFixedPitch(true);
  tmpFont.setStyleHint(QFont::TypeWriter);
  defaultFont = config->readFontEntry("defaultfont", &tmpFont);
  setFont(QMIN(config->readUnsignedNumEntry("font",3),TOPFONT));

  QString schema = config->readEntry("Schema");

  s_kconfigSchema=config->readEntry("schema", "");
  ColorSchema* sch = colors->find(schema.isEmpty() ? s_kconfigSchema : schema);
  if (!sch) {
    sch=(ColorSchema*)colors->at(0);  //the default one
  }
  if (sch->hasSchemaFileChanged()) sch->rereadSchemaFile();
  s_schema = sch->relPath();
  curr_schema = sch->numb();
  pmPath = sch->imagePath();
  te->setColorTable(sch->table()); //FIXME: set twice here to work around a bug

  if (sch->useTransparency()) {
    //KONSOLEDEBUG << "Setting up transparency" << endl;
    rootxpm->setFadeEffect(sch->tr_x(), QColor(sch->tr_r(), sch->tr_g(), sch->tr_b()));
    rootxpm->start();
  }
  else {
    rootxpm->stop();
    pixmap_menu_activated(sch->alignment());
  }

  if (b_histEnabled && m_histSize)
    se->setHistory(HistoryTypeBuffer(m_histSize));
  else if (b_histEnabled && !m_histSize)
    se->setHistory(HistoryTypeFile());
  else
    se->setHistory(HistoryTypeNone());

  se->setKeymapNo(n_keytab);
  te->setBellMode(n_bell);
  te->setBlinkingCursor(config->readBoolEntry("BlinkingCursor",false));
  te->setFrameStyle( b_framevis?(QFrame::WinPanel|QFrame::Sunken):QFrame::NoFrame );
  te->setLineSpacing( config->readUnsignedNumEntry( "LineSpacing", 0 ) );
  te->setScrollbarLocation(n_scroll);
  te->setWordCharacters(s_word_seps);

  delete config;

  config = new KConfig("kltrc",true);
  config->setDesktopGroup();
  te->setTerminalSizeHint( config->readBoolEntry("TerminalSizeHint",true) );
  config->setGroup("UTMP");
  se->setAddToUtmp( config->readBoolEntry("AddToUtmp",true));
  delete config;
}

void kltPart::saveProperties()
{
  KConfig* config = new KConfig("kltpartrc");
  config->setDesktopGroup();

  config->writeEntry("bellmode",n_bell);
  config->writeEntry("BlinkingCursor", te->blinkingCursor());
  config->writeEntry("defaultfont", defaultFont);
  config->writeEntry("font",n_font);
  config->writeEntry("history", se->history().getSize());
  config->writeEntry("historyenabled", b_histEnabled);
  config->writeEntry("keytab",n_keytab);
  config->writeEntry("has frame",b_framevis);
  config->writeEntry("LineSpacing", te->lineSpacing());
  config->writeEntry("schema",s_kconfigSchema);
  config->writeEntry("scrollbar",n_scroll);
  config->writeEntry("wordseps",s_word_seps);

  config->sync();
  delete config;
}

void kltPart::sendSignal(int sn)
{
  if (se) se->sendSignal(sn);
}

void kltPart::closeCurrentSession()
{
  se->closeSession();
}

void kltPart::slotToggleFrame()
{
  b_framevis = showFrame->isChecked();
  te->setFrameStyle( b_framevis?(QFrame::WinPanel|QFrame::Sunken):QFrame::NoFrame);
}

void kltPart::slotSelectScrollbar()
{
  n_scroll = selectScrollbar->currentItem();
  te->setScrollbarLocation(n_scroll);
}

void kltPart::slotSelectFont() {
  int item = selectFont->currentItem();
  // KONSOLEDEBUG << "slotSelectFont " << item << endl;
  if (item == DEFAULTFONT) {
    if ( KFontDialog::getFont(defaultFont, true) == QDialog::Rejected ) {
      selectFont->setCurrentItem(n_font);
      return;
    }
  }
  setFont(item);
}

void kltPart::setFont(int fontno)
{
  QFont f;
  if (fontno == DEFAULTFONT)
    f = defaultFont;
  else
  if (fonts[fontno][0] == '-')
  {
    f.setRawName( fonts[fontno] );
    f.setFixedPitch(true);
    f.setStyleHint( QFont::TypeWriter );
    if ( !f.exactMatch() && fontno != DEFAULTFONT)
    {
      // Ugly hack to prevent bug #20487
      fontNotFound_par=fonts[fontno];
      QTimer::singleShot(1,this,SLOT(fontNotFound()));
      return;
    }
  }
  else
  {
    f.setFamily("fixed");
    f.setFixedPitch(true);
    f.setStyleHint(QFont::TypeWriter);
    f.setPixelSize(QString(fonts[fontno]).toInt());
  }


  se->setFontNo(fontno);
  te->setVTFont(f);
  n_font = fontno;
}

void kltPart::fontNotFound()
{
  QString msg = i18n("Font `%1' not found.\nCheck README.linux.console for help.").arg(fontNotFound_par);
  KMessageBox::error(parentWidget,  msg);
}

void kltPart::updateKeytabMenu()
{
  m_keytab->setItemChecked(n_keytab,false);
  m_keytab->setItemChecked(se->keymapNo(),true);
  n_keytab = se->keymapNo();
}

void kltPart::keytab_menu_activated(int item)
{
  se->setKeymapNo(item);
  updateKeytabMenu();
}

void kltPart::schema_menu_activated(int item)
{
  setSchema(item);
  s_kconfigSchema = s_schema; // This is the new default
}

void kltPart::schema_menu_check()
{
  if (colors->checkSchemas()) {
    colors->sort();
    updateSchemaMenu();
  }
}

void kltPart::updateSchemaMenu()
{
  m_schema->clear();
  for (int i = 0; i < (int) colors->count(); i++)  {
    ColorSchema* s = (ColorSchema*)colors->at(i);
    m_schema->insertItem(s->title(),s->numb(),0);
  }

  if (te && se) {
    m_schema->setItemChecked(se->schemaNo(),true);
  }
}

void kltPart::setSchema(int numb)
{
  ColorSchema* s = colors->find(numb);
  if (!s) {
    kdWarning() << "No schema found. Using default." << endl;
    s=(ColorSchema*)colors->at(0);
  }
  if (s->numb() != numb)  {
    kdWarning() << "No schema with number " << numb << endl;
  }

  if (s->hasSchemaFileChanged()) {
    const_cast<ColorSchema *>(s)->rereadSchemaFile();
  }
  if (s) setSchema(s);
}

void kltPart::setSchema(ColorSchema* s)
{
  if (!s) return;

  if (m_schema) {
    m_schema->setItemChecked(curr_schema,false);
    m_schema->setItemChecked(s->numb(),true);
  }

  s_schema = s->relPath();
  curr_schema = s->numb();
  pmPath = s->imagePath();
  te->setColorTable(s->table()); //FIXME: set twice here to work around a bug

  if (s->useTransparency()) {
    rootxpm->setFadeEffect(s->tr_x(), QColor(s->tr_r(), s->tr_g(), s->tr_b()));
    rootxpm->start();
  }
  else {
    rootxpm->stop();
    pixmap_menu_activated(s->alignment());
  }

  te->setColorTable(s->table());
  se->setSchemaNo(s->numb());
}

void kltPart::notifySize(int lines, int columns)
{
  ColorSchema *sch=colors->find(s_schema);

  if (sch && sch->alignment() >= 3)
    pixmap_menu_activated(sch->alignment());
}

void kltPart::pixmap_menu_activated(int item)
{
  if (item <= 1) pmPath = "";
  QPixmap pm(pmPath);
  if (pm.isNull()) {
    pmPath = "";
    item = 1;
    te->setBackgroundColor(te->getDefaultBackColor());
    return;
  }
  // FIXME: respect scrollbar (instead of te->size)
  n_render= item;
  switch (item) {
    case 1: // none
    case 2: // tile
            te->setBackgroundPixmap(pm);
    break;
    case 3: // center
            { QPixmap bgPixmap;
              bgPixmap.resize(te->size());
              bgPixmap.fill(te->getDefaultBackColor());
              bitBlt( &bgPixmap, ( te->size().width() - pm.width() ) / 2,
                                ( te->size().height() - pm.height() ) / 2,
                      &pm, 0, 0,
                      pm.width(), pm.height() );

              te->setBackgroundPixmap(bgPixmap);
            }
    break;
    case 4: // full
            {
              float sx = (float)te->size().width() / pm.width();
              float sy = (float)te->size().height() / pm.height();
              QWMatrix matrix;
              matrix.scale( sx, sy );
              te->setBackgroundPixmap(pm.xForm( matrix ));
            }
    break;
    default: // oops
             n_render = 1;
  }
}

void kltPart::slotHistoryType()
{
  HistoryTypeDialog dlg(se->history(), m_histSize, (KMainWindow*)parentWidget);
  if (dlg.exec()) {
    if (dlg.isOn()) {
      if (dlg.nbLines() > 0) {
        se->setHistory(HistoryTypeBuffer(dlg.nbLines()));
        m_histSize = dlg.nbLines();
        b_histEnabled = true;
      }
      else {
        se->setHistory(HistoryTypeFile());
        m_histSize = 0;
        b_histEnabled = true;
      }
    }
    else {
      se->setHistory(HistoryTypeNone());
      m_histSize = dlg.nbLines();
      b_histEnabled = false;
    }
  }
}

void kltPart::slotSelectBell() {
  n_bell = selectBell->currentItem();
  te->setBellMode(n_bell);
}

void kltPart::slotSelectLineSpacing()
{
  te->setLineSpacing( selectLineSpacing->currentItem() );
}

void kltPart::slotBlinkingCursor()
{
  te->setBlinkingCursor(blinkingCursor->isChecked());
}

void kltPart::slotWordSeps() {
  KLineEditDlg dlg(i18n("Characters other than alphanumerics considered part of a word when double clicking:"),s_word_seps, (KMainWindow*)parentWidget);
  dlg.setCaption(i18n("Word Connectors"));
  if (dlg.exec()) {
    s_word_seps = dlg.text();
    te->setWordCharacters(s_word_seps);
  }
}

void kltPart::restoreAllListenToKeyPress()
{
    se->setListenToKeyPress(true);
}

void kltPart::updateTitle()
{
    emit setWindowCaption( se->fullTitle() );
}

void kltPart::guiActivateEvent( KParts::GUIActivateEvent * )
{
    // Don't let ReadOnlyPart::guiActivateEvent reset the window caption
}

bool kltPart::doOpenStream( const QString& )
{
	return m_streamEnabled;
}

bool kltPart::doWriteStream( const QByteArray& data )
{
	if ( m_streamEnabled )
	{
		QString cmd = QString::fromLocal8Bit( data.data(), data.size() );
		se->sendSession( cmd );
		return true;
	}
	return false;
}

bool kltPart::doCloseStream()
{
	return m_streamEnabled;
}

//////////////////////////////////////////////////////////////////////

HistoryTypeDialog::HistoryTypeDialog(const HistoryType& histType,
                                     unsigned int histSize,
                                     QWidget *parent)
  : KDialogBase(Plain, i18n("History Configuration"),
                Help | Default | Ok | Cancel, Ok,
                parent)
{
  QFrame *mainFrame = plainPage();

  QHBoxLayout *hb = new QHBoxLayout(mainFrame);

  m_btnEnable    = new QCheckBox(i18n("&Enable"), mainFrame);

  QObject::connect(m_btnEnable, SIGNAL(toggled(bool)),
                   this,      SLOT(slotHistEnable(bool)));

  m_size = new QSpinBox(0, 10 * 1000 * 1000, 100, mainFrame);
  m_size->setValue(histSize);
  m_size->setSpecialValueText(i18n("Unlimited (number of lines)", "Unlimited"));

  m_setUnlimited = new QPushButton(i18n("&Set Unlimited"), mainFrame);
  connect( m_setUnlimited,SIGNAL(clicked()), this,SLOT(slotSetUnlimited()) );

  hb->addWidget(m_btnEnable);
  hb->addSpacing(10);
  hb->addWidget(new QLabel(i18n("Number of lines:"), mainFrame));
  hb->addWidget(m_size);
  hb->addSpacing(10);
  hb->addWidget(m_setUnlimited);

  if ( ! histType.isOn()) {
    m_btnEnable->setChecked(false);
    slotHistEnable(false);
  } else {
    m_btnEnable->setChecked(true);
    m_size->setValue(histType.getSize());
    slotHistEnable(true);
  }
  setHelp("configure-history");
}

void HistoryTypeDialog::slotDefault()
{
  m_btnEnable->setChecked(true);
  m_size->setValue(DEFAULT_HISTORY_SIZE);
  slotHistEnable(true);
}

void HistoryTypeDialog::slotHistEnable(bool b)
{
  m_size->setEnabled(b);
  m_setUnlimited->setEnabled(b);
  if (b) m_size->setFocus();
}

void HistoryTypeDialog::slotSetUnlimited()
{
  m_size->setValue(0);
}

unsigned int HistoryTypeDialog::nbLines() const
{
  return m_size->value();
}

bool HistoryTypeDialog::isOn() const
{
  return m_btnEnable->isChecked();
}

kltBrowserExtension::kltBrowserExtension(kltPart *parent)
  : KParts::BrowserExtension(parent, "kltBrowserExtension")
{
}

kltBrowserExtension::~kltBrowserExtension()
{
}

void kltBrowserExtension::emitOpenURLRequest(const KURL &url)
{
  emit openURLRequest(url);
}

#include "klt_part.moc"
