kalarm

mainwindow.cpp

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