Warning, file /pim/kalarm/src/mainwindow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * mainwindow.cpp - main application window 0003 * Program: kalarm 0004 * SPDX-FileCopyrightText: 2001-2024 David Jarvie <djarvie@kde.org> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "mainwindow.h" 0010 0011 #include "alarmlistdelegate.h" 0012 #include "alarmlistview.h" 0013 #include "birthdaydlg.h" 0014 #include "datepicker.h" 0015 #include "deferdlg.h" 0016 #include "functions.h" 0017 #include "kalarmapp.h" 0018 #include "kernelwakealarm.h" 0019 #include "newalarmaction.h" 0020 #include "prefdlg.h" 0021 #include "preferences.h" 0022 #include "resourcescalendar.h" 0023 #include "resourceselector.h" 0024 #include "templatedlg.h" 0025 #include "traywindow.h" 0026 #include "wakedlg.h" 0027 #include "resources/datamodel.h" 0028 #include "resources/eventmodel.h" 0029 #include "resources/resources.h" 0030 #include "lib/autoqpointer.h" 0031 #include "lib/dragdrop.h" 0032 #include "lib/messagebox.h" 0033 #include "kalarmcalendar/alarmtext.h" 0034 #include "config-kalarm.h" 0035 #include "kalarm_debug.h" 0036 0037 #include <KCalUtils/ICalDrag> 0038 #include <KCalendarCore/MemoryCalendar> 0039 using namespace KCalendarCore; 0040 using namespace KCalUtils; 0041 0042 #include <KAboutData> 0043 #include <KToolBar> 0044 #include <KActionCollection> 0045 #include <KGlobalAccel> 0046 #include <KStandardAction> 0047 #include <KLocalizedString> 0048 #include <KSharedConfig> 0049 #include <KConfigGroup> 0050 #include <KShortcutsDialog> 0051 #include <KEditToolBar> 0052 #include <KXMLGUIFactory> 0053 #include <KToggleAction> 0054 #include <KNotifyConfigWidget> 0055 #include <KToolBarPopupAction> 0056 #include <KWindowSystem> 0057 0058 #include <QAction> 0059 #include <QSplitter> 0060 #include <QVBoxLayout> 0061 #include <QDragEnterEvent> 0062 #include <QDropEvent> 0063 #include <QResizeEvent> 0064 #include <QCloseEvent> 0065 #include <QMenu> 0066 #include <QMimeDatabase> 0067 #include <QInputDialog> 0068 #include <QScrollArea> 0069 #include <QScrollBar> 0070 #include <QTimer> 0071 #include <QUrl> 0072 #include <QMenuBar> 0073 #include <QSystemTrayIcon> 0074 #include <QMimeData> 0075 0076 using namespace KAlarmCal; 0077 0078 //clazy:excludeall=non-pod-global-static 0079 0080 namespace 0081 { 0082 const QString UI_FILE(QStringLiteral("kalarmui.rc")); 0083 const QLatin1String WINDOW_NAME("MainWindow"); 0084 const QLatin1String VIEW_GROUP("View"); 0085 0086 const char* SHOW_COLUMNS = "ShowColumns"; 0087 const char* SHOW_ARCHIVED_KEY = "ShowArchivedAlarms"; 0088 const char* SHOW_RESOURCES_KEY = "ShowResources"; 0089 const char* RESOURCES_WIDTH_KEY = "ResourcesWidth"; 0090 const char* SHOW_DATE_NAVIGATOR = "ShowDateNavigator"; 0091 const char* DATE_NAVIGATOR_TOP = "DateNavigatorTop"; 0092 const char* HIDDEN_TRAY_PARENT = "HiddenTrayParent"; 0093 0094 QString undoText; 0095 QString undoTextStripped; 0096 QList<QKeySequence> undoShortcut; 0097 QString redoText; 0098 QString redoTextStripped; 0099 QList<QKeySequence> redoShortcut; 0100 } 0101 0102 0103 /*============================================================================= 0104 = Class: MainWindow 0105 =============================================================================*/ 0106 0107 MainWindow::WindowList MainWindow::mWindowList; 0108 TemplateDlg* MainWindow::mTemplateDlg = nullptr; 0109 0110 0111 /****************************************************************************** 0112 * Construct an instance. 0113 * To avoid resize() events occurring while still opening the calendar (and 0114 * resultant crashes), the calendar is opened before constructing the instance. 0115 */ 0116 MainWindow* MainWindow::create(bool restored) 0117 { 0118 theApp()->checkCalendar(); // ensure calendar is open 0119 return new MainWindow(restored); 0120 } 0121 0122 MainWindow::MainWindow(bool restored) 0123 : MainWindowBase(nullptr, Qt::WindowContextHelpButtonHint) 0124 { 0125 Q_UNUSED(restored) 0126 qCDebug(KALARM_LOG) << "MainWindow:"; 0127 setAttribute(Qt::WA_DeleteOnClose); 0128 setWindowModality(Qt::WindowModal); 0129 setObjectName(QLatin1StringView("MainWin")); // used by LikeBack 0130 setPlainCaption(KAboutData::applicationData().displayName()); 0131 KConfigGroup config(KSharedConfig::openConfig(), VIEW_GROUP); 0132 mShowResources = config.readEntry(SHOW_RESOURCES_KEY, false); 0133 mShowDateNavigator = config.readEntry(SHOW_DATE_NAVIGATOR, false); 0134 mDateNavigatorTop = config.readEntry(DATE_NAVIGATOR_TOP, true); 0135 mShowArchived = config.readEntry(SHOW_ARCHIVED_KEY, false); 0136 mResourcesWidth = config.readEntry(RESOURCES_WIDTH_KEY, (int)0); 0137 const QList<bool> showColumns = config.readEntry(SHOW_COLUMNS, QList<bool>()); 0138 0139 setAcceptDrops(true); // allow drag-and-drop onto this window 0140 0141 mSplitter = new QSplitter(Qt::Horizontal, this); 0142 mSplitter->setChildrenCollapsible(false); 0143 mSplitter->installEventFilter(this); 0144 setCentralWidget(mSplitter); 0145 mSplitter->setStretchFactor(0, 0); // don't resize side panel when window is resized 0146 mSplitter->setStretchFactor(1, 1); 0147 0148 // Create the side panel, containing the calendar resource selector and 0149 // date picker widgets. 0150 mPanel = new QScrollArea(mSplitter); 0151 QWidget* panelContents = new QWidget(mPanel); 0152 mPanel->setWidget(panelContents); 0153 mPanel->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0154 mPanel->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); 0155 mPanel->setWidgetResizable(true); 0156 mPanel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); 0157 mPanel->verticalScrollBar()->installEventFilter(this); 0158 mPanelLayout = new QVBoxLayout(panelContents); 0159 mPanelLayout->setContentsMargins(0, 0, 0, 0); 0160 0161 DataModel::widgetNeedsDatabase(this); 0162 mResourceSelector = new ResourceSelector(this, panelContents); 0163 mResourceSelector->setResizeToList(); 0164 mPanelLayout->addWidget(mResourceSelector); 0165 mPanelLayout->addStretch(); 0166 0167 mDatePicker = new DatePicker(nullptr); 0168 mPanelLayout->addWidget(mDatePicker); 0169 0170 // Create the alarm list widget 0171 mListFilterModel = DataModel::createAlarmListModel(this); 0172 mListFilterModel->setEventTypeFilter(mShowArchived ? CalEvent::ACTIVE | CalEvent::ARCHIVED : CalEvent::ACTIVE); 0173 mListView = new AlarmListView(WINDOW_NAME, mSplitter); 0174 mListView->setModel(mListFilterModel); 0175 mListView->setColumnsVisible(showColumns); 0176 mListView->setItemDelegate(new AlarmListDelegate(mListView)); 0177 connect(mListView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::slotSelection); 0178 connect(mListView, &AlarmListView::contextMenuRequested, this, &MainWindow::slotContextMenuRequested); 0179 connect(mListView, &AlarmListView::columnsVisibleChanged, this, &MainWindow::slotAlarmListColumnsChanged); 0180 connect(Resources::instance(), &Resources::settingsChanged, 0181 this, &MainWindow::slotCalendarStatusChanged); 0182 connect(mResourceSelector, &ResourceSelector::resized, this, &MainWindow::resourcesResized); 0183 connect(mDatePicker, &DatePicker::datesSelected, this, &MainWindow::datesSelected); 0184 mListView->installEventFilter(this); 0185 initActions(); 0186 0187 setAutoSaveSettings(WINDOW_NAME, true); // save toolbars, window sizes etc. 0188 mWindowList.append(this); 0189 if (mWindowList.count() == 1) 0190 { 0191 // It's the first main window 0192 if (theApp()->wantShowInSystemTray()) 0193 theApp()->displayTrayIcon(true, this); // create system tray icon for run-in-system-tray mode 0194 else if (theApp()->trayWindow()) 0195 theApp()->trayWindow()->setAssocMainWindow(this); // associate this window with the system tray icon 0196 } 0197 slotCalendarStatusChanged(); // initialise action states now that window is registered 0198 } 0199 0200 MainWindow::~MainWindow() 0201 { 0202 qCDebug(KALARM_LOG) << "~MainWindow"; 0203 bool trayParent = isTrayParent(); // must call before removing from window list 0204 mWindowList.removeAt(mWindowList.indexOf(this)); 0205 0206 // Prevent view updates during window destruction 0207 delete mResourceSelector; 0208 mResourceSelector = nullptr; 0209 delete mDatePicker; 0210 mDatePicker = nullptr; 0211 delete mListView; 0212 mListView = nullptr; 0213 0214 if (theApp()->trayWindow()) 0215 { 0216 if (trayParent) 0217 delete theApp()->trayWindow(); 0218 else 0219 theApp()->trayWindow()->removeWindow(this); 0220 } 0221 KSharedConfig::openConfig()->sync(); // save any new window size to disc 0222 theApp()->quitIf(); 0223 } 0224 0225 /****************************************************************************** 0226 * Called when the QApplication::saveStateRequest() signal has been emitted. 0227 * Save settings to the session managed config file, for restoration 0228 * when the program is restored. 0229 */ 0230 void MainWindow::saveProperties(KConfigGroup& config) 0231 { 0232 config.writeEntry(HIDDEN_TRAY_PARENT, isTrayParent() && isHidden()); 0233 config.writeEntry(SHOW_ARCHIVED_KEY, mShowArchived); 0234 config.writeEntry(SHOW_RESOURCES_KEY, mShowResources); 0235 config.writeEntry(SHOW_DATE_NAVIGATOR, mShowDateNavigator); 0236 config.writeEntry(DATE_NAVIGATOR_TOP, mDateNavigatorTop); 0237 config.writeEntry(SHOW_COLUMNS, mListView->columnsVisible()); 0238 config.writeEntry(RESOURCES_WIDTH_KEY, mResourceSelector->isVisible() ? mResourceSelector->width() : 0); 0239 } 0240 0241 /****************************************************************************** 0242 * Read settings from the session managed config file. 0243 * This function is automatically called whenever the app is being 0244 * restored. Read in whatever was saved in saveProperties(). 0245 */ 0246 void MainWindow::readProperties(const KConfigGroup& config) 0247 { 0248 mHiddenTrayParent = config.readEntry(HIDDEN_TRAY_PARENT, true); 0249 mShowArchived = config.readEntry(SHOW_ARCHIVED_KEY, false); 0250 mShowResources = config.readEntry(SHOW_RESOURCES_KEY, false); 0251 mResourcesWidth = config.readEntry(RESOURCES_WIDTH_KEY, (int)0); 0252 if (mResourcesWidth <= 0) 0253 mShowResources = false; 0254 mShowDateNavigator = config.readEntry(SHOW_DATE_NAVIGATOR, false); 0255 mDateNavigatorTop = config.readEntry(DATE_NAVIGATOR_TOP, true); 0256 mListView->setColumnsVisible(config.readEntry(SHOW_COLUMNS, QList<bool>())); 0257 } 0258 0259 /****************************************************************************** 0260 * Get the main main window, i.e. the parent of the system tray icon, or if 0261 * none, the first main window to be created. Visible windows take precedence 0262 * over hidden ones. 0263 */ 0264 MainWindow* MainWindow::mainMainWindow() 0265 { 0266 MainWindow* tray = (theApp() && theApp()->trayWindow()) ? theApp()->trayWindow()->assocMainWindow() : nullptr; 0267 if (tray && tray->isVisible()) 0268 return tray; 0269 for (int i = 0, end = mWindowList.count(); i < end; ++i) 0270 if (mWindowList.at(i)->isVisible()) 0271 return mWindowList.at(i); 0272 if (tray) 0273 return tray; 0274 if (mWindowList.isEmpty()) 0275 return nullptr; 0276 return mWindowList.at(0); 0277 } 0278 0279 /****************************************************************************** 0280 * Check whether this main window is effectively the parent of the system tray icon. 0281 */ 0282 bool MainWindow::isTrayParent() const 0283 { 0284 TrayWindow* tray = theApp()->trayWindow(); 0285 if (!tray || !QSystemTrayIcon::isSystemTrayAvailable()) 0286 return false; 0287 if (tray->assocMainWindow() == this) 0288 return true; 0289 return mWindowList.count() == 1; 0290 } 0291 0292 /****************************************************************************** 0293 * Close all main windows. 0294 */ 0295 void MainWindow::closeAll() 0296 { 0297 while (!mWindowList.isEmpty()) 0298 delete mWindowList[0]; // N.B. the destructor removes the window from the list 0299 } 0300 0301 /****************************************************************************** 0302 * Intercept events for the splitter widget. 0303 */ 0304 bool MainWindow::eventFilter(QObject* obj, QEvent* e) 0305 { 0306 if (obj == mSplitter) 0307 { 0308 switch (e->type()) 0309 { 0310 case QEvent::Resize: 0311 // Don't change resources size while WINDOW is being resized. 0312 // Resize event always occurs before Paint. 0313 mResizing = true; 0314 break; 0315 case QEvent::Paint: 0316 // Allow resources to be resized again 0317 mResizing = false; 0318 break; 0319 default: 0320 break; 0321 } 0322 } 0323 else if (obj == mListView) 0324 { 0325 switch (e->type()) 0326 { 0327 case QEvent::KeyPress: 0328 { 0329 auto ke = static_cast<QKeyEvent*>(e); 0330 if (ke->key() == Qt::Key_Delete && ke->modifiers() == Qt::ShiftModifier) 0331 { 0332 // Prevent Shift-Delete being processed by EventListDelegate 0333 mActionDeleteForce->trigger(); 0334 return true; 0335 } 0336 break; 0337 } 0338 default: 0339 break; 0340 } 0341 } 0342 else if (obj == mPanel->verticalScrollBar()) 0343 { 0344 // The scroll bar width can't be determined correctly until it has been shown. 0345 if (e->type() == QEvent::Show) 0346 { 0347 mPanelScrollBarWidth = mPanel->verticalScrollBar()->width(); 0348 arrangePanel(); 0349 } 0350 } 0351 return false; 0352 } 0353 0354 /****************************************************************************** 0355 * Called when the window's size has changed (before it is painted). 0356 * Sets the last column in the list view to extend at least to the right hand 0357 * edge of the list view. 0358 * Records the new size in the config file. 0359 */ 0360 void MainWindow::resizeEvent(QResizeEvent* re) 0361 { 0362 // Save the window's new size only if it's the first main window 0363 MainWindowBase::resizeEvent(re); 0364 setSplitterSizes(); 0365 } 0366 0367 /****************************************************************************** 0368 * Emitted when the date selection changes in the date picker. 0369 */ 0370 void MainWindow::datesSelected(const QList<QDate>& dates, bool workChange) 0371 { 0372 mListFilterModel->setDateFilter(dates, workChange); 0373 } 0374 0375 /****************************************************************************** 0376 * Called when the resources panel has been resized. 0377 * Records the new size in the config file. 0378 */ 0379 void MainWindow::resourcesResized() 0380 { 0381 if (!mShown || mResizing) 0382 return; 0383 const QList<int> widths = mSplitter->sizes(); 0384 if (widths.count() > 1 && mResourceSelector->isVisible()) 0385 { 0386 mResourcesWidth = widths[0]; 0387 // Width is reported as non-zero when resource selector is 0388 // actually invisible, so note a zero width in these circumstances. 0389 if (mResourcesWidth <= 5) 0390 mResourcesWidth = 0; 0391 else if (mainMainWindow() == this) 0392 { 0393 KConfigGroup config(KSharedConfig::openConfig(), VIEW_GROUP); 0394 config.writeEntry(SHOW_RESOURCES_KEY, mShowResources); 0395 if (mShowResources) 0396 config.writeEntry(RESOURCES_WIDTH_KEY, mResourcesWidth); 0397 config.sync(); 0398 } 0399 } 0400 } 0401 0402 /****************************************************************************** 0403 * Called when the window is first displayed. 0404 * Sets the last column in the list view to extend at least to the right hand 0405 * edge of the list view. 0406 */ 0407 void MainWindow::showEvent(QShowEvent* se) 0408 { 0409 setSplitterSizes(); 0410 MainWindowBase::showEvent(se); 0411 mShown = true; 0412 0413 if (mMenuError) 0414 QTimer::singleShot(0, this, &MainWindow::showMenuErrorMessage); //NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) 0415 } 0416 0417 /****************************************************************************** 0418 * Set the sizes of the splitter panels. 0419 */ 0420 void MainWindow::setSplitterSizes() 0421 { 0422 if (mShowResources && mResourcesWidth > 0) 0423 { 0424 const QList<int> widths{ mResourcesWidth, 0425 width() - mResourcesWidth - mSplitter->handleWidth() 0426 }; 0427 mSplitter->setSizes(widths); 0428 } 0429 } 0430 0431 /****************************************************************************** 0432 * Show the menu error message now that the main window has been displayed. 0433 * Waiting until now lets the user easily associate the message with the main 0434 * window which is faulty. 0435 */ 0436 void MainWindow::showMenuErrorMessage() 0437 { 0438 if (mMenuError) 0439 { 0440 KAMessageBox::error(this, xi18nc("@info", "Failure to create menus (perhaps <filename>%1</filename> missing or corrupted)", UI_FILE)); 0441 mMenuError = false; 0442 } 0443 } 0444 0445 /****************************************************************************** 0446 * Called after the window is hidden. 0447 */ 0448 void MainWindow::hideEvent(QHideEvent* he) 0449 { 0450 MainWindowBase::hideEvent(he); 0451 } 0452 0453 /****************************************************************************** 0454 * Initialise the menu, toolbar and main window actions. 0455 */ 0456 void MainWindow::initActions() 0457 { 0458 KActionCollection* actions = actionCollection(); 0459 0460 mActionTemplates = new QAction(i18nc("@action", "Templates..."), this); 0461 actions->addAction(QStringLiteral("templates"), mActionTemplates); 0462 connect(mActionTemplates, &QAction::triggered, this, &MainWindow::slotTemplates); 0463 0464 mActionNew = new NewAlarmAction(false, i18nc("@action", "New"), this, actions); 0465 mActionNew->setActionNames(QStringLiteral("newDisplay"), QStringLiteral("newCommand"), QStringLiteral("newEmail"), QStringLiteral("newAudio"), QStringLiteral("newFromTemplate")); 0466 actions->addAction(QStringLiteral("new"), mActionNew); 0467 connect(mActionNew, &NewAlarmAction::selected, this, &MainWindow::slotNew); 0468 connect(mActionNew, &NewAlarmAction::selectedTemplate, this, &MainWindow::slotNewFromTemplate); 0469 0470 mActionCreateTemplate = new QAction(i18nc("@action", "Create Template..."), this); 0471 actions->addAction(QStringLiteral("createTemplate"), mActionCreateTemplate); 0472 connect(mActionCreateTemplate, &QAction::triggered, this, &MainWindow::slotNewTemplate); 0473 0474 mActionCopy = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action", "Copy..."), this); 0475 actions->addAction(QStringLiteral("copy"), mActionCopy); 0476 actions->setDefaultShortcut(mActionCopy, QKeySequence(Qt::SHIFT | Qt::Key_Insert)); 0477 connect(mActionCopy, &QAction::triggered, this, &MainWindow::slotCopy); 0478 0479 mActionModify = new QAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18nc("@action", "Edit..."), this); 0480 actions->addAction(QStringLiteral("modify"), mActionModify); 0481 actions->setDefaultShortcut(mActionModify, QKeySequence(Qt::CTRL | Qt::Key_E)); 0482 connect(mActionModify, &QAction::triggered, this, &MainWindow::slotModify); 0483 0484 mActionDelete = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@action", "Delete"), this); 0485 actions->addAction(QStringLiteral("delete"), mActionDelete); 0486 actions->setDefaultShortcut(mActionDelete, QKeySequence::Delete); 0487 connect(mActionDelete, &QAction::triggered, this, &MainWindow::slotDeleteIf); 0488 0489 // Set up Shift-Delete as a shortcut to delete without confirmation 0490 mActionDeleteForce = new QAction(i18nc("@action", "Delete Without Confirmation"), this); 0491 actions->addAction(QStringLiteral("delete-force"), mActionDeleteForce); 0492 actions->setDefaultShortcut(mActionDeleteForce, QKeySequence::Delete | Qt::SHIFT); 0493 connect(mActionDeleteForce, &QAction::triggered, this, &MainWindow::slotDeleteForce); 0494 0495 mActionReactivate = new QAction(i18nc("@action", "Reactivate"), this); 0496 actions->addAction(QStringLiteral("undelete"), mActionReactivate); 0497 actions->setDefaultShortcut(mActionReactivate, QKeySequence(Qt::CTRL | Qt::Key_R)); 0498 connect(mActionReactivate, &QAction::triggered, this, &MainWindow::slotReactivate); 0499 0500 mActionEnable = new QAction(this); 0501 actions->addAction(QStringLiteral("disable"), mActionEnable); 0502 actions->setDefaultShortcut(mActionEnable, QKeySequence(Qt::CTRL | Qt::Key_B)); 0503 connect(mActionEnable, &QAction::triggered, this, &MainWindow::slotEnable); 0504 0505 #if ENABLE_RTC_WAKE_FROM_SUSPEND 0506 if (!KernelWakeAlarm::isAvailable()) 0507 { 0508 // Only enable RTC wake from suspend if kernel wake alarms are not available 0509 QAction* waction = new QAction(i18nc("@action", "Wake From Suspend..."), this); 0510 actions->addAction(QStringLiteral("wakeSuspend"), waction); 0511 connect(waction, &QAction::triggered, this, &MainWindow::slotWakeFromSuspend); 0512 } 0513 #endif 0514 0515 QAction* action = KAlarm::createStopPlayAction(this); 0516 actions->addAction(QStringLiteral("stopAudio"), action); 0517 KGlobalAccel::setGlobalShortcut(action, QList<QKeySequence>()); // allow user to set a global shortcut 0518 0519 mActionShowArchived = new KToggleAction(i18nc("@action", "Show Archived Alarms"), this); 0520 actions->addAction(QStringLiteral("showArchivedAlarms"), mActionShowArchived); 0521 actions->setDefaultShortcut(mActionShowArchived, QKeySequence(Qt::CTRL | Qt::Key_P)); 0522 connect(mActionShowArchived, &KToggleAction::triggered, this, &MainWindow::slotShowArchived); 0523 0524 mActionToggleTrayIcon = new KToggleAction(i18nc("@action", "Show in System Tray"), this); 0525 actions->addAction(QStringLiteral("showInSystemTray"), mActionToggleTrayIcon); 0526 connect(mActionToggleTrayIcon, &KToggleAction::triggered, this, &MainWindow::slotToggleTrayIcon); 0527 0528 mActionToggleResourceSel = new KToggleAction(QIcon::fromTheme(QStringLiteral("view-choose")), i18nc("@action", "Show Calendars"), this); 0529 actions->addAction(QStringLiteral("showResources"), mActionToggleResourceSel); 0530 connect(mActionToggleResourceSel, &KToggleAction::triggered, this, &MainWindow::slotToggleResourceSelector); 0531 0532 mActionToggleDateNavigator = new KToggleAction(QIcon::fromTheme(QStringLiteral("view-calendar-month")), i18nc("@action", "Show Date Selector"), this); 0533 actions->addAction(QStringLiteral("showDateSelector"), mActionToggleDateNavigator); 0534 connect(mActionToggleDateNavigator, &KToggleAction::triggered, this, &MainWindow::slotToggleDateNavigator); 0535 0536 if (!KWindowSystem::isPlatformWayland()) // Wayland doesn't allow positioning of windows 0537 { 0538 mActionSpreadWindows = KAlarm::createSpreadWindowsAction(this); 0539 actions->addAction(QStringLiteral("spread"), mActionSpreadWindows); 0540 KGlobalAccel::setGlobalShortcut(mActionSpreadWindows, QList<QKeySequence>()); // allow user to set a global shortcut 0541 } 0542 0543 mActionImportAlarms = new QAction(i18nc("@action", "Import Alarms..."), this); 0544 actions->addAction(QStringLiteral("importAlarms"), mActionImportAlarms); 0545 connect(mActionImportAlarms, &QAction::triggered, this, &MainWindow::slotImportAlarms); 0546 0547 if (Preferences::useAkonadi()) 0548 { 0549 mActionImportBirthdays = new QAction(i18nc("@action", "Import Birthdays..."), this); 0550 actions->addAction(QStringLiteral("importBirthdays"), mActionImportBirthdays); 0551 connect(mActionImportBirthdays, &QAction::triggered, this, &MainWindow::slotBirthdays); 0552 } 0553 0554 mActionExportAlarms = new QAction(i18nc("@action", "Export Selected Alarms..."), this); 0555 actions->addAction(QStringLiteral("exportAlarms"), mActionExportAlarms); 0556 connect(mActionExportAlarms, &QAction::triggered, this, &MainWindow::slotExportAlarms); 0557 0558 mActionExport = new QAction(i18nc("@action", "Export..."), this); 0559 actions->addAction(QStringLiteral("export"), mActionExport); 0560 connect(mActionExport, &QAction::triggered, this, &MainWindow::slotExportAlarms); 0561 0562 action = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18nc("@action", "Refresh Alarms"), this); 0563 actions->addAction(QStringLiteral("refreshAlarms"), action); 0564 connect(action, &QAction::triggered, this, &MainWindow::slotRefreshAlarms); 0565 0566 KToggleAction* toggleAction = KAlarm::createAlarmEnableAction(this); 0567 actions->addAction(QStringLiteral("alarmsEnable"), toggleAction); 0568 if (undoText.isNull()) 0569 { 0570 // Get standard texts, etc., for Undo and Redo actions 0571 QAction* act = KStandardAction::undo(this, nullptr, actions); 0572 undoShortcut = act->shortcuts(); 0573 undoText = act->text(); 0574 undoTextStripped = KLocalizedString::removeAcceleratorMarker(undoText); 0575 delete act; 0576 act = KStandardAction::redo(this, nullptr, actions); 0577 redoShortcut = act->shortcuts(); 0578 redoText = act->text(); 0579 redoTextStripped = KLocalizedString::removeAcceleratorMarker(redoText); 0580 delete act; 0581 } 0582 mActionUndo = new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("edit-undo")), undoText, this); 0583 actions->addAction(QStringLiteral("edit_undo"), mActionUndo); 0584 actions->setDefaultShortcuts(mActionUndo, undoShortcut); 0585 connect(mActionUndo, &KToolBarPopupAction::triggered, this, &MainWindow::slotUndo); 0586 0587 mActionRedo = new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("edit-redo")), redoText, this); 0588 actions->addAction(QStringLiteral("edit_redo"), mActionRedo); 0589 actions->setDefaultShortcuts(mActionRedo, redoShortcut); 0590 connect(mActionRedo, &KToolBarPopupAction::triggered, this, &MainWindow::slotRedo); 0591 0592 KStandardAction::find(mListView, &EventListView::slotFind, actions); 0593 mActionFindNext = KStandardAction::findNext(mListView, &EventListView::slotFindNext, actions); 0594 mActionFindPrev = KStandardAction::findPrev(mListView, &EventListView::slotFindPrev, actions); 0595 KStandardAction::selectAll(mListView, &QTreeView::selectAll, actions); 0596 KStandardAction::deselect(mListView, &QAbstractItemView::clearSelection, actions); 0597 // Quit only once the event loop is called; otherwise, the parent window will 0598 // be deleted while still processing the action, resulting in a crash. 0599 QAction* act = KStandardAction::quit(nullptr, nullptr, actions); 0600 connect(act, &QAction::triggered, this, &MainWindow::slotQuit, Qt::QueuedConnection); 0601 KStandardAction::keyBindings(this, &MainWindow::slotConfigureKeys, actions); 0602 KStandardAction::configureNotifications(this, &MainWindow::slotConfigureNotifications, actions); 0603 KStandardAction::configureToolbars(this, &MainWindow::slotConfigureToolbar, actions); 0604 KStandardAction::preferences(this, &MainWindow::slotPreferences, actions); 0605 mActionShowMenuBar = KStandardAction::showMenubar(this, &MainWindow::slotToggleMenubar, actions); 0606 mHamburgerMenu = KStandardAction::hamburgerMenu(nullptr, nullptr, actions); 0607 mHamburgerMenu->setShowMenuBarAction(mActionShowMenuBar); 0608 mHamburgerMenu->setMenuBar(menuBar()); 0609 connect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, [this]() { 0610 slotInitHamburgerMenu(); 0611 // Needs to be run on demand, but the contents won't change, so disconnect now. 0612 disconnect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, nullptr); 0613 }); 0614 mResourceSelector->initActions(actions); 0615 setStandardToolBarMenuEnabled(true); 0616 createGUI(UI_FILE); 0617 // Load menu and toolbar settings 0618 applyMainWindowSettings(KSharedConfig::openConfig()->group(WINDOW_NAME)); 0619 0620 mContextMenu = static_cast<QMenu*>(factory()->container(QStringLiteral("listContext"), this)); 0621 QMenu* actionsMenu = static_cast<QMenu*>(factory()->container(QStringLiteral("actions"), this)); 0622 mMenuError = (!mContextMenu || !actionsMenu || !resourceContextMenu()); 0623 connect(mActionUndo->popupMenu(), &QMenu::aboutToShow, this, &MainWindow::slotInitUndoMenu); 0624 connect(mActionUndo->popupMenu(), &QMenu::triggered, this, &MainWindow::slotUndoItem); 0625 connect(mActionRedo->popupMenu(), &QMenu::aboutToShow, this, &MainWindow::slotInitRedoMenu); 0626 connect(mActionRedo->popupMenu(), &QMenu::triggered, this, &MainWindow::slotRedoItem); 0627 connect(Undo::instance(), &Undo::changed, this, &MainWindow::slotUndoStatus); 0628 connect(mListView, &AlarmListView::findActive, this, &MainWindow::slotFindActive); 0629 Preferences::connect(&Preferences::archivedKeepDaysChanged, this, &MainWindow::updateKeepArchived); 0630 Preferences::connect(&Preferences::showInSystemTrayChanged, this, &MainWindow::updateTrayIconAction); 0631 connect(theApp(), &KAlarmApp::trayIconToggled, this, &MainWindow::updateTrayIconAction); 0632 0633 // Set menu item states 0634 setEnableText(true); 0635 mActionShowArchived->setChecked(mShowArchived); 0636 if (!Preferences::archivedKeepDays()) 0637 mActionShowArchived->setEnabled(false); 0638 mActionToggleResourceSel->setChecked(mShowResources); 0639 mActionToggleDateNavigator->setChecked(mShowDateNavigator); 0640 slotToggleResourceSelector(); // give priority to resource selector over date navigator 0641 slotToggleDateNavigator(); 0642 updateTrayIconAction(); // set the correct text for this action 0643 mActionUndo->setEnabled(Undo::haveUndo()); 0644 mActionRedo->setEnabled(Undo::haveRedo()); 0645 mActionFindNext->setEnabled(false); 0646 mActionFindPrev->setEnabled(false); 0647 0648 mActionCopy->setEnabled(false); 0649 mActionModify->setEnabled(false); 0650 mActionDelete->setEnabled(false); 0651 mActionReactivate->setEnabled(false); 0652 mActionEnable->setEnabled(false); 0653 mActionCreateTemplate->setEnabled(false); 0654 mActionExport->setEnabled(false); 0655 0656 mActionShowMenuBar->setChecked(Preferences::showMenuBar()); 0657 slotToggleMenubar(true); 0658 0659 Undo::emitChanged(); // set the Undo/Redo menu texts 0660 } 0661 0662 /****************************************************************************** 0663 * Set up the Hamburger menu, which allows the menu bar to be easily reinstated 0664 * after it has been hidden. 0665 */ 0666 void MainWindow::slotInitHamburgerMenu() 0667 { 0668 QMenu* menu = new QMenu(this); 0669 KActionCollection* actions = actionCollection(); 0670 menu->addAction(actions->action(QStringLiteral("new"))); 0671 menu->addAction(actions->action(QStringLiteral("templates"))); 0672 menu->addSeparator(); 0673 menu->addAction(actions->action(QStringLiteral("edit_find"))); 0674 menu->addSeparator(); 0675 menu->addAction(actions->action(QStringLiteral("showArchivedAlarms"))); 0676 menu->addAction(actions->action(QStringLiteral("showDateSelector"))); 0677 menu->addSeparator(); 0678 menu->addAction(actions->action(KStandardAction::name(KStandardAction::Quit))); 0679 mHamburgerMenu->setMenu(menu); 0680 } 0681 0682 /****************************************************************************** 0683 * Enable or disable the Templates menu item in every main window instance. 0684 */ 0685 void MainWindow::enableTemplateMenuItem(bool enable) 0686 { 0687 for (int i = 0, end = mWindowList.count(); i < end; ++i) 0688 mWindowList[i]->mActionTemplates->setEnabled(enable); 0689 } 0690 0691 /****************************************************************************** 0692 * Refresh the alarm list in every main window instance. 0693 */ 0694 void MainWindow::refresh() 0695 { 0696 qCDebug(KALARM_LOG) << "MainWindow::refresh"; 0697 DataModel::reload(); 0698 } 0699 0700 /****************************************************************************** 0701 * Called when the keep archived alarm setting changes in the user preferences. 0702 * Enable/disable Show archived alarms option. 0703 */ 0704 void MainWindow::updateKeepArchived(int days) 0705 { 0706 qCDebug(KALARM_LOG) << "MainWindow::updateKeepArchived:" << (bool)days; 0707 if (mShowArchived && !days) 0708 slotShowArchived(); // toggle Show Archived option setting 0709 mActionShowArchived->setEnabled(days); 0710 } 0711 0712 /****************************************************************************** 0713 * Select an alarm in the displayed list. 0714 */ 0715 void MainWindow::selectEvent(const QString& eventId) 0716 { 0717 mListView->clearSelection(); 0718 const QModelIndex index = mListFilterModel->eventIndex(eventId); 0719 if (index.isValid()) 0720 { 0721 mListView->select(index); 0722 mListView->scrollTo(index); 0723 } 0724 } 0725 0726 /****************************************************************************** 0727 * Return the single selected alarm in the displayed list. 0728 */ 0729 KAEvent MainWindow::selectedEvent() const 0730 { 0731 return mListView->selectedEvent(); 0732 } 0733 0734 /****************************************************************************** 0735 * Deselect all alarms in the displayed list. 0736 */ 0737 void MainWindow::clearSelection() 0738 { 0739 mListView->clearSelection(); 0740 } 0741 0742 /****************************************************************************** 0743 * Provide the context menu for the resource selector to use. 0744 */ 0745 QMenu* MainWindow::resourceContextMenu() 0746 { 0747 // Recreate the resource selector context menu if it has been deleted 0748 // (which happens if the toolbar is edited). 0749 if (!mResourceContextMenu) 0750 mResourceContextMenu = static_cast<QMenu*>(factory()->container(QStringLiteral("resourceContext"), this)); 0751 return mResourceContextMenu; 0752 } 0753 0754 /****************************************************************************** 0755 * Called when the New button is clicked to edit a new alarm to add to the list. 0756 */ 0757 void MainWindow::slotNew(EditAlarmDlg::Type type) 0758 { 0759 KAlarm::editNewAlarm(type, mListView); 0760 } 0761 0762 /****************************************************************************** 0763 * Called when a template is selected from the New From Template popup menu. 0764 * Executes a New Alarm dialog, preset from the selected template. 0765 */ 0766 void MainWindow::slotNewFromTemplate(const KAEvent& tmplate) 0767 { 0768 KAlarm::editNewAlarm(tmplate, mListView); 0769 } 0770 0771 /****************************************************************************** 0772 * Called when the New Template button is clicked to create a new template 0773 * based on the currently selected alarm. 0774 */ 0775 void MainWindow::slotNewTemplate() 0776 { 0777 KAEvent event = mListView->selectedEvent(); 0778 if (event.isValid()) 0779 KAlarm::editNewTemplate(event, this); 0780 } 0781 0782 /****************************************************************************** 0783 * Called when the Copy button is clicked to edit a copy of an existing alarm, 0784 * to add to the list. 0785 */ 0786 void MainWindow::slotCopy() 0787 { 0788 KAEvent event = mListView->selectedEvent(); 0789 if (event.isValid()) 0790 KAlarm::editNewAlarm(event, this); 0791 } 0792 0793 /****************************************************************************** 0794 * Called when the Modify button is clicked to edit the currently highlighted 0795 * alarm in the list. 0796 */ 0797 void MainWindow::slotModify() 0798 { 0799 KAEvent event = mListView->selectedEvent(); 0800 if (event.isValid()) 0801 KAlarm::editAlarm(event, this); // edit alarm (view-only mode if archived or read-only) 0802 } 0803 0804 /****************************************************************************** 0805 * Called when the Delete button is clicked to delete the currently highlighted 0806 * alarms in the list. 0807 */ 0808 void MainWindow::slotDelete(bool force) 0809 { 0810 QList<KAEvent> events = mListView->selectedEvents(); 0811 if (!force && Preferences::confirmAlarmDeletion()) 0812 { 0813 int n = events.count(); 0814 if (KAMessageBox::warningContinueCancel(this, i18ncp("@info", "Do you really want to delete the selected alarm?", 0815 "Do you really want to delete the %1 selected alarms?", n), 0816 i18ncp("@title:window", "Delete Alarm", "Delete Alarms", n), 0817 KGuiItem(i18nc("@action:button", "Delete"), QStringLiteral("edit-delete")), 0818 KStandardGuiItem::cancel(), 0819 Preferences::CONFIRM_ALARM_DELETION) 0820 != KMessageBox::Continue) 0821 return; 0822 } 0823 0824 // Remove any events which have just triggered, from the list to delete. 0825 Undo::EventList undos; 0826 for (int i = 0; i < events.count(); ) 0827 { 0828 Resource res = Resources::resourceForEvent(events[i].id()); 0829 if (!res.isValid()) 0830 events.remove(i); 0831 else 0832 undos.append(events[i++], res); 0833 } 0834 0835 if (events.isEmpty()) 0836 qCDebug(KALARM_LOG) << "MainWindow::slotDelete: No alarms left to delete"; 0837 else 0838 { 0839 // Delete the events from the calendar and displays 0840 Resource resource; 0841 const KAlarm::UpdateResult status = KAlarm::deleteEvents(events, resource, true, this); 0842 if (status.status < KAlarm::UPDATE_FAILED) 0843 { 0844 // Create the undo list 0845 for (int i = status.failed.count(); --i >= 0; ) 0846 undos.removeAt(status.failed.at(i)); 0847 Undo::saveDeletes(undos); 0848 } 0849 } 0850 } 0851 0852 /****************************************************************************** 0853 * Called when the Reactivate button is clicked to reinstate the currently 0854 * highlighted archived alarms in the list. 0855 */ 0856 void MainWindow::slotReactivate() 0857 { 0858 QList<KAEvent> events = mListView->selectedEvents(); 0859 mListView->clearSelection(); 0860 0861 // Add the alarms to the displayed lists and to the calendar file 0862 Resource resource; // active alarms resource which alarms are restored to 0863 QList<int> ineligibleIndexes; 0864 const KAlarm::UpdateResult status = KAlarm::reactivateEvents(events, ineligibleIndexes, resource, this); 0865 if (status.status < KAlarm::UPDATE_FAILED) 0866 { 0867 // Create the undo list, excluding ineligible events 0868 Undo::EventList undos; 0869 for (int i = 0, end = events.count(); i < end; ++i) 0870 { 0871 if (!ineligibleIndexes.contains(i) && !status.failed.contains(i)) 0872 undos.append(events[i], resource); 0873 } 0874 Undo::saveReactivates(undos); 0875 } 0876 } 0877 0878 /****************************************************************************** 0879 * Called when the Enable/Disable button is clicked to enable or disable the 0880 * currently highlighted alarms in the list. 0881 */ 0882 void MainWindow::slotEnable() 0883 { 0884 bool enable = mActionEnableEnable; // save since changed in response to KAlarm::enableEvent() 0885 const QList<KAEvent> events = mListView->selectedEvents(); 0886 QList<KAEvent> eventCopies; 0887 eventCopies.reserve(events.count()); 0888 for (const KAEvent& event : events) 0889 eventCopies += event; 0890 KAlarm::enableEvents(eventCopies, enable, this); 0891 slotSelection(); // update Enable/Disable action text 0892 } 0893 0894 /****************************************************************************** 0895 * Called when the columns visible in the alarm list view have changed. 0896 */ 0897 void MainWindow::slotAlarmListColumnsChanged() 0898 { 0899 KConfigGroup config(KSharedConfig::openConfig(), VIEW_GROUP); 0900 config.writeEntry(SHOW_COLUMNS, mListView->columnsVisible()); 0901 config.sync(); 0902 } 0903 0904 /****************************************************************************** 0905 * Called when the Show Archived Alarms menu item is selected or deselected. 0906 */ 0907 void MainWindow::slotShowArchived() 0908 { 0909 mShowArchived = !mShowArchived; 0910 mActionShowArchived->setChecked(mShowArchived); 0911 mActionShowArchived->setToolTip(mShowArchived ? i18nc("@info:tooltip", "Hide Archived Alarms") 0912 : i18nc("@info:tooltip", "Show Archived Alarms")); 0913 mListFilterModel->setEventTypeFilter(mShowArchived ? CalEvent::ACTIVE | CalEvent::ARCHIVED : CalEvent::ACTIVE); 0914 mListView->reset(); 0915 KConfigGroup config(KSharedConfig::openConfig(), VIEW_GROUP); 0916 config.writeEntry(SHOW_ARCHIVED_KEY, mShowArchived); 0917 config.sync(); 0918 } 0919 0920 /****************************************************************************** 0921 * Called when the Spread Windows global shortcut is selected, to spread alarm 0922 * windows so that they are all visible. 0923 */ 0924 void MainWindow::slotSpreadWindowsShortcut() 0925 { 0926 mActionSpreadWindows->trigger(); 0927 } 0928 0929 /****************************************************************************** 0930 * Called when the Wake From Suspend menu option is selected. 0931 */ 0932 void MainWindow::slotWakeFromSuspend() 0933 { 0934 #if ENABLE_RTC_WAKE_FROM_SUSPEND 0935 (WakeFromSuspendDlg::create(this))->show(); 0936 #endif 0937 } 0938 0939 /****************************************************************************** 0940 * Called when the Import Alarms menu item is selected, to merge alarms from an 0941 * external calendar into the current calendars. 0942 */ 0943 void MainWindow::slotImportAlarms() 0944 { 0945 Resource resource; 0946 KAlarm::importAlarms(resource, this); 0947 } 0948 0949 /****************************************************************************** 0950 * Called when the Export Alarms menu item is selected, to export the selected 0951 * alarms to an external calendar. 0952 */ 0953 void MainWindow::slotExportAlarms() 0954 { 0955 const QList<KAEvent> events = mListView->selectedEvents(); 0956 if (!events.isEmpty()) 0957 KAlarm::exportAlarms(events, this); 0958 } 0959 0960 /****************************************************************************** 0961 * Called when the Import Birthdays menu item is selected, to display birthdays 0962 * from the address book for selection as alarms. 0963 */ 0964 void MainWindow::slotBirthdays() 0965 { 0966 if (Preferences::useAkonadi()) 0967 { 0968 // Use AutoQPointer to guard against crash on application exit while 0969 // the dialogue is still open. It prevents double deletion (both on 0970 // deletion of MainWindow, and on return from this function). 0971 AutoQPointer<BirthdayDlg> dlg = new BirthdayDlg(this); 0972 if (dlg->exec() == QDialog::Accepted) 0973 { 0974 QList<KAEvent> events = dlg->events(); 0975 if (!events.isEmpty()) 0976 { 0977 mListView->clearSelection(); 0978 // Add alarm to the displayed lists and to the calendar file 0979 Resource resource; 0980 const KAlarm::UpdateResult status = KAlarm::addEvents(events, resource, dlg, true, true); 0981 if (status.status < KAlarm::UPDATE_FAILED) 0982 { 0983 // Create the undo list 0984 Undo::EventList undos; 0985 for (int i = 0, end = events.count(); i < end; ++i) 0986 if (!status.failed.contains(i)) 0987 undos.append(events[i], resource); 0988 Undo::saveAdds(undos, i18nc("@info", "Import birthdays")); 0989 0990 KAlarm::outputAlarmWarnings(dlg); 0991 } 0992 } 0993 } 0994 } 0995 } 0996 0997 /****************************************************************************** 0998 * Called when the Templates menu item is selected, to display the alarm 0999 * template editing dialog. 1000 */ 1001 void MainWindow::slotTemplates() 1002 { 1003 if (!mTemplateDlg) 1004 { 1005 mTemplateDlg = TemplateDlg::create(this); 1006 enableTemplateMenuItem(false); // disable menu item in all windows 1007 connect(mTemplateDlg, &QDialog::finished, this, &MainWindow::slotTemplatesEnd); 1008 mTemplateDlg->show(); 1009 } 1010 } 1011 1012 /****************************************************************************** 1013 * Called when the alarm template editing dialog has exited. 1014 */ 1015 void MainWindow::slotTemplatesEnd() 1016 { 1017 if (mTemplateDlg) 1018 { 1019 mTemplateDlg->deleteLater(); // this deletes the dialog once it is safe to do so 1020 mTemplateDlg = nullptr; 1021 enableTemplateMenuItem(true); // re-enable menu item in all windows 1022 } 1023 } 1024 1025 /****************************************************************************** 1026 * Called when the Display System Tray Icon menu item is selected. 1027 */ 1028 void MainWindow::slotToggleTrayIcon() 1029 { 1030 theApp()->displayTrayIcon(!theApp()->trayIconDisplayed(), this); 1031 } 1032 1033 /****************************************************************************** 1034 * Called when the Show Resource Selector menu item is selected. 1035 */ 1036 void MainWindow::slotToggleResourceSelector() 1037 { 1038 mShowResources = mActionToggleResourceSel->isChecked(); 1039 if (mShowResources) 1040 { 1041 if (mResourcesWidth <= 0) 1042 mResourcesWidth = mResourceSelector->sizeHint().width(); 1043 mResourceSelector->resize(mResourcesWidth, mResourceSelector->height()); 1044 mDateNavigatorTop = mShowDateNavigator; 1045 } 1046 else 1047 mResourceSelector->hide(); 1048 arrangePanel(); 1049 1050 KConfigGroup config(KSharedConfig::openConfig(), VIEW_GROUP); 1051 config.writeEntry(SHOW_RESOURCES_KEY, mShowResources); 1052 if (mShowResources) 1053 config.writeEntry(RESOURCES_WIDTH_KEY, mResourcesWidth); 1054 config.writeEntry(DATE_NAVIGATOR_TOP, mDateNavigatorTop); 1055 config.sync(); 1056 } 1057 1058 /****************************************************************************** 1059 * Called when the Show Date Navigator menu item is selected. 1060 */ 1061 void MainWindow::slotToggleDateNavigator() 1062 { 1063 mShowDateNavigator = mActionToggleDateNavigator->isChecked(); 1064 if (mShowDateNavigator) 1065 { 1066 const int panelWidth = mDatePicker->sizeHint().width(); 1067 mDatePicker->resize(panelWidth, mDatePicker->height()); 1068 mDateNavigatorTop = !mShowResources; 1069 } 1070 else 1071 { 1072 // When the date navigator is not visible, prevent it from filtering alarms. 1073 mDatePicker->clearSelection(); 1074 mDatePicker->hide(); 1075 } 1076 arrangePanel(); 1077 1078 KConfigGroup config(KSharedConfig::openConfig(), VIEW_GROUP); 1079 config.writeEntry(SHOW_DATE_NAVIGATOR, mShowDateNavigator); 1080 config.writeEntry(DATE_NAVIGATOR_TOP, mDateNavigatorTop); 1081 config.sync(); 1082 } 1083 1084 /****************************************************************************** 1085 * Arrange the contents and set the width of the side panel containing the 1086 * resource selector or date navigator. 1087 */ 1088 void MainWindow::arrangePanel() 1089 { 1090 // Clear the panel layout before recreating it. 1091 QLayoutItem* item; 1092 while ((item = mPanelLayout->takeAt(0)) != nullptr) 1093 delete item; 1094 1095 QWidget* date = mShowDateNavigator ? mDatePicker : nullptr; 1096 QWidget* res = mShowResources ? mResourceSelector : nullptr; 1097 QWidget* top = mDateNavigatorTop ? date : res; 1098 QWidget* bottom = mDateNavigatorTop ? res : date; 1099 if (bottom && !top) 1100 { 1101 top = bottom; 1102 bottom = nullptr; 1103 } 1104 if (!top) 1105 mPanel->hide(); 1106 else 1107 { 1108 int minWidth = 0; 1109 top->show(); 1110 mPanelLayout->addWidget(top); 1111 mPanelLayout->addStretch(); 1112 mPanel->show(); 1113 minWidth = top->minimumSizeHint().width(); 1114 if (bottom) 1115 { 1116 bottom->show(); 1117 if (!mPanelDivider) 1118 { 1119 mPanelDivider = new QFrame(mPanel); 1120 mPanelDivider->setFrameShape(QFrame::HLine); 1121 } 1122 mPanelDivider->show(); 1123 mPanelLayout->addWidget(mPanelDivider); 1124 mPanelLayout->addWidget(bottom); 1125 minWidth = std::max(minWidth, bottom->minimumSizeHint().width()); 1126 } 1127 else if (mPanelDivider) 1128 mPanelDivider->hide(); 1129 // Warning: mPanel->vericalScrollBar()->width() returns a silly value 1130 // until AFTER showEvent() has been executed. 1131 mPanel->setMinimumWidth(minWidth + mPanelScrollBarWidth); 1132 1133 int panelWidth = 0; 1134 if (mShowDateNavigator) 1135 panelWidth = mDatePicker->sizeHint().width(); 1136 if (mShowResources) 1137 panelWidth = std::max(panelWidth, mResourcesWidth); 1138 panelWidth += mPanelScrollBarWidth; 1139 1140 const int listWidth = width() - mSplitter->handleWidth() - panelWidth; 1141 mListView->resize(listWidth, mListView->height()); 1142 mSplitter->setSizes({ panelWidth, listWidth }); 1143 } 1144 } 1145 1146 /****************************************************************************** 1147 * Called when an error occurs in the resource calendar, to display a message. 1148 */ 1149 void MainWindow::showErrorMessage(const QString& msg) 1150 { 1151 KAMessageBox::error(this, msg); 1152 } 1153 1154 /****************************************************************************** 1155 * Called when the system tray icon is created or destroyed. 1156 * Set the system tray icon menu text according to whether or not the system 1157 * tray icon is currently visible. 1158 */ 1159 void MainWindow::updateTrayIconAction() 1160 { 1161 mActionToggleTrayIcon->setEnabled(QSystemTrayIcon::isSystemTrayAvailable()); 1162 mActionToggleTrayIcon->setChecked(theApp()->trayIconDisplayed()); 1163 } 1164 1165 /****************************************************************************** 1166 * Called when the active status of Find changes. 1167 */ 1168 void MainWindow::slotFindActive(bool active) 1169 { 1170 mActionFindNext->setEnabled(active); 1171 mActionFindPrev->setEnabled(active); 1172 } 1173 1174 /****************************************************************************** 1175 * Called when the Undo action is selected. 1176 */ 1177 void MainWindow::slotUndo() 1178 { 1179 Undo::undo(this, KLocalizedString::removeAcceleratorMarker(mActionUndo->text())); 1180 } 1181 1182 /****************************************************************************** 1183 * Called when the Redo action is selected. 1184 */ 1185 void MainWindow::slotRedo() 1186 { 1187 Undo::redo(this, KLocalizedString::removeAcceleratorMarker(mActionRedo->text())); 1188 } 1189 1190 /****************************************************************************** 1191 * Called when an Undo item is selected. 1192 */ 1193 void MainWindow::slotUndoItem(QAction* action) 1194 { 1195 int id = mUndoMenuIds.value(action); 1196 Undo::undo(id, this, Undo::actionText(Undo::UNDO, id)); 1197 } 1198 1199 /****************************************************************************** 1200 * Called when a Redo item is selected. 1201 */ 1202 void MainWindow::slotRedoItem(QAction* action) 1203 { 1204 int id = mUndoMenuIds.value(action); 1205 Undo::redo(id, this, Undo::actionText(Undo::REDO, id)); 1206 } 1207 1208 /****************************************************************************** 1209 * Called when the Undo menu is about to show. 1210 * Populates the menu. 1211 */ 1212 void MainWindow::slotInitUndoMenu() 1213 { 1214 initUndoMenu(mActionUndo->popupMenu(), Undo::UNDO); 1215 } 1216 1217 /****************************************************************************** 1218 * Called when the Redo menu is about to show. 1219 * Populates the menu. 1220 */ 1221 void MainWindow::slotInitRedoMenu() 1222 { 1223 initUndoMenu(mActionRedo->popupMenu(), Undo::REDO); 1224 } 1225 1226 /****************************************************************************** 1227 * Populate the undo or redo menu. 1228 */ 1229 void MainWindow::initUndoMenu(QMenu* menu, Undo::Type type) 1230 { 1231 menu->clear(); 1232 mUndoMenuIds.clear(); 1233 const QString& action = (type == Undo::UNDO) ? undoTextStripped : redoTextStripped; 1234 const QList<int> ids = Undo::ids(type); 1235 for (const int id : ids) 1236 { 1237 const QString actText = Undo::actionText(type, id); 1238 const QString descrip = Undo::description(type, id); 1239 const QString text = descrip.isEmpty() 1240 ? i18nc("@action Undo/Redo [action]", "%1 %2", action, actText) 1241 : i18nc("@action Undo [action]: message", "%1 %2: %3", action, actText, descrip); 1242 QAction* act = menu->addAction(text); 1243 mUndoMenuIds[act] = id; 1244 } 1245 } 1246 1247 /****************************************************************************** 1248 * Called when the status of the Undo or Redo list changes. 1249 * Change the Undo or Redo text to include the action which would be undone/redone. 1250 */ 1251 void MainWindow::slotUndoStatus(const QString& undo, const QString& redo) 1252 { 1253 if (undo.isNull()) 1254 { 1255 mActionUndo->setEnabled(false); 1256 mActionUndo->setText(undoText); 1257 } 1258 else 1259 { 1260 mActionUndo->setEnabled(true); 1261 mActionUndo->setText(QStringLiteral("%1 %2").arg(undoText, undo)); 1262 } 1263 if (redo.isNull()) 1264 { 1265 mActionRedo->setEnabled(false); 1266 mActionRedo->setText(redoText); 1267 } 1268 else 1269 { 1270 mActionRedo->setEnabled(true); 1271 mActionRedo->setText(QStringLiteral("%1 %2").arg(redoText, redo)); 1272 } 1273 } 1274 1275 /****************************************************************************** 1276 * Called when the Refresh Alarms menu item is selected. 1277 */ 1278 void MainWindow::slotRefreshAlarms() 1279 { 1280 KAlarm::refreshAlarms(); 1281 } 1282 1283 /****************************************************************************** 1284 * Called when the "Configure KAlarm" menu item is selected. 1285 */ 1286 void MainWindow::slotPreferences() 1287 { 1288 KAlarmPrefDlg::display(); 1289 } 1290 1291 /****************************************************************************** 1292 * Called when the Show Menubar menu item is selected. 1293 */ 1294 void MainWindow::slotToggleMenubar(bool dontShowWarning) 1295 { 1296 if (menuBar()) 1297 { 1298 if (mActionShowMenuBar->isChecked()) 1299 menuBar()->show(); 1300 else 1301 { 1302 if (!dontShowWarning 1303 && (!toolBar()->isVisible() || !toolBar()->actions().contains(mHamburgerMenu))) 1304 { 1305 const QString accel = mActionShowMenuBar->shortcut().toString(); 1306 KMessageBox::information(this, 1307 i18n("<qt>This will hide the menu bar completely." 1308 " You can show it again by typing %1.</qt>", accel), 1309 i18n("Hide menu bar"), QStringLiteral("HideMenuBarWarning")); 1310 } 1311 menuBar()->hide(); 1312 } 1313 Preferences::setShowMenuBar(mActionShowMenuBar->isChecked()); 1314 Preferences::self()->save(); 1315 } 1316 } 1317 1318 /****************************************************************************** 1319 * Called when the Configure Keys menu item is selected. 1320 */ 1321 void MainWindow::slotConfigureKeys() 1322 { 1323 KShortcutsDialog::showDialog(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, this); 1324 } 1325 1326 /****************************************************************************** 1327 * Called when the Configure Notifications menu item is selected. 1328 */ 1329 void MainWindow::slotConfigureNotifications() 1330 { 1331 KNotifyConfigWidget::configure(this); 1332 } 1333 1334 /****************************************************************************** 1335 * Called when the Configure Toolbars menu item is selected. 1336 */ 1337 void MainWindow::slotConfigureToolbar() 1338 { 1339 KConfigGroup grp(KSharedConfig::openConfig()->group(WINDOW_NAME)); 1340 saveMainWindowSettings(grp); 1341 KEditToolBar dlg(factory()); 1342 connect(&dlg, &KEditToolBar::newToolBarConfig, this, &MainWindow::slotNewToolbarConfig); 1343 dlg.exec(); 1344 } 1345 1346 /****************************************************************************** 1347 * Called when OK or Apply is clicked in the Configure Toolbars dialog, to save 1348 * the new configuration. 1349 */ 1350 void MainWindow::slotNewToolbarConfig() 1351 { 1352 createGUI(UI_FILE); 1353 applyMainWindowSettings(KSharedConfig::openConfig()->group(WINDOW_NAME)); 1354 } 1355 1356 /****************************************************************************** 1357 * Called when the Quit menu item is selected. 1358 * Note that this must be called by the event loop, not directly from the menu 1359 * item, since otherwise the window will be deleted while still processing the 1360 * menu, resulting in a crash. 1361 */ 1362 void MainWindow::slotQuit() 1363 { 1364 theApp()->doQuit(this); 1365 } 1366 1367 /****************************************************************************** 1368 * Called when the user or the session manager attempts to close the window. 1369 */ 1370 void MainWindow::closeEvent(QCloseEvent* ce) 1371 { 1372 if (!qApp->isSavingSession()) 1373 { 1374 // The user (not the session manager) wants to close the window. 1375 if (isTrayParent()) 1376 { 1377 // It's the parent window of the system tray icon, so just hide 1378 // it to prevent the system tray icon closing. 1379 hide(); 1380 theApp()->quitIf(); 1381 ce->ignore(); 1382 return; 1383 } 1384 } 1385 ce->accept(); 1386 } 1387 1388 /****************************************************************************** 1389 * Called when the drag cursor enters a main or system tray window, to accept 1390 * or reject the dragged object. 1391 */ 1392 void MainWindow::executeDragEnterEvent(QDragEnterEvent* e) 1393 { 1394 const QMimeData* data = e->mimeData(); 1395 bool accept = ICalDrag::canDecode(data) ? !e->source() // don't accept "text/calendar" objects from this application 1396 : data->hasText() || data->hasUrls(); 1397 if (accept) 1398 e->acceptProposedAction(); 1399 } 1400 1401 /****************************************************************************** 1402 * Called when an object is dropped on the window. 1403 * If the object is recognised, the edit alarm dialog is opened appropriately. 1404 */ 1405 void MainWindow::dropEvent(QDropEvent* e) 1406 { 1407 executeDropEvent(this, e); 1408 } 1409 1410 /****************************************************************************** 1411 * Called when an object is dropped on a main or system tray window, to 1412 * evaluate the action required and extract the text. 1413 */ 1414 void MainWindow::executeDropEvent(MainWindow* win, QDropEvent* e) 1415 { 1416 qCDebug(KALARM_LOG) << "MainWindow::executeDropEvent: Formats:" << e->mimeData()->formats(); 1417 const QMimeData* data = e->mimeData(); 1418 KAEvent::SubAction action = KAEvent::SubAction::Message; 1419 AlarmText alarmText; 1420 MemoryCalendar::Ptr calendar(new MemoryCalendar(Preferences::timeSpecAsZone())); 1421 #ifndef NDEBUG 1422 const QString fmts = data->formats().join(QLatin1String(", ")); 1423 qCDebug(KALARM_LOG) << "MainWindow::executeDropEvent:" << fmts; 1424 #endif 1425 1426 /* The order of the tests below matters, since some dropped objects 1427 * provide more than one mime type. 1428 * Don't change them without careful thought !! 1429 */ 1430 if (DragDrop::dropRFC822(data, alarmText)) 1431 { 1432 // Email message(s). Ignore all but the first. 1433 qCDebug(KALARM_LOG) << "MainWindow::executeDropEvent: email"; 1434 //TODO: Fetch attachments if an email alarm is created below 1435 } 1436 else if (ICalDrag::fromMimeData(data, calendar)) 1437 { 1438 // iCalendar - If events are included, use the first event 1439 qCDebug(KALARM_LOG) << "MainWindow::executeDropEvent: iCalendar"; 1440 const Event::List events = calendar->rawEvents(); 1441 if (!events.isEmpty()) 1442 { 1443 Event::Ptr event = events[0]; 1444 if (event->alarms().isEmpty()) 1445 { 1446 Alarm::Ptr alarm = event->newAlarm(); 1447 alarm->setEnabled(true); 1448 alarm->setTime(event->dtStart()); 1449 alarm->setDisplayAlarm(event->summary().isEmpty() ? event->description() : event->summary()); 1450 event->addAlarm(alarm); 1451 } 1452 KAEvent ev(event); 1453 KAlarm::editNewAlarm(ev, win); 1454 return; 1455 } 1456 // If todos are included, use the first todo 1457 const Todo::List todos = calendar->rawTodos(); 1458 if (!todos.isEmpty()) 1459 { 1460 Todo::Ptr todo = todos[0]; 1461 alarmText.setTodo(todo); 1462 KADateTime start(todo->dtStart(true)); 1463 KADateTime due(todo->dtDue(true)); 1464 bool haveBothTimes = false; 1465 if (todo->hasDueDate()) 1466 { 1467 if (start.isValid()) 1468 haveBothTimes = true; 1469 else 1470 start = due; 1471 } 1472 if (todo->allDay()) 1473 start.setDateOnly(true); 1474 KAEvent::Flags flags = KAEvent::DEFAULT_FONT; 1475 if (start.isDateOnly()) 1476 flags |= KAEvent::ANY_TIME; 1477 KAEvent ev(start, todo->summary(), alarmText.displayText(), Preferences::defaultBgColour(), Preferences::defaultFgColour(), 1478 QFont(), KAEvent::SubAction::Message, 0, flags, true); 1479 ev.startChanges(); 1480 if (todo->recurs()) 1481 { 1482 ev.setRecurrence(*todo->recurrence()); 1483 ev.setNextOccurrence(KADateTime::currentUtcDateTime()); 1484 } 1485 const Alarm::List alarms = todo->alarms(); 1486 if (!alarms.isEmpty() && alarms[0]->type() == Alarm::Display) 1487 { 1488 // A display alarm represents a reminder 1489 int offset = 0; 1490 if (alarms[0]->hasStartOffset()) 1491 offset = alarms[0]->startOffset().asSeconds(); 1492 else if (alarms[0]->hasEndOffset()) 1493 { 1494 offset = alarms[0]->endOffset().asSeconds(); 1495 if (haveBothTimes) 1496 { 1497 // Get offset relative to start time instead of due time 1498 offset += start.secsTo(due); 1499 } 1500 } 1501 if (offset / 60) 1502 ev.setReminder(-offset / 60, false); 1503 } 1504 ev.endChanges(); 1505 KAlarm::editNewAlarm(ev, win); 1506 } 1507 return; 1508 } 1509 else 1510 { 1511 QUrl url; 1512 if (KAlarm::dropAkonadiEmail(data, url, alarmText)) 1513 { 1514 // It's an email held in Akonadi 1515 qCDebug(KALARM_LOG) << "MainWindow::executeDropEvent: Akonadi email"; 1516 //TODO: Fetch attachments if an email alarm is created below 1517 } 1518 else if (!url.isEmpty()) 1519 { 1520 // The data provides a URL, but it isn't an Akonadi email URL. 1521 qCDebug(KALARM_LOG) << "MainWindow::executeDropEvent: URL"; 1522 // Try to find the mime type of the file, without downloading a remote file 1523 QMimeDatabase mimeDb; 1524 const QString mimeTypeName = mimeDb.mimeTypeForUrl(url).name(); 1525 action = mimeTypeName.startsWith(QLatin1String("audio/")) ? KAEvent::SubAction::Audio : KAEvent::SubAction::File; 1526 alarmText.setText(url.toDisplayString()); 1527 } 1528 } 1529 if (alarmText.isEmpty()) 1530 { 1531 if (data->hasText()) 1532 { 1533 const QString text = data->text(); 1534 qCDebug(KALARM_LOG) << "MainWindow::executeDropEvent: text"; 1535 alarmText.setText(text); 1536 } 1537 else 1538 return; 1539 } 1540 1541 if (!alarmText.isEmpty()) 1542 { 1543 if (action == KAEvent::SubAction::Message 1544 && (alarmText.isEmail() || alarmText.isScript())) 1545 { 1546 // If the alarm text could be interpreted as an email or command script, 1547 // prompt for which type of alarm to create. 1548 QStringList types; 1549 types += i18nc("@item:inlistbox", "Display Alarm"); 1550 if (alarmText.isEmail()) 1551 types += i18nc("@item:inlistbox", "Email Alarm"); 1552 else if (alarmText.isScript()) 1553 types += i18nc("@item:inlistbox", "Command Alarm"); 1554 bool ok = false; 1555 const QString type = QInputDialog::getItem(mainMainWindow(), i18nc("@title:window", "Alarm Type"), 1556 i18nc("@info", "Choose alarm type to create:"), types, 0, false, &ok); 1557 if (!ok) 1558 return; // user didn't press OK 1559 int i = types.indexOf(type); 1560 if (i == 1) 1561 action = alarmText.isEmail() ? KAEvent::SubAction::Email : KAEvent::SubAction::Command; 1562 } 1563 KAlarm::editNewAlarm(action, win, &alarmText); 1564 } 1565 } 1566 1567 /****************************************************************************** 1568 * Called when the status of a calendar has changed. 1569 * Enable or disable actions appropriately. 1570 */ 1571 void MainWindow::slotCalendarStatusChanged() 1572 { 1573 // Find whether there are any writable calendars 1574 bool active = !Resources::enabledResources(CalEvent::ACTIVE, true).isEmpty(); 1575 bool templat = !Resources::enabledResources(CalEvent::TEMPLATE, true).isEmpty(); 1576 for (MainWindow* w : std::as_const(mWindowList)) 1577 { 1578 w->mActionImportAlarms->setEnabled(active || templat); 1579 if (w->mActionImportBirthdays) 1580 w->mActionImportBirthdays->setEnabled(active); 1581 w->mActionCreateTemplate->setEnabled(templat); 1582 // Note: w->mActionNew enabled status is set in the NewAlarmAction class. 1583 w->slotSelection(); 1584 } 1585 } 1586 1587 /****************************************************************************** 1588 * Called when the selected items in the ListView change. 1589 * Enables the actions appropriately. 1590 */ 1591 void MainWindow::slotSelection() 1592 { 1593 // Find which events have been selected 1594 QList<KAEvent> events = mListView->selectedEvents(); 1595 int count = events.count(); 1596 if (!count) 1597 { 1598 selectionCleared(); // disable actions 1599 Q_EMIT selectionChanged(); 1600 return; 1601 } 1602 1603 // Find whether there are any writable resources 1604 bool active = mActionNew->isEnabled(); 1605 1606 bool readOnly = false; 1607 bool allArchived = true; 1608 bool enableReactivate = true; 1609 bool enableEnableDisable = true; 1610 bool enableEnable = false; 1611 bool enableDisable = false; 1612 const KADateTime now = KADateTime::currentUtcDateTime(); 1613 for (int i = 0; i < count; ++i) 1614 { 1615 const KAEvent ev = ResourcesCalendar::event(EventId(events.at(i))); // get up-to-date status 1616 const KAEvent& event = ev.isValid() ? ev : events[i]; 1617 bool expired = event.expired(); 1618 if (!expired) 1619 allArchived = false; 1620 if (KAlarm::eventReadOnly(event.id())) 1621 readOnly = true; 1622 if (enableReactivate 1623 && (!expired || !event.occursAfter(now, true))) 1624 enableReactivate = false; 1625 if (enableEnableDisable) 1626 { 1627 if (expired) 1628 enableEnableDisable = enableEnable = enableDisable = false; 1629 else 1630 { 1631 if (!enableEnable && !event.enabled()) 1632 enableEnable = true; 1633 if (!enableDisable && event.enabled()) 1634 enableDisable = true; 1635 } 1636 } 1637 } 1638 1639 qCDebug(KALARM_LOG) << "MainWindow::slotSelection: true"; 1640 mActionCreateTemplate->setEnabled((count == 1) && !Resources::enabledResources(CalEvent::TEMPLATE, true).isEmpty()); 1641 mActionExportAlarms->setEnabled(true); 1642 mActionExport->setEnabled(true); 1643 mActionCopy->setEnabled(active && count == 1); 1644 mActionModify->setEnabled(count == 1); 1645 mActionDelete->setEnabled(!readOnly && (active || allArchived)); 1646 mActionReactivate->setEnabled(active && enableReactivate); 1647 mActionEnable->setEnabled(active && !readOnly && (enableEnable || enableDisable)); 1648 if (enableEnable || enableDisable) 1649 setEnableText(enableEnable); 1650 1651 Q_EMIT selectionChanged(); 1652 } 1653 1654 /****************************************************************************** 1655 * Called when a context menu is requested in the ListView. 1656 * Displays a context menu to modify or delete the selected item. 1657 */ 1658 void MainWindow::slotContextMenuRequested(const QPoint& globalPos) 1659 { 1660 qCDebug(KALARM_LOG) << "MainWindow::slotContextMenuRequested"; 1661 // Recreate the context menu if it has been deleted (which happens if the 1662 // toolbar is edited). 1663 if (!mContextMenu) 1664 mContextMenu = static_cast<QMenu*>(factory()->container(QStringLiteral("listContext"), this)); 1665 mContextMenu->popup(globalPos); 1666 } 1667 1668 /****************************************************************************** 1669 * Disables actions when no item is selected. 1670 */ 1671 void MainWindow::selectionCleared() 1672 { 1673 mActionCreateTemplate->setEnabled(false); 1674 mActionExportAlarms->setEnabled(false); 1675 mActionExport->setEnabled(false); 1676 mActionCopy->setEnabled(false); 1677 mActionModify->setEnabled(false); 1678 mActionDelete->setEnabled(false); 1679 mActionReactivate->setEnabled(false); 1680 mActionEnable->setEnabled(false); 1681 } 1682 1683 /****************************************************************************** 1684 * Set the text of the Enable/Disable menu action. 1685 */ 1686 void MainWindow::setEnableText(bool enable) 1687 { 1688 mActionEnableEnable = enable; 1689 mActionEnable->setText(enable ? i18nc("@action", "Enable") : i18nc("@action", "Disable")); 1690 } 1691 1692 /****************************************************************************** 1693 * Display or hide the specified main window. 1694 * This should only be called when the application doesn't run in the system tray. 1695 */ 1696 MainWindow* MainWindow::toggleWindow(MainWindow* win) 1697 { 1698 if (win && mWindowList.indexOf(win) != -1) 1699 { 1700 // A window is specified (and it exists) 1701 if (win->isVisible()) 1702 { 1703 // The window is visible, so close it 1704 win->close(); 1705 return nullptr; 1706 } 1707 else 1708 { 1709 // The window is hidden, so display it 1710 win->hide(); // in case it's on a different desktop 1711 win->setWindowState(win->windowState() & ~Qt::WindowMinimized); 1712 win->raise(); 1713 win->activateWindow(); 1714 return win; 1715 } 1716 } 1717 1718 // No window is specified, or the window doesn't exist. Open a new one. 1719 win = create(); 1720 win->show(); 1721 return win; 1722 } 1723 1724 /****************************************************************************** 1725 * Called when the Edit button is clicked in an alarm message window. 1726 * This controls the alarm edit dialog created by the alarm window, and allows 1727 * it to remain unaffected by the alarm window closing. 1728 * See MessageWindow::slotEdit() for more information. 1729 */ 1730 void MainWindow::editAlarm(EditAlarmDlg* dlg, const KAEvent& event) 1731 { 1732 mEditAlarmMap[dlg] = event; 1733 connect(dlg, &KEditToolBar::accepted, this, &MainWindow::editAlarmOk); 1734 connect(dlg, &KEditToolBar::destroyed, this, &MainWindow::editAlarmDeleted); 1735 dlg->setAttribute(Qt::WA_DeleteOnClose, true); // ensure no memory leaks 1736 dlg->show(); 1737 } 1738 1739 /****************************************************************************** 1740 * Called when OK is clicked in the alarm edit dialog shown by editAlarm(). 1741 * Updates the event which has been edited. 1742 */ 1743 void MainWindow::editAlarmOk() 1744 { 1745 auto dlg = qobject_cast<EditAlarmDlg*>(sender()); 1746 if (!dlg) 1747 return; 1748 QMap<EditAlarmDlg*, KAEvent>::Iterator it = mEditAlarmMap.find(dlg); 1749 if (it == mEditAlarmMap.end()) 1750 return; 1751 KAEvent event = it.value(); 1752 mEditAlarmMap.erase(it); 1753 if (!event.isValid()) 1754 return; 1755 if (dlg->result() != QDialog::Accepted) 1756 return; 1757 Resource res = Resources::resourceForEvent(event.id()); 1758 KAlarm::updateEditedAlarm(dlg, event, res); 1759 } 1760 1761 /****************************************************************************** 1762 * Called when the alarm edit dialog shown by editAlarm() is deleted. 1763 * Removes the dialog from the pending list. 1764 */ 1765 void MainWindow::editAlarmDeleted(QObject* obj) 1766 { 1767 mEditAlarmMap.remove(static_cast<EditAlarmDlg*>(obj)); 1768 } 1769 1770 /****************************************************************************** 1771 * Called when the Defer button is clicked in an alarm window or notification. 1772 * This controls the defer dialog created by the alarm display, and allows it to 1773 * remain unaffected by the alarm display closing. 1774 * See MessageWindow::slotEdit() for more information. 1775 */ 1776 void MainWindow::showDeferAlarmDlg(MessageDisplay::DeferDlgData* data) 1777 { 1778 DeferAlarmDlg* dlg = data->dlg; 1779 mDeferAlarmMap[dlg] = data; 1780 connect(dlg, &KEditToolBar::finished, this, &MainWindow::deferAlarmDlgDone); 1781 connect(dlg, &KEditToolBar::destroyed, this, &MainWindow::deferAlarmDlgDeleted); 1782 dlg->setAttribute(Qt::WA_DeleteOnClose, true); // ensure no memory leaks 1783 dlg->show(); 1784 } 1785 1786 /****************************************************************************** 1787 * Called when OK is clicked in the defer alarm dialog shown by 1788 * showDeferAlarmDlg(). 1789 */ 1790 void MainWindow::deferAlarmDlgDone(int result) 1791 { 1792 processDeferAlarmDlg(sender(), result); 1793 } 1794 1795 /****************************************************************************** 1796 * Called when the defer alarm dialog shown by showDeferAlarmDlg() is complete. 1797 * Removes the dialog from the pending list, and processes the result. 1798 */ 1799 void MainWindow::processDeferAlarmDlg(QObject* obj, int result) 1800 { 1801 auto dlg = qobject_cast<DeferAlarmDlg*>(obj); 1802 if (!dlg) 1803 return; 1804 QMap<DeferAlarmDlg*, MessageDisplay::DeferDlgData*>::Iterator it = mDeferAlarmMap.find(dlg); 1805 if (it == mDeferAlarmMap.end()) 1806 return; 1807 MessageDisplay::DeferDlgData* data = it.value(); 1808 mDeferAlarmMap.erase(it); 1809 MessageDisplay::processDeferDlg(data, result); 1810 } 1811 1812 #include "moc_mainwindow.cpp" 1813 1814 // vim: et sw=4: