/*
    Requires the TQt widget libraries, available at no cost at
    http://www.troll.no

    Copyright (C) 1997-2000 Peter Putzer
                            putzer@kde.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of version 2 of the GNU General Public License
    as published by the Free Software Foundation.

    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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/****************************************************************
**
** KSysV
** Toplevel Widget
**
****************************************************************/

#include <ctype.h>

#include <tqpopupmenu.h>
#include <tqkeycode.h>
#include <tqmessagebox.h>
#include <tqfontmetrics.h>
#include <tqpainter.h>
#include <tqmultilineedit.h>
#include <tqdatetime.h>
#include <kprinter.h>
#include <tqpaintdevicemetrics.h>
#include <tqbuttongroup.h>
#include <tqclipboard.h>
#include <tqtooltip.h>
#include <tqcheckbox.h>
#include <tqhbox.h>
#include <tqregexp.h>
#include <tqdatastream.h>
#include <tqpixmapcache.h>
#include <tqtextview.h>
#include <tqfileinfo.h>
#include <tqtextstream.h>
#include <tqwhatsthis.h>
#include <tqsimplerichtext.h>

#include <kresolver.h>
#include <tdetoolbar.h>
#include <kkeydialog.h>
#include <tdemenubar.h>
#include <kcompletion.h>
#include <tdeaction.h>
#include <kstdaction.h>
#include <kdebug.h>
#include <tdeapplication.h>
#include <tdeglobal.h>
#include <khelpmenu.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <tdestdaccel.h>
#include <kedittoolbar.h>
#include <kiconloader.h>
#include <tdefiledialog.h>
#include <tdeaboutdata.h>
#include <kcursor.h>

#include "kbusymanager.h"
#include "ServiceDlg.h"
#include "PreferencesDialog.h"
#include "ActionList.h"
#include "ksv_core.h"
#include "ksv_conf.h"
#include "RunlevelAuthIcon.h"
#include "ksvdraglist.h"
#include "Data.h"
#include "ksvdrag.h"
#include "OldView.h"
#include "IOCore.h"
#include "TopWidget.h"
#include <tqlabel.h>
#include <kstatusbar.h>

namespace Status
{
  enum {
    Changed, Checklist, Writable
  };
} // namespace Status

KSVTopLevel::KSVTopLevel()
  : TDEMainWindow(0, 0L, WStyle_ContextHelp|WDestructiveClose),
    mConfig(KSVConfig::self()),
	mView (0L),
    mPreferences (0L),

	mEditUndo (0L), mEditCut (0L), mEditCopy (0L), mEditPaste (0L),
    mEditProperties (0L),

	mFileRevert (0L), mFileLoad (0L), mFilePrint (0L), mFilePrintLog (0L),
    mFileSave (0L), mFileSaveAs (0L), mFileSaveLog(0L), mFileQuit (0L),

	mToolsStartService (0L), mToolsStopService (0L),
    mToolsRestartService (0L), mToolsEditService (0L),

    mOptionsToggleLog (0L),

    mOpenWith (0L), mOpenDefault (0L),

    mUndoList (new ActionList (this, "UndoList")),
	mRedoList (new ActionList (this, "RedoList")),
	mStartDlg (new ServiceDlg (i18n("Start Service"),
							   i18n("&Choose which service to start:"),
							   this)),
	mStopDlg (new ServiceDlg (i18n("Stop Service"),
							  i18n("&Choose which service to stop:"),
							  this)),
	mRestartDlg (new ServiceDlg (i18n("Restart Service"),
								 i18n("&Choose which service to restart:"),
								 this)),
	mEditDlg (new ServiceDlg (i18n("Edit Service"),
							  i18n("&Choose which service to edit:"),
							  this)),
    mVisible (new TQCheckBox*[ksv::runlevelNumber])
{
  setCaption(false);

  initStatusBar(); // order dependency
  initActions(); // order dependency
  mView = new KSVContent (mOpenWith->popupMenu(), this, "Content"); // order dependency
  initTools(); // order dependency

  setCentralWidget(mView);

  // ensure that the statusbar gets updated correctly
  connect (mView, TQ_SIGNAL(sigRun(const TQString&)), this, TQ_SLOT(slotUpdateRunning(const TQString&)));
  connect (mView, TQ_SIGNAL(sigStop()), statusBar(), TQ_SLOT(clear()));
  connect (mView, TQ_SIGNAL(cannotGenerateNumber()), this, TQ_SLOT(catchCannotGenerateNumber()));
  connect (mView, TQ_SIGNAL(undoAction(KSVAction*)), this, TQ_SLOT(pushUndoAction(KSVAction*)));
  connect (mView, TQ_SIGNAL(logChanged()), this, TQ_SLOT(enableLogActions()));

  // cut & copy
  connect (mView, TQ_SIGNAL (newOrigin()),
		   this, TQ_SLOT (dispatchEdit()));

  // undo
  connect (mUndoList, TQ_SIGNAL(empty()), this, TQ_SLOT(disableUndo()));
  connect (mUndoList, TQ_SIGNAL(filled()), this, TQ_SLOT(enableUndo()));

  // and redo
  connect (mRedoList, TQ_SIGNAL(empty()), this, TQ_SLOT(disableRedo()));
  connect (mRedoList, TQ_SIGNAL(filled()), this, TQ_SLOT(enableRedo()));

  // paste
  connect (kapp->clipboard(), TQ_SIGNAL (dataChanged()),
		   this, TQ_SLOT (dispatchEdit()));

  // init mView according to saved preferences
  slotReadConfig();
  initView();
  setMinimumSize(600,400);

  // restore size and position
  move(mConfig->position()); // doesnt seem to work while unmapped
  setAutoSaveSettings();

  // start watching the directories
  mAuth->setCheckEnabled(true);

  dispatchEdit(); // disable cut & copy on startup
}

KSVTopLevel::~KSVTopLevel()
{
  mUndoList->clear();
  mRedoList->clear();

  delete[] mVisible;
}

void KSVTopLevel::initTools()
{
  connect (mStartDlg, TQ_SIGNAL(doAction(const TQString&)),
		   mView, TQ_SLOT(startService(const TQString&)));
  connect (mStopDlg, TQ_SIGNAL(doAction(const TQString&)),
		   mView, TQ_SLOT(editService(const TQString&)));
  connect (mRestartDlg, TQ_SIGNAL(doAction(const TQString&)),
		   mView, TQ_SLOT(restartService(const TQString&)));
  connect (mEditDlg, TQ_SIGNAL(doAction(const TQString&)),
		   mView, TQ_SLOT(editService(const TQString&)));

  connect (mStartDlg, TQ_SIGNAL (display (bool)),
		   this, TQ_SLOT (dispatchStartService (bool)));
  connect (mStopDlg, TQ_SIGNAL (display (bool)),
		   this, TQ_SLOT (dispatchStopService (bool)));
  connect (mRestartDlg, TQ_SIGNAL (display (bool)),
		   this, TQ_SLOT (dispatchRestartService (bool)));
  connect (mEditDlg, TQ_SIGNAL (display (bool)),
		   this, TQ_SLOT (dispatchEditService (bool)));

}

void KSVTopLevel::initActions ()
{
  TDEActionCollection* coll = actionCollection();

  // setup File menu
  mFileRevert = KStdAction::revert (this, TQ_SLOT (slotClearChanges()), coll);
  mFileRevert->setText (i18n("Re&vert Configuration"));

  mFileLoad = KStdAction::open (this, TQ_SLOT (load()), coll);
  mFileLoad->setText (i18n ("&Open..."));

  mFileSave = KStdAction::save(this, TQ_SLOT(slotAcceptChanges()), coll);
  mFileSave->setText (i18n("&Save Configuration"));

  mFileSaveAs = KStdAction::saveAs (this, TQ_SLOT (saveAs ()), coll);

  mFileSaveLog = KStdAction::save (this, TQ_SLOT(slotSaveLog()), coll, "ksysv_save_log");
  mFileSaveLog->setText (i18n("Save &Log..."));
  mFileSaveLog->setShortcut (Key_L+CTRL);
  mFileSaveLog->setEnabled (false);

  // disabled due to complexity
  //  mFilePrint = KStdAction::print (this, TQ_SLOT (print()), coll);

  mFilePrintLog = KStdAction::print(this, TQ_SLOT(printLog()), coll, "ksysv_print_log");
  mFilePrintLog->setText( i18n("&Print Log..."));
  mFilePrintLog->setEnabled (false);

  mFileQuit = KStdAction::quit(this, TQ_SLOT(close()), coll);

  // setup Edit menu
  mEditUndo = KStdAction::undo(this, TQ_SLOT(editUndo()), coll);
  mEditUndo->setEnabled (false);
  mEditRedo = KStdAction::redo(this, TQ_SLOT(editRedo()), coll);
  mEditUndo->setEnabled (false);
  mEditCut = KStdAction::cut(this, TQ_SLOT(editCut()), coll);
  mEditCopy = KStdAction::copy(this, TQ_SLOT(editCopy()), coll);
  mEditPaste = KStdAction::paste(this, TQ_SLOT(editPaste()), coll);
  mPasteAppend = KStdAction::paste (this, TQ_SLOT (pasteAppend()),
									coll, "ksysv_paste_append");

  mEditProperties = new TDEAction (i18n("P&roperties"), 0,
                                 this, TQ_SLOT(properties()),
                                 coll, "ksysv_properties");

  mOpenDefault = new TDEAction (i18n ("&Open"), 0,
                              this, TQ_SLOT (editService()),
                              coll, "ksysv_open_service");

  mOpenWith = new TDEActionMenu (i18n ("Open &With"), coll, "ksysv_open_with");

  // setup Settings menu
  createStandardStatusBarAction();
  setStandardToolBarMenuEnabled(true);
  KStdAction::keyBindings (this, TQ_SLOT(configureKeys()), coll);
  KStdAction::configureToolbars (this, TQ_SLOT(configureToolbars()), coll);
  KStdAction::saveOptions(this, TQ_SLOT(saveOptions()), coll);
  KStdAction::preferences(this, TQ_SLOT(slotShowConfig()), coll);
  mOptionsToggleLog = new TDEToggleAction (i18n("Show &Log"), "toggle_log", 0,
										 this, TQ_SLOT (toggleLog()),
										 coll, "ksysv_toggle_log");
  mOptionsToggleLog->setCheckedState(i18n("Hide &Log"));

  // setup Tools menu
  mToolsStartService = new TDEToggleAction (i18n("&Start Service..."), "ksysv_start", 0,
                                          mStartDlg, TQ_SLOT (toggle()),
                                          coll, "ksysv_start_service");

  mToolsStopService = new TDEToggleAction (i18n("&Stop Service..."), "ksysv_stop", 0,
                                         mStopDlg, TQ_SLOT (toggle()),
                                         coll, "ksysv_stop_service");

  mToolsRestartService = new TDEToggleAction (i18n("&Restart Service..."), 0,
                                            mRestartDlg, TQ_SLOT (toggle()),
                                            coll, "ksysv_restart_service");

  mToolsEditService = new TDEToggleAction (i18n("&Edit Service..."), 0,
                                         mEditDlg, TQ_SLOT (toggle()),
                                         coll, "ksysv_edit_service");

  createGUI(xmlFile());
}

//
bool KSVTopLevel::queryExit() 
{
  uint res = KMessageBox::Continue;

  if (mChanged) {
    res = KMessageBox::warningContinueCancel(kapp->mainWidget(),
				    i18n("There are unsaved changes. Are you sure you want to quit?"),
				    i18n("Quit"),
				    KStdGuiItem::quit());

  }

  return res == KMessageBox::Continue;
}

void KSVTopLevel::slotClearChanges()
{
  if (mChanged &&
      KMessageBox::Yes ==
      KMessageBox::questionYesNo(kapp->mainWidget(),
				 i18n("Do you really want to revert all unsaved changes?"),
				 i18n("Revert Configuration"),
				 i18n("&Revert"),
				 KStdGuiItem::cancel()))
    {
      mUndoList->undoAll();
	  mRedoList->clear();
    }
}

void KSVTopLevel::slotAcceptChanges() {
  if (KMessageBox::Continue ==
      KMessageBox::warningContinueCancel(kapp->mainWidget(),
				i18n("You're about to save the changes made to your init "
				     "configuration. Wrong settings can "
				     "make your system hang on startup.\n"
				     "Do you wish to continue?"),
				i18n("Save Configuration"),
				KStdGuiItem::save()))
    {
      mView->slotWriteSysV();
      initView();
    }
}

void KSVTopLevel::initView()
{
  const bool authEnabled = mAuth->isCheckEnabled();
  mAuth->setCheckEnabled(false);

  mUndoList->clear();
  mRedoList->clear();

  mView->initScripts();
  mView->initRunlevels();

  setChanged(false);

  // disable ToolsMenu_ entries when they can't do anything
  ServiceDlg* tmp = new ServiceDlg ("","", this);

  tmp->resetChooser (mView->scripts, false);
  if (!tmp->count())
    {
	  mToolsStartService->setEnabled (false);
	  mToolsStopService->setEnabled (false);
	  mToolsRestartService->setEnabled (false);
    }
  else
    {
	  mToolsStartService->setEnabled (true);
	  mToolsStopService->setEnabled (true);
	  mToolsRestartService->setEnabled (true);
    }

  tmp->resetChooser (mView->scripts, true);
  if (!tmp->count())
    {
	  mToolsEditService->setEnabled (false);
    }
  else
    {

	  mToolsEditService->setEnabled (true);
    }
  delete tmp;

  // reset tools
  mStartDlg->resetChooser (mView->scripts, false);
  mStopDlg->resetChooser (mView->scripts, false);
  mRestartDlg->resetChooser (mView->scripts, false);
  mEditDlg->resetChooser (mView->scripts, true);

  mAuth->setCheckEnabled(authEnabled);
}

void KSVTopLevel::initStatusBar()
{
  KStatusBar* status = statusBar();

  TQHBox* visBox = new TQHBox (status, "visBox");
  TQButtonGroup* group = new TQButtonGroup (this, "visButtonGroup");
  group->hide();
  connect (group, TQ_SIGNAL (clicked (int)), this, TQ_SLOT (toggleRunlevel (int)));

  TQWhatsThis::add (visBox, i18n ("<p>Click on the checkboxes to <strong>show</strong> or "\
                                 "<strong>hide</strong> runlevels.</p> " \
                                 "<p>The list of currently visible runlevels is saved "\
                                 "when you use the <strong>Save Options command</strong>.</p>"));
  TQToolTip::add (visBox, i18n ("Show only the selected runlevels"));

  new TQLabel (i18n("Show runlevels:"), visBox, "visLabel");
  for (int i = 0; i < ksv::runlevelNumber; ++i)
	{
	  TQString label; label.setNum (i);

	  mVisible[i] = new TQCheckBox (label, visBox, label.latin1());
	  mVisible[i]->setChecked (mConfig->showRunlevel (i));

	  group->insert (mVisible[i]);
	}

  TQHBox* authIconBox = new TQHBox (status, "AuthIconBox");
  TQWidget* strut = new TQWidget (authIconBox, "Strut");
  strut->setFixedWidth (KDialog::spacingHint());
  mAuth = new RunlevelAuthIcon (mConfig->scriptPath(), mConfig->runlevelPath(), authIconBox);
  connect (mAuth, TQ_SIGNAL (authChanged(bool)), mView, TQ_SLOT(multiplexEnabled(bool)));
  connect (mAuth, TQ_SIGNAL (authChanged(bool)), this, TQ_SLOT(writingEnabled(bool)));

  TQWhatsThis::add (authIconBox, i18n ("<p>If the lock is closed <img src=\"user|ksysv_locked\"/>, "\
                                      "you don't have the right " \
                                      "<strong>permissions</strong> to edit the init configuration.</p>" \
                                      "<p>Either restart %1 as root (or another more privileged user), " \
                                      "or ask your sysadmin to install %1 <em>suid</em> or " \
                                      "<em>sgid</em>.</p><p>The latter way is <strong>not</strong> "\
                                      "recommended though, due to security issues.</p>")
                   .arg (kapp->aboutData()->programName()).arg(kapp->aboutData()->programName()));

  authIconBox->setMinimumSize (authIconBox->minimumSizeHint());
  visBox->setMinimumSize (visBox->minimumSizeHint());

  status->addWidget (authIconBox, 0, false);
  status->insertItem ("", Status::Changed, 100);
  status->addWidget (visBox, 0, true);

  status->setItemAlignment (Status::Changed, AlignLeft|AlignVCenter);
}

void KSVTopLevel::slotShowConfig()
{
  if (!mPreferences)
    {
      mPreferences = KSVPreferences::self();

      connect (mPreferences, TQ_SIGNAL (updateColors ()),
               this, TQ_SLOT (updateColors ()));

      connect (mPreferences, TQ_SIGNAL (updateServicesPath ()),
               this, TQ_SLOT (updateServicesPath ()));

      connect (mPreferences, TQ_SIGNAL (updateRunlevelsPath ()),
               this, TQ_SLOT (updateRunlevelsPath ()));

      connect (mPreferences, TQ_SIGNAL (updateFonts ()),
               mView, TQ_SLOT (repaintRunlevels ()));
    }

//   mPreferences->setInitialSize (TQSize (400,300), true);
  mPreferences->exec();
}

void KSVTopLevel::updateColors ()
{
  ksv::serviceCompletion ()->clear ();

  mView->setColors (mConfig->newNormalColor(),
                    mConfig->newSelectedColor(),
                    mConfig->changedNormalColor(),
                    mConfig->changedSelectedColor());
}

void KSVTopLevel::updateServicesPath ()
{
  mView->updateServicesAfterChange (mConfig->scriptPath());
  mAuth->setServicesPath (mConfig->scriptPath());
}

void KSVTopLevel::updateRunlevelsPath ()
{
  mView->updateRunlevelsAfterChange ();
  mAuth->setRunlevelPath (mConfig->runlevelPath());
}

void KSVTopLevel::slotReadConfig() {
  setLog(mConfig->showLog());
}

void KSVTopLevel::toggleLog() {
  const bool value = !mConfig->showLog();
  setLog(value);
}

void KSVTopLevel::saveOptions()
{
  mConfig->writeSettings();
}

void KSVTopLevel::slotUpdateRunning (const TQString& text)
{
  statusBar()->changeItem(text, Status::Changed);
}

void KSVTopLevel::editCut() {
  KSVDragList* list = mView->getOrigin();

  if (list && list->currentItem())
	{
	  KSVDrag* mime = new KSVDrag (*list->currentItem()->data(), 0L, 0L);
	  kapp->clipboard()->setData (mime);

	  KSVData data = *list->currentItem()->data();
	  delete list->currentItem();

	  mUndoList->push (new RemoveAction (list, &data));
	  setChanged (true);
	}
}

void KSVTopLevel::editCopy()
{
  KSVDragList* list = mView->getOrigin();

  if (list)
	{
	  KSVDrag* mime = new KSVDrag (*static_cast<KSVItem*> (list->currentItem()), 0L, 0L);
	  kapp->clipboard()->setData (mime);
	}
}

void KSVTopLevel::editPaste()
{
  KSVDragList* list = mView->getOrigin();

  if (list)
    {
	  KSVData data;

	  if (KSVDrag::decodeNative (kapp->clipboard()->data(), data))
		{
		  KSVAction* action = 0L;

		  if (list->insert (data, list->currentItem(), action))
			{
			  setChanged (true);
			  mUndoList->push (new AddAction (list, list->match (data)->data()));
			}
		}
	}
  else
    tqFatal("Bug: could not get origin of \"Paste\" event.\n" \
		   "Please notify the maintainer of this program,\n" \
		   "Peter Putzer <putzer@kde.org>.");
}

void KSVTopLevel::setChanged (bool val)
{
  mChanged = val;
  setCaption(val);

  mFileRevert->setEnabled (val);
  mFileSave->setEnabled (val);

  // update statusbar
  statusBar()->changeItem(val ? i18n(" Changed") : TQString(), Status::Changed);

  // clear messages
  statusBar()->clear();
}

void KSVTopLevel::properties()
{
  KSVDragList* list = mView->getOrigin();

  if (list)
    mView->infoOnData(list->currentItem());
}

void KSVTopLevel::scriptProperties()
{
  KSVDragList* list = mView->getOrigin();

  if (list)
    mView->slotScriptProperties(list->currentItem());
}

void KSVTopLevel::editUndo ()
{
  KSVAction* action = mUndoList->top();

  mUndoList->undoLast();

  mRedoList->push (action);
}

void KSVTopLevel::editRedo ()
{
  KSVAction* action = mRedoList->top();

  mRedoList->redoLast();

  setChanged (true);
  mUndoList->push (action);
}

void KSVTopLevel::setPaste (bool val)
{
  mEditPaste->setEnabled (val);
  mPasteAppend->setEnabled (val);
}

void KSVTopLevel::setLog (bool val)
{
  mConfig->setShowLog(val);

  mOptionsToggleLog->setChecked (val);

  mView->setDisplayScriptOutput(val);
}

void KSVTopLevel::writingEnabled (bool on)
{
  mFileLoad->setEnabled(on);
}

void KSVTopLevel::print()
{
// #define checkPage if (metrics.height() - y < fm.lineSpacing()) prt.newPage();

//   static KPrinter prt;
//   prt.setDocName(kapp->aboutData()->programName() + " Configuration");
//   prt.setCreator(kapp->aboutData()->programName());

//   static TQPrintDialog* dlg = new TQPrintDialog (&prt, this, "KSysV Print Dialog");
//   dlg->setCaption(kapp->makeStdCaption (i18n("Print")));

//   if (dlg->exec() == TQDialog::Accepted)
//     {
//       int y = 10;
//       TQPainter p;
//       p.begin( &prt );

//       TQPaintDeviceMetrics metrics (&prt);

//       p.setFont (TQFont("courier", 20, TQFont::Bold));
//       TQFontMetrics fm = p.fontMetrics();

//       p.drawText (10, y, i18n("%1 Configuration of %2")
//                   .arg (kapp->aboutData()->programName())
//                   .arg (ksv::hostname()));
//       y += fm.lineSpacing();

//       p.drawText (10, y, TQDateTime::currentDateTime().toString());
//       y += fm.lineSpacing() * 2; // an extra empty line

//       for (int i = 0; i < ksv::runlevelNumber; ++i)
//         {
//           p.setFont (TQFont("courier", 16, TQFont::Bold));
//           TQFontMetrics fm = p.fontMetrics();

//           p.drawText (10, y, i18n ("Runlevel %1").arg(i));
//           y += fm.lineSpacing();

//           checkPage

//           p.drawText (10, y, i18n ("Started Services"));
//           y += fm.lineSpacing() * 2; // an extra empty line

//        checkPage

//           p.setFont (TQFont("courier", 10));
//           fm = p.fontMetrics();

//           for (TQListViewItemIterator it (mView->startRL[i]);
//                it.current();
//                ++it)
//             {
//               KSVItem* item = static_cast<KSVItem*> (it.current());

//               y += fm.ascent();
//               p.drawText (10, y, item->toString());
//               y += fm.descent();

//        checkPage

//             }

//           p.setFont (TQFont("courier", 16, TQFont::Bold));
//           fm = p.fontMetrics();
//           y += fm.lineSpacing(); // an extra empty line
//           p.drawText (10, y, i18n ("Stopped Services"));
//           y += fm.lineSpacing() * 2; // an extra empty line

//        checkPage

//           p.setFont (TQFont("courier", 10));
//           fm = p.fontMetrics();

//           for (TQListViewItemIterator it (mView->stopRL[i]);
//                it.current();
//                ++it)
//             {
//               KSVItem* item = static_cast<KSVItem*> (it.current());
//        checkPage

//               y += fm.ascent();
//               p.drawText (10, y, item->toString());
//               y += fm.descent();
//             }
//        checkPage

//           p.setFont (TQFont("courier", 16, TQFont::Bold));
//           fm = p.fontMetrics();
//           y += fm.lineSpacing() * 3; // two extra empty line
//         }
//       //      TQStringList lines = TQStringList::split ('\n', mView->log(), true);
//       //       for(TQStringList::Iterator it = lines.begin();
//       //           it != lines.end();
//       //           ++it)
//       //         {
//       //           y += fm.ascent();

//       //           TQString line = *it;
//       //           if (line.isNull())
//       //             line = " ";

//       //           line.replace( TQRegExp("\t"), "        " );

//       //           strncpy(buf,line.data(),160);

//       //           for (int j = 0 ; j <150; j++)
//       //             {
//       //               if (!isprint(buf[j]))
//       //                 buf[j] = ' ';
//       //             }

//       //           buf[line.length()] = '\0';
//       //           p.drawText( 10, y, buf );
//       //           y += fm.descent();
//       //         }

//       p.end();
//     }
}

void KSVTopLevel::printLog()
{
  KPrinter *prt = new KPrinter();
  prt->setDocName(kapp->aboutData()->programName() + " Log File");
  prt->setCreator(kapp->aboutData()->programName());

  if (prt->setup(this, i18n("Print Log File")))
    {
      KBusyManager::self()->setBusy (true);

      TQPainter p (prt);
      TQPaintDeviceMetrics pm (prt);
      const int height = pm.height();
      const int width = pm.width();

      TQStringList lines = TQStringList::split ('\n', mView->xmlLog(), true);
      TQStringList::Iterator line = lines.begin();

      int y = 0;

      {
        TQSimpleRichText rheading (i18n("<h1>TDE Sys-V Init Editor Log</h1>"),
                                  TQFont("times"), TQString(), ksv::styleSheet(),
                                  TQMimeSourceFactory::defaultFactory());
        rheading.setWidth (&p, width);
        int tmp_h = rheading.height();
        TQRegion region (0, y, width, tmp_h);
        rheading.draw (&p, 0, y, region, colorGroup(), 0L);

        y += tmp_h;

        TQSimpleRichText rdate (i18n("<h3>Printed on %1</h3><br/><br/>").arg(TDEGlobal::locale()->formatDateTime(TQDateTime::currentDateTime())),
                               TQFont("times"), TQString(), ksv::styleSheet(),
                               TQMimeSourceFactory::defaultFactory());
        rdate.setWidth (&p, width);
        tmp_h = rdate.height();
	TQRegion r2 (0, y, width, tmp_h);
        rdate.draw (&p, 0, y, r2, colorGroup(), 0L);

        y += tmp_h;
      }

      while (line != lines.end())
        {
          while (y < height)
            {
              TQSimpleRichText rich (*line, TQFont("times"), TQString(), ksv::styleSheet(),
                                    TQMimeSourceFactory::defaultFactory());
              rich.setWidth (&p, width);

              int tmp_h = rich.height();
              if (y + tmp_h > height)
                break;

              TQRegion region (0, y, width, tmp_h);
              rich.draw (&p, 0, y, region, colorGroup(), 0L);

              y += tmp_h;
              ++line;

              if (line == lines.end())
                goto printing_finished;

              kapp->processEvents();
            }

          prt->newPage();
          y = 0;
        }

    printing_finished:

      p.end();

      KBusyManager::self()->restore();
      delete prt;
    }
}

void KSVTopLevel::catchCannotGenerateNumber()
{
  if (mConfig->showMessage (ksv::CouldNotGenerateSortingNumber)) {
    KMessageBox::information (kapp->mainWidget(),
                              i18n ("<p>Unable to generate a valid " \
                                    "sorting number for this position. This means " \
                                    "that there was no number available between "\
                                    "the two adjacent services, and the service " \
                                    "did not fit in lexically.</p>" \
                                    "<p>Please adjust the sorting numbers manually "\
                                    "via the <strong>Properties dialog box</strong>.</p>"),
                              i18n ("Unable to Generate Sorting Number"),
                              ksv::notifications[ksv::CouldNotGenerateSortingNumber]);
  }

  statusBar()->message (i18n ("Unable to generate sorting number. Please change manually."),
                        5000);
}

void KSVTopLevel::closeEvent (TQCloseEvent* e)
{
  if (KBusyManager::self()->isBusy())
    {
      // do not allow a close during clearing => otherwise we get a segfault
	  e->ignore();
      return;
    }

  TDEMainWindow::closeEvent (e);
}

void KSVTopLevel::dispatchEdit ()
{
  KSVDragList* list = mView->getOrigin();

  if (!list)
    {
      mEditCopy->setEnabled (false);
      mEditCut->setEnabled (false);
      mEditProperties->setEnabled (false);
      setPaste (false);

      return;
    }

  KSVItem* current = list->currentItem();

  if (current) // there's a list, and it's got items...
	{
      mEditCopy->setEnabled (true);
      mEditCut->setEnabled (true);
      mEditProperties->setEnabled (true);
	}
  else // no current item
	{
      mEditCopy->setEnabled (false);
      mEditCut->setEnabled (false);
      mEditProperties->setEnabled (false);
	}

  if (mView->scripts == list)
	{
      mEditCut->setEnabled (false);
	  setPaste (false);
	}
  else
	{
	  TQMimeSource* mime = kapp->clipboard()->data();

	  if (mime && mime->provides ("application/x-ksysv"))
		setPaste (true);
	  else
		setPaste (false);
	}
}

void KSVTopLevel::enableUndo()
{
  mEditUndo->setEnabled (true);
}

void KSVTopLevel::disableUndo()
{
  mEditUndo->setEnabled (false);
  setChanged(false);
}

void KSVTopLevel::enableRedo()
{
  mEditRedo->setEnabled (true);
}

void KSVTopLevel::disableRedo ()
{
  mEditRedo->setEnabled (false);
}

void KSVTopLevel::slotSaveLog()
{
  static const TQString& filter = ksv::logFileFilter();
  static const TQString& ext = ksv::logFileExtension();
  TQString filename = KFileDialog::getSaveFileName(0L, filter, this);

  if (filename.isEmpty())
    return;
  else if (filename.right(ext.length()) != ext)
    filename += ext;

  TQFile file(filename);

  file.open( IO_WriteOnly | IO_Raw );
  TQTextStream s(&file);

  s << "TDE System V Init Editor"
    << endl
    << TQDateTime::currentDateTime().toString()
    << endl << endl
    << mView->log()
    << endl;

  file.close();
}

void KSVTopLevel::enableLogActions ()
{
  mFileSaveLog->setEnabled (true);
  mFilePrintLog->setEnabled (true); // disabled due to complexity
}

void KSVTopLevel::setCaption (bool changed)
{
  setPlainCaption (kapp->makeStdCaption(KNetwork::KResolver::localHostName(), true, changed));
}

TDEActionCollection* KSVTopLevel::filteredActions ()
{
  // remove unwanted (internal) actions
  static TDEActionCollection coll = *actionCollection();
  static bool initialized = false;

  if (!initialized)
    {
      coll.take(mPasteAppend);
      coll.take(mOpenDefault);
      initialized = true;
    }

  return &coll;
}

void KSVTopLevel::configureKeys ()
{
  KKeyDialog::configure (filteredActions(), this, true);
}

void KSVTopLevel::configureToolbars ()
{
  KEditToolbar dlg(filteredActions(), xmlFile(), true, this);
  connect(&dlg, TQ_SIGNAL( newToolbarConfig() ), this, TQ_SLOT( slotNewToolbarConfig() ));
  dlg.exec();
}

void KSVTopLevel::slotNewToolbarConfig()
{
  createGUI (xmlFile());
}

void KSVTopLevel::dispatchEditService (bool val)
{
  mToolsEditService->setChecked (val);
}

void KSVTopLevel::dispatchStartService (bool val)
{
  mToolsStartService->setChecked (val);
}

void KSVTopLevel::dispatchStopService (bool val)
{
  mToolsStopService->setChecked (val);
}

void KSVTopLevel::dispatchRestartService (bool val)
{
  mToolsRestartService->setChecked (val);
}

void KSVTopLevel::pasteAppend ()
{
  mView->pasteAppend ();
}

void KSVTopLevel::editService ()
{
  mView->editService ();
}

void KSVTopLevel::toggleRunlevel (int index)
{
  bool state = mVisible[index]->isChecked();

  if (state)
	mView->showRunlevel (index);
  else
	mView->hideRunlevel (index);

  mConfig->setShowRunlevel (index, state);
}

void KSVTopLevel::saveAs ()
{
  static const TQString& filter = ksv::nativeFileFilter();
  static const TQString& ext = ksv::nativeFileExtension();
  TQString filename = KFileDialog::getSaveFileName(0L, filter, this);

  if (filename.isEmpty())
    return;
  else if (filename.right(ext.length()) != ext)
    filename += ext;

  TQFile file(filename);
  // we're busy
  KBusyManager::self()->setBusy (true);

  file.open (IO_WriteOnly | IO_Raw);
  TQDataStream s (&file);

  if (ksv::IO::saveConfiguration (s, mView->startRL, mView->stopRL))
    {
      statusBar()->message(i18n("Configuration package saved successfully."), 5000);
    }
  else
    {
      kdDebug(3000) << "ERROR saving file" << endl;
    }

  file.close();

  KBusyManager::self()->restore();
}

void KSVTopLevel::load ()
{
  static const TQString& filter = ksv::nativeFileFilter();
  TQString filename = KFileDialog::getOpenFileName(0L, filter, this);

  if (filename.isEmpty())
    return;

  TQFile file(filename);
  KBusyManager::self()->setBusy (true);

  file.open (IO_ReadOnly | IO_Raw);
  TQDataStream s (&file);
  TQValueList<KSVData>* startLists = new TQValueList<KSVData>[ksv::runlevelNumber];
  TQValueList<KSVData>* stopLists = new TQValueList<KSVData>[ksv::runlevelNumber];

  if (ksv::IO::loadSavedConfiguration (s, startLists, stopLists))
    {
      statusBar()->message(i18n("Configuration package loaded successfully."), 5000);
      mView->mergeLoadedPackage (startLists, stopLists);
    }
  else
    {
      kdDebug (3000) << "ERROR loading file" << endl;
    }

  file.close();

  delete[] startLists;
  delete[] stopLists;

  KBusyManager::self()->restore();
}

void KSVTopLevel::pushUndoAction (KSVAction* action)
{
  mRedoList->clear();
  mUndoList->push (action);

  setChanged(true);
}

#include "TopWidget.moc"
