2 * mainwindow.cpp - main application window
4 * Copyright © 2001-2015 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.h"
24 #include "alarmcalendar.h"
25 #include "alarmlistdelegate.h"
26 #include "autoqpointer.h"
27 #include "alarmlistview.h"
28 #include "birthdaydlg.h"
29 #include "functions.h"
30 #include "kalarmapp.h"
32 #include "messagebox.h"
33 #include "newalarmaction.h"
35 #include "preferences.h"
36 #include "resourceselector.h"
37 #include "synchtimer.h"
38 #include "templatedlg.h"
39 #include "templatemenuaction.h"
40 #include "templatepickdlg.h"
41 #include "traywindow.h"
44 #include <kalarmcal/alarmtext.h>
45 #include <kalarmcal/kaevent.h>
47 #include <Libkdepim/MaillistDrag>
48 #include <kmime/kmime_content.h>
49 #include <KCalCore/MemoryCalendar>
50 #include <KCalUtils/kcalutils/icaldrag.h>
51 #include <AkonadiWidgets/controlgui.h>
52 using namespace KCalCore
;
53 using namespace KCalUtils
;
55 #include <K4AboutData>
57 #include <kactioncollection.h>
58 #include <ksystemtrayicon.h>
59 #include <kstandardaction.h>
60 #include <kiconloader.h>
61 #include <KLocalizedString>
62 #include <KSharedConfig>
63 #include <kconfiggroup.h>
64 #include <kshortcutsdialog.h>
65 #include <kedittoolbar.h>
66 #include <kxmlguifactory.h>
67 #include <ktoggleaction.h>
68 #include <ktoolbarpopupaction.h>
74 #include <QDragEnterEvent>
76 #include <QResizeEvent>
77 #include <QCloseEvent>
78 #include <QDesktopWidget>
80 #include <QMimeDatabase>
81 #include <qinputdialog.h>
83 #include "kalarm_debug.h"
85 using namespace KAlarmCal
;
89 const QString
UI_FILE(QStringLiteral("kalarmui.rc"));
90 const char* WINDOW_NAME
= "MainWindow";
92 const char* VIEW_GROUP
= "View";
93 const char* SHOW_TIME_KEY
= "ShowAlarmTime";
94 const char* SHOW_TIME_TO_KEY
= "ShowTimeToAlarm";
95 const char* SHOW_ARCHIVED_KEY
= "ShowArchivedAlarms";
96 const char* SHOW_RESOURCES_KEY
= "ShowResources";
99 QString undoTextStripped
;
100 QList
<QKeySequence
> undoShortcut
;
102 QString redoTextStripped
;
103 QList
<QKeySequence
> redoShortcut
;
107 /*=============================================================================
109 =============================================================================*/
111 MainWindow::WindowList
MainWindow::mWindowList
;
112 TemplateDlg
* MainWindow::mTemplateDlg
= Q_NULLPTR
;
114 // Collect these widget labels together to ensure consistent wording and
115 // translations across different modules.
116 QString
MainWindow::i18n_a_ShowAlarmTimes() { return i18nc("@action", "Show &Alarm Times"); }
117 QString
MainWindow::i18n_chk_ShowAlarmTime() { return i18nc("@option:check", "Show alarm time"); }
118 QString
MainWindow::i18n_o_ShowTimeToAlarms() { return i18nc("@action", "Show Time t&o Alarms"); }
119 QString
MainWindow::i18n_chk_ShowTimeToAlarm() { return i18nc("@option:check", "Show time until alarm"); }
122 /******************************************************************************
123 * Construct an instance.
124 * To avoid resize() events occurring while still opening the calendar (and
125 * resultant crashes), the calendar is opened before constructing the instance.
127 MainWindow
* MainWindow::create(bool restored
)
129 theApp()->checkCalendar(); // ensure calendar is open
130 return new MainWindow(restored
);
133 MainWindow::MainWindow(bool restored
)
134 : MainWindowBase(Q_NULLPTR
, Qt::WindowContextHelpButtonHint
),
136 mHiddenTrayParent(false),
141 setAttribute(Qt::WA_DeleteOnClose
);
142 setWindowModality(Qt::WindowModal
);
143 setObjectName(QStringLiteral("MainWin")); // used by LikeBack
144 setPlainCaption(KComponentData::mainComponent().aboutData()->programName());
145 KConfigGroup
config(KSharedConfig::openConfig(), VIEW_GROUP
);
146 mShowResources
= config
.readEntry(SHOW_RESOURCES_KEY
, false);
147 mShowArchived
= config
.readEntry(SHOW_ARCHIVED_KEY
, false);
148 mShowTime
= config
.readEntry(SHOW_TIME_KEY
, true);
149 mShowTimeTo
= config
.readEntry(SHOW_TIME_TO_KEY
, false);
152 KConfigGroup
wconfig(KSharedConfig::openConfig(), WINDOW_NAME
);
153 mResourcesWidth
= wconfig
.readEntry(QStringLiteral("Splitter %1").arg(KApplication::desktop()->width()), (int)0);
156 setAcceptDrops(true); // allow drag-and-drop onto this window
158 mShowTime
= true; // ensure at least one time column is visible
160 mSplitter
= new QSplitter(Qt::Horizontal
, this);
161 mSplitter
->setChildrenCollapsible(false);
162 mSplitter
->installEventFilter(this);
163 setCentralWidget(mSplitter
);
165 // Create the calendar resource selector widget
166 Akonadi::ControlGui::widgetNeedsAkonadi(this);
167 mResourceSelector
= new ResourceSelector(mSplitter
);
168 mSplitter
->setStretchFactor(0, 0); // don't resize resource selector when window is resized
169 mSplitter
->setStretchFactor(1, 1);
171 // Create the alarm list widget
172 mListFilterModel
= new AlarmListModel(this);
173 mListFilterModel
->setEventTypeFilter(mShowArchived
? CalEvent::ACTIVE
| CalEvent::ARCHIVED
: CalEvent::ACTIVE
);
174 mListView
= new AlarmListView(WINDOW_NAME
, mSplitter
);
175 mListView
->setModel(mListFilterModel
);
176 mListView
->selectTimeColumns(mShowTime
, mShowTimeTo
);
177 mListView
->sortByColumn(mShowTime
? AlarmListModel::TimeColumn
: AlarmListModel::TimeToColumn
, Qt::AscendingOrder
);
178 mListView
->setItemDelegate(new AlarmListDelegate(mListView
));
179 connect(mListView
->selectionModel(), SIGNAL(selectionChanged(QItemSelection
,QItemSelection
)), SLOT(slotSelection()));
180 connect(mListView
, &AlarmListView::contextMenuRequested
, this, &MainWindow::slotContextMenuRequested
);
181 connect(AkonadiModel::instance(), SIGNAL(collectionStatusChanged(Akonadi::Collection
,AkonadiModel::Change
,QVariant
,bool)),
182 SLOT(slotCalendarStatusChanged()));
183 connect(mResourceSelector
, &ResourceSelector::resized
, this, &MainWindow::resourcesResized
);
184 mListView
->installEventFilter(this);
187 setAutoSaveSettings(QLatin1String(WINDOW_NAME
), true); // save toolbars, window sizes etc.
188 mWindowList
.append(this);
189 if (mWindowList
.count() == 1)
191 // It's the first main window
192 if (theApp()->wantShowInSystemTray())
193 theApp()->displayTrayIcon(true, this); // create system tray icon for run-in-system-tray mode
194 else if (theApp()->trayWindow())
195 theApp()->trayWindow()->setAssocMainWindow(this); // associate this window with the system tray icon
197 slotCalendarStatusChanged(); // initialise action states now that window is registered
200 MainWindow::~MainWindow()
203 bool trayParent
= isTrayParent(); // must call before removing from window list
204 mWindowList
.removeAt(mWindowList
.indexOf(this));
206 // Prevent view updates during window destruction
207 delete mResourceSelector
;
208 mResourceSelector
= Q_NULLPTR
;
210 mListView
= Q_NULLPTR
;
212 if (theApp()->trayWindow())
215 delete theApp()->trayWindow();
217 theApp()->trayWindow()->removeWindow(this);
219 KSharedConfig::openConfig()->sync(); // save any new window size to disc
223 /******************************************************************************
224 * Save settings to the session managed config file, for restoration
225 * when the program is restored.
227 void MainWindow::saveProperties(KConfigGroup
& config
)
229 config
.writeEntry("HiddenTrayParent", isTrayParent() && isHidden());
230 config
.writeEntry("ShowArchived", mShowArchived
);
231 config
.writeEntry("ShowTime", mShowTime
);
232 config
.writeEntry("ShowTimeTo", mShowTimeTo
);
233 config
.writeEntry("ResourcesWidth", mResourceSelector
->isHidden() ? 0 : mResourceSelector
->width());
236 /******************************************************************************
237 * Read settings from the session managed config file.
238 * This function is automatically called whenever the app is being
239 * restored. Read in whatever was saved in saveProperties().
241 void MainWindow::readProperties(const KConfigGroup
& config
)
243 mHiddenTrayParent
= config
.readEntry("HiddenTrayParent", true);
244 mShowArchived
= config
.readEntry("ShowArchived", false);
245 mShowTime
= config
.readEntry("ShowTime", true);
246 mShowTimeTo
= config
.readEntry("ShowTimeTo", false);
247 mResourcesWidth
= config
.readEntry("ResourcesWidth", (int)0);
248 mShowResources
= (mResourcesWidth
> 0);
251 /******************************************************************************
252 * Get the main main window, i.e. the parent of the system tray icon, or if
253 * none, the first main window to be created. Visible windows take precedence
256 MainWindow
* MainWindow::mainMainWindow()
258 MainWindow
* tray
= theApp()->trayWindow() ? theApp()->trayWindow()->assocMainWindow() : Q_NULLPTR
;
259 if (tray
&& tray
->isVisible())
261 for (int i
= 0, end
= mWindowList
.count(); i
< end
; ++i
)
262 if (mWindowList
[i
]->isVisible())
263 return mWindowList
[i
];
266 if (mWindowList
.isEmpty())
268 return mWindowList
[0];
271 /******************************************************************************
272 * Check whether this main window is effectively the parent of the system tray icon.
274 bool MainWindow::isTrayParent() const
276 TrayWindow
* tray
= theApp()->trayWindow();
277 if (!tray
|| !KSystemTrayIcon::isSystemTrayAvailable())
279 if (tray
->assocMainWindow() == this)
281 return mWindowList
.count() == 1;
284 /******************************************************************************
285 * Close all main windows.
287 void MainWindow::closeAll()
289 while (!mWindowList
.isEmpty())
290 delete mWindowList
[0]; // N.B. the destructor removes the window from the list
293 /******************************************************************************
294 * Intercept events for the splitter widget.
296 bool MainWindow::eventFilter(QObject
* obj
, QEvent
* e
)
298 if (obj
== mSplitter
)
303 // Don't change resources size while WINDOW is being resized.
304 // Resize event always occurs before Paint.
308 // Allow resources to be resized again
315 else if (obj
== mListView
)
319 case QEvent::KeyPress
:
321 QKeyEvent
* ke
= static_cast<QKeyEvent
*>(e
);
322 if (ke
->key() == Qt::Key_Delete
&& ke
->modifiers() == Qt::ShiftModifier
)
324 // Prevent Shift-Delete being processed by EventListDelegate
325 mActionDeleteForce
->trigger();
337 /******************************************************************************
338 * Called when the window's size has changed (before it is painted).
339 * Sets the last column in the list view to extend at least to the right hand
340 * edge of the list view.
341 * Records the new size in the config file.
343 void MainWindow::resizeEvent(QResizeEvent
* re
)
345 // Save the window's new size only if it's the first main window
346 MainWindowBase::resizeEvent(re
);
347 if (mResourcesWidth
> 0)
350 widths
.append(mResourcesWidth
);
351 widths
.append(width() - mResourcesWidth
- mSplitter
->handleWidth());
352 mSplitter
->setSizes(widths
);
356 void MainWindow::resourcesResized()
358 if (!mShown
|| mResizing
)
360 QList
<int> widths
= mSplitter
->sizes();
361 if (widths
.count() > 1)
363 mResourcesWidth
= widths
[0];
364 // Width is reported as non-zero when resource selector is
365 // actually invisible, so note a zero width in these circumstances.
366 if (mResourcesWidth
<= 5)
368 else if (mainMainWindow() == this)
370 KConfigGroup
config(KSharedConfig::openConfig(), WINDOW_NAME
);
371 config
.writeEntry(QStringLiteral("Splitter %1").arg(KApplication::desktop()->width()), mResourcesWidth
);
376 /******************************************************************************
377 * Called when the window is first displayed.
378 * Sets the last column in the list view to extend at least to the right hand
379 * edge of the list view.
381 void MainWindow::showEvent(QShowEvent
* se
)
383 if (mResourcesWidth
> 0)
386 widths
.append(mResourcesWidth
);
387 widths
.append(width() - mResourcesWidth
- mSplitter
->handleWidth());
388 mSplitter
->setSizes(widths
);
390 MainWindowBase::showEvent(se
);
394 /******************************************************************************
395 * Display the window.
397 void MainWindow::show()
399 MainWindowBase::show();
402 // Show error message now that the main window has been displayed.
403 // Waiting until now lets the user easily associate the message with
404 // the main window which is faulty.
405 KAMessageBox::error(this, xi18nc("@info", "Failure to create menus (perhaps <filename>%1</filename> missing or corrupted)", UI_FILE
));
410 /******************************************************************************
411 * Called after the window is hidden.
413 void MainWindow::hideEvent(QHideEvent
* he
)
415 MainWindowBase::hideEvent(he
);
418 /******************************************************************************
419 * Initialise the menu, toolbar and main window actions.
421 void MainWindow::initActions()
424 KActionCollection
* actions
= actionCollection();
426 mActionTemplates
= new QAction(i18nc("@action", "&Templates..."), this);
427 actions
->addAction(QStringLiteral("templates"), mActionTemplates
);
428 connect(mActionTemplates
, &QAction::triggered
, this, &MainWindow::slotTemplates
);
430 mActionNew
= new NewAlarmAction(false, i18nc("@action", "&New"), this);
431 actions
->addAction(QStringLiteral("new"), mActionNew
);
433 QAction
* action
= mActionNew
->displayAlarmAction();
434 actions
->addAction(QStringLiteral("newDisplay"), action
);
435 #pragma message("port QT5")
436 //QT5 action->setGlobalShortcut(dummy); // actions->addAction() must be called first!
437 connect(action
, &QAction::triggered
, this, &MainWindow::slotNewDisplay
);
439 action
= mActionNew
->commandAlarmAction();
440 actions
->addAction(QStringLiteral("newCommand"), action
);
441 #pragma message("port QT5")
442 //QT5 action->setGlobalShortcut(dummy); // actions->addAction() must be called first!
443 connect(action
, &QAction::triggered
, this, &MainWindow::slotNewCommand
);
445 action
= mActionNew
->emailAlarmAction();
446 actions
->addAction(QStringLiteral("newEmail"), action
);
447 #pragma message("port QT5")
448 //QT5 action->setGlobalShortcut(dummy); // actions->addAction() must be called first!
449 connect(action
, &QAction::triggered
, this, &MainWindow::slotNewEmail
);
451 action
= mActionNew
->audioAlarmAction();
452 actions
->addAction(QStringLiteral("newAudio"), action
);
453 #pragma message("port QT5")
454 //QT5 action->setGlobalShortcut(dummy); // actions->addAction() must be called first!
455 connect(action
, &QAction::triggered
, this, &MainWindow::slotNewAudio
);
457 TemplateMenuAction
*templateMenuAction
= mActionNew
->fromTemplateAlarmAction();
458 actions
->addAction(QStringLiteral("newFromTemplate"), templateMenuAction
);
459 connect(templateMenuAction
, &TemplateMenuAction::selected
, this, &MainWindow::slotNewFromTemplate
);
461 mActionCreateTemplate
= new QAction(i18nc("@action", "Create Tem&plate..."), this);
462 actions
->addAction(QStringLiteral("createTemplate"), mActionCreateTemplate
);
463 connect(mActionCreateTemplate
, &QAction::triggered
, this, &MainWindow::slotNewTemplate
);
465 mActionCopy
= new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action", "&Copy..."), this);
466 actions
->addAction(QStringLiteral("copy"), mActionCopy
);
467 actions
->setDefaultShortcut(mActionCopy
, QKeySequence(Qt::SHIFT
+ Qt::Key_Insert
));
468 connect(mActionCopy
, &QAction::triggered
, this, &MainWindow::slotCopy
);
470 mActionModify
= new QAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18nc("@action", "&Edit..."), this);
471 actions
->addAction(QStringLiteral("modify"), mActionModify
);
472 actions
->setDefaultShortcut(mActionModify
, QKeySequence(Qt::CTRL
+ Qt::Key_E
));
473 connect(mActionModify
, &QAction::triggered
, this, &MainWindow::slotModify
);
475 mActionDelete
= new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@action", "&Delete"), this);
476 actions
->addAction(QStringLiteral("delete"), mActionDelete
);
477 actions
->setDefaultShortcut(mActionDelete
, QKeySequence::Delete
);
478 connect(mActionDelete
, &QAction::triggered
, this, &MainWindow::slotDeleteIf
);
480 // Set up Shift-Delete as a shortcut to delete without confirmation
481 mActionDeleteForce
= new QAction(i18nc("@action", "Delete Without Confirmation"), this);
482 actions
->addAction(QStringLiteral("delete-force"), mActionDeleteForce
);
483 actions
->setDefaultShortcut(mActionDeleteForce
, QKeySequence::Delete
+ Qt::SHIFT
);
484 connect(mActionDeleteForce
, &QAction::triggered
, this, &MainWindow::slotDeleteForce
);
486 mActionReactivate
= new QAction(i18nc("@action", "Reac&tivate"), this);
487 actions
->addAction(QStringLiteral("undelete"), mActionReactivate
);
488 actions
->setDefaultShortcut(mActionReactivate
, QKeySequence(Qt::CTRL
+ Qt::Key_R
));
489 connect(mActionReactivate
, &QAction::triggered
, this, &MainWindow::slotReactivate
);
491 mActionEnable
= new QAction(this);
492 actions
->addAction(QStringLiteral("disable"), mActionEnable
);
493 actions
->setDefaultShortcut(mActionEnable
, QKeySequence(Qt::CTRL
+ Qt::Key_B
));
494 connect(mActionEnable
, &QAction::triggered
, this, &MainWindow::slotEnable
);
496 action
= new QAction(i18nc("@action", "Wake From Suspend..."), this);
497 actions
->addAction(QStringLiteral("wakeSuspend"), action
);
498 connect(action
, &QAction::triggered
, this, &MainWindow::slotWakeFromSuspend
);
500 action
= KAlarm::createStopPlayAction(this);
501 actions
->addAction(QStringLiteral("stopAudio"), action
);
502 //QT5 action->setGlobalShortcut(dummy); // actions->addAction() must be called first!
504 mActionShowTime
= new KToggleAction(i18n_a_ShowAlarmTimes(), this);
505 actions
->addAction(QStringLiteral("showAlarmTimes"), mActionShowTime
);
506 connect(mActionShowTime
, &KToggleAction::triggered
, this, &MainWindow::slotShowTime
);
508 mActionShowTimeTo
= new KToggleAction(i18n_o_ShowTimeToAlarms(), this);
509 actions
->addAction(QStringLiteral("showTimeToAlarms"), mActionShowTimeTo
);
510 actions
->setDefaultShortcut(mActionShowTimeTo
, QKeySequence(Qt::CTRL
+ Qt::Key_I
));
511 connect(mActionShowTimeTo
, &KToggleAction::triggered
, this, &MainWindow::slotShowTimeTo
);
513 mActionShowArchived
= new KToggleAction(i18nc("@action", "Show Archi&ved Alarms"), this);
514 actions
->addAction(QStringLiteral("showArchivedAlarms"), mActionShowArchived
);
515 actions
->setDefaultShortcut(mActionShowArchived
, QKeySequence(Qt::CTRL
+ Qt::Key_P
));
516 connect(mActionShowArchived
, &KToggleAction::triggered
, this, &MainWindow::slotShowArchived
);
518 mActionToggleTrayIcon
= new KToggleAction(i18nc("@action", "Show in System &Tray"), this);
519 actions
->addAction(QStringLiteral("showInSystemTray"), mActionToggleTrayIcon
);
520 connect(mActionToggleTrayIcon
, &KToggleAction::triggered
, this, &MainWindow::slotToggleTrayIcon
);
522 mActionToggleResourceSel
= new KToggleAction(QIcon::fromTheme(QStringLiteral("view-choose")), i18nc("@action", "Show &Calendars"), this);
523 actions
->addAction(QStringLiteral("showResources"), mActionToggleResourceSel
);
524 connect(mActionToggleResourceSel
, &KToggleAction::triggered
, this, &MainWindow::slotToggleResourceSelector
);
526 mActionSpreadWindows
= KAlarm::createSpreadWindowsAction(this);
527 actions
->addAction(QStringLiteral("spread"), mActionSpreadWindows
);
528 #pragma message("port QT5")
530 //QT5 mActionSpreadWindows->setGlobalShortcut(dummy); // actions->addAction() must be called first!
532 mActionImportAlarms
= new QAction(i18nc("@action", "Import &Alarms..."), this);
533 actions
->addAction(QStringLiteral("importAlarms"), mActionImportAlarms
);
534 connect(mActionImportAlarms
, &QAction::triggered
, this, &MainWindow::slotImportAlarms
);
536 mActionImportBirthdays
= new QAction(i18nc("@action", "Import &Birthdays..."), this);
537 actions
->addAction(QStringLiteral("importBirthdays"), mActionImportBirthdays
);
538 connect(mActionImportBirthdays
, &QAction::triggered
, this, &MainWindow::slotBirthdays
);
540 mActionExportAlarms
= new QAction(i18nc("@action", "E&xport Selected Alarms..."), this);
541 actions
->addAction(QStringLiteral("exportAlarms"), mActionExportAlarms
);
542 connect(mActionExportAlarms
, &QAction::triggered
, this, &MainWindow::slotExportAlarms
);
544 mActionExport
= new QAction(i18nc("@action", "E&xport..."), this);
545 actions
->addAction(QStringLiteral("export"), mActionExport
);
546 connect(mActionExport
, &QAction::triggered
, this, &MainWindow::slotExportAlarms
);
548 action
= new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18nc("@action", "&Refresh Alarms"), this);
549 actions
->addAction(QStringLiteral("refreshAlarms"), action
);
550 connect(action
, &QAction::triggered
, this, &MainWindow::slotRefreshAlarms
);
552 KToggleAction
* toggleAction
= KAlarm::createAlarmEnableAction(this);
553 actions
->addAction(QStringLiteral("alarmsEnable"), toggleAction
);
554 if (undoText
.isNull())
556 // Get standard texts, etc., for Undo and Redo actions
557 QAction
* act
= KStandardAction::undo(this, Q_NULLPTR
, actions
);
558 undoShortcut
= act
->shortcuts();
559 undoText
= act
->text();
560 undoTextStripped
= KLocalizedString::removeAcceleratorMarker(undoText
);
562 act
= KStandardAction::redo(this, Q_NULLPTR
, actions
);
563 redoShortcut
= act
->shortcuts();
564 redoText
= act
->text();
565 redoTextStripped
= KLocalizedString::removeAcceleratorMarker(redoText
);
568 mActionUndo
= new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("edit-undo")), undoText
, this);
569 actions
->addAction(QStringLiteral("edit_undo"), mActionUndo
);
570 mActionUndo
->setShortcuts(undoShortcut
);
571 connect(mActionUndo
, &KToolBarPopupAction::triggered
, this, &MainWindow::slotUndo
);
573 mActionRedo
= new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("edit-redo")), redoText
, this);
574 actions
->addAction(QStringLiteral("edit_redo"), mActionRedo
);
575 mActionRedo
->setShortcuts(redoShortcut
);
576 connect(mActionRedo
, &KToolBarPopupAction::triggered
, this, &MainWindow::slotRedo
);
578 KStandardAction::find(mListView
, SLOT(slotFind()), actions
);
579 mActionFindNext
= KStandardAction::findNext(mListView
, SLOT(slotFindNext()), actions
);
580 mActionFindPrev
= KStandardAction::findPrev(mListView
, SLOT(slotFindPrev()), actions
);
581 KStandardAction::selectAll(mListView
, SLOT(selectAll()), actions
);
582 KStandardAction::deselect(mListView
, SLOT(clearSelection()), actions
);
583 // Quit only once the event loop is called; otherwise, the parent window will
584 // be deleted while still processing the action, resulting in a crash.
585 QAction
* act
= KStandardAction::quit(Q_NULLPTR
, Q_NULLPTR
, actions
);
586 connect(act
, &QAction::triggered
, this, &MainWindow::slotQuit
, Qt::QueuedConnection
);
587 KStandardAction::keyBindings(this, SLOT(slotConfigureKeys()), actions
);
588 KStandardAction::configureToolbars(this, SLOT(slotConfigureToolbar()), actions
);
589 KStandardAction::preferences(this, SLOT(slotPreferences()), actions
);
590 mResourceSelector
->initActions(actions
);
591 setStandardToolBarMenuEnabled(true);
593 // Load menu and toolbar settings
594 applyMainWindowSettings(KSharedConfig::openConfig()->group(WINDOW_NAME
));
596 mContextMenu
= static_cast<QMenu
*>(factory()->container(QStringLiteral("listContext"), this));
597 mActionsMenu
= static_cast<QMenu
*>(factory()->container(QStringLiteral("actions"), this));
598 QMenu
* resourceMenu
= static_cast<QMenu
*>(factory()->container(QStringLiteral("resourceContext"), this));
599 mResourceSelector
->setContextMenu(resourceMenu
);
600 mMenuError
= (!mContextMenu
|| !mActionsMenu
|| !resourceMenu
);
601 connect(mActionUndo
->menu(), SIGNAL(aboutToShow()), SLOT(slotInitUndoMenu()));
602 connect(mActionUndo
->menu(), SIGNAL(triggered(QAction
*)), SLOT(slotUndoItem(QAction
*)));
603 connect(mActionRedo
->menu(), SIGNAL(aboutToShow()), SLOT(slotInitRedoMenu()));
604 connect(mActionRedo
->menu(), SIGNAL(triggered(QAction
*)), SLOT(slotRedoItem(QAction
*)));
605 connect(Undo::instance(), SIGNAL(changed(QString
,QString
)), SLOT(slotUndoStatus(QString
,QString
)));
606 connect(mListView
, &AlarmListView::findActive
, this, &MainWindow::slotFindActive
);
607 Preferences::connect(SIGNAL(archivedKeepDaysChanged(int)), this, SLOT(updateKeepArchived(int)));
608 Preferences::connect(SIGNAL(showInSystemTrayChanged(bool)), this, SLOT(updateTrayIconAction()));
609 connect(theApp(), SIGNAL(trayIconToggled()), SLOT(updateTrayIconAction()));
611 // Set menu item states
613 mActionShowTime
->setChecked(mShowTime
);
614 mActionShowTimeTo
->setChecked(mShowTimeTo
);
615 mActionShowArchived
->setChecked(mShowArchived
);
616 if (!Preferences::archivedKeepDays())
617 mActionShowArchived
->setEnabled(false);
618 mActionToggleResourceSel
->setChecked(mShowResources
);
619 slotToggleResourceSelector();
620 updateTrayIconAction(); // set the correct text for this action
621 mActionUndo
->setEnabled(Undo::haveUndo());
622 mActionRedo
->setEnabled(Undo::haveRedo());
623 mActionFindNext
->setEnabled(false);
624 mActionFindPrev
->setEnabled(false);
626 mActionCopy
->setEnabled(false);
627 mActionModify
->setEnabled(false);
628 mActionDelete
->setEnabled(false);
629 mActionReactivate
->setEnabled(false);
630 mActionEnable
->setEnabled(false);
631 mActionCreateTemplate
->setEnabled(false);
632 mActionExport
->setEnabled(false);
634 Undo::emitChanged(); // set the Undo/Redo menu texts
635 // Daemon::monitoringAlarms();
638 /******************************************************************************
639 * Enable or disable the Templates menu item in every main window instance.
641 void MainWindow::enableTemplateMenuItem(bool enable
)
643 for (int i
= 0, end
= mWindowList
.count(); i
< end
; ++i
)
644 mWindowList
[i
]->mActionTemplates
->setEnabled(enable
);
647 /******************************************************************************
648 * Refresh the alarm list in every main window instance.
650 void MainWindow::refresh()
653 AkonadiModel::instance()->reload();
656 /******************************************************************************
657 * Called when the keep archived alarm setting changes in the user preferences.
658 * Enable/disable Show archived alarms option.
660 void MainWindow::updateKeepArchived(int days
)
662 qCDebug(KALARM_LOG
) << (bool)days
;
663 if (mShowArchived
&& !days
)
664 slotShowArchived(); // toggle Show Archived option setting
665 mActionShowArchived
->setEnabled(days
);
668 /******************************************************************************
669 * Select an alarm in the displayed list.
671 void MainWindow::selectEvent(Akonadi::Item::Id eventId
)
673 mListView
->clearSelection();
674 QModelIndex index
= mListFilterModel
->eventIndex(eventId
);
677 mListView
->select(index
);
678 mListView
->scrollTo(index
);
682 /******************************************************************************
683 * Return the single selected alarm in the displayed list.
685 KAEvent
MainWindow::selectedEvent() const
687 return mListView
->selectedEvent();
690 /******************************************************************************
691 * Deselect all alarms in the displayed list.
693 void MainWindow::clearSelection()
695 mListView
->clearSelection();
698 /******************************************************************************
699 * Called when the New button is clicked to edit a new alarm to add to the list.
701 void MainWindow::slotNew(EditAlarmDlg::Type type
)
703 KAlarm::editNewAlarm(type
, mListView
);
706 /******************************************************************************
707 * Called when a template is selected from the New From Template popup menu.
708 * Executes a New Alarm dialog, preset from the selected template.
710 void MainWindow::slotNewFromTemplate(const KAEvent
* tmplate
)
712 KAlarm::editNewAlarm(tmplate
, mListView
);
715 /******************************************************************************
716 * Called when the New Template button is clicked to create a new template
717 * based on the currently selected alarm.
719 void MainWindow::slotNewTemplate()
721 KAEvent event
= mListView
->selectedEvent();
723 KAlarm::editNewTemplate(&event
, this);
726 /******************************************************************************
727 * Called when the Copy button is clicked to edit a copy of an existing alarm,
728 * to add to the list.
730 void MainWindow::slotCopy()
732 KAEvent event
= mListView
->selectedEvent();
734 KAlarm::editNewAlarm(&event
, this);
737 /******************************************************************************
738 * Called when the Modify button is clicked to edit the currently highlighted
741 void MainWindow::slotModify()
743 KAEvent event
= mListView
->selectedEvent();
745 KAlarm::editAlarm(&event
, this); // edit alarm (view-only mode if archived or read-only)
748 /******************************************************************************
749 * Called when the Delete button is clicked to delete the currently highlighted
750 * alarms in the list.
752 void MainWindow::slotDelete(bool force
)
754 QVector
<KAEvent
> events
= mListView
->selectedEvents();
755 if (!force
&& Preferences::confirmAlarmDeletion())
757 int n
= events
.count();
758 if (KAMessageBox::warningContinueCancel(this, i18ncp("@info", "Do you really want to delete the selected alarm?",
759 "Do you really want to delete the %1 selected alarms?", n
),
760 i18ncp("@title:window", "Delete Alarm", "Delete Alarms", n
),
761 KGuiItem(i18nc("@action:button", "&Delete"), QStringLiteral("edit-delete")),
762 KStandardGuiItem::cancel(),
763 Preferences::CONFIRM_ALARM_DELETION
)
764 != KMessageBox::Continue
)
768 // Remove any events which have just triggered, from the list to delete.
769 Undo::EventList undos
;
770 AlarmCalendar
* resources
= AlarmCalendar::resources();
771 for (int i
= 0; i
< events
.count(); )
773 Akonadi::Collection c
= resources
->collectionForEvent(events
[i
].itemId());
777 undos
.append(events
[i
++], c
);
780 if (events
.isEmpty())
781 qCDebug(KALARM_LOG
) << "No alarms left to delete";
784 // Delete the events from the calendar and displays
785 KAlarm::deleteEvents(events
, true, this);
786 Undo::saveDeletes(undos
);
790 /******************************************************************************
791 * Called when the Reactivate button is clicked to reinstate the currently
792 * highlighted archived alarms in the list.
794 void MainWindow::slotReactivate()
796 QVector
<KAEvent
> events
= mListView
->selectedEvents();
797 mListView
->clearSelection();
799 // Add the alarms to the displayed lists and to the calendar file
800 Undo::EventList undos
;
801 QVector
<EventId
> ineligibleIDs
;
802 KAlarm::reactivateEvents(events
, ineligibleIDs
, Q_NULLPTR
, this);
804 // Create the undo list, excluding ineligible events
805 AlarmCalendar
* resources
= AlarmCalendar::resources();
806 for (int i
= 0, end
= events
.count(); i
< end
; ++i
)
808 if (!ineligibleIDs
.contains(EventId(events
[i
])))
810 undos
.append(events
[i
], resources
->collectionForEvent(events
[i
].itemId()));
813 Undo::saveReactivates(undos
);
816 /******************************************************************************
817 * Called when the Enable/Disable button is clicked to enable or disable the
818 * currently highlighted alarms in the list.
820 void MainWindow::slotEnable()
822 bool enable
= mActionEnableEnable
; // save since changed in response to KAlarm::enableEvent()
823 QVector
<KAEvent
> events
= mListView
->selectedEvents();
824 QVector
<KAEvent
> eventCopies
;
825 for (int i
= 0, end
= events
.count(); i
< end
; ++i
)
826 eventCopies
+= events
[i
];
827 KAlarm::enableEvents(eventCopies
, enable
, this);
828 slotSelection(); // update Enable/Disable action text
831 /******************************************************************************
832 * Called when the Show Alarm Times menu item is selected or deselected.
834 void MainWindow::slotShowTime()
836 mShowTime
= !mShowTime
;
837 mActionShowTime
->setChecked(mShowTime
);
838 if (!mShowTime
&& !mShowTimeTo
)
839 slotShowTimeTo(); // at least one time column must be displayed
842 mListView
->selectTimeColumns(mShowTime
, mShowTimeTo
);
843 KConfigGroup
config(KSharedConfig::openConfig(), VIEW_GROUP
);
844 config
.writeEntry(SHOW_TIME_KEY
, mShowTime
);
845 config
.writeEntry(SHOW_TIME_TO_KEY
, mShowTimeTo
);
849 /******************************************************************************
850 * Called when the Show Time To Alarms menu item is selected or deselected.
852 void MainWindow::slotShowTimeTo()
854 mShowTimeTo
= !mShowTimeTo
;
855 mActionShowTimeTo
->setChecked(mShowTimeTo
);
856 if (!mShowTimeTo
&& !mShowTime
)
857 slotShowTime(); // at least one time column must be displayed
860 mListView
->selectTimeColumns(mShowTime
, mShowTimeTo
);
861 KConfigGroup
config(KSharedConfig::openConfig(), VIEW_GROUP
);
862 config
.writeEntry(SHOW_TIME_KEY
, mShowTime
);
863 config
.writeEntry(SHOW_TIME_TO_KEY
, mShowTimeTo
);
867 /******************************************************************************
868 * Called when the Show Archived Alarms menu item is selected or deselected.
870 void MainWindow::slotShowArchived()
872 mShowArchived
= !mShowArchived
;
873 mActionShowArchived
->setChecked(mShowArchived
);
874 mActionShowArchived
->setToolTip(mShowArchived
? i18nc("@info:tooltip", "Hide Archived Alarms")
875 : i18nc("@info:tooltip", "Show Archived Alarms"));
876 mListFilterModel
->setEventTypeFilter(mShowArchived
? CalEvent::ACTIVE
| CalEvent::ARCHIVED
: CalEvent::ACTIVE
);
878 KConfigGroup
config(KSharedConfig::openConfig(), VIEW_GROUP
);
879 config
.writeEntry(SHOW_ARCHIVED_KEY
, mShowArchived
);
882 /******************************************************************************
883 * Called when the Spread Windows global shortcut is selected, to spread alarm
884 * windows so that they are all visible.
886 void MainWindow::slotSpreadWindowsShortcut()
888 mActionSpreadWindows
->trigger();
891 /******************************************************************************
892 * Called when the Wake From Suspend menu option is selected.
894 void MainWindow::slotWakeFromSuspend()
896 (WakeFromSuspendDlg::create(this))->show();
899 /******************************************************************************
900 * Called when the Import Alarms menu item is selected, to merge alarms from an
901 * external calendar into the current calendars.
903 void MainWindow::slotImportAlarms()
905 AlarmCalendar::importAlarms(this);
908 /******************************************************************************
909 * Called when the Export Alarms menu item is selected, to export the selected
910 * alarms to an external calendar.
912 void MainWindow::slotExportAlarms()
914 QVector
<KAEvent
> events
= mListView
->selectedEvents();
915 if (!events
.isEmpty())
917 KAEvent::List evts
= KAEvent::ptrList(events
);
918 AlarmCalendar::exportAlarms(evts
, this);
922 /******************************************************************************
923 * Called when the Import Birthdays menu item is selected, to display birthdays
924 * from the address book for selection as alarms.
926 void MainWindow::slotBirthdays()
928 // Use AutoQPointer to guard against crash on application exit while
929 // the dialogue is still open. It prevents double deletion (both on
930 // deletion of MainWindow, and on return from this function).
931 AutoQPointer
<BirthdayDlg
> dlg
= new BirthdayDlg(this);
932 if (dlg
->exec() == QDialog::Accepted
)
934 QVector
<KAEvent
> events
= dlg
->events();
935 if (!events
.isEmpty())
937 mListView
->clearSelection();
938 // Add alarm to the displayed lists and to the calendar file
939 KAlarm::UpdateResult status
= KAlarm::addEvents(events
, dlg
, true, true);
941 Undo::EventList undos
;
942 AlarmCalendar
* resources
= AlarmCalendar::resources();
943 for (int i
= 0, end
= events
.count(); i
< end
; ++i
)
945 Akonadi::Collection c
= resources
->collectionForEvent(events
[i
].itemId());
946 undos
.append(events
[i
], c
);
948 Undo::saveAdds(undos
, i18nc("@info", "Import birthdays"));
950 if (status
!= KAlarm::UPDATE_FAILED
)
951 KAlarm::outputAlarmWarnings(dlg
);
956 /******************************************************************************
957 * Called when the Templates menu item is selected, to display the alarm
958 * template editing dialog.
960 void MainWindow::slotTemplates()
964 mTemplateDlg
= TemplateDlg::create(this);
965 enableTemplateMenuItem(false); // disable menu item in all windows
966 connect(mTemplateDlg
, SIGNAL(finished()), SLOT(slotTemplatesEnd()));
967 mTemplateDlg
->show();
971 /******************************************************************************
972 * Called when the alarm template editing dialog has exited.
974 void MainWindow::slotTemplatesEnd()
978 mTemplateDlg
->deleteLater(); // this deletes the dialog once it is safe to do so
979 mTemplateDlg
= Q_NULLPTR
;
980 enableTemplateMenuItem(true); // re-enable menu item in all windows
984 /******************************************************************************
985 * Called when the Display System Tray Icon menu item is selected.
987 void MainWindow::slotToggleTrayIcon()
989 theApp()->displayTrayIcon(!theApp()->trayIconDisplayed(), this);
992 /******************************************************************************
993 * Called when the Show Resource Selector menu item is selected.
995 void MainWindow::slotToggleResourceSelector()
997 mShowResources
= mActionToggleResourceSel
->isChecked();
1000 if (mResourcesWidth
<= 0)
1002 mResourcesWidth
= mResourceSelector
->sizeHint().width();
1003 mResourceSelector
->resize(mResourcesWidth
, mResourceSelector
->height());
1004 QList
<int> widths
= mSplitter
->sizes();
1005 if (widths
.count() == 1)
1007 int listwidth
= widths
[0] - mSplitter
->handleWidth() - mResourcesWidth
;
1008 mListView
->resize(listwidth
, mListView
->height());
1009 widths
.append(listwidth
);
1010 widths
[0] = mResourcesWidth
;
1012 mSplitter
->setSizes(widths
);
1014 mResourceSelector
->show();
1017 mResourceSelector
->hide();
1019 KConfigGroup
config(KSharedConfig::openConfig(), VIEW_GROUP
);
1020 config
.writeEntry(SHOW_RESOURCES_KEY
, mShowResources
);
1023 /******************************************************************************
1024 * Called when an error occurs in the resource calendar, to display a message.
1026 void MainWindow::showErrorMessage(const QString
& msg
)
1028 KAMessageBox::error(this, msg
);
1031 /******************************************************************************
1032 * Called when the system tray icon is created or destroyed.
1033 * Set the system tray icon menu text according to whether or not the system
1034 * tray icon is currently visible.
1036 void MainWindow::updateTrayIconAction()
1038 mActionToggleTrayIcon
->setEnabled(KSystemTrayIcon::isSystemTrayAvailable());
1039 mActionToggleTrayIcon
->setChecked(theApp()->trayIconDisplayed());
1042 /******************************************************************************
1043 * Called when the active status of Find changes.
1045 void MainWindow::slotFindActive(bool active
)
1047 mActionFindNext
->setEnabled(active
);
1048 mActionFindPrev
->setEnabled(active
);
1051 /******************************************************************************
1052 * Called when the Undo action is selected.
1054 void MainWindow::slotUndo()
1056 Undo::undo(this, KLocalizedString::removeAcceleratorMarker(mActionUndo
->text()));
1059 /******************************************************************************
1060 * Called when the Redo action is selected.
1062 void MainWindow::slotRedo()
1064 Undo::redo(this, KLocalizedString::removeAcceleratorMarker(mActionRedo
->text()));
1067 /******************************************************************************
1068 * Called when an Undo item is selected.
1070 void MainWindow::slotUndoItem(QAction
* action
)
1072 int id
= mUndoMenuIds
[action
];
1073 Undo::undo(id
, this, Undo::actionText(Undo::UNDO
, id
));
1076 /******************************************************************************
1077 * Called when a Redo item is selected.
1079 void MainWindow::slotRedoItem(QAction
* action
)
1081 int id
= mUndoMenuIds
[action
];
1082 Undo::redo(id
, this, Undo::actionText(Undo::REDO
, id
));
1085 /******************************************************************************
1086 * Called when the Undo menu is about to show.
1087 * Populates the menu.
1089 void MainWindow::slotInitUndoMenu()
1091 initUndoMenu(mActionUndo
->menu(), Undo::UNDO
);
1094 /******************************************************************************
1095 * Called when the Redo menu is about to show.
1096 * Populates the menu.
1098 void MainWindow::slotInitRedoMenu()
1100 initUndoMenu(mActionRedo
->menu(), Undo::REDO
);
1103 /******************************************************************************
1104 * Populate the undo or redo menu.
1106 void MainWindow::initUndoMenu(QMenu
* menu
, Undo::Type type
)
1109 mUndoMenuIds
.clear();
1110 const QString
& action
= (type
== Undo::UNDO
) ? undoTextStripped
: redoTextStripped
;
1111 QList
<int> ids
= Undo::ids(type
);
1112 for (int i
= 0, end
= ids
.count(); i
< end
; ++i
)
1115 QString actText
= Undo::actionText(type
, id
);
1116 QString descrip
= Undo::description(type
, id
);
1117 QString text
= descrip
.isEmpty()
1118 ? i18nc("@action Undo/Redo [action]", "%1 %2", action
, actText
)
1119 : i18nc("@action Undo [action]: message", "%1 %2: %3", action
, actText
, descrip
);
1120 QAction
* act
= menu
->addAction(text
);
1121 mUndoMenuIds
[act
] = id
;
1125 /******************************************************************************
1126 * Called when the status of the Undo or Redo list changes.
1127 * Change the Undo or Redo text to include the action which would be undone/redone.
1129 void MainWindow::slotUndoStatus(const QString
& undo
, const QString
& redo
)
1133 mActionUndo
->setEnabled(false);
1134 mActionUndo
->setText(undoText
);
1138 mActionUndo
->setEnabled(true);
1139 mActionUndo
->setText(QStringLiteral("%1 %2").arg(undoText
).arg(undo
));
1143 mActionRedo
->setEnabled(false);
1144 mActionRedo
->setText(redoText
);
1148 mActionRedo
->setEnabled(true);
1149 mActionRedo
->setText(QStringLiteral("%1 %2").arg(redoText
).arg(redo
));
1153 /******************************************************************************
1154 * Called when the Refresh Alarms menu item is selected.
1156 void MainWindow::slotRefreshAlarms()
1158 KAlarm::refreshAlarms();
1161 /******************************************************************************
1162 * Called when the "Configure KAlarm" menu item is selected.
1164 void MainWindow::slotPreferences()
1166 KAlarmPrefDlg::display();
1169 /******************************************************************************
1170 * Called when the Configure Keys menu item is selected.
1172 void MainWindow::slotConfigureKeys()
1174 KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed
, this);
1177 /******************************************************************************
1178 * Called when the Configure Toolbars menu item is selected.
1180 void MainWindow::slotConfigureToolbar()
1182 KConfigGroup
grp(KSharedConfig::openConfig()->group(WINDOW_NAME
));
1183 saveMainWindowSettings(grp
);
1184 KEditToolBar
dlg(factory());
1185 connect(&dlg
, &KEditToolBar::newToolBarConfig
, this, &MainWindow::slotNewToolbarConfig
);
1189 /******************************************************************************
1190 * Called when OK or Apply is clicked in the Configure Toolbars dialog, to save
1191 * the new configuration.
1193 void MainWindow::slotNewToolbarConfig()
1196 applyMainWindowSettings(KSharedConfig::openConfig()->group(WINDOW_NAME
));
1199 /******************************************************************************
1200 * Called when the Quit menu item is selected.
1201 * Note that this must be called by the event loop, not directly from the menu
1202 * item, since otherwise the window will be deleted while still processing the
1203 * menu, resulting in a crash.
1205 void MainWindow::slotQuit()
1207 theApp()->doQuit(this);
1210 /******************************************************************************
1211 * Called when the user or the session manager attempts to close the window.
1213 void MainWindow::closeEvent(QCloseEvent
* ce
)
1215 if (!theApp()->sessionClosingDown())
1217 // The user (not the session manager) wants to close the window.
1220 // It's the parent window of the system tray icon, so just hide
1221 // it to prevent the system tray icon closing.
1231 /******************************************************************************
1232 * Called when the drag cursor enters a main or system tray window, to accept
1233 * or reject the dragged object.
1235 void MainWindow::executeDragEnterEvent(QDragEnterEvent
* e
)
1237 const QMimeData
* data
= e
->mimeData();
1238 bool accept
= ICalDrag::canDecode(data
) ? !e
->source() // don't accept "text/calendar" objects from this application
1241 || KPIM::MailList::canDecode(data
);
1243 e
->acceptProposedAction();
1246 /******************************************************************************
1247 * Called when an object is dropped on the window.
1248 * If the object is recognised, the edit alarm dialog is opened appropriately.
1250 void MainWindow::dropEvent(QDropEvent
* e
)
1252 executeDropEvent(this, e
);
1255 static QString
getMailHeader(const char* header
, KMime::Content
& content
)
1257 KMime::Headers::Base
* hd
= content
.headerByType(header
);
1258 return hd
? hd
->asUnicodeString() : QString();
1261 /******************************************************************************
1262 * Called when an object is dropped on a main or system tray window, to
1263 * evaluate the action required and extract the text.
1265 void MainWindow::executeDropEvent(MainWindow
* win
, QDropEvent
* e
)
1267 qCDebug(KALARM_LOG
) << "Formats:" << e
->mimeData()->formats();
1268 const QMimeData
* data
= e
->mimeData();
1269 KAEvent::SubAction action
= KAEvent::MESSAGE
;
1271 AlarmText alarmText
;
1272 KPIM::MailList mailList
;
1274 MemoryCalendar::Ptr
calendar(new MemoryCalendar(Preferences::timeZone(true)));
1276 QString fmts
= data
->formats().join(QStringLiteral(", "));
1277 qCDebug(KALARM_LOG
) << fmts
;
1280 /* The order of the tests below matters, since some dropped objects
1281 * provide more than one mime type.
1282 * Don't change them without careful thought !!
1284 if (!(bytes
= data
->data(QStringLiteral("message/rfc822"))).isEmpty())
1286 // Email message(s). Ignore all but the first.
1287 qCDebug(KALARM_LOG
) << "email";
1288 KMime::Content content
;
1289 content
.setContent(bytes
);
1292 if (content
.textContent())
1293 body
= content
.textContent()->decodedText(true, true); // strip trailing newlines & spaces
1294 unsigned long sernum
= 0;
1295 if (KPIM::MailList::canDecode(data
))
1297 // Get its KMail serial number to allow the KMail message
1298 // to be called up from the alarm message window.
1299 mailList
= KPIM::MailList::fromMimeData(data
);
1300 if (!mailList
.isEmpty())
1301 sernum
= mailList
[0].serialNumber();
1303 alarmText
.setEmail(getMailHeader("To", content
),
1304 getMailHeader("From", content
),
1305 getMailHeader("Cc", content
),
1306 getMailHeader("Date", content
),
1307 getMailHeader("Subject", content
),
1310 else if (KPIM::MailList::canDecode(data
))
1312 mailList
= KPIM::MailList::fromMimeData(data
);
1313 // KMail message(s). Ignore all but the first.
1314 qCDebug(KALARM_LOG
) << "KMail_list";
1315 if (mailList
.isEmpty())
1317 KPIM::MailSummary
& summary
= mailList
[0];
1319 dt
.setTime_t(summary
.date());
1320 QString body
= KAMail::getMailBody(summary
.serialNumber());
1321 alarmText
.setEmail(summary
.to(), summary
.from(), QString(),
1322 KLocale::global()->formatDateTime(dt
), summary
.subject(),
1323 body
, summary
.serialNumber());
1325 else if (ICalDrag::fromMimeData(data
, calendar
))
1327 // iCalendar - If events are included, use the first event
1328 qCDebug(KALARM_LOG
) << "iCalendar";
1329 Event::List events
= calendar
->rawEvents();
1330 if (!events
.isEmpty())
1332 KAEvent
ev(events
[0]);
1333 KAlarm::editNewAlarm(&ev
, win
);
1336 // If todos are included, use the first todo
1337 Todo::List todos
= calendar
->rawTodos();
1338 if (todos
.isEmpty())
1340 Todo::Ptr todo
= todos
[0];
1341 alarmText
.setTodo(todo
);
1342 KDateTime start
= todo
->dtStart(true);
1343 if (!start
.isValid() && todo
->hasDueDate())
1344 start
= todo
->dtDue(true);
1345 KAEvent::Flags flags
= KAEvent::DEFAULT_FONT
;
1346 if (start
.isDateOnly())
1347 flags
|= KAEvent::ANY_TIME
;
1348 KAEvent
ev(start
, alarmText
.displayText(), Preferences::defaultBgColour(), Preferences::defaultFgColour(),
1349 QFont(), KAEvent::MESSAGE
, 0, flags
, true);
1352 ev
.setRecurrence(*todo
->recurrence());
1353 ev
.setNextOccurrence(KDateTime::currentUtcDateTime());
1356 KAlarm::editNewAlarm(&ev
, win
);
1359 else if (!(files
= data
->urls()).isEmpty())
1361 qCDebug(KALARM_LOG
) << "URL";
1362 // Try to find the mime type of the file, without downloading a remote file
1363 QMimeDatabase mimeDb
;
1364 const QString mimeTypeName
= mimeDb
.mimeTypeForUrl(files
[0]).name();
1365 action
= mimeTypeName
.startsWith(QStringLiteral("audio/")) ? KAEvent::AUDIO
: KAEvent::FILE;
1366 alarmText
.setText(files
[0].toDisplayString());
1368 else if (data
->hasText())
1370 QString text
= data
->text();
1371 qCDebug(KALARM_LOG
) << "text";
1372 alarmText
.setText(text
);
1377 if (!alarmText
.isEmpty())
1379 if (action
== KAEvent::MESSAGE
1380 && (alarmText
.isEmail() || alarmText
.isScript()))
1382 // If the alarm text could be interpreted as an email or command script,
1383 // prompt for which type of alarm to create.
1385 types
+= i18nc("@item:inlistbox", "Display Alarm");
1386 if (alarmText
.isEmail())
1387 types
+= i18nc("@item:inlistbox", "Email Alarm");
1388 else if (alarmText
.isScript())
1389 types
+= i18nc("@item:inlistbox", "Command Alarm");
1391 QString type
= QInputDialog::getItem(mainMainWindow(), i18nc("@title:window", "Alarm Type"),
1392 i18nc("@info", "Choose alarm type to create:"), types
, 0, false, &ok
);
1394 return; // user didn't press OK
1395 int i
= types
.indexOf(type
);
1397 action
= alarmText
.isEmail() ? KAEvent::EMAIL
: KAEvent::COMMAND
;
1399 KAlarm::editNewAlarm(action
, win
, &alarmText
);
1403 /******************************************************************************
1404 * Called when the status of a calendar has changed.
1405 * Enable or disable actions appropriately.
1407 void MainWindow::slotCalendarStatusChanged()
1409 // Find whether there are any writable calendars
1410 bool active
= !CollectionControlModel::enabledCollections(CalEvent::ACTIVE
, true).isEmpty();
1411 bool templat
= !CollectionControlModel::enabledCollections(CalEvent::TEMPLATE
, true).isEmpty();
1412 for (int i
= 0, end
= mWindowList
.count(); i
< end
; ++i
)
1414 MainWindow
* w
= mWindowList
[i
];
1415 w
->mActionImportAlarms
->setEnabled(active
|| templat
);
1416 w
->mActionImportBirthdays
->setEnabled(active
);
1417 w
->mActionCreateTemplate
->setEnabled(templat
);
1418 // Note: w->mActionNew enabled status is set in the NewAlarmAction class.
1423 /******************************************************************************
1424 * Called when the selected items in the ListView change.
1425 * Enables the actions appropriately.
1427 void MainWindow::slotSelection()
1429 // Find which events have been selected
1430 QVector
<KAEvent
> events
= mListView
->selectedEvents();
1431 int count
= events
.count();
1434 selectionCleared(); // disable actions
1435 Q_EMIT
selectionChanged();
1439 // Find whether there are any writable resources
1440 bool active
= mActionNew
->isEnabled();
1442 bool readOnly
= false;
1443 bool allArchived
= true;
1444 bool enableReactivate
= true;
1445 bool enableEnableDisable
= true;
1446 bool enableEnable
= false;
1447 bool enableDisable
= false;
1448 AlarmCalendar
* resources
= AlarmCalendar::resources();
1449 KDateTime now
= KDateTime::currentUtcDateTime();
1450 for (int i
= 0; i
< count
; ++i
)
1452 KAEvent
* ev
= resources
->event(EventId(events
[i
])); // get up-to-date status
1453 KAEvent
* event
= ev
? ev
: &events
[i
];
1454 bool expired
= event
->expired();
1456 allArchived
= false;
1457 if (resources
->eventReadOnly(event
->itemId()))
1459 if (enableReactivate
1460 && (!expired
|| !event
->occursAfter(now
, true)))
1461 enableReactivate
= false;
1462 if (enableEnableDisable
)
1465 enableEnableDisable
= enableEnable
= enableDisable
= false;
1468 if (!enableEnable
&& !event
->enabled())
1469 enableEnable
= true;
1470 if (!enableDisable
&& event
->enabled())
1471 enableDisable
= true;
1476 qCDebug(KALARM_LOG
) << "true";
1477 mActionCreateTemplate
->setEnabled((count
== 1) && !CollectionControlModel::enabledCollections(CalEvent::TEMPLATE
, true).isEmpty());
1478 mActionExportAlarms
->setEnabled(true);
1479 mActionExport
->setEnabled(true);
1480 mActionCopy
->setEnabled(active
&& count
== 1);
1481 mActionModify
->setEnabled(count
== 1);
1482 mActionDelete
->setEnabled(!readOnly
&& (active
|| allArchived
));
1483 mActionReactivate
->setEnabled(active
&& enableReactivate
);
1484 mActionEnable
->setEnabled(active
&& !readOnly
&& (enableEnable
|| enableDisable
));
1485 if (enableEnable
|| enableDisable
)
1486 setEnableText(enableEnable
);
1488 Q_EMIT
selectionChanged();
1491 /******************************************************************************
1492 * Called when a context menu is requested in the ListView.
1493 * Displays a context menu to modify or delete the selected item.
1495 void MainWindow::slotContextMenuRequested(const QPoint
& globalPos
)
1497 qCDebug(KALARM_LOG
);
1499 mContextMenu
->popup(globalPos
);
1502 /******************************************************************************
1503 * Disables actions when no item is selected.
1505 void MainWindow::selectionCleared()
1507 mActionCreateTemplate
->setEnabled(false);
1508 mActionExportAlarms
->setEnabled(false);
1509 mActionExport
->setEnabled(false);
1510 mActionCopy
->setEnabled(false);
1511 mActionModify
->setEnabled(false);
1512 mActionDelete
->setEnabled(false);
1513 mActionReactivate
->setEnabled(false);
1514 mActionEnable
->setEnabled(false);
1517 /******************************************************************************
1518 * Set the text of the Enable/Disable menu action.
1520 void MainWindow::setEnableText(bool enable
)
1522 mActionEnableEnable
= enable
;
1523 mActionEnable
->setText(enable
? i18nc("@action", "Ena&ble") : i18nc("@action", "Disa&ble"));
1526 /******************************************************************************
1527 * Display or hide the specified main window.
1528 * This should only be called when the application doesn't run in the system tray.
1530 MainWindow
* MainWindow::toggleWindow(MainWindow
* win
)
1532 if (win
&& mWindowList
.indexOf(win
) != -1)
1534 // A window is specified (and it exists)
1535 if (win
->isVisible())
1537 // The window is visible, so close it
1543 // The window is hidden, so display it
1544 win
->hide(); // in case it's on a different desktop
1545 win
->setWindowState(win
->windowState() & ~Qt::WindowMinimized
);
1547 win
->activateWindow();
1552 // No window is specified, or the window doesn't exist. Open a new one.
1558 /******************************************************************************
1559 * Called when the Edit button is clicked in an alarm message window.
1560 * This controls the alarm edit dialog created by the alarm window, and allows
1561 * it to remain unaffected by the alarm window closing.
1562 * See MessageWin::slotEdit() for more information.
1564 void MainWindow::editAlarm(EditAlarmDlg
* dlg
, const KAEvent
& event
)
1566 mEditAlarmMap
[dlg
] = event
;
1567 connect(dlg
, &KEditToolBar::accepted
, this, &MainWindow::editAlarmOk
);
1568 connect(dlg
, &KEditToolBar::destroyed
, this, &MainWindow::editAlarmDeleted
);
1569 dlg
->setAttribute(Qt::WA_DeleteOnClose
, true); // ensure no memory leaks
1573 /******************************************************************************
1574 * Called when OK is clicked in the alarm edit dialog shown by editAlarm().
1575 * Updates the event which has been edited.
1577 void MainWindow::editAlarmOk()
1579 EditAlarmDlg
* dlg
= qobject_cast
<EditAlarmDlg
*>(sender());
1582 QMap
<EditAlarmDlg
*, KAEvent
>::Iterator it
= mEditAlarmMap
.find(dlg
);
1583 if (it
== mEditAlarmMap
.end())
1585 KAEvent event
= it
.value();
1586 mEditAlarmMap
.erase(it
);
1587 if (!event
.isValid())
1589 if (dlg
->result() != QDialog::Accepted
)
1591 Akonadi::Collection c
= AkonadiModel::instance()->collection(event
);
1592 KAlarm::updateEditedAlarm(dlg
, event
, c
);
1595 /******************************************************************************
1596 * Called when the alarm edit dialog shown by editAlarm() is deleted.
1597 * Removes the dialog from the pending list.
1599 void MainWindow::editAlarmDeleted(QObject
* obj
)
1601 mEditAlarmMap
.remove(static_cast<EditAlarmDlg
*>(obj
));