• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

kalarm

mainwindow.cpp

Go to the documentation of this file.
00001 /*
00002  *  mainwindow.cpp  -  main application window
00003  *  Program:  kalarm
00004  *  Copyright © 2001-2008 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 #include "mainwindow.moc"
00023 
00024 #include "alarmcalendar.h"
00025 #include "alarmevent.h"
00026 #include "alarmlistdelegate.h"
00027 #include "alarmlistfiltermodel.h"
00028 #include "eventlistmodel.h"
00029 #include "alarmlistview.h"
00030 #include "alarmresources.h"
00031 #include "alarmtext.h"
00032 #include "birthdaydlg.h"
00033 #include "functions.h"
00034 #include "kalarmapp.h"
00035 #include "kamail.h"
00036 #include "newalarmaction.h"
00037 #include "prefdlg.h"
00038 #include "preferences.h"
00039 #include "resourceselector.h"
00040 #include "synchtimer.h"
00041 #include "templatedlg.h"
00042 #include "templatemenuaction.h"
00043 #include "templatepickdlg.h"
00044 #include "traywindow.h"
00045 
00046 #include <QHeaderView>
00047 #include <QSplitter>
00048 #include <QByteArray>
00049 #include <QDesktopWidget>
00050 #include <QDragEnterEvent>
00051 #include <QDropEvent>
00052 #include <QResizeEvent>
00053 #include <QCloseEvent>
00054 
00055 #include <kmenubar.h>
00056 #include <ktoolbar.h>
00057 #include <kmenu.h>
00058 #include <kaction.h>
00059 #include <kactioncollection.h>
00060 #include <kinputdialog.h>
00061 
00062 #include <kstandardaction.h>
00063 #include <kiconloader.h>
00064 #include <kmessagebox.h>
00065 #include <kurl.h>
00066 #include <klocale.h>
00067 #include <kglobalsettings.h>
00068 #include <kconfiggroup.h>
00069 #include <kshortcutsdialog.h>
00070 #include <kedittoolbar.h>
00071 #include <kxmlguifactory.h>
00072 #include <kaboutdata.h>
00073 #include <kdebug.h>
00074 #include <ktoggleaction.h>
00075 #include <ktoolbarpopupaction.h>
00076 #include <kicon.h>
00077 #include <libkdepim/maillistdrag.h>
00078 #include <kmime/kmime_content.h>
00079 #include <kcal/calendarlocal.h>
00080 #include <kcal/icaldrag.h>
00081 
00082 using namespace KCal;
00083 
00084 static const char* UI_FILE     = "kalarmui.rc";
00085 static const char* WINDOW_NAME = "MainWindow";
00086 
00087 static const char* VIEW_GROUP         = "View";
00088 static const char* SHOW_TIME_KEY      = "ShowAlarmTime";
00089 static const char* SHOW_TIME_TO_KEY   = "ShowTimeToAlarm";
00090 static const char* SHOW_ARCHIVED_KEY  = "ShowArchivedAlarms";
00091 static const char* SHOW_RESOURCES_KEY = "ShowResources";
00092 
00093 static QString   undoText;
00094 static QString   undoTextStripped;
00095 static KShortcut undoShortcut;
00096 static QString   redoText;
00097 static QString   redoTextStripped;
00098 static KShortcut redoShortcut;
00099 
00100 
00101 /*=============================================================================
00102 =  Class: MainWindow
00103 =============================================================================*/
00104 
00105 MainWindow::WindowList   MainWindow::mWindowList;
00106 TemplateDlg*             MainWindow::mTemplateDlg = 0;
00107 
00108 // Collect these widget labels together to ensure consistent wording and
00109 // translations across different modules.
00110 QString MainWindow::i18n_a_ShowAlarmTimes()        { return i18nc("@action", "Show &Alarm Times"); }
00111 QString MainWindow::i18n_chk_ShowAlarmTime()       { return i18nc("@option:check", "Show alarm time"); }
00112 QString MainWindow::i18n_o_ShowTimeToAlarms()      { return i18nc("@action", "Show Time t&o Alarms"); }
00113 QString MainWindow::i18n_chk_ShowTimeToAlarm()     { return i18nc("@option:check", "Show time until alarm"); }
00114 QString MainWindow::i18n_a_ShowArchivedAlarms()    { return i18nc("@action", "Show &Archived Alarms"); }
00115 QString MainWindow::i18n_tip_ShowArchivedAlarms()  { return i18nc("@info:tooltip", "Show Archived Alarms"); }
00116 QString MainWindow::i18n_tip_HideArchivedAlarms()  { return i18nc("@info:tooltip", "Hide Archived Alarms"); }
00117 
00118 
00119 /******************************************************************************
00120 * Construct an instance.
00121 * To avoid resize() events occurring while still opening the calendar (and
00122 * resultant crashes), the calendar is opened before constructing the instance.
00123 */
00124 MainWindow* MainWindow::create(bool restored)
00125 {
00126     theApp()->checkCalendar();    // ensure calendar is open
00127     return new MainWindow(restored);
00128 }
00129 
00130 MainWindow::MainWindow(bool restored)
00131     : MainWindowBase(0, Qt::WindowContextHelpButtonHint),
00132       mResourcesWidth(-1),
00133       mHiddenTrayParent(false),
00134       mShown(false),
00135       mResizing(false)
00136 {
00137     kDebug();
00138     setAttribute(Qt::WA_DeleteOnClose);
00139     setWindowModality(Qt::WindowModal);
00140     setObjectName("MainWin");    // used by LikeBack
00141     setPlainCaption(KGlobal::mainComponent().aboutData()->programName());
00142     KConfigGroup config(KGlobal::config(), VIEW_GROUP);
00143     mShowResources = config.readEntry(SHOW_RESOURCES_KEY, false);
00144     mShowArchived  = config.readEntry(SHOW_ARCHIVED_KEY, false);
00145     mShowTime      = config.readEntry(SHOW_TIME_KEY, true);
00146     mShowTimeTo    = config.readEntry(SHOW_TIME_TO_KEY, false);
00147     if (!restored)
00148     {
00149         KConfigGroup wconfig(KGlobal::config(), WINDOW_NAME);
00150         mResourcesWidth = wconfig.readEntry(QString::fromLatin1("Splitter %1").arg(KApplication::desktop()->width()), (int)0);
00151     }
00152 
00153     setAcceptDrops(true);         // allow drag-and-drop onto this window
00154     if (!mShowTimeTo)
00155         mShowTime = true;     // ensure at least one time column is visible
00156 
00157     mSplitter = new QSplitter(Qt::Horizontal, this);
00158     mSplitter->setChildrenCollapsible(false);
00159     mSplitter->installEventFilter(this);
00160     setCentralWidget(mSplitter);
00161 
00162     // Create the calendar resource selector widget
00163     AlarmResources* resources = AlarmResources::instance();
00164     mResourceSelector = new ResourceSelector(resources, mSplitter);
00165     mSplitter->setStretchFactor(0, 0);   // don't resize resource selector when window is resized
00166     mSplitter->setStretchFactor(1, 1);
00167     connect(resources, SIGNAL(signalErrorMessage(const QString&)), SLOT(showErrorMessage(const QString&)));
00168 
00169     // Create the alarm list widget
00170     mListFilterModel = new AlarmListFilterModel(EventListModel::alarms());
00171     mListFilterModel->setStatusFilter(mShowArchived ? static_cast<KCalEvent::Status>(KCalEvent::ACTIVE | KCalEvent::ARCHIVED) : KCalEvent::ACTIVE);
00172     mListView = new AlarmListView(WINDOW_NAME, mSplitter);
00173     mListView->setModel(mListFilterModel);
00174     mListView->selectTimeColumns(mShowTime, mShowTimeTo);
00175     mListView->sortByColumn(mShowTime ? EventListModel::TimeColumn : EventListModel::TimeToColumn, Qt::AscendingOrder);
00176     mListView->setItemDelegate(new AlarmListDelegate(mListView));
00177     connect(mListView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)), SLOT(slotSelection()));
00178     connect(mListView, SIGNAL(contextMenuRequested(const QPoint&)), SLOT(slotContextMenuRequested(const QPoint&)));
00179     connect(resources, SIGNAL(resourceStatusChanged(AlarmResource*, AlarmResources::Change)),
00180                        SLOT(slotResourceStatusChanged()));
00181     connect(mResourceSelector, SIGNAL(resized(const QSize&, const QSize&)), SLOT(resourcesResized()));
00182     initActions();
00183 
00184     setAutoSaveSettings(QLatin1String(WINDOW_NAME), true);    // save toolbars, window sizes etc.
00185     mWindowList.append(this);
00186     if (mWindowList.count() == 1)
00187     {
00188         // It's the first main window
00189         if (theApp()->wantShowInSystemTray())
00190             theApp()->displayTrayIcon(true, this);     // create system tray icon for run-in-system-tray mode
00191         else if (theApp()->trayWindow())
00192             theApp()->trayWindow()->setAssocMainWindow(this);    // associate this window with the system tray icon
00193     }
00194     slotResourceStatusChanged();   // initialise action states now that window is registered
00195 }
00196 
00197 MainWindow::~MainWindow()
00198 {
00199     kDebug();
00200     bool trayParent = isTrayParent();   // must call before removing from window list
00201     mWindowList.removeAt(mWindowList.indexOf(this));
00202     if (mWindowList.isEmpty())
00203     {
00204         delete EventListModel::alarms();
00205         delete EventListModel::templates();
00206     }
00207     if (theApp()->trayWindow())
00208     {
00209         if (trayParent)
00210             delete theApp()->trayWindow();
00211         else
00212             theApp()->trayWindow()->removeWindow(this);
00213     }
00214     KGlobal::config()->sync();    // save any new window size to disc
00215     theApp()->quitIf();
00216 }
00217 
00218 /******************************************************************************
00219 * Save settings to the session managed config file, for restoration
00220 * when the program is restored.
00221 */
00222 void MainWindow::saveProperties(KConfigGroup& config)
00223 {
00224     config.writeEntry("HiddenTrayParent", isTrayParent() && isHidden());
00225     config.writeEntry("ShowArchived", mShowArchived);
00226     config.writeEntry("ShowTime", mShowTime);
00227     config.writeEntry("ShowTimeTo", mShowTimeTo);
00228     config.writeEntry("ResourcesWidth", mResourceSelector->isHidden() ? 0 : mResourceSelector->width());
00229 }
00230 
00231 /******************************************************************************
00232 * Read settings from the session managed config file.
00233 * This function is automatically called whenever the app is being
00234 * restored. Read in whatever was saved in saveProperties().
00235 */
00236 void MainWindow::readProperties(const KConfigGroup& config)
00237 {
00238     mHiddenTrayParent = config.readEntry("HiddenTrayParent", true);
00239     mShowArchived     = config.readEntry("ShowArchived", false);
00240     mShowTime         = config.readEntry("ShowTime", true);
00241     mShowTimeTo       = config.readEntry("ShowTimeTo", false);
00242     mResourcesWidth   = config.readEntry("ResourcesWidth", (int)0);
00243     mShowResources    = (mResourcesWidth > 0);
00244 }
00245 
00246 /******************************************************************************
00247 * Get the main main window, i.e. the parent of the system tray icon, or if
00248 * none, the first main window to be created. Visible windows take precedence
00249 * over hidden ones.
00250 */
00251 MainWindow* MainWindow::mainMainWindow()
00252 {
00253     MainWindow* tray = theApp()->trayWindow() ? theApp()->trayWindow()->assocMainWindow() : 0;
00254     if (tray  &&  tray->isVisible())
00255         return tray;
00256     for (int i = 0, end = mWindowList.count();  i < end;  ++i)
00257         if (mWindowList[i]->isVisible())
00258             return mWindowList[i];
00259     if (tray)
00260         return tray;
00261     if (mWindowList.isEmpty())
00262         return 0;
00263     return mWindowList[0];
00264 }
00265 
00266 /******************************************************************************
00267 * Check whether this main window is effectively the parent of the system tray icon.
00268 */
00269 bool MainWindow::isTrayParent() const
00270 {
00271     TrayWindow* tray = theApp()->trayWindow();
00272     if (!tray  ||  !KSystemTrayIcon::isSystemTrayAvailable())
00273         return false;
00274     if (tray->assocMainWindow() == this)
00275         return true;
00276     return mWindowList.count() == 1;
00277 }
00278 
00279 /******************************************************************************
00280 *  Close all main windows.
00281 */
00282 void MainWindow::closeAll()
00283 {
00284     while (!mWindowList.isEmpty())
00285         delete mWindowList[0];    // N.B. the destructor removes the window from the list
00286 }
00287 
00288 /******************************************************************************
00289 * Intercept events for the splitter widget.
00290 */
00291 bool MainWindow::eventFilter(QObject* obj, QEvent* e)
00292 {
00293     if (obj == mSplitter)
00294     {
00295         switch (e->type())
00296         {
00297             case QEvent::Resize:
00298                 // Don't change resources size while WINDOW is being resized.
00299                 // Resize event always occurs before Paint.
00300                 mResizing = true;
00301                 break;
00302             case QEvent::Paint:
00303                 // Allow resources to be resized again
00304                 mResizing = false;
00305                 break;
00306             default:
00307                 break;
00308         }
00309     }
00310     return false;
00311 }
00312 
00313 /******************************************************************************
00314 *  Called when the window's size has changed (before it is painted).
00315 *  Sets the last column in the list view to extend at least to the right hand
00316 *  edge of the list view.
00317 *  Records the new size in the config file.
00318 */
00319 void MainWindow::resizeEvent(QResizeEvent* re)
00320 {
00321     // Save the window's new size only if it's the first main window
00322     MainWindowBase::resizeEvent(re);
00323     if (mResourcesWidth > 0)
00324     {
00325         QList<int> widths;
00326         widths.append(mResourcesWidth);
00327         widths.append(width() - mResourcesWidth - mSplitter->handleWidth());
00328         mSplitter->setSizes(widths);
00329     }
00330 }
00331 
00332 void MainWindow::resourcesResized()
00333 {
00334     if (!mShown  ||  mResizing)
00335         return;
00336     QList<int> widths = mSplitter->sizes();
00337     if (widths.count() > 1)
00338     {
00339         mResourcesWidth = widths[0];
00340         // Width is reported as non-zero when resource selector is
00341         // actually invisible, so note a zero width in these circumstances.
00342         if (mResourcesWidth <= 5)
00343             mResourcesWidth = 0;
00344         else if (mainMainWindow() == this)
00345         {
00346             KConfigGroup config(KGlobal::config(), WINDOW_NAME);
00347             config.writeEntry(QString::fromLatin1("Splitter %1").arg(KApplication::desktop()->width()), mResourcesWidth);
00348         }
00349     }
00350 }
00351 
00352 /******************************************************************************
00353 *  Called when the window is first displayed.
00354 *  Sets the last column in the list view to extend at least to the right hand
00355 *  edge of the list view.
00356 */
00357 void MainWindow::showEvent(QShowEvent* se)
00358 {
00359     if (mResourcesWidth > 0)
00360     {
00361         QList<int> widths;
00362         widths.append(mResourcesWidth);
00363         widths.append(width() - mResourcesWidth - mSplitter->handleWidth());
00364         mSplitter->setSizes(widths);
00365     }
00366     MainWindowBase::showEvent(se);
00367     mShown = true;
00368 }
00369 
00370 /******************************************************************************
00371 *  Display the window.
00372 */
00373 void MainWindow::show()
00374 {
00375     MainWindowBase::show();
00376     if (mMenuError)
00377     {
00378         // Show error message now that the main window has been displayed.
00379         // Waiting until now lets the user easily associate the message with
00380         // the main window which is faulty.
00381         KMessageBox::error(this, i18nc("@info", "Failure to create menus (perhaps <filename>%1</filename> missing or corrupted)", QLatin1String(UI_FILE)));
00382         mMenuError = false;
00383     }
00384 }
00385 
00386 /******************************************************************************
00387 *  Called after the window is hidden.
00388 */
00389 void MainWindow::hideEvent(QHideEvent* he)
00390 {
00391     MainWindowBase::hideEvent(he);
00392 }
00393 
00394 /******************************************************************************
00395 *  Initialise the menu, toolbar and main window actions.
00396 */
00397 void MainWindow::initActions()
00398 {
00399     KActionCollection* actions = actionCollection();
00400 
00401     mActionTemplates = new KAction(i18nc("@action", "&Templates..."), this);
00402     actions->addAction(QLatin1String("templates"), mActionTemplates);
00403     connect(mActionTemplates, SIGNAL(triggered(bool)), SLOT(slotTemplates()));
00404 
00405     mActionNew = new NewAlarmAction(false, i18nc("@action", "&New"), this);
00406     actions->addAction(QLatin1String("new"), mActionNew);
00407     connect(mActionNew, SIGNAL(selected(EditAlarmDlg::Type)), SLOT(slotNew(EditAlarmDlg::Type)));
00408 
00409     mActionNewFromTemplate = KAlarm::createNewFromTemplateAction(i18nc("@action", "New &From Template"), actions, QLatin1String("newFromTempl"));
00410     connect(mActionNewFromTemplate, SIGNAL(selected(const KAEvent*)), SLOT(slotNewFromTemplate(const KAEvent*)));
00411 
00412     mActionCreateTemplate = new KAction(i18nc("@action", "Create Tem&plate..."), this);
00413     actions->addAction(QLatin1String("createTemplate"), mActionCreateTemplate);
00414     connect(mActionCreateTemplate, SIGNAL(triggered(bool)), SLOT(slotNewTemplate()));
00415 
00416     mActionCopy = new KAction(KIcon("edit-copy"), i18nc("@action", "&Copy..."), this);
00417     actions->addAction(QLatin1String("copy"), mActionCopy);
00418     mActionCopy->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Insert));
00419     connect(mActionCopy, SIGNAL(triggered(bool)), SLOT(slotCopy()));
00420 
00421     mActionModify = new KAction(KIcon("document-properties"), i18nc("@action", "&Edit..."), this);
00422     actions->addAction(QLatin1String("modify"), mActionModify);
00423     mActionModify->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E));
00424     connect(mActionModify, SIGNAL(triggered(bool)), SLOT(slotModify()));
00425 
00426     mActionDelete = new KAction(KIcon("edit-delete"), i18nc("@action", "&Delete"), this);
00427     actions->addAction(QLatin1String("delete"), mActionDelete);
00428     mActionDelete->setShortcut(QKeySequence(Qt::Key_Delete));
00429     connect(mActionDelete, SIGNAL(triggered(bool)), SLOT(slotDelete()));
00430 
00431     mActionReactivate = new KAction(i18nc("@action", "Reac&tivate"), this);
00432     actions->addAction(QLatin1String("undelete"), mActionReactivate);
00433     mActionReactivate->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
00434     connect(mActionReactivate, SIGNAL(triggered(bool)), SLOT(slotReactivate()));
00435 
00436     mActionEnable = new KAction(this);
00437     actions->addAction(QLatin1String("disable"), mActionEnable);
00438     mActionEnable->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
00439     connect(mActionEnable, SIGNAL(triggered(bool)), SLOT(slotEnable()));
00440 
00441     mActionShowTime = new KToggleAction(i18n_a_ShowAlarmTimes(), this);
00442     actions->addAction(QLatin1String("showAlarmTimes"), mActionShowTime);
00443     mActionShowTime->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
00444     connect(mActionShowTime, SIGNAL(triggered(bool)), SLOT(slotShowTime()));
00445 
00446     mActionShowTimeTo = new KToggleAction(i18n_o_ShowTimeToAlarms(), this);
00447     actions->addAction(QLatin1String("showTimeToAlarms"), mActionShowTimeTo);
00448     mActionShowTimeTo->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_I));
00449     connect(mActionShowTimeTo, SIGNAL(triggered(bool)), SLOT(slotShowTimeTo()));
00450 
00451     mActionShowArchived = new KToggleAction(i18n_a_ShowArchivedAlarms(), this);
00452     actions->addAction(QLatin1String("showArchivedAlarms"), mActionShowArchived);
00453     mActionShowArchived->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P));
00454     connect(mActionShowArchived, SIGNAL(triggered(bool)), SLOT(slotShowArchived()));
00455 
00456     mActionToggleTrayIcon = new KToggleAction(i18nc("@action", "Show in System &Tray"), this);
00457     actions->addAction(QLatin1String("showInSystemTray"), mActionToggleTrayIcon);
00458     connect(mActionToggleTrayIcon, SIGNAL(triggered(bool)), SLOT(slotToggleTrayIcon()));
00459 
00460     mActionToggleResourceSel = new KToggleAction(i18nc("@action", "Show &Resources"), this);
00461     actions->addAction(QLatin1String("showResources"), mActionToggleResourceSel);
00462     connect(mActionToggleResourceSel, SIGNAL(triggered(bool)), SLOT(slotToggleResourceSelector()));
00463 
00464     mActionImportAlarms = new KAction(i18nc("@action", "Import &Alarms..."), this);
00465     actions->addAction(QLatin1String("importAlarms"), mActionImportAlarms);
00466     connect(mActionImportAlarms, SIGNAL(triggered(bool)), SLOT(slotImportAlarms()));
00467 
00468     mActionImportBirthdays = new KAction(i18nc("@action", "Import &Birthdays..."), this);
00469     actions->addAction(QLatin1String("importBirthdays"), mActionImportBirthdays);
00470     connect(mActionImportBirthdays, SIGNAL(triggered(bool)), SLOT(slotBirthdays()));
00471 
00472     QAction* action = new KAction(KIcon("view-refresh"), i18nc("@action", "&Refresh Alarms"), this);
00473     actions->addAction(QLatin1String("refreshAlarms"), action);
00474     connect(action, SIGNAL(triggered(bool)), SLOT(slotRefreshAlarms()));
00475 
00476     action = KAlarm::createAlarmEnableAction(this);
00477     actions->addAction(QLatin1String("alarmsEnable"), action);
00478     if (undoText.isNull())
00479     {
00480         // Get standard texts, etc., for Undo and Redo actions
00481         QAction * act = KStandardAction::undo(this, 0, actions);
00482         undoShortcut     = KShortcut(act->shortcuts());
00483         undoText         = act->text();
00484         undoTextStripped = KAlarm::stripAccel(undoText);
00485         delete act;
00486         act = KStandardAction::redo(this, 0, actions);
00487         redoShortcut     = KShortcut(act->shortcuts());
00488         redoText         = act->text();
00489         redoTextStripped = KAlarm::stripAccel(redoText);
00490         delete act;
00491     }
00492     mActionUndo = new KToolBarPopupAction(KIcon("edit-undo"), undoText, this);
00493     actions->addAction(QLatin1String("edit_undo"), mActionUndo);
00494     mActionUndo->setShortcut(undoShortcut);
00495     connect(mActionUndo, SIGNAL(triggered(bool)), SLOT(slotUndo()));
00496 
00497     mActionRedo = new KToolBarPopupAction(KIcon("edit-redo"), redoText, this);
00498     actions->addAction(QLatin1String("edit_redo"), mActionRedo);
00499     mActionRedo->setShortcut(redoShortcut);
00500     connect(mActionRedo, SIGNAL(triggered(bool)), SLOT(slotRedo()));
00501 
00502     KStandardAction::find(mListView, SLOT(slotFind()), actions);
00503     mActionFindNext = KStandardAction::findNext(mListView, SLOT(slotFindNext()), actions);
00504     mActionFindPrev = KStandardAction::findPrev(mListView, SLOT(slotFindPrev()), actions);
00505     KStandardAction::selectAll(mListView, SLOT(selectAll()), actions);
00506     KStandardAction::deselect(mListView, SLOT(clearSelection()), actions);
00507     KStandardAction::quit(this, SLOT(slotQuit()), actions);
00508     KStandardAction::keyBindings(this, SLOT(slotConfigureKeys()), actions);
00509     KStandardAction::configureToolbars(this, SLOT(slotConfigureToolbar()), actions);
00510     KStandardAction::preferences(this, SLOT(slotPreferences()), actions);
00511     mResourceSelector->initActions(actions);
00512     setStandardToolBarMenuEnabled(true);
00513     createGUI(UI_FILE);
00514 
00515     mContextMenu = static_cast<KMenu*>(factory()->container("listContext", this));
00516     mActionsMenu = static_cast<KMenu*>(factory()->container("actions", this));
00517     KMenu* resourceMenu = static_cast<KMenu*>(factory()->container("resourceContext", this));
00518     mResourceSelector->setContextMenu(resourceMenu);
00519     mMenuError = (!mContextMenu  ||  !mActionsMenu  ||  !resourceMenu);
00520     connect(mActionUndo->menu(), SIGNAL(aboutToShow()), SLOT(slotInitUndoMenu()));
00521     connect(mActionUndo->menu(), SIGNAL(triggered(QAction*)), SLOT(slotUndoItem(QAction*)));
00522     connect(mActionRedo->menu(), SIGNAL(aboutToShow()), SLOT(slotInitRedoMenu()));
00523     connect(mActionRedo->menu(), SIGNAL(triggered(QAction*)), SLOT(slotRedoItem(QAction*)));
00524     connect(Undo::instance(), SIGNAL(changed(const QString&, const QString&)), SLOT(slotUndoStatus(const QString&, const QString&)));
00525     connect(mListView, SIGNAL(findActive(bool)), SLOT(slotFindActive(bool)));
00526     Preferences::connect(SIGNAL(archivedKeepDaysChanged(int)), this, SLOT(updateKeepArchived(int)));
00527     Preferences::connect(SIGNAL(showInSystemTrayChanged(bool)), this, SLOT(updateTrayIconAction()));
00528     connect(theApp(), SIGNAL(trayIconToggled()), SLOT(updateTrayIconAction()));
00529 
00530     // Set menu item states
00531     setEnableText(true);
00532     mActionShowTime->setChecked(mShowTime);
00533     mActionShowTimeTo->setChecked(mShowTimeTo);
00534     mActionShowArchived->setChecked(mShowArchived);
00535     if (!Preferences::archivedKeepDays())
00536         mActionShowArchived->setEnabled(false);
00537     mActionToggleResourceSel->setChecked(mShowResources);
00538     slotToggleResourceSelector();
00539     updateTrayIconAction();         // set the correct text for this action
00540     mActionUndo->setEnabled(Undo::haveUndo());
00541     mActionRedo->setEnabled(Undo::haveRedo());
00542     mActionFindNext->setEnabled(false);
00543     mActionFindPrev->setEnabled(false);
00544 
00545     mActionCopy->setEnabled(false);
00546     mActionModify->setEnabled(false);
00547     mActionDelete->setEnabled(false);
00548     mActionReactivate->setEnabled(false);
00549     mActionEnable->setEnabled(false);
00550     mActionCreateTemplate->setEnabled(false);
00551 
00552     Undo::emitChanged();     // set the Undo/Redo menu texts
00553 //  Daemon::monitoringAlarms();
00554 }
00555 
00556 /******************************************************************************
00557 * Enable or disable the Templates menu item in every main window instance.
00558 */
00559 void MainWindow::enableTemplateMenuItem(bool enable)
00560 {
00561     for (int i = 0, end = mWindowList.count();  i < end;  ++i)
00562         mWindowList[i]->mActionTemplates->setEnabled(enable);
00563 }
00564 
00565 /******************************************************************************
00566 * Refresh the alarm list in every main window instance.
00567 */
00568 void MainWindow::refresh()
00569 {
00570     kDebug();
00571     EventListModel::alarms()->reload();
00572 }
00573 
00574 /******************************************************************************
00575 * Called when the keep archived alarm setting changes in the user preferences.
00576 * Enable/disable Show archived alarms option.
00577 */
00578 void MainWindow::updateKeepArchived(int days)
00579 {
00580     kDebug() << (bool)days;
00581     if (mShowArchived  &&  !days)
00582         slotShowArchived();   // toggle Show Archived option setting
00583     mActionShowArchived->setEnabled(days);
00584 }
00585 
00586 /******************************************************************************
00587 * Select an alarm in the displayed list.
00588 */
00589 void MainWindow::selectEvent(const QString& eventID)
00590 {
00591     mListView->clearSelection();
00592     QModelIndex index = EventListModel::alarms()->eventIndex(eventID);
00593     if (index.isValid())
00594     {
00595         mListView->select(index);
00596         mListView->scrollTo(index);
00597     }
00598 }
00599 
00600 /******************************************************************************
00601 *  Called when the New button is clicked to edit a new alarm to add to the list.
00602 */
00603 void MainWindow::slotNew(EditAlarmDlg::Type type)
00604 {
00605     KAlarm::editNewAlarm(type, mListView);
00606 }
00607 
00608 /******************************************************************************
00609 *  Called when a template is selected from the New From Template popup menu.
00610 *  Executes a New Alarm dialog, preset from the selected template.
00611 */
00612 void MainWindow::slotNewFromTemplate(const KAEvent* tmplate)
00613 {
00614     KAlarm::editNewAlarm(tmplate, mListView);
00615 }
00616 
00617 /******************************************************************************
00618 *  Called when the New Template button is clicked to create a new template
00619 *  based on the currently selected alarm.
00620 */
00621 void MainWindow::slotNewTemplate()
00622 {
00623     KAEvent* event = mListView->selectedEvent();
00624     if (event)
00625         KAlarm::editNewTemplate(event, this);
00626 }
00627 
00628 /******************************************************************************
00629 *  Called when the Copy button is clicked to edit a copy of an existing alarm,
00630 *  to add to the list.
00631 */
00632 void MainWindow::slotCopy()
00633 {
00634     KAEvent* event = mListView->selectedEvent();
00635     if (event)
00636         KAlarm::editNewAlarm(event, this);
00637 }
00638 
00639 /******************************************************************************
00640 *  Called when the Modify button is clicked to edit the currently highlighted
00641 *  alarm in the list.
00642 */
00643 void MainWindow::slotModify()
00644 {
00645     KAEvent* event = mListView->selectedEvent();
00646     if (event)
00647         KAlarm::editAlarm(event, this);   // edit alarm (view-only mode if archived or read-only)
00648 }
00649 
00650 /******************************************************************************
00651 *  Called when the Delete button is clicked to delete the currently highlighted
00652 *  alarms in the list.
00653 */
00654 void MainWindow::slotDelete()
00655 {
00656     KAEvent::List events = mListView->selectedEvents();
00657     // Copy the events to be deleted, in case any are deleted by being
00658     // triggered while the confirmation prompt is displayed.
00659     KAEvent::List eventCopies;
00660     Undo::EventList undos;
00661     AlarmCalendar* resources = AlarmCalendar::resources();
00662     for (int i = 0, end = events.count();  i < end;  ++i)
00663     {
00664         KAEvent* event = events[i];
00665         eventCopies.append(event);
00666         undos.append(*event, resources->resourceForEvent(event->id()));
00667     }
00668     if (Preferences::confirmAlarmDeletion())
00669     {
00670         int n = events.count();
00671         if (KMessageBox::warningContinueCancel(this, i18ncp("@info", "Do you really want to delete the selected alarm?",
00672                                                            "Do you really want to delete the %1 selected alarms?", n),
00673                                                i18ncp("@title:window", "Delete Alarm", "Delete Alarms", n),
00674                                                KGuiItem(i18nc("@action:button", "&Delete"), "edit-delete"),
00675                                                KStandardGuiItem::cancel(),
00676                                                Preferences::CONFIRM_ALARM_DELETION)
00677             != KMessageBox::Continue)
00678             return;
00679     }
00680 
00681     // Delete the events from the calendar and displays
00682     KAlarm::deleteEvents(eventCopies, true, this);
00683     Undo::saveDeletes(undos);
00684 }
00685 
00686 /******************************************************************************
00687 *  Called when the Reactivate button is clicked to reinstate the currently
00688 *  highlighted archived alarms in the list.
00689 */
00690 void MainWindow::slotReactivate()
00691 {
00692     KAEvent::List events = mListView->selectedEvents();
00693     mListView->clearSelection();
00694 
00695     // Add the alarms to the displayed lists and to the calendar file
00696     Undo::EventList undos;
00697     QStringList ineligibleIDs;
00698     KAlarm::reactivateEvents(events, ineligibleIDs, 0, this);
00699 
00700     // Create the undo list, excluding ineligible events
00701     AlarmCalendar* resources = AlarmCalendar::resources();
00702     for (int i = 0, end = events.count();  i < end;  ++i)
00703     {
00704         QString id = events[i]->id();
00705         if (!ineligibleIDs.contains(id))
00706             undos.append(*events[i], resources->resourceForEvent(id));
00707     }
00708     Undo::saveReactivates(undos);
00709 }
00710 
00711 /******************************************************************************
00712 *  Called when the Enable/Disable button is clicked to enable or disable the
00713 *  currently highlighted alarms in the list.
00714 */
00715 void MainWindow::slotEnable()
00716 {
00717     bool enable = mActionEnableEnable;    // save since changed in response to KAlarm::enableEvent()
00718     KAEvent::List events = mListView->selectedEvents();
00719     KAEvent::List eventCopies;
00720     for (int i = 0, end = events.count();  i < end;  ++i)
00721         eventCopies += events[i];
00722     KAlarm::enableEvents(eventCopies, enable, this);
00723     slotSelection();   // update Enable/Disable action text
00724 }
00725 
00726 /******************************************************************************
00727 *  Called when the Show Alarm Times menu item is selected or deselected.
00728 */
00729 void MainWindow::slotShowTime()
00730 {
00731     mShowTime = !mShowTime;
00732     mActionShowTime->setChecked(mShowTime);
00733     if (!mShowTime  &&  !mShowTimeTo)
00734         slotShowTimeTo();    // at least one time column must be displayed
00735     else
00736     {
00737         mListView->selectTimeColumns(mShowTime, mShowTimeTo);
00738         KConfigGroup config(KGlobal::config(), VIEW_GROUP);
00739         config.writeEntry(SHOW_TIME_KEY, mShowTime);
00740         config.writeEntry(SHOW_TIME_TO_KEY, mShowTimeTo);
00741     }
00742 }
00743 
00744 /******************************************************************************
00745 *  Called when the Show Time To Alarms menu item is selected or deselected.
00746 */
00747 void MainWindow::slotShowTimeTo()
00748 {
00749     mShowTimeTo = !mShowTimeTo;
00750     mActionShowTimeTo->setChecked(mShowTimeTo);
00751     if (!mShowTimeTo  &&  !mShowTime)
00752         slotShowTime();    // at least one time column must be displayed
00753     else
00754     {
00755         mListView->selectTimeColumns(mShowTime, mShowTimeTo);
00756         KConfigGroup config(KGlobal::config(), VIEW_GROUP);
00757         config.writeEntry(SHOW_TIME_KEY, mShowTime);
00758         config.writeEntry(SHOW_TIME_TO_KEY, mShowTimeTo);
00759     }
00760 }
00761 
00762 /******************************************************************************
00763 *  Called when the Show Archived Alarms menu item is selected or deselected.
00764 */
00765 void MainWindow::slotShowArchived()
00766 {
00767     mShowArchived = !mShowArchived;
00768     mActionShowArchived->setChecked(mShowArchived);
00769     mActionShowArchived->setToolTip(mShowArchived ? i18n_tip_HideArchivedAlarms() : i18n_tip_ShowArchivedAlarms());
00770     mListFilterModel->setStatusFilter(mShowArchived ? static_cast<KCalEvent::Status>(KCalEvent::ACTIVE | KCalEvent::ARCHIVED) : KCalEvent::ACTIVE);
00771     mListView->reset();
00772     KConfigGroup config(KGlobal::config(), VIEW_GROUP);
00773     config.writeEntry(SHOW_ARCHIVED_KEY, mShowArchived);
00774 }
00775 
00776 /******************************************************************************
00777 *  Called when the Import Alarms menu item is selected, to merge alarms from an
00778 *  external calendar into the current calendars.
00779 */
00780 void MainWindow::slotImportAlarms()
00781 {
00782     AlarmCalendar::importAlarms(this);
00783 }
00784 
00785 /******************************************************************************
00786 *  Called when the Import Birthdays menu item is selected, to display birthdays
00787 *  from the address book for selection as alarms.
00788 */
00789 void MainWindow::slotBirthdays()
00790 {
00791     BirthdayDlg dlg(this);
00792     if (dlg.exec() == QDialog::Accepted)
00793     {
00794         QList<KAEvent> events = dlg.events();
00795         if (!events.isEmpty())
00796         {
00797             mListView->clearSelection();
00798             // Add alarm to the displayed lists and to the calendar file
00799             KAlarm::UpdateStatus status = KAlarm::addEvents(events, &dlg, true, true);
00800 
00801             Undo::EventList undos;
00802             AlarmCalendar* resources = AlarmCalendar::resources();
00803             for (int i = 0, end = events.count();  i < end;  ++i)
00804                 undos.append(events[i], resources->resourceForEvent(events[i].id()));
00805             Undo::saveAdds(undos, i18nc("@info", "Import birthdays"));
00806 
00807             if (status != KAlarm::UPDATE_FAILED)
00808                 KAlarm::outputAlarmWarnings(&dlg);
00809         }
00810     }
00811 }
00812 
00813 /******************************************************************************
00814 *  Called when the Templates menu item is selected, to display the alarm
00815 *  template editing dialog.
00816 */
00817 void MainWindow::slotTemplates()
00818 {
00819     if (!mTemplateDlg)
00820     {
00821         mTemplateDlg = TemplateDlg::create(this);
00822         enableTemplateMenuItem(false);     // disable menu item in all windows
00823         connect(mTemplateDlg, SIGNAL(finished()), SLOT(slotTemplatesEnd()));
00824         mTemplateDlg->show();
00825     }
00826 }
00827 
00828 /******************************************************************************
00829 *  Called when the alarm template editing dialog has exited.
00830 */
00831 void MainWindow::slotTemplatesEnd()
00832 {
00833     if (mTemplateDlg)
00834     {
00835         mTemplateDlg->delayedDestruct();   // this deletes the dialog once it is safe to do so
00836         mTemplateDlg = 0;
00837         enableTemplateMenuItem(true);      // re-enable menu item in all windows
00838     }
00839 }
00840 
00841 /******************************************************************************
00842 *  Called when the Display System Tray Icon menu item is selected.
00843 */
00844 void MainWindow::slotToggleTrayIcon()
00845 {
00846     theApp()->displayTrayIcon(!theApp()->trayIconDisplayed(), this);
00847 }
00848 
00849 /******************************************************************************
00850 *  Called when the Show Resource Selector menu item is selected.
00851 */
00852 void MainWindow::slotToggleResourceSelector()
00853 {
00854     mShowResources = mActionToggleResourceSel->isChecked();
00855     if (mShowResources)
00856     {
00857         if (mResourcesWidth <= 0)
00858         {
00859             mResourcesWidth = mResourceSelector->sizeHint().width();
00860             mResourceSelector->resize(mResourcesWidth, mResourceSelector->height());
00861             QList<int> widths = mSplitter->sizes();
00862             if (widths.count() == 1)
00863             {
00864                 int listwidth = widths[0] - mSplitter->handleWidth() - mResourcesWidth;
00865                 mListView->resize(listwidth, mListView->height());
00866                 widths.append(listwidth);
00867                 widths[0] = mResourcesWidth;
00868             }
00869             mSplitter->setSizes(widths);
00870         }
00871         mResourceSelector->show();
00872     }
00873     else
00874         mResourceSelector->hide();
00875 
00876     KConfigGroup config(KGlobal::config(), VIEW_GROUP);
00877     config.writeEntry(SHOW_RESOURCES_KEY, mShowResources);
00878 }
00879 
00880 /******************************************************************************
00881 * Called when an error occurs in the resource calendar, to display a message.
00882 */
00883 void MainWindow::showErrorMessage(const QString& msg)
00884 {
00885     KMessageBox::error(this, msg);
00886 }
00887 
00888 /******************************************************************************
00889 * Called when the system tray icon is created or destroyed.
00890 * Set the system tray icon menu text according to whether or not the system
00891 * tray icon is currently visible.
00892 */
00893 void MainWindow::updateTrayIconAction()
00894 {
00895     mActionToggleTrayIcon->setEnabled(KSystemTrayIcon::isSystemTrayAvailable());
00896     mActionToggleTrayIcon->setChecked(theApp()->trayIconDisplayed());
00897 }
00898 
00899 /******************************************************************************
00900 *  Called when the active status of Find changes.
00901 */
00902 void MainWindow::slotFindActive(bool active)
00903 {
00904     mActionFindNext->setEnabled(active);
00905     mActionFindPrev->setEnabled(active);
00906 }
00907 
00908 /******************************************************************************
00909 *  Called when the Undo action is selected.
00910 */
00911 void MainWindow::slotUndo()
00912 {
00913     Undo::undo(this, KAlarm::stripAccel(mActionUndo->text()));
00914 }
00915 
00916 /******************************************************************************
00917 *  Called when the Redo action is selected.
00918 */
00919 void MainWindow::slotRedo()
00920 {
00921     Undo::redo(this, KAlarm::stripAccel(mActionRedo->text()));
00922 }
00923 
00924 /******************************************************************************
00925 *  Called when an Undo item is selected.
00926 */
00927 void MainWindow::slotUndoItem(QAction* action)
00928 {
00929     int id = mUndoMenuIds[action];
00930     Undo::undo(id, this, Undo::actionText(Undo::UNDO, id));
00931 }
00932 
00933 /******************************************************************************
00934 *  Called when a Redo item is selected.
00935 */
00936 void MainWindow::slotRedoItem(QAction* action)
00937 {
00938     int id = mUndoMenuIds[action];
00939     Undo::redo(id, this, Undo::actionText(Undo::REDO, id));
00940 }
00941 
00942 /******************************************************************************
00943 *  Called when the Undo menu is about to show.
00944 *  Populates the menu.
00945 */
00946 void MainWindow::slotInitUndoMenu()
00947 {
00948     initUndoMenu(mActionUndo->menu(), Undo::UNDO);
00949 }
00950 
00951 /******************************************************************************
00952 *  Called when the Redo menu is about to show.
00953 *  Populates the menu.
00954 */
00955 void MainWindow::slotInitRedoMenu()
00956 {
00957     initUndoMenu(mActionRedo->menu(), Undo::REDO);
00958 }
00959 
00960 /******************************************************************************
00961 *  Populate the undo or redo menu.
00962 */
00963 void MainWindow::initUndoMenu(QMenu* menu, Undo::Type type)
00964 {
00965     menu->clear();
00966     mUndoMenuIds.clear();
00967     const QString& action = (type == Undo::UNDO) ? undoTextStripped : redoTextStripped;
00968     QList<int> ids = Undo::ids(type);
00969     for (int i = 0, end = ids.count();  i < end;  ++i)
00970     {
00971         int id = ids[i];
00972         QString actText = Undo::actionText(type, id);
00973         QString descrip = Undo::description(type, id);
00974         QString text = descrip.isEmpty()
00975                      ? i18nc("@action Undo/Redo [action]", "%1 %2", action, actText)
00976                      : i18nc("@action Undo [action]: message", "%1 %2: %3", action, actText, descrip);
00977         QAction* act = menu->addAction(text);
00978         mUndoMenuIds[act] = id;
00979     }
00980 }
00981 
00982 /******************************************************************************
00983 *  Called when the status of the Undo or Redo list changes.
00984 *  Change the Undo or Redo text to include the action which would be undone/redone.
00985 <