/***************************************************************************
                          knowit.cpp  -  description
                             -------------------
    begin                : czw wrz 26 08:27:40 CEST 2002
    copyright            : (C) 2002-2004 by Micha� Rudolf
    email                : mrudolf@kdewebdev.org
 ***************************************************************************/

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

#include <tqtimer.h>
#include <tqclipboard.h>
#include <tqdatetime.h>
#include <tqdir.h>
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqpainter.h>
#include <tqpaintdevicemetrics.h>
#include <tqwhatsthis.h>
#include <tqsimplerichtext.h>
#include <tqsplitter.h>

#include <tdeaction.h>
#include <tdecmdlineargs.h>
#include <kcolordialog.h>
#include <tdeconfig.h>
#include <kedittoolbar.h>
#include <tdefiledialog.h>
#include <kkeydialog.h>
#include <tdemenubar.h>
#include <tdemessagebox.h>
#include <kmimetype.h>
#include <tdepopupmenu.h>
#include <kprinter.h>
#include <kstatusbar.h>
#include <ktip.h>
#include <kpropertiesdialog.h>
#include <kinputdialog.h>

#include "knowit.h"
#include "knowitapp.h"
#include "knowittray.h"
#include "knowittree.h"
#include "knowitlinks.h"

const TQString Knowit::Untitled = i18n("untitled") + ".kno";

Knowit::Knowit(TQWidget*, const char *name) : TDEMainWindow(0, name),
   FindDlg(), PrefDlg(), ChooserDlg(), LinkDlg(), Notes()
{

   statusBar()->insertItem(i18n("Ready"), 0);
   Layout = new TQSplitter(this);
   Items = new KnowitTree(Layout, "Items");
   TQSplitter* EditLayout = new TQSplitter(Layout);
   EditLayout->setOrientation(TQt::Vertical);
   Edit = new KnowitEdit(EditLayout, "Edit");
   Links = new KnowitLinks(EditLayout);

   connect(&FindDlg, TQ_SIGNAL(search()), this, TQ_SLOT(slotEditFind()));
   lastSought = 0;

   /* main view */
   setAutoSaveSettings();
   setCentralWidget(Layout);

   TQWhatsThis::add(Layout, i18n("Move it to change tree/edit layout."));
   connect(Items, TQ_SIGNAL(contextMenu(TDEListView*, TQListViewItem*, const TQPoint&)),
     this, TQ_SLOT(slotContextMenu(TDEListView*, TQListViewItem*, const TQPoint&)));
   connect(Items, TQ_SIGNAL(selectionChanged(TQListViewItem*)), this,
     TQ_SLOT(slotItemChanged(TQListViewItem*)));
   connect(Items, TQ_SIGNAL(selectionChanged(TQListViewItem*)), this,
     TQ_SLOT(slotItemChanged(TQListViewItem*)));

   /* Edit (TQTextEdit) */
   Edit->setMinimumSize(200, 150);
   Edit->setTextFormat(TQt::RichText);
   TQWhatsThis::add(Edit, i18n("<h2>Note text</h2>Add text for selected note here.\n"
      "Text can be formatted, for example <b>bold</b> or <i>italic</i>."));
   connect(Edit, TQ_SIGNAL(selectionChanged()), this, TQ_SLOT(slotEditChanged()));
   connect(Edit, TQ_SIGNAL(textChanged()), this, TQ_SLOT(slotEditChanged()));
   connect(Edit, TQ_SIGNAL(cursorPositionChanged(int, int)), this,
     TQ_SLOT(slotEditCursorChanged(int, int)));
   connect(Edit, TQ_SIGNAL(textDropped(const TQString&, int)),
      this, TQ_SLOT(slotLinkDropped(const TQString&, int)));

   /* Links (TDEListBox) */
   connect(Links, TQ_SIGNAL(doubleClicked(TQListBoxItem*)),
      this, TQ_SLOT(slotShowAttachment(TQListBoxItem*)));
   connect(Links, TQ_SIGNAL(contextMenuRequested(TQListBoxItem*, const TQPoint&)),
      this, TQ_SLOT(slotContextLinksMenu(TQListBoxItem*, const TQPoint&)));
   connect(Links, TQ_SIGNAL(textDropped(const TQString&, int)),
      this, TQ_SLOT(slotLinkDropped(const TQString&, int)));
   connect(Links, TQ_SIGNAL(linkRemove()), this, TQ_SLOT(slotLinkRemove()));
   connect(Links, TQ_SIGNAL(linkOpen()), this, TQ_SLOT(slotLinkOpen()));
   connect(Links, TQ_SIGNAL(linkOpenWith()), this, TQ_SLOT(slotLinkOpenWith()));

   /* Actions: File */
   KStdAction::openNew(this, TQ_SLOT(slotFileNew()), actionCollection());
   KStdAction::open(this, TQ_SLOT(slotFileOpen()), actionCollection());
   actionRecent = KStdAction::openRecent(this, TQ_SLOT(slotFileRecent(const KURL&)), actionCollection());
   KStdAction::save(this, TQ_SLOT(slotFileSave()), actionCollection());
   KStdAction::saveAs(this, TQ_SLOT(slotFileSaveAs()), actionCollection());
   new TDEAction(i18n("&Export to HTML..."), "", "", this,
      TQ_SLOT(slotFileExport()), actionCollection(), "file_export_html");
   KStdAction::print(this, TQ_SLOT(slotFilePrint()), actionCollection());
   new TDEAction(i18n("Document &information..."), "", "", this,
      TQ_SLOT(slotFileInfo()), actionCollection(), "file_info");
   new TDEAction(i18n("&Properties..."), "document-properties", "", this,
      TQ_SLOT(slotFileProperties()), actionCollection(), "file_properties");
   KStdAction::quit(this, TQ_SLOT(slotFileQuit()), actionCollection());

   /* Actions: Edit */
   actionCut = KStdAction::cut(Edit, TQ_SLOT(cut()), actionCollection());
   actionCopy = KStdAction::copy(Edit, TQ_SLOT(copy()), actionCollection());
   KStdAction::paste(Edit, TQ_SLOT(paste()), actionCollection());
   actionUndo = KStdAction::undo(Edit, TQ_SLOT(undo()), actionCollection());
   actionRedo = KStdAction::redo(Edit, TQ_SLOT(redo()), actionCollection());
   actionBold = new TDEToggleAction(i18n("Toggle &bold"), "format-text-bold",
      "Ctrl+B", this, TQ_SLOT(slotEditBold()), actionCollection(), "edit_bold");
   actionItalic = new TDEToggleAction(i18n("Toggle &italic"), "format-text-italic",
      "Ctrl+I", this, TQ_SLOT(slotEditItalic()), actionCollection(),
      "edit_italic");
   actionUnderline = new TDEToggleAction(i18n("Toggle &underline"), "format-text-underline",
      "Ctrl+U", this, TQ_SLOT(slotEditUnderline()), actionCollection(),
      "edit_underline");
   new TDEAction(i18n("&Text color..."), "color_line", "Ctrl+#", this,
      TQ_SLOT(slotEditColor()), actionCollection(), "edit_color");
   new TDEAction(i18n("&Superscript"), "text_super", "", this,
      TQ_SLOT(slotEditSuperscript()), actionCollection(), "edit_superscript");
   new TDEAction(i18n("&Subscript"), "text_sub", "", this,
      TQ_SLOT(slotEditSubscript()), actionCollection(), "edit_subscript");
   new TDEAction(i18n("&Normal text"), "", "", this,
      TQ_SLOT(slotEditNormal()), actionCollection(), "edit_align_normal");
   new TDEAction(i18n("&Bullet list"), "", "", this,
      TQ_SLOT(slotEditListBullet()), actionCollection(), "list_bullet");
   new TDEAction(i18n("&Numbered list"), "", "", this,
      TQ_SLOT(slotEditListNumber()), actionCollection(), "list_number");
   new TDEAction(i18n("&Uppercase list"), "", "", this,
      TQ_SLOT(slotEditListUpper()), actionCollection(), "list_upper");
   new TDEAction(i18n("&Lowercase list"), "", "", this,
      TQ_SLOT(slotEditListLower()), actionCollection(), "list_lower");
   new TDEAction(i18n("N&o list"), "", "", this,
      TQ_SLOT(slotEditListNone()), actionCollection(), "list_none");
   KStdAction::find(&FindDlg, TQ_SLOT(exec()), actionCollection());
   KStdAction::findNext(this, TQ_SLOT(slotEditFindNext()), actionCollection());
   new TDEAction(i18n("&Go to &note..."), "goto", "Ctrl+G", this,
      TQ_SLOT(slotEditGoTo()), actionCollection(), "goto_note");
   actionEditAlignLeft = new TDEToggleAction(i18n("Align &left"), "format-text-direction-ltr", "Ctrl+L", this,
      TQ_SLOT(slotEditAlignLeft()), actionCollection(), "edit_align_left");
   actionEditAlignRight = new TDEToggleAction(i18n("Align &right"), "format-text-direction-rtl", "Ctrl+R",
      this, TQ_SLOT(slotEditAlignRight()), actionCollection(), "edit_align_right");
   actionEditAlignJustify = new TDEToggleAction(i18n("&Justify"), "text_block", "Ctrl+J",
      this, TQ_SLOT(slotEditAlignJustify()), actionCollection(), "edit_align_justify");
   actionEditAlignCenter = new TDEToggleAction(i18n("&Center"), "text_center", "Ctrl+E", this,
      TQ_SLOT(slotEditAlignCenter()), actionCollection(), "edit_align_center");
   new TDEAction(i18n("Insert &date"), "date", "F5", this,
      TQ_SLOT(slotEditInsertDate()), actionCollection(), "edit_insert_date");
   new TDEAction(i18n("Insert &file..."), "", "", this,
      TQ_SLOT(slotEditInsertFile()), actionCollection(), "edit_insert_file");
   actionRawTextMode = new TDEToggleAction(i18n("&Raw Text Mode"),
       "text-x-src", "F10", this, TQ_SLOT(slotRawTextMode()),
       actionCollection(), "edit_raw_text");

   /* Actions: edit setup */
   actionCut->setEnabled(false);
   actionCopy->setEnabled(false);
   connect(Edit, TQ_SIGNAL(copyAvailable(bool)), actionCut, TQ_SLOT(setEnabled(bool)));
   connect(Edit, TQ_SIGNAL(copyAvailable(bool)), actionCopy, TQ_SLOT(setEnabled(bool)));
   connect(Edit, TQ_SIGNAL(undoAvailable(bool)), actionUndo, TQ_SLOT(setEnabled(bool)));
   connect(Edit, TQ_SIGNAL(redoAvailable(bool)), actionRedo, TQ_SLOT(setEnabled(bool)));

   /* Actions: notes */
   new TDEAction(i18n("&Add"), "", "Alt+Insert", this, TQ_SLOT(slotNoteAdd()),
      actionCollection(), "note_add");
   new TDEAction(i18n("Add &subnote"), "", "Alt+Shift+Insert", this,
      TQ_SLOT(slotNoteAddChild()), actionCollection(), "note_add_child");
   new TDEAction(i18n("&Delete"), "", "Alt+Delete", this,
      TQ_SLOT(slotNoteRemove()), actionCollection(), "note_delete");
   new TDEAction(i18n("&Rename"), "", "F2", this,
      TQ_SLOT(slotNoteRename()), actionCollection(), "note_rename");
   new TDEAction(i18n("E&xpand all"), "", "", Items,
      TQ_SLOT(slotExpandAll()), actionCollection(), "note_expand_all");
   new TDEAction(i18n("&Expand current"), "", "Alt++", Items,
      TQ_SLOT(slotExpand()), actionCollection(), "note_expand");
   new TDEAction(i18n("Co&llapse all"), "", "", Items,
      TQ_SLOT(slotCollapseAll()), actionCollection(), "note_collapse_all");
   new TDEAction(i18n("&Collapse current"), "", "Alt+-", Items,
      TQ_SLOT(slotCollapse()), actionCollection(), "note_collapse");
   new TDEAction(i18n("Move up"), "go-up", "Alt+Shift+Up", this,
      TQ_SLOT(slotNoteMoveUp()), actionCollection(), "note_move_up");
   new TDEAction(i18n("Move down"), "go-down", "Alt+Shift+Down", this,
      TQ_SLOT(slotNoteMoveDown()), actionCollection(), "note_move_down");
   new TDEAction(i18n("Move level up"), "back", "Alt+Shift+Left", this,
      TQ_SLOT(slotNoteMoveLeft()), actionCollection(), "note_move_left");
   new TDEAction(i18n("Move level down"), "forward", "Alt+Shift+Right", this,
      TQ_SLOT(slotNoteMoveRight()), actionCollection(), "note_move_right");
   new TDEAction(i18n("Move at the beginning"), "go-top", "Alt+Shift+Home", this,
      TQ_SLOT(slotNoteMoveBegin()), actionCollection(), "note_move_begin");
   new TDEAction(i18n("Move at the end"), "go-bottom", "Alt+Shift+End", this,
      TQ_SLOT(slotNoteMoveEnd()), actionCollection(), "note_move_end");
   new TDEAction(i18n("Sort"), "", "", this,
      TQ_SLOT(slotNoteSort()), actionCollection(), "note_sort");

   /* Actions: Links */
   new TDEAction(i18n("&Add link..."), "attach", "Ctrl+Shift+I", this,
      TQ_SLOT(slotLinkAdd()), actionCollection(), "link_add");
   new TDEAction(i18n("&Remove link"), "", "", this,
      TQ_SLOT(slotLinkRemove()), actionCollection(), "link_remove");
   new TDEAction(i18n("Open link"), "system-run", "", this,
      TQ_SLOT(slotLinkOpen()), actionCollection(), "link_open");
   new TDEAction(i18n("Open link with..."), "", "", this,
      TQ_SLOT(slotLinkOpenWith()), actionCollection(), "link_open_with");
   new TDEAction(i18n("&Modify link..."), "", "", this,
      TQ_SLOT(slotLinkModify()), actionCollection(), "link_modify");
   new TDEAction(i18n("&Copy link location"), "", "", this,
      TQ_SLOT(slotLinkCopy()), actionCollection(), "link_copy");

   /* Actions: Options */
   KStdAction::keyBindings(this, TQ_SLOT(slotOptionsKeys()), actionCollection());
   KStdAction::configureToolbars(this, TQ_SLOT(slotOptionsToolbar()), actionCollection());
   KStdAction::preferences(this, TQ_SLOT(slotOptions()), actionCollection());

   /* Actions: Help */
   new TDEAction(i18n("&Tip of the day"), "idea", "", this,
      TQ_SLOT(slotHelpTip()), actionCollection(), "help_tip");

   /* Actions: nonplugged */
   new TDEAction(i18n("Minimize"), "", "", this, TQ_SLOT(showMinimized()),
      actionCollection(), "window_minimize");
   new TDEAction(i18n("Switch area"), "", "Ctrl+M", this,
      TQ_SLOT(slotEditSwitch()), actionCollection(), "edit_switch");
   new TDEAction(i18n("Overwrite Mode"), "", "Insert", this,
      TQ_SLOT(slotOverwriteModeChange()), actionCollection(), "overwrite_mode_change");
   new TDEAction(i18n("Go to previous note"), "", "Alt+Up", Items,
      TQ_SLOT(slotItemUp()), actionCollection(), "note_previous");
   new TDEAction(i18n("Go to next note"), "", "Alt+Down", Items,
      TQ_SLOT(slotItemDown()), actionCollection(), "note_next");
   new TDEAction(i18n("Go to first note"), "", "Alt+Home", Items,
      TQ_SLOT(slotItemBegin()), actionCollection(), "note_begin");
   new TDEAction(i18n("Go to last note"), "", "Alt+End", Items,
      TQ_SLOT(slotItemEnd()), actionCollection(), "note_end");
   new TDEAction(i18n("Go to first subnote"), "", "Alt+Right", Items,
      TQ_SLOT(slotItemRight()), actionCollection(), "note_right");
   new TDEAction(i18n("Go to parent note"), "", "Alt+Left", Items,
      TQ_SLOT(slotItemLeft()), actionCollection(), "note_left");

   /* Actions */
   setStandardToolBarMenuEnabled(true);
   createGUI("knowitui.rc", false);

   /* Last save date */
   TQString t = TDEGlobal::locale()->formatDateTime(TQDateTime::currentDateTime(), true, true);
   statusBar()->insertFixedItem(t, StatusLastSave, true);
   statusBar()->changeItem(i18n("Not saved"), StatusLastSave);

   /* Insert/overwrite mode */
   statusBar()->insertFixedItem(("WWW"), StatusOvr, true);
   statusBar()->changeItem(i18n("INS"), StatusOvr);
   connect(statusBar(), TQ_SIGNAL(pressed(int)), this,
      TQ_SLOT(slotOverwriteModeChange(int)));

   /* System tray */
   systray = new KnowitTray(this, "Systray");
   systray->setPixmap(Notes.Pixmaps[1]);
   systray->setAlignment(TQt::AlignHCenter | TQt::AlignVCenter);

   /* Autosave */
   AutosaveTimer = new TQTimer(this);
   connect(AutosaveTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotFileAutosave()));

   /* Configuration */
   config = kapp->config();
   readOptions();

   if (Options.docked && Options.dockOnStart)
       hide();
   else
       show();

   bool opened = false;
   TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
   for(int i = 0; i < args->count(); i++)
       if (open(args->url(i))) {
          opened = true; break;
          }
   args->clear();

   if (!opened && Options.reopen && filename.path() != "")
      open(KURL(filename));

   slotActionUpdate();

   KTipDialog::showTip(this);

   shuttingDown = false;

   applyMainWindowSettings(config);

   /* check if knowituirc was found */
   TQWidget *w = factory()->container("notes_popup", this);
   if (!w)
      KMessageBox::error(0, i18n("<qt><p>Cannot open resource file <b>knowitui.rc</b>. "
          "Some of the menus and toolbars will be missing.</p>"
          "<p>Probably Knowit was not installed properly. "
	  "If you installed from source, please invoke <i>make install</i>."
	  "If you use precompiled package, please contact packager.</p></qt>"));
}

Knowit::~Knowit()
{
   delete systray;
   delete AutosaveTimer;
}

bool Knowit::open(const KURL& fname)
{
   TQFile file(fname.path());
   if (!file.open(IO_ReadOnly)) {
      KMessageBox::error(0, i18n("<qt>Cannot open file<br><b>%1</b></qt>")
         .arg(fname.url()));
      if (filename == fname)
         filename = "";
      return false;
      }
   uint prevdepth = 0;
   reset();
   TQTextStream ts(&file);
   ts.setEncoding(TQTextStream::UnicodeUTF8);
   TQString s = "";
   TQListViewItem* current = 0;
   TQListViewItem* active = 0;
   Notes.autoUpdate = false;
   while (!s.isNull()) {
      s = ts.readLine();
      if (s.left(9) == "\\NewEntry" || s.left(13) == "\\CurrentEntry") {
         TQString name;
         uint depth;
         TQTextIStream ls(&s);
         ls >> name >> depth;
         name = ls.readLine();
         name = name.stripWhiteSpace();
         if (depth == prevdepth) /* same level */
            if (depth) current = new TDEListViewItem(current->parent(), current, name);
            else current = new TDEListViewItem(Items, current, name);
         else if (depth > prevdepth)   /* subnote */
            current = new TDEListViewItem(current, name);
         else {   /* parent note */
            for(uint i=depth; i<prevdepth && current; i++)
               current = current->parent();
            if (current && current->parent())
               current = new TDEListViewItem(current->parent(), current, name);
            else current = new TDEListViewItem(Items, current, name);
         }
         prevdepth = depth;
         Notes.addNote(current);
         Notes.find(current)->open(ts);
         if (s.left(13) == "\\CurrentEntry")
            active = current;
      }
   }
   Notes.autoUpdate = true;
   Notes.updateNotesView();
   filename = fname;
   setCaption(fname.fileName());
   Notes.modified = false;
   Edit->clear();
   slotNoteChanged(active);
   Edit->setModified(false);
   actionRecent->addURL(filename);
   slotStatusMsg(i18n("File %1 opened.").arg(filename.fileName()));
   slotActionUpdate();

   TQFileInfo fi(file);
   slotStatusLastSave(fi.lastModified());

   file.close();
   if (Options.backup)
     URLOperator.copy(fname.path(), fname.path() + "~", false, false);
   if (Options.autosave)
     AutosaveTimer->start(Options.autosave * 60 * 1000, true);
   return true;
}

bool Knowit::save(const KURL& fname)
{
  TQFile file(fname.path());
  if (!file.open(IO_WriteOnly)) {
     KMessageBox::error(0, i18n("<qt>Cannot save file<br><b>%1</b></qt>")
         .arg(fname.url()));
     return false;
     }
  if (Items->prevItem && Edit->isModified())
     Notes.changeNote(Items->prevItem, Edit->length() ? Edit->text() : TQString());

  TQTextStream ts(&file);
  ts.setEncoding(TQTextStream::UnicodeUTF8);
  for (TQListViewItemIterator it(Items); it.current(); it++)
     Notes.find(it.current())->save(ts, it.current() == Items->currentItem());
  filename = fname;
  setCaption(fname.fileName());
  Notes.modified = false;
  Edit->setModified(false);
  actionRecent->addURL(filename);
  slotStatusMsg(i18n("File %1 saved.").arg(filename.fileName()));
  slotStatusLastSave(TQDateTime::currentDateTime());
  if (Options.autosave)
     AutosaveTimer->start(Options.autosave * 60 * 1000, true);
  return true;
}

void Knowit::reset()
{
   Items->prevItem = 0;
   Notes.clearNotes();
   Items->clear();
   Edit->clear();
   filename = "";
   setCaption(Untitled);
   Notes.modified = false;
   slotActionUpdate();
   statusBar()->changeItem(i18n("Not saved"), StatusLastSave);
}



void Knowit::closeEvent(TQCloseEvent* e)
{
   if (!Options.docked || ((KnowitApplication*)kapp)->closeByLogout()) {
      saveOptions();
      TDEMainWindow::closeEvent(e);
      }
   else
      hide();
}

bool Knowit::queryClose()
{
   if (!modified()) return shuttingDown = true;
   else if (Options.unconditionalSave) {
       slotFileSave();
       return shuttingDown = filename.isEmpty() || !modified()  || (KMessageBox::questionYesNo(0,
           i18n("<qt>File <b>%1</b><br>\ncannot be saved. Quit anyway?</qt>").arg(filename.fileName()))
	   == KMessageBox::Yes);
       }
   else
      switch (KMessageBox::questionYesNoCancel(0,
       i18n("<qt>File <b>%1</b><br>\nwas modified. Do you want to save it?</qt>")
          .arg(filename.isEmpty() ? Untitled : filename.fileName()))) {
      case KMessageBox::Yes:
         slotFileSave();
         return shuttingDown = !modified();
      case KMessageBox::No:
         return shuttingDown = true;
      default:
         return false;
      }
}

bool Knowit::queryExit()
{
   if (!shuttingDown) {
      /* brutally closed by session manager */
      if (modified())
         save(filename.isEmpty() ? i18n("untitled.kno") : filename);
      saveOptions();
   }
   return true;
}


void Knowit::find(TQListViewItem* start)
{
   if (soughtText.isEmpty() || !Items->firstChild()) return;
   if (start && lastSought == start &&
      Edit->find(soughtText, FindDlg.case_sensitive(), false))
      return;
   if (!start) start = Items->firstChild();
   TQListViewItemIterator it(start);
   while (it.current()) {
      TQString s = Notes.text(it.current());
      if (lastSought != it.current() &&
         s.contains(soughtText, FindDlg.case_sensitive())) {
         slotNoteChanged(it.current());
         Edit->find(soughtText, FindDlg.case_sensitive(), false);
         lastSought = it.current();
         return;
      }
      it++;
   }
   KMessageBox::information(0, i18n("<qt>Sought text:<br><b>%1</b><br>not found.</qt>").arg(soughtText));
}


void Knowit::saveOptions()
{
  config->setGroup("MainWindow");
  config->writeEntry("Widgets", Layout->sizes());
  Options.save(config);
  config->setGroup("General");
  config->writeEntry("Minimized", isMinimized() || !isVisible());
  config->writeEntry("LastFile", filename.path());
  config->writeEntry("Geometry", size());
  actionCollection()->writeShortcutSettings("Keys", config);
  config->deleteGroup("Recent Files");
  actionRecent->saveEntries(config, "Recent Files");
  saveMainWindowSettings(config);
}

void Knowit::readOptions()
{
   config->setGroup("MainWindow");
   TQValueList<int> sizes = config->readIntListEntry("Widgets");
   if (sizes.count() == 2)
      Layout->setSizes(sizes);
   Options.read(config);
   config->setGroup("General");
   TQString oldfile = config->readEntry("LastFile");
   TQSize defSize = size();
   resize(config->readSizeEntry("Geometry", &defSize));
   actionCollection()->readShortcutSettings("Keys", config);
   actionRecent->loadEntries(config,"Recent Files");
   if (!oldfile.isEmpty())
      filename = KURL(oldfile);
   applyOptions(Options);
}

void Knowit::slotNoteChanged(TQListViewItem* item)
{
   if (item) {
      if (Options.autoCollapse)
         Items->slotCollapseAll();
      Items->setCurrentItem(item);
      Items->setSelected(item, true);
      Items->ensureItemVisible(item);
   }
}

bool Knowit::modified()
{
   return Notes.modified || (Items->currentItem() && Edit->isModified());
}

void Knowit::applyOptions(const KnowitOptions& O, bool store)
{
   if (store) Options = O;
   if (O.docked)
      systray->show();
   else
      systray->hide();

   if (O.customColors) {
      Edit->setPaletteForegroundColor(TQColor(Options.foreEditColor));
      Edit->setPaletteBackgroundColor(TQColor(Options.backEditColor));
   }
   else Edit->unsetPalette();

   if (Options.customFont)
      Edit->setFont(TQFont(Options.fontFamily, Options.fontSize));
   else
      Edit->unsetFont();

   Edit->setWordWrap(O.wordwrap ? TQTextEdit::WidgetWidth : TQTextEdit::NoWrap);
   Edit->setTabChangesFocus(O.tabfocus);
   if (!O.autosave)
       AutosaveTimer->stop();
   else
       AutosaveTimer->start(O.autosave * 60 * 1000, true);
   Edit->swapEOL = O.enterBreakLine;
   Layout->setOrientation(O.horizontalSplit ? TQt::Horizontal :
         TQt::Vertical);
   Items->setAlternateBackground(O.alternateTree ? TQColor(O.alternateColor) : TQColor());
   Items->repaintContents();
   if (Items->currentItem())
      slotItemChanged(Items->currentItem());
   slotNoteChanged(Items->currentItem());
}

TNote* Knowit::currentNote() const
{
   if (!Items->currentItem()) return 0;
   return Notes.find(Items->currentItem());
}






/*** Slots ***/
void Knowit::slotStatusMsg(const TQString &text)
{
   statusBar()->clear();
   statusBar()->changeItem(text, 0);
}


void Knowit::slotStatusLastSave(const TQDateTime &timestamp)
{
    TQString t = TDEGlobal::locale()->formatDateTime(timestamp, true, true);
    statusBar()->changeItem(t, StatusLastSave);
}


void Knowit::slotContextMenu(TDEListView*, TQListViewItem*, const TQPoint& p)
{
   TQWidget *w = factory()->container("notes_popup", this);
   if (w)
      static_cast<TQPopupMenu *>(w)->exec(p);
}


void Knowit::slotContextLinksMenu(TQListBoxItem*, const TQPoint& p)
{
   TQWidget *w = factory()->container("links_popup", this);
   if (w)
      static_cast<TQPopupMenu *>(w)->exec(p);
}



/******* Slots: Notes *******/
void Knowit::slotNoteAdd()
{
   bool Ok;
   TDEListViewItem* elt;
   TQString text = KInputDialog::getText(i18n("Add note"),
      i18n("Note title:"), Options.defaultName, &Ok);
   if (!Ok) return;
   if (Items->currentItem())
      if (Items->currentItem()->parent())
         elt = new TDEListViewItem(Items->currentItem()->parent(),
            Items->currentItem(), text);
      else
         elt = new TDEListViewItem(Items, Items->currentItem(), text);
   else
      elt = new TDEListViewItem(Items, text);
   Notes.addNote(elt);
   slotNoteChanged(elt);
   if (Notes.count() == 1)
      slotActionUpdate();
}

void Knowit::slotNoteAddChild()
{
   if (!Items->currentItem()) {
      KMessageBox::error(0, i18n("You have to choose note before adding subnote."));
      return;
   }
   bool Ok;
   TQString text = KInputDialog::getText(i18n("Add subnote"),
      i18n("Note title:"), Options.defaultName, &Ok);
   if (!Ok) return;
   TQListViewItem* lastChild = Items->currentItem()->firstChild();
   while (lastChild && lastChild->nextSibling())
      lastChild = lastChild->nextSibling();

   TDEListViewItem* elt;
   if (lastChild)
       elt = new TDEListViewItem(Items->currentItem(), lastChild, text);
   else
      elt = new TDEListViewItem(Items->currentItem(), text);
   Notes.addNote(elt);
   slotNoteChanged(elt);
}

void Knowit::slotNoteRemove()
{
   TQListViewItem* elt = Items->currentItem();
   if (!elt) return;
   TQString msg = elt->childCount() ?
      i18n("<qt>Are you sure you want to delete note<br><b>%1</b><br> "
         "and its subnotes?</qt>") :
      i18n("<qt>Are you sure you want to delete note<br><b>%1</b>?</qt>");
   if (KMessageBox::questionYesNo(0, msg.arg(elt->text(0))) == KMessageBox::Yes) {
      TQListViewItem* parent = elt->parent();
      Notes.removeNote(elt);
      if (!Notes.count())
         slotActionUpdate();
      if (!parent)
         parent = Items->firstChild();
      Items->prevItem = 0;
      slotNoteChanged(parent);
      }
}

void Knowit::slotNoteRename()
{
    if (Items->currentItem()) {
       Items->currentItem()->setRenameEnabled(0, true);
       Items->currentItem()->startRename(0);
       }
}






void Knowit::slotItemChanged(TQListViewItem* i)
{
   if (Items->prevItem && Edit->isModified())
      Notes.changeNote(Items->prevItem, Edit->length() ? Edit->text() : TQString());
   Items->prevItem = i;
   TQString s;
   if (!Items->prevItem || (s = Notes.text(Items->prevItem)).isEmpty())
      Edit->setText("");
   else
      Edit->setText(s);
   Edit->setModified(false);
   Links->clear();
   TNote* note = Notes.find(i);
   if (note)
      for (int j=0; j<note->linkCount(); j++)
         Links->insertItem(note->link(j).icon(), note->link(j).text(Options.linkFormat));
   if (Links->count())
      Links->show();
   else
      Links->hide();
}

void Knowit::slotNoteMoveUp()
{
   TQListViewItem* elt = Items->currentItem();
   if (elt && elt->itemAbove()) {
      TQListViewItem* above = elt->parent() ? elt->parent()->firstChild()
         : Items->firstChild();
      if (above == elt)
         return;
      if (!above->nextSibling() || above->nextSibling() == elt)
         above = 0;
      else while (above->nextSibling()->nextSibling() != elt)
         above = above->nextSibling();
      if (above)
         elt->moveItem(above);
      else {
         TQListViewItem* parent = elt->parent();
         Items->takeNode(elt);
         Items->insertNode(parent, elt);
      }
      slotNoteChanged(elt);
      Notes.modified = true;
   }
}

void Knowit::slotNoteMoveDown()
{
   TQListViewItem* elt = Items->currentItem();
   if (elt && elt->nextSibling()) {
      elt->moveItem(elt->nextSibling());
      slotNoteChanged(elt);
      Notes.modified = true;
      }
}

void Knowit::slotNoteMoveBegin()
{
   TQListViewItem* elt = Items->currentItem();
   if (elt) {
      TQListViewItem* parent = elt->parent();
      Items->takeNode(elt);
      Items->insertItem(elt);
      if (parent)
         Notes.find(parent)->updateView();
      slotNoteChanged(elt);
      Notes.modified = true;
      }
}

void Knowit::slotNoteMoveEnd()
{
   TQListViewItem* elt = Items->currentItem();
   if (!elt)
      return;
   TQListViewItem* last = Items->firstChild();
   TQListViewItem* parent = elt->parent();
   while (last->nextSibling())
      last = last->nextSibling();
   if (elt && elt != last) {
      Items->takeNode(elt);
      Items->insertNode(0, elt, last);
      slotNoteChanged(elt);
      if (parent)
         Notes.find(parent)->updateView();
      Notes.modified = true;
      }
}

void Knowit::slotNoteMoveLeft()
{
   TQListViewItem* elt = Items->currentItem();
   TQListViewItem* parent = elt->parent();
   if (elt && parent) {
      Items->takeNode(elt);
      Items->insertNode(parent->parent(), elt, parent);
      Notes.find(parent)->updateView();
      slotNoteChanged(elt);
      Notes.modified = true;
      }
}

void Knowit::slotNoteMoveRight()
{
   TQListViewItem* elt = Items->currentItem();
   TQListViewItem* above = elt->itemAbove();
   if (elt && above) {
      if (above->depth() < elt->depth())
         return;
      else if (above->depth() == elt->depth()) {
         Items->takeNode(elt);
	 Items->insertNode(above, elt);
	 }
      else {
         while (above->depth() > elt->depth()+1)
            above = above->parent();
         Items->takeNode(elt);
         Items->insertNode(above->parent(), elt, above);
	 }
      Notes.find(above)->updateView();
      slotNoteChanged(elt);
      Notes.modified = true;
   }
}

void Knowit::slotNoteSort()
{
   if (Items->currentItem()) {
      Items->currentItem()->sortChildItems(0, true);
      Items->repaintContents();
   }
}



void Knowit::slotFileNew()
{
   if (queryClose()) reset();
}

void Knowit::slotFileOpen()
{
   if (!queryClose()) return;
   KURL url=KFileDialog::getOpenURL(TQString(),
      i18n("*.kno|KnowIt files (*.kno)\n*|All files"), this, i18n("Open File..."));
   if (!url.isEmpty())
      open(url);
}

void Knowit::slotFileSave()
{
  if (filename.isEmpty())
     slotFileSaveAs();
  else {
     save(filename);
     }
}

void Knowit::slotFileAutosave()
{
  if (modified())
     slotFileSave();
  if (modified()) {	/* file wasn't saved */
     KMessageBox::sorry(0, i18n("<qt><p>File couldn not be saved automatically."
          "<p>Autosaving disabled - save file manually to turn autosaving on.</p></qt>"));
     AutosaveTimer->stop();
     }
}


void Knowit::slotFileRecent(const KURL& url)
{
   if (queryClose())
      if (!open(url))
         actionRecent->removeURL(url);
}


void Knowit::slotFileSaveAs()
{
   KURL url=KFileDialog::getSaveURL(TQDir::currentDirPath(),
        i18n("*.kno|KnowIt files (*.kno)\n*|All files"), this, i18n("Save as..."));
   if (!url.isEmpty()) {
      if (!url.fileName().contains('.'))
        url = KURL(url.path() + ".kno");
      TQFileInfo fileinfo(url.path());
      if (fileinfo.exists() && KMessageBox::questionYesNo(0,
         i18n("<qt>File<br><b>%1</b><br>already exists. Overwrite it?</qt>")
            .arg(url.path())) == KMessageBox::No)
         return;
      save(url);
  }
}


void Knowit::slotFileInfo()
{
   int count = 0;
   TQListViewItemIterator it(Items);
   while (it.current()) {
      count++;
     it++;
   }
   KMessageBox::information(0, i18n("<qt><h1>%1</h1>"
      "Document path: %2<br>"
      "Number of notes: %3</qt>").arg(filename.fileName())
         .arg(filename.path()).arg(count));
}


void Knowit::slotFileProperties()
{
    KPropertiesDialog::showDialog(filename, this, nullptr, true);
}


void Knowit::slotFilePrint()
{
   KPrinter printer;
   printer.setFullPage(true);
   if (Edit->text().stripWhiteSpace().isEmpty() || !printer.setup(this))
      return;

   TQSimpleRichText richText(Edit->text(), Edit->font());
   TQPainter p(&printer);
   TQPaintDeviceMetrics metrics(p.device());
   int dpix = metrics.logicalDpiX();
   int dpiy = metrics.logicalDpiY();
   const int margin = 72; // pt
   TQRect body(margin*dpix / 72, margin*dpiy / 72,
      metrics.width()-  margin*dpix /72*2,
      metrics.height()-margin*dpiy/72*2);
   richText.setWidth(&p, body.width());
   TQRect view(body);
   int page = 1;
   while (true) {
      richText.draw(&p, body.left(), body.top(), view, colorGroup());
         view.moveBy(0, body.height());
      p.translate( 0 , -body.height());
      p.setFont(Edit->font());
      p.drawText( view.right() - p.fontMetrics().width( TQString::number(page)),
         view.bottom() + p.fontMetrics().ascent() + 5, TQString::number(page));
      if (view.top() >= body.top() + richText.height())
         break;
      printer.newPage();
      page++;
   }
}




void Knowit::slotFileQuit()
{
   if (queryClose()) {
      saveOptions();
      kapp->quit();
      }
}

void Knowit::slotFileExport()
{
  if (!Items->firstChild()) return;         /* nothing to export */
  ChooserDlg.setChoice(Options.exportFlags);
  if (ChooserDlg.exec() != TQDialog::Accepted) return; /* cancelled */

  /* Deduce filename from Knowit document name */
  TQString htmlfile;
  if (filename.isValid()) {
     htmlfile = filename.path();
     if (htmlfile.right(4) == ".kno")
        htmlfile = htmlfile.left(htmlfile.length() - 4) + ".html";
     else htmlfile = "";
  }
  if (htmlfile.isEmpty()) {
     htmlfile = TQDir::currentDirPath();
  }
  /* Confirm/choose filename */
  KURL url=KFileDialog::getSaveURL(htmlfile,
        i18n("*.html|HTML files (*.html)\n*|All files"), this, i18n("Export to HTML"));
  if (!url.isEmpty()) {
     if (!url.fileName().contains('.'))
        url = KURL(url.path() + ".html");
     TQFileInfo fileinfo(url.path());
     if (fileinfo.exists() && KMessageBox::questionYesNo(0,
         i18n("<qt>File<br><b>%1</b><br>already exists. Overwrite it?</qt>")
            .arg(url.path())) == KMessageBox::No)
        return;
     int choice = ChooserDlg.getChoice();
     TQListViewItem* start = (choice & KnowitChooser::SaveAll) ?
         Items->firstChild() : Items->currentItem();
     TQString origname = filename.isEmpty() ? Untitled : filename.path();
     TQString style;
     if (choice & KnowitChooser::Style)
        style = TQString("body {font-family: \"%1\"; color: %2; background-color: %3}")
           .arg(Edit->family()).arg(Edit->paletteForegroundColor().name())
           .arg(Edit->paletteBackgroundColor().name());
     Notes.find(start)->saveHTML(url, origname, style, choice);
     Options.exportFlags = choice;
  }
}

void Knowit::slotEditBold()
{
   Edit->setBold(actionBold->isChecked());
}

void Knowit::slotEditItalic()
{
   Edit->setItalic(actionItalic->isChecked());
}

void Knowit::slotEditUnderline()
{
   Edit->setUnderline(actionUnderline->isChecked());
}

void Knowit::slotEditColor()
{
   TQColor color = Edit->color();
   if (KColorDialog::getColor(color) == TQDialog::Accepted)
      Edit->setColor(color);
}

void Knowit::slotEditSuperscript()
{
   Edit->setVerticalAlignment(TQTextEdit::AlignSuperScript);
}

void Knowit::slotEditSubscript()
{
   Edit->setVerticalAlignment(TQTextEdit::AlignSubScript);
}

void Knowit::slotEditNormal()
{
   Edit->setVerticalAlignment(TQTextEdit::AlignNormal);
}

void Knowit::slotEditAlignLeft()
{
   Edit->setAlignment(TQt::AlignLeft);
}

void Knowit::slotEditAlignRight()
{
   Edit->setAlignment(TQt::AlignRight);
}

void Knowit::slotEditAlignJustify()
{
   Edit->setAlignment(TQt::AlignJustify);
}

void Knowit::slotEditAlignCenter()
{
   Edit->setAlignment(TQt::AlignCenter);
}

void Knowit::slotEditListBullet()
{
   Edit->setParagType(TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDisc);
}

void Knowit::slotEditListNumber()
{
   Edit->setParagType(TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDecimal);
}

void Knowit::slotEditListUpper()
{
   Edit->setParagType(TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListUpperAlpha);
}

void Knowit::slotEditListLower()
{
   Edit->setParagType(TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListLowerAlpha);
}

void Knowit::slotEditListNone()
{
   Edit->setParagType(TQStyleSheetItem::DisplayBlock, TQStyleSheetItem::ListDisc);
}

void Knowit::slotEditFind()
{
   if (soughtText != FindDlg.getText()) {
      soughtText = FindDlg.getText();
      lastSought = 0;
      find();
      }
   else
      find(Items->currentItem());
}

void Knowit::slotEditFindNext()
{
   if (soughtText.isEmpty()) FindDlg.exec();
   find(Items->currentItem());
}

void Knowit::slotEditGoTo()
{
   bool Ok;
   TQString page = KInputDialog::getText(i18n("Go to"),
      i18n("Go to page with given title"), "", &Ok);
   if (Ok && !page.isEmpty()) {
      TQListViewItem* item = Items->findItem(page, 0);
      if (!item) item = Items->findItem(page, 0, TQt::ExactMatch);
      if (!item) item = Items->findItem(page, 0, TQt::Contains);
      slotNoteChanged(item);
   }
}

void Knowit::slotEditInsertDate()
{
   if (Items->currentItem()) {
      bool ib = actionBold->isChecked(), ii=actionItalic->isChecked(), iu=actionUnderline->isChecked();
      TQColor color = Edit->color();
      Edit->setItalic(Options.insertDateItalic);
      Edit->setBold(Options.insertDateBold);
      Edit->setUnderline(Options.insertDateUnderline);
      Edit->setColor(TQColor(Options.insertDateColor));
      Edit->insert(TQString("%1")
         .arg(TQDateTime::currentDateTime().toString(Options.insertDateFormat)));
      Edit->setItalic(ii);
      Edit->setBold(ib);
      Edit->setUnderline(iu);
      Edit->setColor(color);

   }
}

void Knowit::slotEditInsertFile()
{
   if (!Items->currentItem())
      return;
   KURL url=KFileDialog::getOpenURL(TQString(),
      i18n("*|All files"), this, i18n("Insert file..."));
   if (url.isEmpty())
      return;
   TQFile file(url.path());
   if (!file.open(IO_ReadOnly)) {
      KMessageBox::error(0, i18n("<qt>Cannot open file<br><b>%1</b></qt>")
         .arg(url.url()));
      return;
      }
   TQTextStream ts(&file);
   ts.setEncoding(TQTextStream::UnicodeUTF8);
   TQString s, text;
   while (true) {
      s = ts.readLine();
      if (s.isNull())
         break;
      if (s.isEmpty())
         text += '\n';
      else
         text += s;
      }
   Edit->insert(text);
}


void Knowit::slotEditSwitch()
{
   if (Items->hasFocus())
      Edit->setFocus();
   else Items->setFocus();
}

void Knowit::slotEditChanged()
{
   actionBold->setChecked(Edit->bold());
   actionItalic->setChecked(Edit->italic());
   actionUnderline->setChecked(Edit->underline());
   actionEditAlignLeft->setChecked(Edit->alignment() == TQt::AlignLeft);
   actionEditAlignRight->setChecked(Edit->alignment() == TQt::AlignRight);
   actionEditAlignCenter->setChecked(Edit->alignment() == TQt::AlignCenter);
   actionEditAlignJustify->setChecked(Edit->alignment() == TQt::AlignJustify);
}

void Knowit::slotEditCursorChanged(int, int)
{
   slotEditChanged();
}



void Knowit::slotOptions()
{
   PrefDlg.setOptions(Options);
   if (PrefDlg.exec() == TQDialog::Accepted)
      applyOptions(PrefDlg.getOptions());
}

void Knowit::slotOptionsKeys()
{
   KKeyDialog K(false);
   K.configure(actionCollection());
}

void Knowit::slotOptionsToolbar()
{
   KEditToolbar dlg(actionCollection());
   if (dlg.exec())
      createGUI();
}


void Knowit::slotUndock()
{
   Options.docked = false;
   applyOptions(Options);
}

void Knowit::slotHelpTip()
{
   KTipDialog::showTip(this, 0, true);
}


void Knowit::slotActionUpdate()
{
   if (Items->childCount())
      stateChanged("notesPresent");
   else
      stateChanged("notesPresent", KXMLGUIClient::StateReverse);
   Edit->setEnabled(Notes.count());
}

void Knowit::slotOverwriteModeChange(int i)
{
   if (i == StatusOvr)
      slotOverwriteModeChange();
}

void Knowit::slotOverwriteModeChange()
{
   Edit->setOverwriteMode(!Edit->isOverwriteMode());
   statusBar()->changeItem(Edit->isOverwriteMode() ? i18n("OVR") :
      i18n("INS"), StatusOvr);
}

void Knowit::slotRawTextMode()
{
   if (!Items->currentItem())
      return;
   if (Items->prevItem && Edit->isModified())
      Notes.changeNote(Items->prevItem, Edit->length() ? Edit->text() : TQString());
   Edit->setTextFormat(actionRawTextMode->isChecked() ?
      TQt::PlainText : TQt::RichText);
   Edit->setText(Notes.text(Items->currentItem()));
}

void Knowit::slotShowAttachment(TQListBoxItem*)
{
   slotLinkOpen();
}

void Knowit::slotLinkAdd()
{
   slotLinkDropped("", 0);
}

void Knowit::slotLinkDropped(const TQString& s, int flags)
{
   TNoteLink link;
   link.link = s;
   if (!flags && !LinkDlg.modifyLink(link))
      return;
   currentNote()->addLink(link);
   Links->insertItem(link.icon(), link.text(Options.linkFormat));
   if (Links->count() == 1)
      Links->show();
   if (Options.firstLink) {
      KMessageBox::information(0, i18n("You have just added your first link. "
      "Please remember that only links are stored in Knowit document, "
      "not linked files. If you move your document to other computer, "
      "links to local files probably won't work."));
      Options.firstLink = false;
   }
}

void Knowit::slotLinkRemove()
{
   TQString msg = i18n("<qt>Are you sure you want to remove link:<br><b>%1</b>?</qt>");
   if (Links->currentItem() != -1 && KMessageBox::questionYesNo(0,
      msg.arg(Links->currentText())) == KMessageBox::Yes) {
      currentNote()->removeLink(Links->currentItem());
      Links->removeItem(Links->currentItem());
      if (!Links->count())
         Links->hide();
      }
}

void Knowit::slotLinkOpen()
{
   if (Links->currentItem() == -1)
       return;
   TNoteLink link = currentNote()->link(Links->currentItem());
   if (link.isLocalReference()) {
      TQString s = link.link.remove(0, 9);
      TQListViewItem* item = Items->findItem(s, 0);
      if (!item) Items->findItem(s, 0, TQt::BeginsWith);
      if (!item) Items->findItem(s, 0, TQt::Contains);
      slotNoteChanged(item);
   }
   else
      link.open();
}

void Knowit::slotLinkOpenWith()
{
   if (Links->currentItem() != -1)
       currentNote()->link(Links->currentItem()).openWith();
}

void Knowit::slotLinkModify()
{
   if (Links->currentItem() == -1) return;
   TNoteLink link = currentNote()->link(Links->currentItem());
   if (LinkDlg.modifyLink(link)) {
      currentNote()->modifyLink(Links->currentItem(), link);
      Links->changeItem(link.icon(), link.text(Options.linkFormat),
         Links->currentItem());
      }
}

void Knowit::slotLinkCopy()
{
   if (Links->currentItem() == -1) return;
   TNoteLink link = currentNote()->link(Links->currentItem());
   kapp->clipboard()->setText(link.link, TQClipboard::Clipboard);
   kapp->clipboard()->setText(link.link, TQClipboard::Selection);
}

#include "knowit.moc"
