2 * mainwindow.cpp - main application window
4 * Copyright © 2001-2011 by David Jarvie <djarvie@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "mainwindow.moc"
24 #include "alarmcalendar.h"
25 #include "alarmlistdelegate.h"
26 #include "autoqpointer.h"
27 #include "alarmlistview.h"
29 #include "alarmlistfiltermodel.h"
30 #include "alarmresources.h"
31 #include "eventlistmodel.h"
33 #include "birthdaydlg.h"
34 #include "functions.h"
35 #include "kalarmapp.h"
37 #include "messagebox.h"
38 #include "newalarmaction.h"
40 #include "preferences.h"
41 #include "resourceselector.h"
42 #include "synchtimer.h"
43 #include "templatedlg.h"
44 #include "templatemenuaction.h"
45 #include "templatepickdlg.h"
46 #include "traywindow.h"
49 #include <kalarmcal/alarmtext.h>
50 #include <kalarmcal/kaevent.h>
52 #include <libkdepim/maillistdrag.h>
53 #include <kmime/kmime_content.h>
55 #include <kcalcore/memorycalendar.h>
56 #include <kcalutils/icaldrag.h>
57 using namespace KCalCore
;
58 using namespace KCalUtils
;
60 #include <kcal/calendarlocal.h>
61 #include <kcal/icaldrag.h>
69 #include <kactioncollection.h>
70 #include <kinputdialog.h>
71 #include <ksystemtrayicon.h>
72 #include <kstandardaction.h>
73 #include <kiconloader.h>
76 #include <kglobalsettings.h>
77 #include <kconfiggroup.h>
78 #include <kshortcutsdialog.h>
79 #include <kedittoolbar.h>
80 #include <kxmlguifactory.h>
81 #include <kaboutdata.h>
83 #include <ktoggleaction.h>
84 #include <ktoolbarpopupaction.h>
87 #include <QHeaderView>
90 #include <QDesktopWidget>
91 #include <QDragEnterEvent>
93 #include <QResizeEvent>
94 #include <QCloseEvent>
97 using namespace KAlarmCal
;
99 static const char* UI_FILE
= "kalarmui.rc";
100 static const char* WINDOW_NAME
= "MainWindow";
102 static const char* VIEW_GROUP
= "View";
103 static const char* SHOW_TIME_KEY
= "ShowAlarmTime";
104 static const char* SHOW_TIME_TO_KEY
= "ShowTimeToAlarm";
105 static const char* SHOW_ARCHIVED_KEY
= "ShowArchivedAlarms";
106 static const char* SHOW_RESOURCES_KEY
= "ShowResources";
108 static QString undoText
;
109 static QString undoTextStripped
;
110 static KShortcut undoShortcut
;
111 static QString redoText
;
112 static QString redoTextStripped
;
113 static KShortcut redoShortcut
;
116 /*=============================================================================
118 =============================================================================*/
120 MainWindow::WindowList
MainWindow::mWindowList
;
121 TemplateDlg
* MainWindow::mTemplateDlg
= 0;
123 // Collect these widget labels together to ensure consistent wording and
124 // translations across different modules.
125 QString
MainWindow::i18n_a_ShowAlarmTimes() { return i18nc("@action", "Show &Alarm Times"); }
126 QString
MainWindow::i18n_chk_ShowAlarmTime() { return i18nc("@option:check", "Show alarm time"); }
127 QString
MainWindow::i18n_o_ShowTimeToAlarms() { return i18nc("@action", "Show Time t&o Alarms"); }
128 QString
MainWindow::i18n_chk_ShowTimeToAlarm() { return i18nc("@option:check", "Show time until alarm"); }
131 /******************************************************************************
132 * Construct an instance.
133 * To avoid resize() events occurring while still opening the calendar (and
134 * resultant crashes), the calendar is opened before constructing the instance.
136 MainWindow
* MainWindow::create(bool restored
)
138 theApp()->checkCalendar(); // ensure calendar is open
139 return new MainWindow(restored
);
142 MainWindow::MainWindow(bool restored
)
143 : MainWindowBase(0, Qt::WindowContextHelpButtonHint
),
145 mHiddenTrayParent(false),
150 setAttribute(Qt::WA_DeleteOnClose
);
151 setWindowModality(Qt::WindowModal
);
152 setObjectName("MainWin"); // used by LikeBack
153 setPlainCaption(KGlobal::mainComponent().aboutData()->programName());
154 KConfigGroup
config(KGlobal::config(), VIEW_GROUP
);
155 mShowResources
= config
.readEntry(SHOW_RESOURCES_KEY
, false);
156 mShowArchived
= config
.readEntry(SHOW_ARCHIVED_KEY
, false);
157 mShowTime
= config
.readEntry(SHOW_TIME_KEY
, true);
158 mShowTimeTo
= config
.readEntry(SHOW_TIME_TO_KEY
, false);
161 KConfigGroup
wconfig(KGlobal::config(), WINDOW_NAME
);
162 mResourcesWidth
= wconfig
.readEntry(QString::fromLatin1("Splitter %1").arg(KApplication::desktop()->width()), (int)0);
165 setAcceptDrops(true); // allow drag-and-drop onto this window
167 mShowTime
= true; // ensure at least one time column is visible
169 mSplitter
= new QSplitter(Qt::Horizontal
, this);
170 mSplitter
->setChildrenCollapsible(false);
171 mSplitter
->installEventFilter(this);
172 setCentralWidget(mSplitter
);
174 // Create the calendar resource selector widget
176 mResourceSelector
= new ResourceSelector(mSplitter
);
178 AlarmResources
* resources
= AlarmResources::instance();
179 mResourceSelector
= new ResourceSelector(resources
, mSplitter
);
181 mSplitter
->setStretchFactor(0, 0); // don't resize resource selector when window is resized
182 mSplitter
->setStretchFactor(1, 1);
184 connect(resources
, SIGNAL(signalErrorMessage(QString
)), SLOT(showErrorMessage(QString
)));
187 // Create the alarm list widget
189 mListFilterModel
= new AlarmListModel(this);
190 mListFilterModel
->setEventTypeFilter(mShowArchived
? CalEvent::ACTIVE
| CalEvent::ARCHIVED
: CalEvent::ACTIVE
);
192 mListFilterModel
= new AlarmListFilterModel(EventListModel::alarms(), this);
193 mListFilterModel
->setStatusFilter(mShowArchived
? CalEvent::ACTIVE
| CalEvent::ARCHIVED
: CalEvent::ACTIVE
);
195 mListView
= new AlarmListView(WINDOW_NAME
, mSplitter
);
196 mListView
->setModel(mListFilterModel
);
197 mListView
->selectTimeColumns(mShowTime
, mShowTimeTo
);
199 mListView
->sortByColumn(mShowTime
? AlarmListModel::TimeColumn
: AlarmListModel::TimeToColumn
, Qt::AscendingOrder
);
201 mListView
->sortByColumn(mShowTime
? EventListModel::TimeColumn
: EventListModel::TimeToColumn
, Qt::AscendingOrder
);
203 mListView
->setItemDelegate(new AlarmListDelegate(mListView
));
204 connect(mListView
->selectionModel(), SIGNAL(selectionChanged(QItemSelection
,QItemSelection
)), SLOT(slotSelection()));
205 connect(mListView
, SIGNAL(contextMenuRequested(QPoint
)), SLOT(slotContextMenuRequested(QPoint
)));
207 connect(AkonadiModel::instance(), SIGNAL(collectionStatusChanged(Akonadi::Collection
,AkonadiModel::Change
,QVariant
,bool)),
208 SLOT(slotCalendarStatusChanged()));
210 connect(resources
, SIGNAL(resourceStatusChanged(AlarmResource
*,AlarmResources::Change
)),
211 SLOT(slotCalendarStatusChanged()));
213 connect(mResourceSelector
, SIGNAL(resized(QSize
,QSize
)), SLOT(resourcesResized()));
214 mListView
->installEventFilter(this);
217 setAutoSaveSettings(QLatin1String(WINDOW_NAME
), true); // save toolbars, window sizes etc.
218 mWindowList
.append(this);
219 if (mWindowList
.count() == 1)
221 // It's the first main window
222 if (theApp()->wantShowInSystemTray())
223 theApp()->displayTrayIcon(true, this); // create system tray icon for run-in-system-tray mode
224 else if (theApp()->trayWindow())
225 theApp()->trayWindow()->setAssocMainWindow(this); // associate this window with the system tray icon
227 slotCalendarStatusChanged(); // initialise action states now that window is registered
230 MainWindow::~MainWindow()
233 bool trayParent
= isTrayParent(); // must call before removing from window list
234 mWindowList
.removeAt(mWindowList
.indexOf(this));
236 // Prevent view updates during window destruction
237 delete mResourceSelector
;
238 mResourceSelector
= 0;
242 if (theApp()->trayWindow())
245 delete theApp()->trayWindow();
247 theApp()->trayWindow()->removeWindow(this);
249 KGlobal::config()->sync(); // save any new window size to disc
253 /******************************************************************************
254 * Save settings to the session managed config file, for restoration
255 * when the program is restored.
257 void MainWindow::saveProperties(KConfigGroup
& config
)
259 config
.writeEntry("HiddenTrayParent", isTrayParent() && isHidden());
260 config
.writeEntry("ShowArchived", mShowArchived
);
261 config
.writeEntry("ShowTime", mShowTime
);
262 config
.writeEntry("ShowTimeTo", mShowTimeTo
);
263 config
.writeEntry("ResourcesWidth", mResourceSelector
->isHidden() ? 0 : mResourceSelector
->width());
266 /******************************************************************************
267 * Read settings from the session managed config file.
268 * This function is automatically called whenever the app is being
269 * restored. Read in whatever was saved in saveProperties().
271 void MainWindow::readProperties(const KConfigGroup
& config
)
273 mHiddenTrayParent
= config
.readEntry("HiddenTrayParent", true);
274 mShowArchived
= config
.readEntry("ShowArchived", false);
275 mShowTime
= config
.readEntry("ShowTime", true);
276 mShowTimeTo
= config
.readEntry("ShowTimeTo", false);
277 mResourcesWidth
= config
.readEntry("ResourcesWidth", (int)0);
278 mShowResources
= (mResourcesWidth
> 0);
281 /******************************************************************************
282 * Get the main main window, i.e. the parent of the system tray icon, or if
283 * none, the first main window to be created. Visible windows take precedence
286 MainWindow
* MainWindow::mainMainWindow()
288 MainWindow
* tray
= theApp()->trayWindow() ? theApp()->trayWindow()->assocMainWindow() : 0;
289 if (tray
&& tray
->isVisible())
291 for (int i
= 0, end
= mWindowList
.count(); i
< end
; ++i
)
292 if (mWindowList
[i
]->isVisible())
293 return mWindowList
[i
];
296 if (mWindowList
.isEmpty())
298 return mWindowList
[0];
301 /******************************************************************************
302 * Check whether this main window is effectively the parent of the system tray icon.
304 bool MainWindow::isTrayParent() const
306 TrayWindow
* tray
= theApp()->trayWindow();
307 if (!tray
|| !KSystemTrayIcon::isSystemTrayAvailable())
309 if (tray
->assocMainWindow() == this)
311 return mWindowList
.count() == 1;
314 /******************************************************************************
315 * Close all main windows.
317 void MainWindow::closeAll()
319 while (!mWindowList
.isEmpty())
320 delete mWindowList
[0]; // N.B. the destructor removes the window from the list
323 /******************************************************************************
324 * Intercept events for the splitter widget.
326 bool MainWindow::eventFilter(QObject
* obj
, QEvent
* e
)
328 if (obj
== mSplitter
)
333 // Don't change resources size while WINDOW is being resized.
334 // Resize event always occurs before Paint.
338 // Allow resources to be resized again
345 else if (obj
== mListView
)
349 case QEvent::KeyPress
:
351 QKeyEvent
* ke
= static_cast<QKeyEvent
*>(e
);
352 if (ke
->key() == Qt::Key_Delete
&& ke
->modifiers() == Qt::ShiftModifier
)
354 // Prevent Shift-Delete being processed by EventListDelegate
355 mActionDeleteForce
->trigger();
367 /******************************************************************************
368 * Called when the window's size has changed (before it is painted).
369 * Sets the last column in the list view to extend at least to the right hand
370 * edge of the list view.
371 * Records the new size in the config file.
373 void MainWindow::resizeEvent(QResizeEvent
* re
)
375 // Save the window's new size only if it's the first main window
376 MainWindowBase::resizeEvent(re
);
377 if (mResourcesWidth
> 0)
380 widths
.append(mResourcesWidth
);
381 widths
.append(width() - mResourcesWidth
- mSplitter
->handleWidth());
382 mSplitter
->setSizes(widths
);
386 void MainWindow::resourcesResized()
388 if (!mShown
|| mResizing
)
390 QList
<int> widths
= mSplitter
->sizes();
391 if (widths
.count() > 1)
393 mResourcesWidth
= widths
[0];
394 // Width is reported as non-zero when resource selector is
395 // actually invisible, so note a zero width in these circumstances.
396 if (mResourcesWidth
<= 5)
398 else if (mainMainWindow() == this)
400 KConfigGroup
config(KGlobal::config(), WINDOW_NAME
);
401 config
.writeEntry(QString::fromLatin1("Splitter %1").arg(KApplication::desktop()->width()), mResourcesWidth
);
406 /******************************************************************************
407 * Called when the window is first displayed.
408 * Sets the last column in the list view to extend at least to the right hand
409 * edge of the list view.
411 void MainWindow::showEvent(QShowEvent
* se
)
413 if (mResourcesWidth
> 0)
416 widths
.append(mResourcesWidth
);
417 widths
.append(width() - mResourcesWidth
- mSplitter
->handleWidth());
418 mSplitter
->setSizes(widths
);
420 MainWindowBase::showEvent(se
);
424 /******************************************************************************
425 * Display the window.
427 void MainWindow::show()
429 MainWindowBase::show();
432 // Show error message now that the main window has been displayed.
433 // Waiting until now lets the user easily associate the message with
434 // the main window which is faulty.
435 KAMessageBox::error(this, i18nc("@info", "Failure to create menus (perhaps <filename>%1</filename> missing or corrupted)", QLatin1String(UI_FILE
)));
440 /******************************************************************************
441 * Called after the window is hidden.
443 void MainWindow::hideEvent(QHideEvent
* he
)
445 MainWindowBase::hideEvent(he
);
448 /******************************************************************************
449 * Initialise the menu, toolbar and main window actions.
451 void MainWindow::initActions()
454 KActionCollection
* actions
= actionCollection();
456 mActionTemplates
= new KAction(i18nc("@action", "&Templates..."), this);
457 actions
->addAction(QLatin1String("templates"), mActionTemplates
);
458 connect(mActionTemplates
, SIGNAL(triggered(bool)), SLOT(slotTemplates()));
460 mActionNew
= new NewAlarmAction(false, i18nc("@action", "&New"), this);
461 actions
->addAction(QLatin1String("new"), mActionNew
);
463 KAction
* action
= mActionNew
->displayAlarmAction();
464 actions
->addAction(QLatin1String("newDisplay"), action
);
465 action
->setGlobalShortcut(dummy
); // actions->addAction() must be called first!
466 connect(action
, SIGNAL(triggered(bool)), SLOT(slotNewDisplay()));
468 action
= mActionNew
->commandAlarmAction();
469 actions
->addAction(QLatin1String("newCommand"), action
);
470 action
->setGlobalShortcut(dummy
); // actions->addAction() must be called first!
471 connect(action
, SIGNAL(triggered(bool)), SLOT(slotNewCommand()));
473 action
= mActionNew
->emailAlarmAction();
474 actions
->addAction(QLatin1String("newEmail"), action
);
475 action
->setGlobalShortcut(dummy
); // actions->addAction() must be called first!
476 connect(action
, SIGNAL(triggered(bool)), SLOT(slotNewEmail()));
478 action
= mActionNew
->audioAlarmAction();
479 actions
->addAction(QLatin1String("newAudio"), action
);
480 action
->setGlobalShortcut(dummy
); // actions->addAction() must be called first!
481 connect(action
, SIGNAL(triggered(bool)), SLOT(slotNewAudio()));
483 action
= mActionNew
->fromTemplateAlarmAction();
484 actions
->addAction(QLatin1String("newFromTemplate"), action
);
485 connect(action
, SIGNAL(selected(const KAEvent
*)), SLOT(slotNewFromTemplate(const KAEvent
*)));
487 mActionCreateTemplate
= new KAction(i18nc("@action", "Create Tem&plate..."), this);
488 actions
->addAction(QLatin1String("createTemplate"), mActionCreateTemplate
);
489 connect(mActionCreateTemplate
, SIGNAL(triggered(bool)), SLOT(slotNewTemplate()));
491 mActionCopy
= new KAction(KIcon("edit-copy"), i18nc("@action", "&Copy..."), this);
492 actions
->addAction(QLatin1String("copy"), mActionCopy
);
493 mActionCopy
->setShortcut(QKeySequence(Qt::SHIFT
+ Qt::Key_Insert
));
494 connect(mActionCopy
, SIGNAL(triggered(bool)), SLOT(slotCopy()));
496 mActionModify
= new KAction(KIcon("document-properties"), i18nc("@action", "&Edit..."), this);
497 actions
->addAction(QLatin1String("modify"), mActionModify
);
498 mActionModify
->setShortcut(QKeySequence(Qt::CTRL
+ Qt::Key_E
));
499 connect(mActionModify
, SIGNAL(triggered(bool)), SLOT(slotModify()));
501 mActionDelete
= new KAction(KIcon("edit-delete"), i18nc("@action", "&Delete"), this);
502 actions
->addAction(QLatin1String("delete"), mActionDelete
);
503 mActionDelete
->setShortcut(QKeySequence::Delete
);
504 connect(mActionDelete
, SIGNAL(triggered(bool)), SLOT(slotDeleteIf()));
506 // Set up Shift-Delete as a shortcut to delete without confirmation
507 mActionDeleteForce
= new KAction(i18nc("@action", "Delete Without Confirmation"), this);
508 actions
->addAction(QLatin1String("delete-force"), mActionDeleteForce
);
509 mActionDeleteForce
->setShortcut(QKeySequence::Delete
+ Qt::SHIFT
);
510 connect(mActionDeleteForce
, SIGNAL(triggered(bool)), SLOT(slotDeleteForce()));
512 mActionReactivate
= new KAction(i18nc("@action", "Reac&tivate"), this);
513 actions
->addAction(QLatin1String("undelete"), mActionReactivate
);
514 mActionReactivate
->setShortcut(QKeySequence(Qt::CTRL
+ Qt::Key_R
));
515 connect(mActionReactivate
, SIGNAL(triggered(bool)), SLOT(slotReactivate()));
517 mActionEnable
= new KAction(this);
518 actions
->addAction(QLatin1String("disable"), mActionEnable
);
519 mActionEnable
->setShortcut(QKeySequence(Qt::CTRL
+ Qt::Key_B
));
520 connect(mActionEnable
, SIGNAL(triggered(bool)), SLOT(slotEnable()));
522 action
= new KAction(i18nc("@action", "Wake From Suspend"), this);
523 actions
->addAction(QLatin1String("wakeSuspend"), action
);
524 connect(action
, SIGNAL(triggered(bool)), SLOT(slotWakeFromSuspend()));
526 action
= KAlarm::createStopPlayAction(this);
527 actions
->addAction(QLatin1String("stopAudio"), action
);
528 action
->setGlobalShortcut(dummy
); // actions->addAction() must be called first!
530 mActionShowTime
= new KToggleAction(i18n_a_ShowAlarmTimes(), this);
531 actions
->addAction(QLatin1String("showAlarmTimes"), mActionShowTime
);
532 connect(mActionShowTime
, SIGNAL(triggered(bool)), SLOT(slotShowTime()));
534 mActionShowTimeTo
= new KToggleAction(i18n_o_ShowTimeToAlarms(), this);
535 actions
->addAction(QLatin1String("showTimeToAlarms"), mActionShowTimeTo
);
536 mActionShowTimeTo
->setShortcut(QKeySequence(Qt::CTRL
+ Qt::Key_I
));
537 connect(mActionShowTimeTo
, SIGNAL(triggered(bool)), SLOT(slotShowTimeTo()));
539 mActionShowArchived
= new KToggleAction(i18nc("@action", "Show Archi&ved Alarms"), this);
540 actions
->addAction(QLatin1String("showArchivedAlarms"), mActionShowArchived
);
541 mActionShowArchived
->setShortcut(QKeySequence(Qt::CTRL
+ Qt::Key_P
));
542 connect(mActionShowArchived
, SIGNAL(triggered(bool)), SLOT(slotShowArchived()));
544 mActionToggleTrayIcon
= new KToggleAction(i18nc("@action", "Show in System &Tray"), this);
545 actions
->addAction(QLatin1String("showInSystemTray"), mActionToggleTrayIcon
);
546 connect(mActionToggleTrayIcon
, SIGNAL(triggered(bool)), SLOT(slotToggleTrayIcon()));
548 mActionToggleResourceSel
= new KToggleAction(KIcon("view-choose"), i18nc("@action", "Show &Calendars"), this);
549 actions
->addAction(QLatin1String("showResources"), mActionToggleResourceSel
);
550 connect(mActionToggleResourceSel
, SIGNAL(triggered(bool)), SLOT(slotToggleResourceSelector()));
552 mActionSpreadWindows
= KAlarm::createSpreadWindowsAction(this);
553 actions
->addAction(QLatin1String("spread"), mActionSpreadWindows
);
554 mActionSpreadWindows
->setGlobalShortcut(dummy
); // actions->addAction() must be called first!
556 mActionImportAlarms
= new KAction(i18nc("@action", "Import &Alarms..."), this);
557 actions
->addAction(QLatin1String("importAlarms"), mActionImportAlarms
);
558 connect(mActionImportAlarms
, SIGNAL(triggered(bool)), SLOT(slotImportAlarms()));
560 mActionImportBirthdays
= new KAction(i18nc("@action", "Import &Birthdays..."), this);
561 actions
->addAction(QLatin1String("importBirthdays"), mActionImportBirthdays
);
562 connect(mActionImportBirthdays
, SIGNAL(triggered(bool)), SLOT(slotBirthdays()));
564 mActionExportAlarms
= new KAction(i18nc("@action", "E&xport Selected Alarms..."), this);
565 actions
->addAction(QLatin1String("exportAlarms"), mActionExportAlarms
);
566 connect(mActionExportAlarms
, SIGNAL(triggered(bool)), SLOT(slotExportAlarms()));
568 mActionExport
= new KAction(i18nc("@action", "E&xport..."), this);
569 actions
->addAction(QLatin1String("export"), mActionExport
);
570 connect(mActionExport
, SIGNAL(triggered(bool)), SLOT(slotExportAlarms()));
572 action
= new KAction(KIcon("view-refresh"), i18nc("@action", "&Refresh Alarms"), this);
573 actions
->addAction(QLatin1String("refreshAlarms"), action
);
574 connect(action
, SIGNAL(triggered(bool)), SLOT(slotRefreshAlarms()));
576 action
= KAlarm::createAlarmEnableAction(this);
577 actions
->addAction(QLatin1String("alarmsEnable"), action
);
578 if (undoText
.isNull())
580 // Get standard texts, etc., for Undo and Redo actions
581 QAction
* act
= KStandardAction::undo(this, 0, actions
);
582 undoShortcut
= KShortcut(act
->shortcuts());
583 undoText
= act
->text();
584 undoTextStripped
= KGlobal::locale()->removeAcceleratorMarker(undoText
);
586 act
= KStandardAction::redo(this, 0, actions
);
587 redoShortcut
= KShortcut(act
->shortcuts());
588 redoText
= act
->text();
589 redoTextStripped
= KGlobal::locale()->removeAcceleratorMarker(redoText
);
592 mActionUndo
= new KToolBarPopupAction(KIcon("edit-undo"), undoText
, this);
593 actions
->addAction(QLatin1String("edit_undo"), mActionUndo
);
594 mActionUndo
->setShortcut(undoShortcut
);
595 connect(mActionUndo
, SIGNAL(triggered(bool)), SLOT(slotUndo()));
597 mActionRedo
= new KToolBarPopupAction(KIcon("edit-redo"), redoText
, this);
598 actions
->addAction(QLatin1String("edit_redo"), mActionRedo
);
599 mActionRedo
->setShortcut(redoShortcut
);
600 connect(mActionRedo
, SIGNAL(triggered(bool)), SLOT(slotRedo()));
602 KStandardAction::find(mListView
, SLOT(slotFind()), actions
);
603 mActionFindNext
= KStandardAction::findNext(mListView
, SLOT(slotFindNext()), actions
);
604 mActionFindPrev
= KStandardAction::findPrev(mListView
, SLOT(slotFindPrev()), actions
);
605 KStandardAction::selectAll(mListView
, SLOT(selectAll()), actions
);
606 KStandardAction::deselect(mListView
, SLOT(clearSelection()), actions
);
607 // Quit only once the event loop is called; otherwise, the parent window will
608 // be deleted while still processing the action, resulting in a crash.
609 KAction
* act
= KStandardAction::quit(0, 0, actions
);
610 connect(act
, SIGNAL(triggered(bool)), SLOT(slotQuit()), Qt::QueuedConnection
);
611 KStandardAction::keyBindings(this, SLOT(slotConfigureKeys()), actions
);
612 KStandardAction::configureToolbars(this, SLOT(slotConfigureToolbar()), actions
);
613 KStandardAction::preferences(this, SLOT(slotPreferences()), actions
);
614 mResourceSelector
->initActions(actions
);
615 setStandardToolBarMenuEnabled(true);
617 // Load menu and toolbar settings
618 applyMainWindowSettings(KGlobal::config()->group(WINDOW_NAME
));
620 mContextMenu
= static_cast<KMenu
*>(factory()->container("listContext", this));
621 mActionsMenu
= static_cast<KMenu
*>(factory()->container("actions", this));
622 KMenu
* resourceMenu
= static_cast<KMenu
*>(factory()->container("resourceContext", this));
623 mResourceSelector
->setContextMenu(resourceMenu
);
624 mMenuError
= (!mContextMenu
|| !mActionsMenu
|| !resourceMenu
);
625 connect(mActionUndo
->menu(), SIGNAL(aboutToShow()), SLOT(slotInitUndoMenu()));
626 connect(mActionUndo
->menu(), SIGNAL(triggered(QAction
*)), SLOT(slotUndoItem(QAction
*)));
627 connect(mActionRedo
->menu(), SIGNAL(aboutToShow()), SLOT(slotInitRedoMenu()));
628 connect(mActionRedo
->menu(), SIGNAL(triggered(QAction
*)), SLOT(slotRedoItem(QAction
*)));
629 connect(Undo::instance(), SIGNAL(changed(QString
,QString
)), SLOT(slotUndoStatus(QString
,QString
)));
630 connect(mListView
, SIGNAL(findActive(bool)), SLOT(slotFindActive(bool)));
631 Preferences::connect(SIGNAL(archivedKeepDaysChanged(int)), this, SLOT(updateKeepArchived(int)));
632 Preferences::connect(SIGNAL(showInSystemTrayChanged(bool)), this, SLOT(updateTrayIconAction()));
633 connect(theApp(), SIGNAL(trayIconToggled()), SLOT(updateTrayIconAction()));
635 // Set menu item states
637 mActionShowTime
->setChecked(mShowTime
);
638 mActionShowTimeTo
->setChecked(mShowTimeTo
);
639 mActionShowArchived
->setChecked(mShowArchived
);
640 if (!Preferences::archivedKeepDays())
641 mActionShowArchived
->setEnabled(false);
642 mActionToggleResourceSel
->setChecked(mShowResources
);
643 slotToggleResourceSelector();
644 updateTrayIconAction(); // set the correct text for this action
645 mActionUndo
->setEnabled(Undo::haveUndo());
646 mActionRedo
->setEnabled(Undo::haveRedo());
647 mActionFindNext
->setEnabled(false);
648 mActionFindPrev
->setEnabled(false);
650 mActionCopy
->setEnabled(false);
651 mActionModify
->setEnabled(false);
652 mActionDelete
->setEnabled(false);
653 mActionReactivate
->setEnabled(false);
654 mActionEnable
->setEnabled(false);
655 mActionCreateTemplate
->setEnabled(false);
656 mActionExport
->setEnabled(false);
658 Undo::emitChanged(); // set the Undo/Redo menu texts
659 // Daemon::monitoringAlarms();
662 /******************************************************************************
663 * Enable or disable the Templates menu item in every main window instance.
665 void MainWindow::enableTemplateMenuItem(bool enable
)
667 for (int i
= 0, end
= mWindowList
.count(); i
< end
; ++i
)
668 mWindowList
[i
]->mActionTemplates
->setEnabled(enable
);
671 /******************************************************************************
672 * Refresh the alarm list in every main window instance.
674 void MainWindow::refresh()
678 AkonadiModel::instance()->reload();
680 EventListModel::alarms()->reload();
684 /******************************************************************************
685 * Called when the keep archived alarm setting changes in the user preferences.
686 * Enable/disable Show archived alarms option.
688 void MainWindow::updateKeepArchived(int days
)
690 kDebug() << (bool)days
;
691 if (mShowArchived
&& !days
)
692 slotShowArchived(); // toggle Show Archived option setting
693 mActionShowArchived
->setEnabled(days
);
696 /******************************************************************************
697 * Select an alarm in the displayed list.
700 void MainWindow::selectEvent(Akonadi::Item::Id eventId
)
702 void MainWindow::selectEvent(const QString
& eventId
)
705 mListView
->clearSelection();
707 QModelIndex index
= mListFilterModel
->eventIndex(eventId
);
710 mListView
->select(index
);
711 mListView
->scrollTo(index
);
714 mListView
->select(eventId
, true);
718 /******************************************************************************
719 * Return the single selected alarm in the displayed list.
722 KAEvent
MainWindow::selectedEvent() const
724 KAEvent
* MainWindow::selectedEvent() const
727 return mListView
->selectedEvent();
730 /******************************************************************************
731 * Deselect all alarms in the displayed list.
733 void MainWindow::clearSelection()
735 mListView
->clearSelection();
738 /******************************************************************************
739 * Called when the New button is clicked to edit a new alarm to add to the list.
741 void MainWindow::slotNew(EditAlarmDlg::Type type
)
743 KAlarm::editNewAlarm(type
, mListView
);
746 /******************************************************************************
747 * Called when a template is selected from the New From Template popup menu.
748 * Executes a New Alarm dialog, preset from the selected template.
750 void MainWindow::slotNewFromTemplate(const KAEvent
* tmplate
)
752 KAlarm::editNewAlarm(tmplate
, mListView
);
755 /******************************************************************************
756 * Called when the New Template button is clicked to create a new template
757 * based on the currently selected alarm.
759 void MainWindow::slotNewTemplate()
762 KAEvent event
= mListView
->selectedEvent();
764 KAlarm::editNewTemplate(&event
, this);
766 KAEvent
* event
= mListView
->selectedEvent();
768 KAlarm::editNewTemplate(event
, this);
772 /******************************************************************************
773 * Called when the Copy button is clicked to edit a copy of an existing alarm,
774 * to add to the list.
776 void MainWindow::slotCopy()
779 KAEvent event
= mListView
->selectedEvent();
781 KAlarm::editNewAlarm(&event
, this);
783 KAEvent
* event
= mListView
->selectedEvent();
785 KAlarm::editNewAlarm(event
, this);
789 /******************************************************************************
790 * Called when the Modify button is clicked to edit the currently highlighted
793 void MainWindow::slotModify()
796 KAEvent event
= mListView
->selectedEvent();
798 KAlarm::editAlarm(&event
, this); // edit alarm (view-only mode if archived or read-only)
800 KAEvent
* event
= mListView
->selectedEvent();
802 KAlarm::editAlarm(event
, this); // edit alarm (view-only mode if archived or read-only)
806 /******************************************************************************
807 * Called when the Delete button is clicked to delete the currently highlighted
808 * alarms in the list.
810 void MainWindow::slotDelete(bool force
)
813 QVector
<KAEvent
> events
= mListView
->selectedEvents();
815 KAEvent::List events
= mListView
->selectedEvents();
816 // Save the IDs of the events to be deleted, in case any events are
817 // deleted by being triggered while the confirmation prompt is displayed
818 // (in which case their pointers will become invalid).
820 for (int i
= 0, end
= events
.count(); i
< end
; ++i
)
821 ids
.append(events
[i
]->id());
824 if (!force
&& Preferences::confirmAlarmDeletion())
826 int n
= events
.count();
827 if (KAMessageBox::warningContinueCancel(this, i18ncp("@info", "Do you really want to delete the selected alarm?",
828 "Do you really want to delete the %1 selected alarms?", n
),
829 i18ncp("@title:window", "Delete Alarm", "Delete Alarms", n
),
830 KGuiItem(i18nc("@action:button", "&Delete"), "edit-delete"),
831 KStandardGuiItem::cancel(),
832 Preferences::CONFIRM_ALARM_DELETION
)
833 != KMessageBox::Continue
)
837 // Remove any events which have just triggered, from the list to delete.
838 Undo::EventList undos
;
839 AlarmCalendar
* resources
= AlarmCalendar::resources();
841 for (int i
= 0; i
< events
.count(); )
843 Akonadi::Collection c
= resources
->collectionForEvent(events
[i
].itemId());
847 undos
.append(events
[i
++], c
);
850 for (int i
= 0, e
= 0, end
= ids
.count(); i
< end
; ++i
)
852 AlarmResource
* r
= resources
->resourceForEvent(ids
[i
]);
856 undos
.append(*events
[e
++], r
);
860 if (events
.isEmpty())
861 kDebug() << "No alarms left to delete";
864 // Delete the events from the calendar and displays
865 KAlarm::deleteEvents(events
, true, this);
866 Undo::saveDeletes(undos
);
870 /******************************************************************************
871 * Called when the Reactivate button is clicked to reinstate the currently
872 * highlighted archived alarms in the list.
874 void MainWindow::slotReactivate()
877 QVector
<KAEvent
> events
= mListView
->selectedEvents();
879 KAEvent::List events
= mListView
->selectedEvents();
881 mListView
->clearSelection();
883 // Add the alarms to the displayed lists and to the calendar file
884 Undo::EventList undos
;
885 QStringList ineligibleIDs
;
886 KAlarm::reactivateEvents(events
, ineligibleIDs
, 0, this);
888 // Create the undo list, excluding ineligible events
889 AlarmCalendar
* resources
= AlarmCalendar::resources();
890 for (int i
= 0, end
= events
.count(); i
< end
; ++i
)
893 if (!ineligibleIDs
.contains(events
[i
].id()))
895 Akonadi::Collection c
= resources
->collectionForEvent(events
[i
].itemId());
896 undos
.append(events
[i
], c
);
899 QString id
= events
[i
]->id();
900 if (!ineligibleIDs
.contains(id
))
901 undos
.append(*events
[i
], resources
->resourceForEvent(id
));
904 Undo::saveReactivates(undos
);
907 /******************************************************************************
908 * Called when the Enable/Disable button is clicked to enable or disable the
909 * currently highlighted alarms in the list.
911 void MainWindow::slotEnable()
913 bool enable
= mActionEnableEnable
; // save since changed in response to KAlarm::enableEvent()
915 QVector
<KAEvent
> events
= mListView
->selectedEvents();
916 QVector
<KAEvent
> eventCopies
;
918 KAEvent::List events
= mListView
->selectedEvents();
919 KAEvent::List eventCopies
;
921 for (int i
= 0, end
= events
.count(); i
< end
; ++i
)
922 eventCopies
+= events
[i
];
923 KAlarm::enableEvents(eventCopies
, enable
, this);
924 slotSelection(); // update Enable/Disable action text
927 /******************************************************************************
928 * Called when the Show Alarm Times menu item is selected or deselected.
930 void MainWindow::slotShowTime()
932 mShowTime
= !mShowTime
;
933 mActionShowTime
->setChecked(mShowTime
);
934 if (!mShowTime
&& !mShowTimeTo
)
935 slotShowTimeTo(); // at least one time column must be displayed
938 mListView
->selectTimeColumns(mShowTime
, mShowTimeTo
);
939 KConfigGroup
config(KGlobal::config(), VIEW_GROUP
);
940 config
.writeEntry(SHOW_TIME_KEY
, mShowTime
);
941 config
.writeEntry(SHOW_TIME_TO_KEY
, mShowTimeTo
);
945 /******************************************************************************
946 * Called when the Show Time To Alarms menu item is selected or deselected.
948 void MainWindow::slotShowTimeTo()
950 mShowTimeTo
= !mShowTimeTo
;
951 mActionShowTimeTo
->setChecked(mShowTimeTo
);
952 if (!mShowTimeTo
&& !mShowTime
)
953 slotShowTime(); // at least one time column must be displayed
956 mListView
->selectTimeColumns(mShowTime
, mShowTimeTo
);
957 KConfigGroup
config(KGlobal::config(), VIEW_GROUP
);
958 config
.writeEntry(SHOW_TIME_KEY
, mShowTime
);
959 config
.writeEntry(SHOW_TIME_TO_KEY
, mShowTimeTo
);
963 /******************************************************************************
964 * Called when the Show Archived Alarms menu item is selected or deselected.
966 void MainWindow::slotShowArchived()
968 mShowArchived
= !mShowArchived
;
969 mActionShowArchived
->setChecked(mShowArchived
);
970 mActionShowArchived
->setToolTip(mShowArchived
? i18nc("@info:tooltip", "Hide Archived Alarms")
971 : i18nc("@info:tooltip", "Show Archived Alarms"));
973 mListFilterModel
->setEventTypeFilter(mShowArchived
? CalEvent::ACTIVE
| CalEvent::ARCHIVED
: CalEvent::ACTIVE
);
975 mListFilterModel
->setStatusFilter(mShowArchived
? CalEvent::ACTIVE
| CalEvent::ARCHIVED
: CalEvent::ACTIVE
);
978 KConfigGroup
config(KGlobal::config(), VIEW_GROUP
);
979 config
.writeEntry(SHOW_ARCHIVED_KEY
, mShowArchived
);
982 /******************************************************************************
983 * Called when the Spread Windows global shortcut is selected, to spread alarm
984 * windows so that they are all visible.
986 void MainWindow::slotSpreadWindowsShortcut()
988 mActionSpreadWindows
->trigger();
991 /******************************************************************************
992 * Called when the Wake From Suspend menu option is selected.
994 void MainWindow::slotWakeFromSuspend()
996 (WakeFromSuspendDlg::create(this))->show();
999 /******************************************************************************
1000 * Called when the Import Alarms menu item is selected, to merge alarms from an
1001 * external calendar into the current calendars.
1003 void MainWindow::slotImportAlarms()
1005 AlarmCalendar::importAlarms(this);
1008 /******************************************************************************
1009 * Called when the Export Alarms menu item is selected, to export the selected
1010 * alarms to an external calendar.
1012 void MainWindow::slotExportAlarms()
1015 QVector
<KAEvent
> events
= mListView
->selectedEvents();
1016 if (!events
.isEmpty())
1018 KAEvent::List evts
= KAEvent::ptrList(events
);
1019 AlarmCalendar::exportAlarms(evts
, this);
1022 KAEvent::List events
= mListView
->selectedEvents();
1023 if (!events
.isEmpty())
1024 AlarmCalendar::exportAlarms(events
, this);
1028 /******************************************************************************
1029 * Called when the Import Birthdays menu item is selected, to display birthdays
1030 * from the address book for selection as alarms.
1032 void MainWindow::slotBirthdays()
1034 // Use AutoQPointer to guard against crash on application exit while
1035 // the dialogue is still open. It prevents double deletion (both on
1036 // deletion of MainWindow, and on return from this function).
1037 AutoQPointer
<BirthdayDlg
> dlg
= new BirthdayDlg(this);
1038 if (dlg
->exec() == QDialog::Accepted
)
1040 QVector
<KAEvent
> events
= dlg
->events();
1041 if (!events
.isEmpty())
1043 mListView
->clearSelection();
1044 // Add alarm to the displayed lists and to the calendar file
1045 KAlarm::UpdateStatus status
= KAlarm::addEvents(events
, dlg
, true, true);
1047 Undo::EventList undos
;
1048 AlarmCalendar
* resources
= AlarmCalendar::resources();
1049 for (int i
= 0, end
= events
.count(); i
< end
; ++i
)
1052 Akonadi::Collection c
= resources
->collectionForEvent(events
[i
].itemId());
1053 undos
.append(events
[i
], c
);
1056 undos
.append(events
[i
], resources
->resourceForEvent(events
[i
].id()));
1058 Undo::saveAdds(undos
, i18nc("@info", "Import birthdays"));
1060 if (status
!= KAlarm::UPDATE_FAILED
)
1061 KAlarm::outputAlarmWarnings(dlg
);
1066 /******************************************************************************
1067 * Called when the Templates menu item is selected, to display the alarm
1068 * template editing dialog.
1070 void MainWindow::slotTemplates()
1074 mTemplateDlg
= TemplateDlg::create(this);
1075 enableTemplateMenuItem(false); // disable menu item in all windows
1076 connect(mTemplateDlg
, SIGNAL(finished()), SLOT(slotTemplatesEnd()));
1077 mTemplateDlg
->show();
1081 /******************************************************************************
1082 * Called when the alarm template editing dialog has exited.
1084 void MainWindow::slotTemplatesEnd()
1088 mTemplateDlg
->delayedDestruct(); // this deletes the dialog once it is safe to do so
1090 enableTemplateMenuItem(true); // re-enable menu item in all windows
1094 /******************************************************************************
1095 * Called when the Display System Tray Icon menu item is selected.
1097 void MainWindow::slotToggleTrayIcon()
1099 theApp()->displayTrayIcon(!theApp()->trayIconDisplayed(), this);
1102 /******************************************************************************
1103 * Called when the Show Resource Selector menu item is selected.
1105 void MainWindow::slotToggleResourceSelector()
1107 mShowResources
= mActionToggleResourceSel
->isChecked();
1110 if (mResourcesWidth
<= 0)
1112 mResourcesWidth
= mResourceSelector
->sizeHint().width();
1113 mResourceSelector
->resize(mResourcesWidth
, mResourceSelector
->height());
1114 QList
<int> widths
= mSplitter
->sizes();
1115 if (widths
.count() == 1)
1117 int listwidth
= widths
[0] - mSplitter
->handleWidth() - mResourcesWidth
;
1118 mListView
->resize(listwidth
, mListView
->height());
1119 widths
.append(listwidth
);
1120 widths
[0] = mResourcesWidth
;
1122 mSplitter
->setSizes(widths
);
1124 mResourceSelector
->show();
1127 mResourceSelector
->hide();
1129 KConfigGroup
config(KGlobal::config(), VIEW_GROUP
);
1130 config
.writeEntry(SHOW_RESOURCES_KEY
, mShowResources
);
1133 /******************************************************************************
1134 * Called when an error occurs in the resource calendar, to display a message.
1136 void MainWindow::showErrorMessage(const QString
& msg
)
1138 KAMessageBox::error(this, msg
);
1141 /******************************************************************************
1142 * Called when the system tray icon is created or destroyed.
1143 * Set the system tray icon menu text according to whether or not the system
1144 * tray icon is currently visible.
1146 void MainWindow::updateTrayIconAction()
1148 mActionToggleTrayIcon
->setEnabled(KSystemTrayIcon::isSystemTrayAvailable());
1149 mActionToggleTrayIcon
->setChecked(theApp()->trayIconDisplayed());
1152 /******************************************************************************
1153 * Called when the active status of Find changes.
1155 void MainWindow::slotFindActive(bool active
)
1157 mActionFindNext
->setEnabled(active
);
1158 mActionFindPrev
->setEnabled(active
);
1161 /******************************************************************************
1162 * Called when the Undo action is selected.
1164 void MainWindow::slotUndo()
1166 Undo::undo(this, KGlobal::locale()->removeAcceleratorMarker(mActionUndo
->text()));
1169 /******************************************************************************
1170 * Called when the Redo action is selected.
1172 void MainWindow::slotRedo()
1174 Undo::redo(this, KGlobal::locale()->removeAcceleratorMarker(mActionRedo
->text()));
1177 /******************************************************************************
1178 * Called when an Undo item is selected.
1180 void MainWindow::slotUndoItem(QAction
* action
)
1182 int id
= mUndoMenuIds
[action
];
1183 Undo::undo(id
, this, Undo::actionText(Undo::UNDO
, id
));
1186 /******************************************************************************
1187 * Called when a Redo item is selected.
1189 void MainWindow::slotRedoItem(QAction
* action
)
1191 int id
= mUndoMenuIds
[action
];
1192 Undo::redo(id
, this, Undo::actionText(Undo::REDO
, id
));
1195 /******************************************************************************
1196 * Called when the Undo menu is about to show.
1197 * Populates the menu.
1199 void MainWindow::slotInitUndoMenu()
1201 initUndoMenu(mActionUndo
->menu(), Undo::UNDO
);
1204 /******************************************************************************
1205 * Called when the Redo menu is about to show.
1206 * Populates the menu.
1208 void MainWindow::slotInitRedoMenu()
1210 initUndoMenu(mActionRedo
->menu(), Undo::REDO
);
1213 /******************************************************************************
1214 * Populate the undo or redo menu.
1216 void MainWindow::initUndoMenu(QMenu
* menu
, Undo::Type type
)
1219 mUndoMenuIds
.clear();
1220 const QString
& action
= (type
== Undo::UNDO
) ? undoTextStripped
: redoTextStripped
;
1221 QList
<int> ids
= Undo::ids(type
);
1222 for (int i
= 0, end
= ids
.count(); i
< end
; ++i
)
1225 QString actText
= Undo::actionText(type
, id
);
1226 QString descrip
= Undo::description(type
, id
);
1227 QString text
= descrip
.isEmpty()
1228 ? i18nc("@action Undo/Redo [action]", "%1 %2", action
, actText
)
1229 : i18nc("@action Undo [action]: message", "%1 %2: %3", action
, actText
, descrip
);
1230 QAction
* act
= menu
->addAction(text
);
1231 mUndoMenuIds
[act
] = id
;
1235 /******************************************************************************
1236 * Called when the status of the Undo or Redo list changes.
1237 * Change the Undo or Redo text to include the action which would be undone/redone.
1239 void MainWindow::slotUndoStatus(const QString
& undo
, const QString
& redo
)
1243 mActionUndo
->setEnabled(false);
1244 mActionUndo
->setText(undoText
);
1248 mActionUndo
->setEnabled(true);
1249 mActionUndo
->setText(QString("%1 %2").arg(undoText
).arg(undo
));
1253 mActionRedo
->setEnabled(false);
1254 mActionRedo
->setText(redoText
);
1258 mActionRedo
->setEnabled(true);
1259 mActionRedo
->setText(QString("%1 %2").arg(redoText
).arg(redo
));
1263 /******************************************************************************
1264 * Called when the Refresh Alarms menu item is selected.
1266 void MainWindow::slotRefreshAlarms()
1268 KAlarm::refreshAlarms();
1271 /******************************************************************************
1272 * Called when the "Configure KAlarm" menu item is selected.
1274 void MainWindow::slotPreferences()
1276 KAlarmPrefDlg::display();
1279 /******************************************************************************
1280 * Called when the Configure Keys menu item is selected.
1282 void MainWindow::slotConfigureKeys()
1284 KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed
, this);
1287 /******************************************************************************
1288 * Called when the Configure Toolbars menu item is selected.
1290 void MainWindow::slotConfigureToolbar()
1292 saveMainWindowSettings(KGlobal::config()->group(WINDOW_NAME
));
1293 KEditToolBar
dlg(factory());
1294 connect(&dlg
, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig()));
1298 /******************************************************************************
1299 * Called when OK or Apply is clicked in the Configure Toolbars dialog, to save
1300 * the new configuration.
1302 void MainWindow::slotNewToolbarConfig()
1305 applyMainWindowSettings(KGlobal::config()->group(WINDOW_NAME
));
1308 /******************************************************************************
1309 * Called when the Quit menu item is selected.
1310 * Note that this must be called by the event loop, not directly from the menu
1311 * item, since otherwise the window will be deleted while still processing the
1312 * menu, resulting in a crash.
1314 void MainWindow::slotQuit()
1316 theApp()->doQuit(this);
1319 /******************************************************************************
1320 * Called when the user or the session manager attempts to close the window.
1322 void MainWindow::closeEvent(QCloseEvent
* ce
)
1324 if (!theApp()->sessionClosingDown())
1326 // The user (not the session manager) wants to close the window.
1329 // It's the parent window of the system tray icon, so just hide
1330 // it to prevent the system tray icon closing.
1340 /******************************************************************************
1341 * Called when the drag cursor enters a main or system tray window, to accept
1342 * or reject the dragged object.
1344 void MainWindow::executeDragEnterEvent(QDragEnterEvent
* e
)
1346 const QMimeData
* data
= e
->mimeData();
1347 bool accept
= ICalDrag::canDecode(data
) ? !e
->source() // don't accept "text/calendar" objects from this application
1349 || KUrl::List::canDecode(data
)
1350 || KPIM::MailList::canDecode(data
);
1352 e
->acceptProposedAction();
1355 /******************************************************************************
1356 * Called when an object is dropped on the window.
1357 * If the object is recognised, the edit alarm dialog is opened appropriately.
1359 void MainWindow::dropEvent(QDropEvent
* e
)
1361 executeDropEvent(this, e
);
1364 static QString
getMailHeader(const char* header
, KMime::Content
& content
)
1366 KMime::Headers::Base
* hd
= content
.headerByType(header
);
1367 return hd
? hd
->asUnicodeString() : QString();
1370 /******************************************************************************
1371 * Called when an object is dropped on a main or system tray window, to
1372 * evaluate the action required and extract the text.
1374 void MainWindow::executeDropEvent(MainWindow
* win
, QDropEvent
* e
)
1376 kDebug() << "Formats:" << e
->mimeData()->formats();
1377 const QMimeData
* data
= e
->mimeData();
1378 KAEvent::SubAction action
= KAEvent::MESSAGE
;
1380 AlarmText alarmText
;
1381 KPIM::MailList mailList
;
1384 MemoryCalendar::Ptr
calendar(new MemoryCalendar(Preferences::timeZone(true)));
1386 CalendarLocal
calendar(Preferences::timeZone(true));
1389 QString fmts
= data
->formats().join(", ");
1393 /* The order of the tests below matters, since some dropped objects
1394 * provide more than one mime type.
1395 * Don't change them without careful thought !!
1397 if (!(bytes
= data
->data("message/rfc822")).isEmpty())
1399 // Email message(s). Ignore all but the first.
1400 kDebug() << "email";
1401 KMime::Content content
;
1402 content
.setContent(bytes
);
1405 if (content
.textContent())
1406 body
= content
.textContent()->decodedText(true, true); // strip trailing newlines & spaces
1407 unsigned long sernum
= 0;
1408 if (KPIM::MailList::canDecode(data
))
1410 // Get its KMail serial number to allow the KMail message
1411 // to be called up from the alarm message window.
1412 mailList
= KPIM::MailList::fromMimeData(data
);
1413 if (!mailList
.isEmpty())
1414 sernum
= mailList
[0].serialNumber();
1416 alarmText
.setEmail(getMailHeader("To", content
),
1417 getMailHeader("From", content
),
1418 getMailHeader("Cc", content
),
1419 getMailHeader("Date", content
),
1420 getMailHeader("Subject", content
),
1423 #ifdef KMAIL_SUPPORTED
1424 else if (KPIM::MailList::canDecode(data
))
1426 mailList
= KPIM::MailList::fromMimeData(data
);
1427 // KMail message(s). Ignore all but the first.
1428 kDebug() << "KMail_list";
1429 if (mailList
.isEmpty())
1431 KPIM::MailSummary
& summary
= mailList
[0];
1433 dt
.setTime_t(summary
.date());
1434 QString body
= KAMail::getMailBody(summary
.serialNumber());
1435 alarmText
.setEmail(summary
.to(), summary
.from(), QString(),
1436 KGlobal::locale()->formatDateTime(dt
), summary
.subject(),
1437 body
, summary
.serialNumber());
1441 else if (ICalDrag::fromMimeData(data
, calendar
))
1443 else if (ICalDrag::fromMimeData(data
, &calendar
))
1446 // iCalendar - If events are included, use the first event
1447 kDebug() << "iCalendar";
1449 Event::List events
= calendar
->rawEvents();
1451 Event::List events
= calendar
.rawEvents();
1453 if (!events
.isEmpty())
1455 KAEvent
ev(events
[0]);
1456 KAlarm::editNewAlarm(&ev
, win
);
1459 // If todos are included, use the first todo
1461 Todo::List todos
= calendar
->rawTodos();
1463 Todo::List todos
= calendar
.rawTodos();
1465 if (todos
.isEmpty())
1468 Todo::Ptr todo
= todos
[0];
1470 Todo
* todo
= todos
[0];
1472 alarmText
.setTodo(todo
);
1473 KDateTime start
= todo
->dtStart(true);
1474 if (!start
.isValid() && todo
->hasDueDate())
1475 start
= todo
->dtDue(true);
1476 KAEvent::Flags flags
= KAEvent::DEFAULT_FONT
;
1477 if (start
.isDateOnly())
1478 flags
|= KAEvent::ANY_TIME
;
1479 KAEvent
ev(start
, alarmText
.displayText(), Preferences::defaultBgColour(), Preferences::defaultFgColour(),
1480 QFont(), KAEvent::MESSAGE
, 0, flags
, true);
1483 ev
.setRecurrence(*todo
->recurrence());
1484 ev
.setNextOccurrence(KDateTime::currentUtcDateTime());
1487 KAlarm::editNewAlarm(&ev
, win
);
1490 else if (!(files
= KUrl::List::fromMimeData(data
)).isEmpty())
1493 // Try to find the mime type of the file, without downloading a remote file
1494 KMimeType::Ptr mimeType
= KMimeType::findByUrl(files
[0]);
1495 action
= mimeType
->name().startsWith(QLatin1String("audio/")) ? KAEvent::AUDIO
: KAEvent::FILE;
1496 alarmText
.setText(files
[0].prettyUrl());
1498 else if (data
->hasText())
1500 QString text
= data
->text();
1502 alarmText
.setText(text
);
1507 if (!alarmText
.isEmpty())
1509 if (action
== KAEvent::MESSAGE
1510 && (alarmText
.isEmail() || alarmText
.isScript()))
1512 // If the alarm text could be interpreted as an email or command script,
1513 // prompt for which type of alarm to create.
1515 types
+= i18nc("@item:inlistbox", "Display Alarm");
1516 if (alarmText
.isEmail())
1517 types
+= i18nc("@item:inlistbox", "Email Alarm");
1518 else if (alarmText
.isScript())
1519 types
+= i18nc("@item:inlistbox", "Command Alarm");
1521 QString type
= KInputDialog::getItem(i18nc("@title:window", "Alarm Type"),
1522 i18nc("@info", "Choose alarm type to create:"), types
, 0, false, &ok
, mainMainWindow());
1524 return; // user didn't press OK
1525 int i
= types
.indexOf(type
);
1527 action
= alarmText
.isEmail() ? KAEvent::EMAIL
: KAEvent::COMMAND
;
1529 KAlarm::editNewAlarm(action
, win
, &alarmText
);
1533 /******************************************************************************
1534 * Called when the status of a calendar has changed.
1535 * Enable or disable actions appropriately.
1537 void MainWindow::slotCalendarStatusChanged()
1539 // Find whether there are any writable calendars
1541 bool active
= !CollectionControlModel::enabledCollections(CalEvent::ACTIVE
, true).isEmpty();
1542 bool templat
= !CollectionControlModel::enabledCollections(CalEvent::TEMPLATE
, true).isEmpty();
1544 AlarmResources
* resources
= AlarmResources::instance();
1545 bool active
= resources
->activeCount(CalEvent::ACTIVE
, true);
1546 bool templat
= resources
->activeCount(CalEvent::TEMPLATE
, true);
1548 for (int i
= 0, end
= mWindowList
.count(); i
< end
; ++i
)
1550 MainWindow
* w
= mWindowList
[i
];
1551 w
->mActionImportAlarms
->setEnabled(active
|| templat
);
1552 w
->mActionImportBirthdays
->setEnabled(active
);
1553 w
->mActionCreateTemplate
->setEnabled(templat
);
1554 // Note: w->mActionNew enabled status is set in the NewAlarmAction class.
1559 /******************************************************************************
1560 * Called when the selected items in the ListView change.
1561 * Enables the actions appropriately.
1563 void MainWindow::slotSelection()
1565 // Find which events have been selected
1567 QVector
<KAEvent
> events
= mListView
->selectedEvents();
1569 KAEvent::List events
= mListView
->selectedEvents();
1571 int count
= events
.count();
1574 selectionCleared(); // disable actions
1575 emit
selectionChanged();
1579 // Find whether there are any writable resources
1580 bool active
= mActionNew
->isEnabled();
1582 bool readOnly
= false;
1583 bool allArchived
= true;
1584 bool enableReactivate
= true;
1585 bool enableEnableDisable
= true;
1586 bool enableEnable
= false;
1587 bool enableDisable
= false;
1588 AlarmCalendar
* resources
= AlarmCalendar::resources();
1589 KDateTime now
= KDateTime::currentUtcDateTime();
1590 for (int i
= 0; i
< count
; ++i
)
1593 KAEvent
* ev
= resources
->event(events
[i
].id()); // get up-to-date status
1594 KAEvent
* event
= ev
? ev
: &events
[i
];
1596 KAEvent
* event
= events
[i
];
1598 bool expired
= event
->expired();
1600 allArchived
= false;
1602 if (resources
->eventReadOnly(event
->itemId()))
1604 if (resources
->eventReadOnly(event
->id()))
1607 if (enableReactivate
1608 && (!expired
|| !event
->occursAfter(now
, true)))
1609 enableReactivate
= false;
1610 if (enableEnableDisable
)
1613 enableEnableDisable
= enableEnable
= enableDisable
= false;
1616 if (!enableEnable
&& !event
->enabled())
1617 enableEnable
= true;
1618 if (!enableDisable
&& event
->enabled())
1619 enableDisable
= true;
1626 mActionCreateTemplate
->setEnabled((count
== 1) && !CollectionControlModel::enabledCollections(CalEvent::TEMPLATE
, true).isEmpty());
1628 mActionCreateTemplate
->setEnabled((count
== 1) && (AlarmResources::instance()->activeCount(CalEvent::TEMPLATE
, true) > 0));
1630 mActionExportAlarms
->setEnabled(true);
1631 mActionExport
->setEnabled(true);
1632 mActionCopy
->setEnabled(active
&& count
== 1);
1633 mActionModify
->setEnabled(count
== 1);
1634 mActionDelete
->setEnabled(!readOnly
&& (active
|| allArchived
));
1635 mActionReactivate
->setEnabled(active
&& enableReactivate
);
1636 mActionEnable
->setEnabled(active
&& !readOnly
&& (enableEnable
|| enableDisable
));
1637 if (enableEnable
|| enableDisable
)
1638 setEnableText(enableEnable
);
1640 emit
selectionChanged();
1643 /******************************************************************************
1644 * Called when a context menu is requested in the ListView.
1645 * Displays a context menu to modify or delete the selected item.
1647 void MainWindow::slotContextMenuRequested(const QPoint
& globalPos
)
1651 mContextMenu
->popup(globalPos
);
1654 /******************************************************************************
1655 * Disables actions when no item is selected.
1657 void MainWindow::selectionCleared()
1659 mActionCreateTemplate
->setEnabled(false);
1660 mActionExportAlarms
->setEnabled(false);
1661 mActionExport
->setEnabled(false);
1662 mActionCopy
->setEnabled(false);
1663 mActionModify
->setEnabled(false);
1664 mActionDelete
->setEnabled(false);
1665 mActionReactivate
->setEnabled(false);
1666 mActionEnable
->setEnabled(false);
1669 /******************************************************************************
1670 * Set the text of the Enable/Disable menu action.
1672 void MainWindow::setEnableText(bool enable
)
1674 mActionEnableEnable
= enable
;
1675 mActionEnable
->setText(enable
? i18nc("@action", "Ena&ble") : i18nc("@action", "Disa&ble"));
1678 /******************************************************************************
1679 * Display or hide the specified main window.
1680 * This should only be called when the application doesn't run in the system tray.
1682 MainWindow
* MainWindow::toggleWindow(MainWindow
* win
)
1684 if (win
&& mWindowList
.indexOf(win
) != -1)
1686 // A window is specified (and it exists)
1687 if (win
->isVisible())
1689 // The window is visible, so close it
1695 // The window is hidden, so display it
1696 win
->hide(); // in case it's on a different desktop
1697 win
->setWindowState(win
->windowState() & ~Qt::WindowMinimized
);
1699 win
->activateWindow();
1704 // No window is specified, or the window doesn't exist. Open a new one.
1710 /******************************************************************************
1711 * Called when the Edit button is clicked in an alarm message window.
1712 * This controls the alarm edit dialog created by the alarm window, and allows
1713 * it to remain unaffected by the alarm window closing.
1714 * See MessageWin::slotEdit() for more information.
1717 void MainWindow::editAlarm(EditAlarmDlg
* dlg
, const KAEvent
& event
)
1719 void MainWindow::editAlarm(EditAlarmDlg
* dlg
, const KAEvent
& event
, AlarmResource
* resource
)
1723 mEditAlarmMap
[dlg
] = event
;
1726 ev
.setResource(resource
);
1727 mEditAlarmMap
[dlg
] = ev
;
1729 connect(dlg
, SIGNAL(accepted()), SLOT(editAlarmOk()));
1730 connect(dlg
, SIGNAL(destroyed(QObject
*)), SLOT(editAlarmDeleted(QObject
*)));
1731 dlg
->setAttribute(Qt::WA_DeleteOnClose
, true); // ensure no memory leaks
1735 /******************************************************************************
1736 * Called when OK is clicked in the alarm edit dialog shown by editAlarm().
1737 * Updates the event which has been edited.
1739 void MainWindow::editAlarmOk()
1741 EditAlarmDlg
* dlg
= qobject_cast
<EditAlarmDlg
*>(sender());
1744 QMap
<EditAlarmDlg
*, KAEvent
>::Iterator it
= mEditAlarmMap
.find(dlg
);
1745 if (it
== mEditAlarmMap
.end())
1747 KAEvent event
= it
.value();
1748 mEditAlarmMap
.erase(it
);
1749 if (!event
.isValid())
1751 if (dlg
->result() != QDialog::Accepted
)
1754 Akonadi::Collection c
= AkonadiModel::instance()->collection(event
);
1755 KAlarm::updateEditedAlarm(dlg
, event
, c
);
1757 KAlarm::updateEditedAlarm(dlg
, event
, event
.resource());
1761 /******************************************************************************
1762 * Called when the alarm edit dialog shown by editAlarm() is deleted.
1763 * Removes the dialog from the pending list.
1765 void MainWindow::editAlarmDeleted(QObject
* obj
)
1767 mEditAlarmMap
.remove(static_cast<EditAlarmDlg
*>(obj
));