kalarm

mainwindow.cpp

00001 /*
00002  *  mainwindow.cpp  -  main application window
00003  *  Program:  kalarm
00004  *  Copyright © 2001-2007 by David Jarvie <djarvie@kde.org>
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License along
00017  *  with this program; if not, write to the Free Software Foundation, Inc.,
00018  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "kalarm.h"
00022 
00023 #include <tqiconset.h>
00024 #include <tqdragobject.h>
00025 #include <tqheader.h>
00026 
00027 #include <kmenubar.h>
00028 #include <ktoolbar.h>
00029 #include <kpopupmenu.h>
00030 #include <kaccel.h>
00031 #include <kaction.h>
00032 #include <kactionclasses.h>
00033 #include <kstdaction.h>
00034 #include <kiconloader.h>
00035 #include <kmessagebox.h>
00036 #include <kurldrag.h>
00037 #include <klocale.h>
00038 #include <kglobalsettings.h>
00039 #include <kconfig.h>
00040 #include <kkeydialog.h>
00041 #include <kedittoolbar.h>
00042 #include <kaboutdata.h>
00043 #include <dcopclient.h>
00044 #include <kdebug.h>
00045 
00046 #include <libkdepim/maillistdrag.h>
00047 #include <libkmime/kmime_content.h>
00048 #include <libkcal/calendarlocal.h>
00049 #include <libkcal/icaldrag.h>
00050 
00051 #include "alarmcalendar.h"
00052 #include "alarmevent.h"
00053 #include "alarmlistview.h"
00054 #include "alarmtext.h"
00055 #include "birthdaydlg.h"
00056 #include "daemon.h"
00057 #include "editdlg.h"
00058 #include "functions.h"
00059 #include "kalarmapp.h"
00060 #include "kamail.h"
00061 #include "prefdlg.h"
00062 #include "preferences.h"
00063 #include "synchtimer.h"
00064 #include "templatepickdlg.h"
00065 #include "templatedlg.h"
00066 #include "traywindow.h"
00067 #include "mainwindow.moc"
00068 
00069 using namespace KCal;
00070 
00071 static const char* UI_FILE     = "kalarmui.rc";
00072 static const char* WINDOW_NAME = "MainWindow";
00073 
00074 static const TQString VIEW_GROUP         = TQString::fromLatin1("View");
00075 static const TQString SHOW_TIME_KEY      = TQString::fromLatin1("ShowAlarmTime");
00076 static const TQString SHOW_TIME_TO_KEY   = TQString::fromLatin1("ShowTimeToAlarm");
00077 static const TQString SHOW_ARCHIVED_KEY  = TQString::fromLatin1("ShowArchivedAlarms");
00078 static const TQString SHOW_RESOURCES_KEY = TQString::fromLatin1("ShowResources");
00079 
00080 static TQString   undoText;
00081 static TQString   undoTextStripped;
00082 static TQString   undoIcon;
00083 static KShortcut undoShortcut;
00084 static TQString   redoText;
00085 static TQString   redoTextStripped;
00086 static TQString   redoIcon;
00087 static KShortcut redoShortcut;
00088 
00089 
00090 /*=============================================================================
00091 =  Class: MainWindow
00092 =============================================================================*/
00093 
00094 MainWindow::WindowList   MainWindow::mWindowList;
00095 TemplateDlg*             MainWindow::mTemplateDlg = 0;
00096 
00097 // Collect these widget labels together to ensure consistent wording and
00098 // translations across different modules.
00099 TQString MainWindow::i18n_a_ShowAlarmTimes()    { return i18n("Show &Alarm Times"); }
00100 TQString MainWindow::i18n_m_ShowAlarmTime()     { return i18n("Show alarm ti&me"); }
00101 TQString MainWindow::i18n_o_ShowTimeToAlarms()  { return i18n("Show Time t&o Alarms"); }
00102 TQString MainWindow::i18n_l_ShowTimeToAlarm()   { return i18n("Show time unti&l alarm"); }
00103 TQString MainWindow::i18n_ShowExpiredAlarms()   { return i18n("Show Expired Alarms"); }
00104 TQString MainWindow::i18n_e_ShowExpiredAlarms() { return i18n("Show &Expired Alarms"); }
00105 TQString MainWindow::i18n_HideExpiredAlarms()   { return i18n("Hide Expired Alarms"); }
00106 TQString MainWindow::i18n_e_HideExpiredAlarms() { return i18n("Hide &Expired Alarms"); }
00107 
00108 
00109 /******************************************************************************
00110 * Construct an instance.
00111 * To avoid resize() events occurring while still opening the calendar (and
00112 * resultant crashes), the calendar is opened before constructing the instance.
00113 */
00114 MainWindow* MainWindow::create(bool restored)
00115 {
00116     theApp()->checkCalendarDaemon();    // ensure calendar is open and daemon started
00117     return new MainWindow(restored);
00118 }
00119 
00120 MainWindow::MainWindow(bool restored)
00121     : MainWindowBase(0, "MainWin", WGroupLeader | WStyle_ContextHelp | WDestructiveClose),
00122       mMinuteTimerActive(false),
00123       mHiddenTrayParent(false)
00124 {
00125     kdDebug(5950) << "MainWindow::MainWindow()\n";
00126     setAutoSaveSettings(TQString::fromLatin1(WINDOW_NAME));    // save window sizes etc.
00127     setPlainCaption(kapp->aboutData()->programName());
00128     KConfig* config = KGlobal::config();
00129     config->setGroup(VIEW_GROUP);
00130     mShowExpired = config->readBoolEntry(SHOW_ARCHIVED_KEY, false);
00131     mShowTime    = config->readBoolEntry(SHOW_TIME_KEY, true);
00132     mShowTimeTo  = config->readBoolEntry(SHOW_TIME_TO_KEY, false);
00133     if (!restored)
00134     {
00135         TQSize s;
00136         if (KAlarm::readConfigWindowSize(WINDOW_NAME, s))
00137             resize(s);
00138     }
00139     config->setGroup(TQString::fromLatin1(WINDOW_NAME));
00140     TQValueList<int> order = config->readIntListEntry(TQString::fromLatin1("ColumnOrder"));
00141 
00142     setAcceptDrops(true);         // allow drag-and-drop onto this window
00143     if (!mShowTimeTo)
00144         mShowTime = true;     // ensure at least one time column is visible
00145     mListView = new AlarmListView(order, this, "listView");
00146     mListView->selectTimeColumns(mShowTime, mShowTimeTo);
00147     mListView->showExpired(mShowExpired);
00148     setCentralWidget(mListView);
00149     mListView->refresh();          // populate the alarm list
00150     mListView->clearSelection();
00151 
00152     connect(mListView, TQT_SIGNAL(itemDeleted()), TQT_SLOT(slotDeletion()));
00153     connect(mListView, TQT_SIGNAL(selectionChanged()), TQT_SLOT(slotSelection()));
00154     connect(mListView, TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint&, int)),
00155             TQT_SLOT(slotContextMenuRequested(TQListViewItem*, const TQPoint&, int)));
00156     connect(mListView, TQT_SIGNAL(mouseButtonClicked(int, TQListViewItem*, const TQPoint&, int)),
00157             TQT_SLOT(slotMouseClicked(int, TQListViewItem*, const TQPoint&, int)));
00158     connect(mListView, TQT_SIGNAL(executed(TQListViewItem*)), TQT_SLOT(slotDoubleClicked(TQListViewItem*)));
00159     connect(mListView->header(), TQT_SIGNAL(indexChange(int, int, int)), TQT_SLOT(columnsReordered()));
00160     initActions();
00161 
00162     mWindowList.append(this);
00163     if (mWindowList.count() == 1  &&  Daemon::isDcopHandlerReady())
00164     {
00165         // It's the first main window, and the DCOP handler is ready
00166         if (theApp()->wantRunInSystemTray())
00167             theApp()->displayTrayIcon(true, this);     // create system tray icon for run-in-system-tray mode
00168         else if (theApp()->trayWindow())
00169             theApp()->trayWindow()->setAssocMainWindow(this);    // associate this window with the system tray icon
00170     }
00171     setUpdateTimer();
00172 }
00173 
00174 MainWindow::~MainWindow()
00175 {
00176     kdDebug(5950) << "MainWindow::~MainWindow()\n";
00177     mWindowList.remove(this);
00178     if (theApp()->trayWindow())
00179     {
00180         if (isTrayParent())
00181             delete theApp()->trayWindow();
00182         else
00183             theApp()->trayWindow()->removeWindow(this);
00184     }
00185     MinuteTimer::disconnect(TQT_TQOBJECT(this));
00186     mMinuteTimerActive = false;    // to ensure that setUpdateTimer() works correctly
00187     setUpdateTimer();
00188     MainWindow* main = mainMainWindow();
00189     if (main)
00190         KAlarm::writeConfigWindowSize(WINDOW_NAME, main->size());
00191     KToolBar* tb = toolBar();
00192     if (tb)
00193         tb->saveSettings(KGlobal::config(), "Toolbars");
00194     KGlobal::config()->sync();    // save any new window size to disc
00195     theApp()->quitIf();
00196 }
00197 
00198 /******************************************************************************
00199 * Save settings to the session managed config file, for restoration
00200 * when the program is restored.
00201 */
00202 void MainWindow::saveProperties(KConfig* config)
00203 {
00204     config->writeEntry(TQString::fromLatin1("HiddenTrayParent"), isTrayParent() && isHidden());
00205     config->writeEntry(TQString::fromLatin1("ShowExpired"), mShowExpired);
00206     config->writeEntry(TQString::fromLatin1("ShowTime"), mShowTime);
00207     config->writeEntry(TQString::fromLatin1("ShowTimeTo"), mShowTimeTo);
00208 }
00209 
00210 /******************************************************************************
00211 * Read settings from the session managed config file.
00212 * This function is automatically called whenever the app is being
00213 * restored. Read in whatever was saved in saveProperties().
00214 */
00215 void MainWindow::readProperties(KConfig* config)
00216 {
00217     mHiddenTrayParent = config->readBoolEntry(TQString::fromLatin1("HiddenTrayParent"));
00218     mShowExpired      = config->readBoolEntry(TQString::fromLatin1("ShowExpired"));
00219     mShowTime         = config->readBoolEntry(TQString::fromLatin1("ShowTime"));
00220     mShowTimeTo       = config->readBoolEntry(TQString::fromLatin1("ShowTimeTo"));
00221 }
00222 
00223 /******************************************************************************
00224 * Get the main main window, i.e. the parent of the system tray icon, or if
00225 * none, the first main window to be created. Visible windows take precedence
00226 * over hidden ones.
00227 */
00228 MainWindow* MainWindow::mainMainWindow()
00229 {
00230     MainWindow* tray = theApp()->trayWindow() ? theApp()->trayWindow()->assocMainWindow() : 0;
00231     if (tray  &&  tray->isVisible())
00232         return tray;
00233     for (WindowList::Iterator it = mWindowList.begin();  it != mWindowList.end();  ++it)
00234         if ((*it)->isVisible())
00235             return *it;
00236     if (tray)
00237         return tray;
00238     if (mWindowList.isEmpty())
00239         return 0;
00240     return mWindowList.first();
00241 }
00242 
00243 /******************************************************************************
00244 * Check whether this main window is the parent of the system tray icon.
00245 */
00246 bool MainWindow::isTrayParent() const
00247 {
00248     return theApp()->wantRunInSystemTray()  &&  theApp()->trayMainWindow() == this;
00249 }
00250 
00251 /******************************************************************************
00252 *  Close all main windows.
00253 */
00254 void MainWindow::closeAll()
00255 {
00256     while (!mWindowList.isEmpty())
00257         delete mWindowList.first();    // N.B. the destructor removes the window from the list
00258 }
00259 
00260 /******************************************************************************
00261 *  Called when the window's size has changed (before it is painted).
00262 *  Sets the last column in the list view to extend at least to the right hand
00263 *  edge of the list view.
00264 *  Records the new size in the config file.
00265 */
00266 void MainWindow::resizeEvent(TQResizeEvent* re)
00267 {
00268     // Save the window's new size only if it's the first main window
00269     if (mainMainWindow() == this)
00270         KAlarm::writeConfigWindowSize(WINDOW_NAME, re->size());
00271     MainWindowBase::resizeEvent(re);
00272 }
00273 
00274 /******************************************************************************
00275 *  Called when the window is first displayed.
00276 *  Sets the last column in the list view to extend at least to the right hand
00277 *  edge of the list view.
00278 */
00279 void MainWindow::showEvent(TQShowEvent* se)
00280 {
00281     setUpdateTimer();
00282     slotUpdateTimeTo();
00283     MainWindowBase::showEvent(se);
00284 }
00285 
00286 /******************************************************************************
00287 *  Display the window.
00288 */
00289 void MainWindow::show()
00290 {
00291     MainWindowBase::show();
00292     if (mMenuError)
00293     {
00294         // Show error message now that the main window has been displayed.
00295         // Waiting until now lets the user easily associate the message with
00296         // the main window which is faulty.
00297         KMessageBox::error(this, i18n("Failure to create menus\n(perhaps %1 missing or corrupted)").arg(TQString::fromLatin1(UI_FILE)));
00298         mMenuError = false;
00299     }
00300 }
00301 
00302 /******************************************************************************
00303 *  Called after the window is hidden.
00304 */
00305 void MainWindow::hideEvent(TQHideEvent* he)
00306 {
00307     setUpdateTimer();
00308     MainWindowBase::hideEvent(he);
00309 }
00310 
00311 /******************************************************************************
00312 *  Called when the list's column order is changed.
00313 *  Save the new column order as the default the next time the program is run.
00314 */
00315 void MainWindow::columnsReordered()
00316 {
00317     KConfig* config = KGlobal::config();
00318     config->setGroup(TQString::fromLatin1(WINDOW_NAME));
00319     config->writeEntry(TQString::fromLatin1("ColumnOrder"), mListView->columnOrder());
00320     config->sync();
00321 }
00322 
00323 /******************************************************************************
00324 *  Initialise the menu, toolbar and main window actions.
00325 */
00326 void MainWindow::initActions()
00327 {
00328     KActionCollection* actions = actionCollection();
00329     mActionTemplates       = new KAction(i18n("&Templates..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotTemplates()), actions, "templates");
00330     mActionNew             = KAlarm::createNewAlarmAction(i18n("&New..."), TQT_TQOBJECT(this), TQT_SLOT(slotNew()), actions, "new");
00331     mActionNewFromTemplate = KAlarm::createNewFromTemplateAction(i18n("New &From Template"), TQT_TQOBJECT(this), TQT_SLOT(slotNewFromTemplate(const KAEvent&)), actions, "newFromTempl");
00332     mActionCreateTemplate  = new KAction(i18n("Create Tem&plate..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotNewTemplate()), actions, "createTemplate");
00333     mActionCopy            = new KAction(i18n("&Copy..."), "editcopy", TQt::SHIFT+TQt::Key_Insert, TQT_TQOBJECT(this), TQT_SLOT(slotCopy()), actions, "copy");
00334     mActionModify          = new KAction(i18n("&Edit..."), "edit", TQt::CTRL+TQt::Key_E, TQT_TQOBJECT(this), TQT_SLOT(slotModify()), actions, "modify");
00335     mActionDelete          = new KAction(i18n("&Delete"), "editdelete", TQt::Key_Delete, TQT_TQOBJECT(this), TQT_SLOT(slotDelete()), actions, "delete");
00336     mActionReactivate      = new KAction(i18n("Reac&tivate"), 0, TQt::CTRL+TQt::Key_R, TQT_TQOBJECT(this), TQT_SLOT(slotReactivate()), actions, "undelete");
00337     mActionEnable          = new KAction(TQString(), 0, TQt::CTRL+TQt::Key_B, TQT_TQOBJECT(this), TQT_SLOT(slotEnable()), actions, "disable");
00338     mActionView            = new KAction(i18n("&View"), "viewmag", TQt::CTRL+TQt::Key_W, TQT_TQOBJECT(this), TQT_SLOT(slotView()), actions, "view");
00339     mActionShowTime        = new KToggleAction(i18n_a_ShowAlarmTimes(), TQt::CTRL+TQt::Key_M, TQT_TQOBJECT(this), TQT_SLOT(slotShowTime()), actions, "showAlarmTimes");
00340     mActionShowTime->setCheckedState(i18n("Hide &Alarm Times"));
00341     mActionShowTimeTo      = new KToggleAction(i18n_o_ShowTimeToAlarms(), TQt::CTRL+TQt::Key_I, TQT_TQOBJECT(this), TQT_SLOT(slotShowTimeTo()), actions, "showTimeToAlarms");
00342     mActionShowTimeTo->setCheckedState(i18n("Hide Time t&o Alarms"));
00343     mActionShowExpired     = new KToggleAction(i18n_e_ShowExpiredAlarms(), "history", TQt::CTRL+TQt::Key_P, TQT_TQOBJECT(this), TQT_SLOT(slotShowExpired()), actions, "showExpiredAlarms");
00344     mActionShowExpired->setCheckedState(i18n_e_HideExpiredAlarms());
00345     mActionToggleTrayIcon  = new KToggleAction(i18n("Show in System &Tray"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotToggleTrayIcon()), actions, "showInSystemTray");
00346     mActionToggleTrayIcon->setCheckedState(i18n("Hide From System &Tray"));
00347     new KAction(i18n("Import &Alarms..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotImportAlarms()), actions, "importAlarms");
00348     new KAction(i18n("Import &Birthdays..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotBirthdays()), actions, "importBirthdays");
00349     new KAction(i18n("&Refresh Alarms"), "reload", 0, TQT_TQOBJECT(this), TQT_SLOT(slotResetDaemon()), actions, "refreshAlarms");
00350     Daemon::createAlarmEnableAction(actions, "alarmEnable");
00351     if (undoText.isNull())
00352     {
00353         // Get standard texts, etc., for Undo and Redo actions
00354         KAction* act = KStdAction::undo(TQT_TQOBJECT(this), 0, actions);
00355         undoIcon         = act->icon();
00356         undoShortcut     = act->shortcut();
00357         undoText         = act->text();
00358         undoTextStripped = KAlarm::stripAccel(undoText);
00359         delete act;
00360         act = KStdAction::redo(TQT_TQOBJECT(this), 0, actions);
00361         redoIcon         = act->icon();
00362         redoShortcut     = act->shortcut();
00363         redoText         = act->text();
00364         redoTextStripped = KAlarm::stripAccel(redoText);
00365         delete act;
00366     }
00367     mActionUndo = new KToolBarPopupAction(undoText, undoIcon, undoShortcut, TQT_TQOBJECT(this), TQT_SLOT(slotUndo()), actions, "edit_undo");
00368     mActionRedo = new KToolBarPopupAction(redoText, redoIcon, redoShortcut, TQT_TQOBJECT(this), TQT_SLOT(slotRedo()), actions, "edit_redo");
00369     KStdAction::find(TQT_TQOBJECT(mListView), TQT_SLOT(slotFind()), actions);
00370     mActionFindNext = KStdAction::findNext(TQT_TQOBJECT(mListView), TQT_SLOT(slotFindNext()), actions);
00371     mActionFindPrev = KStdAction::findPrev(TQT_TQOBJECT(mListView), TQT_SLOT(slotFindPrev()), actions);
00372     KStdAction::selectAll(TQT_TQOBJECT(mListView), TQT_SLOT(slotSelectAll()), actions);
00373     KStdAction::deselect(TQT_TQOBJECT(mListView), TQT_SLOT(slotDeselect()), actions);
00374     KStdAction::quit(TQT_TQOBJECT(this), TQT_SLOT(slotQuit()), actions);
00375     KStdAction::keyBindings(TQT_TQOBJECT(this), TQT_SLOT(slotConfigureKeys()), actions);
00376     KStdAction::configureToolbars(TQT_TQOBJECT(this), TQT_SLOT(slotConfigureToolbar()), actions);
00377     KStdAction::preferences(TQT_TQOBJECT(this), TQT_SLOT(slotPreferences()), actions);
00378     setStandardToolBarMenuEnabled(true);
00379     createGUI(UI_FILE);
00380 
00381     mContextMenu = static_cast<KPopupMenu*>(factory()->container("listContext", this));
00382     mActionsMenu = static_cast<KPopupMenu*>(factory()->container("actions", this));
00383     mMenuError = (!mContextMenu  ||  !mActionsMenu);
00384     connect(mActionsMenu, TQT_SIGNAL(aboutToShow()), TQT_SLOT(updateActionsMenu()));
00385     connect(mActionUndo->popupMenu(), TQT_SIGNAL(aboutToShow()), TQT_SLOT(slotInitUndoMenu()));
00386     connect(mActionUndo->popupMenu(), TQT_SIGNAL(activated(int)), TQT_SLOT(slotUndoItem(int)));
00387     connect(mActionRedo->popupMenu(), TQT_SIGNAL(aboutToShow()), TQT_SLOT(slotInitRedoMenu()));
00388     connect(mActionRedo->popupMenu(), TQT_SIGNAL(activated(int)), TQT_SLOT(slotRedoItem(int)));
00389     connect(Undo::instance(), TQT_SIGNAL(changed(const TQString&, const TQString&)), TQT_SLOT(slotUndoStatus(const TQString&, const TQString&)));
00390     connect(mListView, TQT_SIGNAL(findActive(bool)), TQT_SLOT(slotFindActive(bool)));
00391     Preferences::connect(TQT_SIGNAL(preferencesChanged()), TQT_TQOBJECT(this), TQT_SLOT(slotPrefsChanged()));
00392     connect(theApp(), TQT_SIGNAL(trayIconToggled()), TQT_SLOT(updateTrayIconAction()));
00393 
00394     // Set menu item states
00395     setEnableText(true);
00396     mActionShowTime->setChecked(mShowTime);
00397     mActionShowTimeTo->setChecked(mShowTimeTo);
00398     mActionShowExpired->setChecked(mShowExpired);
00399     slotPrefsChanged();         // set the correct text for this action
00400     mActionUndo->setEnabled(Undo::haveUndo());
00401     mActionRedo->setEnabled(Undo::haveRedo());
00402     mActionFindNext->setEnabled(false);
00403     mActionFindPrev->setEnabled(false);
00404 
00405     mActionCopy->setEnabled(false);
00406     mActionModify->setEnabled(false);
00407     mActionDelete->setEnabled(false);
00408     mActionReactivate->setEnabled(false);
00409     mActionView->setEnabled(false);
00410     mActionEnable->setEnabled(false);
00411     mActionCreateTemplate->setEnabled(false);
00412 
00413     KToolBar* tb = toolBar();
00414     if (tb)
00415         tb->applySettings(KGlobal::config(), "Toolbars");
00416 
00417     Undo::emitChanged();     // set the Undo/Redo menu texts
00418     Daemon::checkStatus();
00419     Daemon::monitoringAlarms();
00420 }
00421 
00422 /******************************************************************************
00423 * Enable or disable the Templates menu item in every main window instance.
00424 */
00425 void MainWindow::enableTemplateMenuItem(bool enable)
00426 {
00427     for (WindowList::Iterator it = mWindowList.begin();  it != mWindowList.end();  ++it)
00428         (*it)->mActionTemplates->setEnabled(enable);
00429 }
00430 
00431 /******************************************************************************
00432 * Refresh the alarm list in every main window instance.
00433 */
00434 void MainWindow::refresh()
00435 {
00436     kdDebug(5950) << "MainWindow::refresh()\n";
00437     for (WindowList::Iterator it = mWindowList.begin();  it != mWindowList.end();  ++it)
00438         (*it)->mListView->refresh();
00439 }
00440 
00441 /******************************************************************************
00442 * Refresh the alarm list in every main window instance which is displaying
00443 * expired alarms.
00444 * Called when an expired alarm setting changes in the user preferences.
00445 */
00446 void MainWindow::updateExpired()
00447 {
00448     kdDebug(5950) << "MainWindow::updateExpired()\n";
00449     bool enableShowExpired = Preferences::expiredKeepDays();
00450     for (WindowList::Iterator it = mWindowList.begin();  it != mWindowList.end();  ++it)
00451     {
00452         MainWindow* w = *it;
00453         if (w->mShowExpired)
00454         {
00455             if (!enableShowExpired)
00456                 w->slotShowExpired();
00457             else
00458                 w->mListView->refresh();
00459         }
00460         w->mActionShowExpired->setEnabled(enableShowExpired);
00461     }
00462 }
00463 
00464 /******************************************************************************
00465 * Start or stop the timer which updates the time-to-alarm values every minute.
00466 * Should be called whenever a main window is created or destroyed, or shown or
00467 * hidden.
00468 */
00469 void MainWindow::setUpdateTimer()
00470 {
00471     // Check whether any windows need to be updated
00472     MainWindow* needTimer = 0;
00473     MainWindow* timerWindow = 0;
00474     for (WindowList::Iterator it = mWindowList.begin();  it != mWindowList.end();  ++it)
00475     {
00476         MainWindow* w = *it;
00477         if (w->isVisible()  &&  w->mListView->showingTimeTo())
00478             needTimer = w;
00479         if (w->mMinuteTimerActive)
00480             timerWindow = w;
00481     }
00482 
00483     // Start or stop the update timer if necessary
00484     if (needTimer  &&  !timerWindow)
00485     {
00486         // Timeout every minute.
00487         needTimer->mMinuteTimerActive = true;
00488         MinuteTimer::connect(TQT_TQOBJECT(needTimer), TQT_SLOT(slotUpdateTimeTo()));
00489         kdDebug(5950) << "MainWindow::setUpdateTimer(): started timer" << endl;
00490     }
00491     else if (!needTimer  &&  timerWindow)
00492     {
00493         timerWindow->mMinuteTimerActive = false;
00494         MinuteTimer::disconnect(TQT_TQOBJECT(timerWindow));
00495         kdDebug(5950) << "MainWindow::setUpdateTimer(): stopped timer" << endl;
00496     }
00497 }
00498 /******************************************************************************
00499 * Update the time-to-alarm values for each main window which is displaying them.
00500 */
00501 void MainWindow::slotUpdateTimeTo()
00502 {
00503     kdDebug(5950) << "MainWindow::slotUpdateTimeTo()" << endl;
00504     for (WindowList::Iterator it = mWindowList.begin();  it != mWindowList.end();  ++it)
00505     {
00506         MainWindow* w = *it;
00507         if (w->isVisible()  &&  w->mListView->showingTimeTo())
00508             w->mListView->updateTimeToAlarms();
00509     }
00510 }
00511 
00512 /******************************************************************************
00513 * Select an alarm in the displayed list.
00514 */
00515 void MainWindow::selectEvent(const TQString& eventID)
00516 {
00517     mListView->clearSelection();
00518     AlarmListViewItem* item = mListView->getEntry(eventID);
00519     if (item)
00520     {
00521         mListView->setSelected(item, true);
00522         mListView->setCurrentItem(item);
00523         mListView->ensureItemVisible(item);
00524     }
00525 }
00526 
00527 /******************************************************************************
00528 *  Called when the New button is clicked to edit a new alarm to add to the list.
00529 */
00530 void MainWindow::slotNew()
00531 {
00532     executeNew(this);
00533 }
00534 
00535 /******************************************************************************
00536 *  Execute a New Alarm dialog, optionally either presetting it to the supplied
00537 *  event, or setting the action and text.
00538 */
00539 void MainWindow::executeNew(MainWindow* win, const KAEvent* evnt, KAEvent::Action action, const AlarmText& text)
00540 {
00541     EditAlarmDlg editDlg(false, i18n("New Alarm"), win, 0, evnt);
00542     if (!text.isEmpty())
00543         editDlg.setAction(action, text);
00544     if (editDlg.exec() == TQDialog::Accepted)
00545     {
00546         KAEvent event;
00547         editDlg.getEvent(event);
00548 
00549         // Add the alarm to the displayed lists and to the calendar file
00550         if (KAlarm::addEvent(event, (win ? win->mListView : 0), &editDlg) == KAlarm::UPDATE_KORG_ERR)
00551             KAlarm::displayKOrgUpdateError(&editDlg, KAlarm::KORG_ERR_ADD, 1);
00552         Undo::saveAdd(event);
00553 
00554         KAlarm::outputAlarmWarnings(&editDlg, &event);
00555     }
00556 }
00557 
00558 /******************************************************************************
00559 *  Called when a template is selected from the New From Template popup menu.
00560 *  Executes a New Alarm dialog, preset from the selected template.
00561 */
00562 void MainWindow::slotNewFromTemplate(const KAEvent& tmplate)
00563 {
00564     executeNew(this, &tmplate);
00565 }
00566 
00567 /******************************************************************************
00568 *  Called when the New Template button is clicked to create a new template
00569 *  based on the currently selected alarm.
00570 */
00571 void MainWindow::slotNewTemplate()
00572 {
00573     AlarmListViewItem* item = mListView->selectedItem();
00574     if (item)
00575     {
00576         KAEvent event = item->event();
00577         TemplateDlg::createTemplate(&event, this);
00578     }
00579 }
00580 
00581 /******************************************************************************
00582 *  Called when the Copy button is clicked to edit a copy of an existing alarm,
00583 *  to add to the list.
00584 */
00585 void MainWindow::slotCopy()
00586 {
00587     AlarmListViewItem* item = mListView->selectedItem();
00588     if (item)
00589         executeNew(this, &item->event());
00590 }
00591 
00592 /******************************************************************************
00593 *  Called when the Modify button is clicked to edit the currently highlighted
00594 *  alarm in the list.
00595 */
00596 void MainWindow::slotModify()
00597 {
00598     AlarmListViewItem* item = mListView->selectedItem();
00599     if (item)
00600     {
00601         KAEvent event = item->event();
00602         executeEdit(event, this);
00603     }
00604 }
00605 
00606 /******************************************************************************
00607 *  Open the Edit Alarm dialogue to edit the specified alarm.
00608 */
00609 void MainWindow::executeEdit(KAEvent& event, MainWindow* win)
00610 {
00611     EditAlarmDlg editDlg(false, i18n("Edit Alarm"), win, 0, &event);
00612     if (editDlg.exec() == TQDialog::Accepted)
00613     {
00614         KAEvent newEvent;
00615         bool changeDeferral = !editDlg.getEvent(newEvent);
00616 
00617         // Update the event in the displays and in the calendar file
00618         AlarmListView* view = win ? win->mListView : 0;
00619         if (changeDeferral)
00620         {
00621             // The only change has been to an existing deferral
00622             if (KAlarm::updateEvent(newEvent, view, &editDlg, true, false) != KAlarm::UPDATE_OK)   // keep the same event ID
00623                 return;   // failed to save event
00624         }
00625         else
00626         {
00627             if (KAlarm::modifyEvent(event, newEvent, view, &editDlg) == KAlarm::UPDATE_KORG_ERR)
00628                 KAlarm::displayKOrgUpdateError(&editDlg, KAlarm::KORG_ERR_MODIFY, 1);
00629         }
00630         Undo::saveEdit(event, newEvent);
00631 
00632         KAlarm::outputAlarmWarnings(&editDlg, &newEvent);
00633     }
00634 }
00635 
00636 /******************************************************************************
00637 *  Called when the View button is clicked to view the currently highlighted
00638 *  alarm in the list.
00639 */
00640 void MainWindow::slotView()
00641 {
00642     AlarmListViewItem* item = mListView->selectedItem();
00643     if (item)
00644     {
00645         KAEvent event = item->event();
00646         EditAlarmDlg editDlg(false, (event.expired() ? i18n("Expired Alarm") + " [" + i18n("read-only") + ']'
00647                                                      : i18n("View Alarm")),
00648                              this, 0, &event, true);
00649         editDlg.exec();
00650     }
00651 }
00652 
00653 /******************************************************************************
00654 *  Called when the Delete button is clicked to delete the currently highlighted
00655 *  alarms in the list.
00656 */
00657 void MainWindow::slotDelete()
00658 {
00659     TQValueList<EventListViewItemBase*> items = mListView->selectedItems();
00660     // Copy the events to be deleted, in case any are deleted by being
00661     // triggered while the confirmation prompt is displayed.
00662     TQValueList<KAEvent> events;
00663     TQValueList<KAEvent> origEvents;
00664     for (TQValueList<EventListViewItemBase*>::Iterator iit = items.begin();  iit != items.end();  ++iit)
00665     {
00666         AlarmListViewItem* item = (AlarmListViewItem*)(*iit);
00667         events.append(item->event());
00668         origEvents.append(item->event());
00669     }
00670     if (Preferences::confirmAlarmDeletion())
00671     {
00672         int n = items.count();
00673         if (KMessageBox::warningContinueCancel(this, i18n("Do you really want to delete the selected alarm?",
00674                                                           "Do you really want to delete the %n selected alarms?", n),
00675                                                i18n("Delete Alarm", "Delete Alarms", n),
00676                                                KGuiItem(i18n("&Delete"), "editdelete"),
00677                                                Preferences::CONFIRM_ALARM_DELETION)
00678             != KMessageBox::Continue)
00679             return;
00680     }
00681 
00682     int warnErr = 0;
00683     int warnKOrg = 0;
00684     AlarmCalendar::activeCalendar()->startUpdate();    // prevent multiple saves of the calendars until we're finished
00685     AlarmCalendar::expiredCalendar()->startUpdate();
00686     for (TQValueList<KAEvent>::Iterator it = events.begin();  it != events.end();  ++it)
00687     {
00688         // Delete the event from the calendar and displays
00689         switch (KAlarm::deleteEvent(*it))
00690         {
00691             case KAlarm::UPDATE_ERROR:
00692             case KAlarm::UPDATE_FAILED:
00693             case KAlarm::SAVE_FAILED:
00694                 ++warnErr;
00695                 break;
00696             case KAlarm::UPDATE_KORG_ERR:
00697                 ++warnKOrg;
00698                 break;
00699             default:
00700                 break;
00701         }
00702     }
00703     if (!AlarmCalendar::activeCalendar()->endUpdate())      // save the calendars now
00704         warnErr = events.count();
00705     AlarmCalendar::expiredCalendar()->endUpdate();
00706     Undo::saveDeletes(origEvents);
00707 
00708     if (warnErr)
00709         KAlarm::displayUpdateError(this, KAlarm::UPDATE_FAILED, KAlarm::ERR_DELETE, warnErr);
00710     else if (warnKOrg)
00711         KAlarm::displayKOrgUpdateError(this, KAlarm::KORG_ERR_DELETE, warnKOrg);
00712 }
00713 
00714 /******************************************************************************
00715 *  Called when the Reactivate button is clicked to reinstate the currently
00716 *  highlighted expired alarms in the list.
00717 */
00718 void MainWindow::slotReactivate()
00719 {
00720     int warnErr = 0;
00721     int warnKOrg = 0;
00722     TQValueList<KAEvent> events;
00723     TQValueList<EventListViewItemBase*> items = mListView->selectedItems();
00724     mListView->clearSelection();
00725     AlarmCalendar::activeCalendar()->startUpdate();    // prevent multiple saves of the calendars until we're finished
00726     AlarmCalendar::expiredCalendar()->startUpdate();
00727     for (TQValueList<EventListViewItemBase*>::Iterator it = items.begin();  it != items.end();  ++it)
00728     {
00729         // Add the alarm to the displayed lists and to the calendar file
00730         AlarmListViewItem* item = (AlarmListViewItem*)(*it);
00731         KAEvent event = item->event();
00732         events.append(event);
00733         switch (KAlarm::reactivateEvent(event, mListView, true))
00734         {
00735             case KAlarm::UPDATE_ERROR:
00736             case KAlarm::UPDATE_FAILED:
00737             case KAlarm::SAVE_FAILED:
00738                 ++warnErr;
00739                 break;
00740             case KAlarm::UPDATE_KORG_ERR:
00741                 ++warnKOrg;
00742                 break;
00743             default:
00744                 break;
00745         }
00746     }
00747     if (!AlarmCalendar::activeCalendar()->endUpdate())      // save the calendars now
00748         warnErr = items.count();
00749     AlarmCalendar::expiredCalendar()->endUpdate();
00750     Undo::saveReactivates(events);
00751 
00752     if (warnErr)
00753         KAlarm::displayUpdateError(this, KAlarm::UPDATE_FAILED, KAlarm::ERR_REACTIVATE, warnErr);
00754     else if (warnKOrg)
00755         KAlarm::displayKOrgUpdateError(this, KAlarm::KORG_ERR_ADD, warnKOrg);
00756 }
00757 
00758 /******************************************************************************
00759 *  Called when the Enable/Disable button is clicked to enable or disable the
00760 *  currently highlighted alarms in the list.
00761 */
00762 void MainWindow::slotEnable()
00763 {
00764     bool enable = mActionEnableEnable;    // save since changed in response to KAlarm::enableEvent()
00765     int warnErr = 0;
00766     TQValueList<EventListViewItemBase*> items = mListView->selectedItems();
00767     AlarmCalendar::activeCalendar()->startUpdate();    // prevent multiple saves of the calendars until we're finished
00768     for (TQValueList<EventListViewItemBase*>::Iterator it = items.begin();  it != items.end();  ++it)
00769     {
00770         AlarmListViewItem* item = (AlarmListViewItem*)(*it);
00771         KAEvent event = item->event();
00772 
00773         // Enable the alarm in the displayed lists and in the calendar file
00774         if (KAlarm::enableEvent(event, mListView, enable) != KAlarm::UPDATE_OK)
00775             ++warnErr;
00776     }
00777     if (!AlarmCalendar::activeCalendar()->endUpdate())      // save the calendars now
00778         warnErr = items.count();
00779     if (warnErr)
00780         KAlarm::displayUpdateError(this, KAlarm::UPDATE_FAILED, KAlarm::ERR_ADD, warnErr);
00781 }
00782 
00783 /******************************************************************************
00784 *  Called when the Show Alarm Times menu item is selected or deselected.
00785 */
00786 void MainWindow::slotShowTime()
00787 {
00788     mShowTime = !mShowTime;
00789     mActionShowTime->setChecked(mShowTime);
00790     if (!mShowTime  &&  !mShowTimeTo)
00791         slotShowTimeTo();    // at least one time column must be displayed
00792     else
00793     {
00794         mListView->selectTimeColumns(mShowTime, mShowTimeTo);
00795         KConfig* config = KGlobal::config();
00796         config->setGroup(VIEW_GROUP);
00797         config->writeEntry(SHOW_TIME_KEY, mShowTime);
00798         config->writeEntry(SHOW_TIME_TO_KEY, mShowTimeTo);
00799     }
00800 }
00801 
00802 /******************************************************************************
00803 *  Called when the Show Time To Alarms menu item is selected or deselected.
00804 */
00805 void MainWindow::slotShowTimeTo()
00806 {
00807     mShowTimeTo = !mShowTimeTo;
00808     mActionShowTimeTo->setChecked(mShowTimeTo);
00809     if (!mShowTimeTo  &&  !mShowTime)
00810         slotShowTime();    // at least one time column must be displayed
00811     else
00812     {
00813         mListView->selectTimeColumns(mShowTime, mShowTimeTo);
00814         KConfig* config = KGlobal::config();
00815         config->setGroup(VIEW_GROUP);
00816         config->writeEntry(SHOW_TIME_KEY, mShowTime);
00817         config->writeEntry(SHOW_TIME_TO_KEY, mShowTimeTo);
00818     }
00819     setUpdateTimer();
00820 }
00821 
00822 /******************************************************************************
00823 *  Called when the Show Expired Alarms menu item is selected or deselected.
00824 */
00825 void MainWindow::slotShowExpired()
00826 {
00827     mShowExpired = !mShowExpired;
00828     mActionShowExpired->setChecked(mShowExpired);
00829     mActionShowExpired->setToolTip(mShowExpired ? i18n_HideExpiredAlarms() : i18n_ShowExpiredAlarms());
00830     mListView->showExpired(mShowExpired);
00831     mListView->refresh();
00832     KConfig* config = KGlobal::config();
00833     config->setGroup(VIEW_GROUP);
00834     config->writeEntry(SHOW_ARCHIVED_KEY, mShowExpired);
00835 }
00836 
00837 /******************************************************************************
00838 *  Called when the Import Alarms menu item is selected, to merge alarms from an
00839 *  external calendar into the current calendars.
00840 */
00841 void MainWindow::slotImportAlarms()
00842 {
00843     if (AlarmCalendar::importAlarms(this))
00844         mListView->refresh();
00845 }
00846 
00847 /******************************************************************************
00848 *  Called when the Import Birthdays menu item is selected, to display birthdays
00849 *  from the address book for selection as alarms.
00850 */
00851 void MainWindow::slotBirthdays()
00852 {
00853     BirthdayDlg dlg(this);
00854     if (dlg.exec() == TQDialog::Accepted)
00855     {
00856         TQValueList<KAEvent> events = dlg.events();
00857         if (events.count())
00858         {
00859             mListView->clearSelection();
00860             int warnErr = 0;
00861             int warnKOrg = 0;
00862             for (TQValueList<KAEvent>::Iterator ev = events.begin();  ev != events.end();  ++ev)
00863             {
00864                 // Add alarm to the displayed lists and to the calendar file
00865                 switch (KAlarm::addEvent(*ev, mListView))
00866                 {
00867                     case KAlarm::UPDATE_ERROR:
00868                     case KAlarm::UPDATE_FAILED:
00869                     case KAlarm::SAVE_FAILED:
00870                         ++warnErr;
00871                         break;
00872                     case KAlarm::UPDATE_KORG_ERR:
00873                         ++warnKOrg;
00874                         break;
00875                     default:
00876                         break;
00877                 }
00878             }
00879             if (warnErr)
00880                 KAlarm::displayUpdateError(this, KAlarm::UPDATE_FAILED, KAlarm::ERR_ADD, warnErr);
00881             else if (warnKOrg)
00882                 KAlarm::displayKOrgUpdateError(this, KAlarm::KORG_ERR_ADD, warnKOrg);
00883             KAlarm::outputAlarmWarnings(&dlg);
00884         }
00885     }
00886 }
00887 
00888 /******************************************************************************
00889 *  Called when the Templates menu item is selected, to display the alarm
00890 *  template editing dialogue.
00891 */
00892 void MainWindow::slotTemplates()
00893 {
00894     if (!mTemplateDlg)
00895     {
00896         mTemplateDlg = TemplateDlg::create(this);
00897         enableTemplateMenuItem(false);     // disable menu item in all windows
00898         connect(mTemplateDlg, TQT_SIGNAL(finished()), TQT_SLOT(slotTemplatesEnd()));
00899         mTemplateDlg->show();
00900     }
00901 }
00902 
00903 /******************************************************************************
00904 *  Called when the alarm template editing dialogue has exited.
00905 */
00906 void MainWindow::slotTemplatesEnd()
00907 {
00908     if (mTemplateDlg)
00909     {
00910         mTemplateDlg->delayedDestruct();   // this deletes the dialogue once it is safe to do so
00911         mTemplateDlg = 0;
00912         enableTemplateMenuItem(true);      // re-enable menu item in all windows
00913     }
00914 }
00915 
00916 /******************************************************************************
00917 *  Called when the Display System Tray Icon menu item is selected.
00918 */
00919 void MainWindow::slotToggleTrayIcon()
00920 {
00921     theApp()->displayTrayIcon(!theApp()->trayIconDisplayed(), this);
00922 }
00923 
00924 /******************************************************************************
00925 * Called when the user preferences have changed.
00926 */
00927 void MainWindow::slotPrefsChanged()
00928 {
00929     mActionShowExpired->setEnabled(Preferences::expiredKeepDays());
00930     updateTrayIconAction();
00931 }
00932 
00933 /******************************************************************************
00934 * Called when the system tray icon is created or destroyed.
00935 * Set the system tray icon menu text according to whether or not the system
00936 * tray icon is currently visible.
00937 */
00938 void MainWindow::updateTrayIconAction()
00939 {
00940     mActionToggleTrayIcon->setEnabled(theApp()->haveSystemTray() && !theApp()->wantRunInSystemTray());
00941     mActionToggleTrayIcon->setChecked(theApp()->trayIconDisplayed());
00942 }
00943 
00944 /******************************************************************************
00945 * Called when the Actions menu is about to be displayed.
00946 * Update the status of the Alarms Enabled menu item.
00947 */
00948 void MainWindow::updateActionsMenu()
00949 {
00950     Daemon::checkStatus();   // update the Alarms Enabled item status
00951 }
00952 
00953 /******************************************************************************
00954 *  Called when the active status of Find changes.
00955 */
00956 void MainWindow::slotFindActive(bool active)
00957 {
00958     mActionFindNext->setEnabled(active);
00959     mActionFindPrev->setEnabled(active);
00960 }
00961 
00962 /******************************************************************************
00963 *  Called when the Undo action is selected.
00964 */
00965 void MainWindow::slotUndo()
00966 {
00967     Undo::undo(this, KAlarm::stripAccel(mActionUndo->text()));
00968 }
00969 
00970 /******************************************************************************
00971 *  Called when the Redo action is selected.
00972 */
00973 void MainWindow::slotRedo()
00974 {
00975     Undo::redo(this, KAlarm::stripAccel(mActionRedo->text()));
00976 }
00977 
00978 /******************************************************************************
00979 *  Called when an Undo item is selected.
00980 */
00981 void MainWindow::slotUndoItem(int id)
00982 {
00983     Undo::undo(id, this, Undo::actionText(Undo::UNDO, id));
00984 }
00985 
00986 /******************************************************************************
00987 *  Called when a Redo item is selected.
00988 */
00989 void MainWindow::slotRedoItem(int id)
00990 {
00991     Undo::redo(id, this, Undo::actionText(Undo::REDO, id));
00992 }
00993 
00994 /******************************************************************************
00995 *  Called when the Undo menu is about to show.
00996 *  Populates the menu.
00997 */
00998 void MainWindow::slotInitUndoMenu()
00999 {
01000     initUndoMenu(mActionUndo->popupMenu(), Undo::UNDO);
01001 }
01002 
01003 /******************************************************************************
01004 *  Called when the Redo menu is about to show.
01005 *  Populates the menu.
01006 */
01007 void MainWindow::slotInitRedoMenu()
01008 {
01009     initUndoMenu(mActionRedo->popupMenu(), Undo::REDO);
01010 }
01011 
01012 /******************************************************************************
01013 *  Populate the undo or redo menu.
01014 */
01015 void MainWindow::initUndoMenu(KPopupMenu* menu, Undo::Type type)
01016 {
01017     menu->clear();
01018     const TQString& action = (type == Undo::UNDO) ? undoTextStripped : redoTextStripped;
01019     TQValueList<int> ids = Undo::ids(type);
01020     for (TQValueList<int>::ConstIterator it = ids.begin();  it != ids.end();  ++it)
01021     {
01022         int id = *it;
01023         TQString actText = Undo::actionText(type, id);
01024         TQString descrip = Undo::description(type, id);
01025         TQString text = descrip.isEmpty()
01026                      ? i18n("Undo/Redo [action]", "%1 %2").arg(action).arg(actText)
01027                      : i18n("Undo [action]: message", "%1 %2: %3").arg(action).arg(actText).arg(descrip);
01028         menu->insertItem(text, id);
01029     }
01030 }
01031 
01032 /******************************************************************************
01033 *  Called when the status of the Undo or Redo list changes.
01034 *  Change the Undo or Redo text to include the action which would be undone/redone.
01035 */
01036 void MainWindow::slotUndoStatus(const TQString& undo, const TQString& redo)
01037 {
01038     if (undo.isNull())
01039     {
01040         mActionUndo->setEnabled(false);
01041         mActionUndo->setText(undoText);
01042     }
01043     else
01044     {
01045         mActionUndo->setEnabled(true);
01046         mActionUndo->setText(TQString("%1 %2").arg(undoText).arg(undo));
01047     }
01048     if (redo.isNull())
01049     {
01050         mActionRedo->setEnabled(false);
01051         mActionRedo->setText(redoText);
01052     }
01053     else
01054     {
01055         mActionRedo->setEnabled(true);
01056         mActionRedo->setText(TQString("%1 %2").arg(redoText).arg(redo));
01057     }
01058 }
01059 
01060 /******************************************************************************
01061 *  Called when the Reset Daemon menu item is selected.
01062 */
01063 void MainWindow::slotResetDaemon()
01064 {
01065     KAlarm::resetDaemon();
01066 }
01067 
01068 /******************************************************************************
01069 *  Called when the "Configure KAlarm" menu item is selected.
01070 */
01071 void MainWindow::slotPreferences()
01072 {
01073     KAlarmPrefDlg::display();
01074 }
01075 
01076 /******************************************************************************
01077 *  Called when the Configure Keys menu item is selected.
01078 */
01079 void MainWindow::slotConfigureKeys()
01080 {
01081     KKeyDialog::configure(actionCollection(), this);
01082 }
01083 
01084 /******************************************************************************
01085 *  Called when the Configure Toolbars menu item is selected.
01086 */
01087 void MainWindow::slotConfigureToolbar()
01088 {
01089     saveMainWindowSettings(KGlobal::config(), WINDOW_NAME);
01090     KEditToolbar dlg(factory());
01091     connect(&dlg, TQT_SIGNAL(newToolbarConfig()), TQT_TQOBJECT(this), TQT_SLOT(slotNewToolbarConfig()));
01092     dlg.exec();
01093 }
01094 
01095 /******************************************************************************
01096 *  Called when OK or Apply is clicked in the Configure Toolbars dialog, to save
01097 *  the new configuration.
01098 */
01099 void MainWindow::slotNewToolbarConfig()
01100 {
01101     createGUI(UI_FILE);
01102     applyMainWindowSettings(KGlobal::config(), WINDOW_NAME);
01103 }
01104 
01105 /******************************************************************************
01106 *  Called when the Quit menu item is selected.
01107 */
01108 void MainWindow::slotQuit()
01109 {
01110     theApp()->doQuit(this);
01111 }
01112 
01113 /******************************************************************************
01114 *  Called when the user or the session manager attempts to close the window.
01115 */
01116 void MainWindow::closeEvent(TQCloseEvent* ce)
01117 {
01118     if (!theApp()->sessionClosingDown()  &&  isTrayParent())
01119     {
01120         // The user (not the session manager) wants to close the window.
01121         // It's the parent window of the system tray icon, so just hide
01122         // it to prevent the system tray icon closing.
01123         hide();
01124         theApp()->quitIf();
01125         ce->ignore();
01126     }
01127     else
01128         ce->accept();
01129 }
01130 
01131 /******************************************************************************
01132 *  Called when an item is deleted from the ListView.
01133 *  Disables the actions if no item is still selected.
01134 */
01135 void MainWindow::slotDeletion()
01136 {
01137     if (!mListView->selectedCount())
01138     {
01139         kdDebug(5950) << "MainWindow::slotDeletion(true)\n";
01140         mActionCreateTemplate->setEnabled(false);
01141         mActionCopy->setEnabled(false);
01142         mActionModify->setEnabled(false);
01143         mActionView->setEnabled(false);
01144         mActionDelete->setEnabled(false);
01145         mActionReactivate->setEnabled(false);
01146         mActionEnable->setEnabled(false);
01147     }
01148 }
01149 
01150 /******************************************************************************
01151 *  Called when the drag cursor enters the window.
01152 */
01153 void MainWindow::dragEnterEvent(TQDragEnterEvent* e)
01154 {
01155     executeDragEnterEvent(e);
01156 }
01157 
01158 /******************************************************************************
01159 *  Called when the drag cursor enters a main or system tray window, to accept
01160 *  or reject the dragged object.
01161 */
01162 void MainWindow::executeDragEnterEvent(TQDragEnterEvent* e)
01163 {
01164     if (KCal::ICalDrag::canDecode(e))
01165         e->accept(!AlarmListView::dragging());   // don't accept "text/calendar" objects from KAlarm
01166     else
01167         e->accept(TQTextDrag::canDecode(e)
01168                || KURLDrag::canDecode(e)
01169                || KPIM::MailListDrag::canDecode(e));
01170 }
01171 
01172 /******************************************************************************
01173 *  Called when an object is dropped on the window.
01174 *  If the object is recognised, the edit alarm dialog is opened appropriately.
01175 */
01176 void MainWindow::dropEvent(TQDropEvent* e)
01177 {
01178     executeDropEvent(this, e);
01179 }
01180 
01181 static TQString getMailHeader(const char* header, KMime::Content& content)
01182 {
01183     KMime::Headers::Base* hd = content.getHeaderByType(header);
01184     return hd ? hd->asUnicodeString() : TQString();
01185 }
01186 
01187 /******************************************************************************
01188 *  Called when an object is dropped on a main or system tray window, to
01189 *  evaluate the action required and extract the text.
01190 */
01191 void MainWindow::executeDropEvent(MainWindow* win, TQDropEvent* e)
01192 {
01193     KAEvent::Action action = KAEvent::MESSAGE;
01194     TQString        text;
01195     TQByteArray     bytes;
01196     AlarmText      alarmText;
01197     KPIM::MailList mailList;
01198     KURL::List     files;
01199     KCal::CalendarLocal calendar(TQString::fromLatin1("UTC"));
01200     calendar.setLocalTime();    // default to local time (i.e. no time zone)
01201 #ifndef NDEBUG
01202     TQCString fmts;
01203     for (int idbg = 0;  e->format(idbg);  ++idbg)
01204     {
01205         if (idbg) fmts += ", ";
01206         fmts += e->format(idbg);
01207     }
01208     kdDebug(5950) << "MainWindow::executeDropEvent(): " << fmts << endl;
01209 #endif
01210 
01211     /* The order of the tests below matters, since some dropped objects
01212      * provide more than one mime type.
01213      * Don't change them without careful thought !!
01214      */
01215     if (e->provides("message/rfc822")
01216     &&  !(bytes = e->encodedData("message/rfc822")).isEmpty())
01217     {
01218         // Email message(s). Ignore all but the first.
01219         kdDebug(5950) << "MainWindow::executeDropEvent(email)" << endl;
01220         TQCString mails(bytes.data(), bytes.size());
01221         KMime::Content content;
01222         content.setContent(mails);
01223         content.parse();
01224         TQString body;
01225         if (content.textContent())
01226             content.textContent()->decodedText(body, true, true);    // strip trailing newlines & spaces
01227         unsigned long sernum = 0;
01228         if (e->provides(KPIM::MailListDrag::format())
01229         &&  KPIM::MailListDrag::decode(e, mailList)
01230         &&  mailList.count())
01231         {
01232             // Get its KMail serial number to allow the KMail message
01233             // to be called up from the alarm message window.
01234             sernum = mailList.first().serialNumber();
01235         }
01236         alarmText.setEmail(getMailHeader("To", content),
01237                            getMailHeader("From", content),
01238                            getMailHeader("Cc", content),
01239                            getMailHeader("Date", content),
01240                            getMailHeader("Subject", content),
01241                    body, sernum);
01242     }
01243     else if (KURLDrag::decode(e, files)  &&  files.count())
01244     {
01245         kdDebug(5950) << "MainWindow::executeDropEvent(URL)" << endl;
01246         action = KAEvent::FILE;
01247         alarmText.setText(files.first().prettyURL());
01248     }
01249     else if (e->provides(KPIM::MailListDrag::format())
01250     &&       KPIM::MailListDrag::decode(e, mailList))
01251     {
01252         // KMail message(s). Ignore all but the first.
01253         kdDebug(5950) << "MainWindow::executeDropEvent(KMail_list)" << endl;
01254         if (!mailList.count())
01255             return;
01256         KPIM::MailSummary& summary = mailList.first();
01257         TQDateTime dt;
01258         dt.setTime_t(summary.date());
01259         TQString body = KAMail::getMailBody(summary.serialNumber());
01260         alarmText.setEmail(summary.to(), summary.from(), TQString(),
01261                            KGlobal::locale()->formatDateTime(dt), summary.subject(),
01262                            body, summary.serialNumber());
01263     }
01264     else if (KCal::ICalDrag::decode(e, &calendar))
01265     {
01266         // iCalendar - ignore all but the first event
01267         kdDebug(5950) << "MainWindow::executeDropEvent(iCalendar)" << endl;
01268         KCal::Event::List events = calendar.rawEvents();
01269         if (!events.isEmpty())
01270         {
01271             KAEvent ev(*events.first());
01272             executeNew(win, &ev);
01273         }
01274         return;
01275     }
01276     else if (TQTextDrag::decode(e, text))
01277     {
01278         kdDebug(5950) << "MainWindow::executeDropEvent(text)" << endl;
01279         alarmText.setText(text);
01280     }
01281     else
01282         return;
01283 
01284     if (!alarmText.isEmpty())
01285         executeNew(win, 0, action, alarmText);
01286 }
01287 
01288 /******************************************************************************
01289 *  Called when the selected items in the ListView changes.
01290 *  Selects the new current item, and enables the actions appropriately.
01291 */
01292 void MainWindow::slotSelection()
01293 {
01294     // Find which item has been selected, and whether more than one is selected
01295     TQValueList<EventListViewItemBase*> items = mListView->selectedItems();
01296     int count = items.count();
01297     AlarmListViewItem* item = (AlarmListViewItem*)((count == 1) ? items.first() : 0);
01298     bool enableReactivate = true;
01299     bool enableEnableDisable = true;
01300     bool enableEnable = false;
01301     bool enableDisable = false;
01302     TQDateTime now = TQDateTime::currentDateTime();
01303     for (TQValueList<EventListViewItemBase*>::Iterator it = items.begin();  it != items.end();  ++it)
01304     {
01305         const KAEvent& event = ((AlarmListViewItem*)(*it))->event();
01306         if (enableReactivate
01307         &&  (!event.expired()  ||  !event.occursAfter(now, true)))
01308             enableReactivate = false;
01309         if (enableEnableDisable)
01310         {
01311             if (event.expired())
01312                 enableEnableDisable = enableEnable = enableDisable = false;
01313             else
01314             {
01315                 if (!enableEnable  &&  !event.enabled())
01316                     enableEnable = true;
01317                 if (!enableDisable  &&  event.enabled())
01318                     enableDisable = true;
01319             }
01320         }
01321     }
01322 
01323     kdDebug(5950) << "MainWindow::slotSelection(true)\n";
01324     mActionCreateTemplate->setEnabled(count == 1);
01325     mActionCopy->setEnabled(count == 1);
01326     mActionModify->setEnabled(item && !mListView->expired(item));
01327     mActionView->setEnabled(count == 1);
01328     mActionDelete->setEnabled(count);
01329     mActionReactivate->setEnabled(count && enableReactivate);
01330     mActionEnable->setEnabled(enableEnable || enableDisable);
01331     if (enableEnable || enableDisable)
01332         setEnableText(enableEnable);
01333 }
01334 
01335 /******************************************************************************
01336 * Called when a context menu is requested either by a mouse click or by a
01337 * key press.
01338 */
01339 void MainWindow::slotContextMenuRequested(TQListViewItem* item, const TQPoint& pt, int)
01340 {
01341     kdDebug(5950) << "MainWindow::slotContextMenuRequested()" << endl;
01342     if (mContextMenu)
01343         mContextMenu->popup(pt);
01344 }
01345 
01346 /******************************************************************************
01347 * Called when the mouse is clicked on the ListView.
01348 * Deselects the current item and disables the actions if appropriate.
01349 * Note that if a right button click is handled by slotContextMenuRequested().
01350 */
01351 void MainWindow::slotMouseClicked(int button, TQListViewItem* item, const TQPoint& pt, int)
01352 {
01353     if (button != Qt::RightButton  &&  !item)
01354     {
01355         kdDebug(5950) << "MainWindow::slotMouseClicked(left)" << endl;
01356         mListView->clearSelection();
01357         mActionCreateTemplate->setEnabled(false);
01358         mActionCopy->setEnabled(false);
01359         mActionModify->setEnabled(false);
01360         mActionView->setEnabled(false);
01361         mActionDelete->setEnabled(false);
01362         mActionReactivate->setEnabled(false);
01363         mActionEnable->setEnabled(false);
01364     }
01365 }
01366 
01367 /******************************************************************************
01368 *  Called when the mouse is double clicked on the ListView.
01369 *  Displays the Edit Alarm dialog, for the clicked item if applicable.
01370 */
01371 void MainWindow::slotDoubleClicked(TQListViewItem* item)
01372 {
01373     kdDebug(5950) << "MainWindow::slotDoubleClicked()\n";
01374     if (item)
01375     {
01376         if (mListView->expired((AlarmListViewItem*)item))
01377             slotView();
01378         else
01379             slotModify();
01380     }
01381     else
01382         slotNew();
01383 }
01384 
01385 /******************************************************************************
01386 *  Set the text of the Enable/Disable menu action.
01387 */
01388 void MainWindow::setEnableText(bool enable)
01389 {
01390     mActionEnableEnable = enable;
01391     mActionEnable->setText(enable ? i18n("Ena&ble") : i18n("Disa&ble"));
01392 }
01393 
01394 /******************************************************************************
01395 *  Display or hide the specified main window.
01396 *  This should only be called when the application doesn't run in the system tray.
01397 */
01398 MainWindow* MainWindow::toggleWindow(MainWindow* win)
01399 {
01400     if (win  &&  mWindowList.find(win) != mWindowList.end())
01401     {
01402         // A window is specified (and it exists)
01403         if (win->isVisible())
01404         {
01405             // The window is visible, so close it
01406             win->close();
01407             return 0;
01408         }
01409         else
01410         {
01411             // The window is hidden, so display it
01412             win->hide();        // in case it's on a different desktop
01413             win->showNormal();
01414             win->raise();
01415             win->setActiveWindow();
01416             return win;
01417         }
01418     }
01419 
01420     // No window is specified, or the window doesn't exist. Open a new one.
01421     win = create();
01422     win->show();
01423     return win;
01424 }