File indexing completed on 2024-05-12 05:21:18
0001 /* 0002 This file is part of KOrganizer. 0003 0004 SPDX-FileCopyrightText: 2002 Mike Pilone <mpilone@slac.com> 0005 SPDX-FileCopyrightText: 2002 Don Sanders <sanders@kde.org> 0006 SPDX-FileCopyrightText: 2004 Cornelius Schumacher <schumacher@kde.org> 0007 SPDX-FileCopyrightText: 2004 Reinhold Kainhofer <reinhold@kainhofer.com> 0008 SPDX-FileCopyrightText: 2005 Rafal Rzepecki <divide@users.sourceforge.net> 0009 SPDX-FileCopyrightText: 2010-2024 Laurent Montel <montel@kde.org> 0010 SPDX-FileCopyrightText: 2012-2019 Allen Winter <winter@kde.org> 0011 0012 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0013 */ 0014 #include "actionmanager.h" 0015 #include "akonadicollectionview.h" 0016 #include "calendaradaptor.h" 0017 #include "calendarinterfaceadaptor.h" 0018 #include "calendarview.h" 0019 #include "kocore.h" 0020 #include "kodialogmanager.h" 0021 #include "koglobals.h" 0022 #include "korganizeradaptor.h" 0023 #include "koviewmanager.h" 0024 #include "kowindowlist.h" 0025 #include "prefs/koprefs.h" 0026 #include <KAuthorized> 0027 #include <config-korganizer.h> 0028 0029 #include <CalendarSupport/CollectionSelection> 0030 #include <CalendarSupport/EventArchiver> 0031 #include <CalendarSupport/KCalPrefs> 0032 0033 #include <IncidenceEditor/IncidenceEditorSettings> 0034 0035 #include <Akonadi/CalendarUtils> 0036 #include <Akonadi/ETMViewStateSaver> 0037 #include <Akonadi/EntityDisplayAttribute> 0038 #include <Akonadi/EntityTreeModel> 0039 #include <Akonadi/EntityTreeView> 0040 #include <Akonadi/History> 0041 #include <Akonadi/ICalImporter> 0042 0043 #include <KCalendarCore/FileStorage> 0044 #include <KCalendarCore/ICalFormat> 0045 #include <KCalendarCore/Person> 0046 0047 #include <KIO/FileCopyJob> 0048 #include <KIO/StatJob> 0049 #include <KJobWidgets> 0050 #include <KMime/KMimeMessage> 0051 0052 #include <KActionCollection> 0053 #include <KActionMenu> 0054 #include <KColorSchemeMenu> 0055 #include <KMessageBox> 0056 #include <KSelectAction> 0057 #include <KShortcutsDialog> 0058 #include <KStandardAction> 0059 #include <QAction> 0060 #include <QFileDialog> 0061 #include <QMenu> 0062 #include <QMenuBar> 0063 #include <QProcess> 0064 0065 #include "korganizer_debug.h" 0066 #include "korganizer_options.h" 0067 #include <KNSWidgets/Action> 0068 #include <KToggleAction> 0069 #include <KWindowSystem> 0070 #include <QIcon> 0071 #include <QTemporaryFile> 0072 0073 #include <KCheckableProxyModel> 0074 #include <KColorSchemeManager> 0075 #include <KSharedConfig> 0076 #include <QApplication> 0077 #include <QStandardPaths> 0078 #include <QTimer> 0079 #include <QToolBar> 0080 #include <QWindow> 0081 0082 KOWindowList *ActionManager::mWindowList = nullptr; 0083 0084 ActionManager::ActionManager(KXMLGUIClient *client, 0085 CalendarView *widget, 0086 QObject *parent, 0087 KOrg::MainWindow *mainWindow, 0088 bool isPart, 0089 QMenuBar *menuBar, 0090 QToolBar *toolBar) 0091 : QObject(parent) 0092 { 0093 new KOrgCalendarAdaptor(this); 0094 0095 // reminder daemon interface 0096 new CalendarInterfaceAdaptor(this); 0097 QDBusConnection::sessionBus().registerObject(QStringLiteral("/Calendar"), this); 0098 0099 mGUIClient = client; 0100 mACollection = mGUIClient->actionCollection(); 0101 mCalendarView = widget; 0102 mIsPart = isPart; 0103 mMainWindow = mainWindow; 0104 mMenuBar = menuBar; 0105 mToolBar = toolBar; 0106 } 0107 0108 ActionManager::~ActionManager() 0109 { 0110 delete mTempFile; 0111 0112 // Take this window out of the window list. 0113 mWindowList->removeWindow(mMainWindow); 0114 0115 delete mCollectionSelectionModelStateSaver; 0116 delete mCollectionViewStateSaver; 0117 0118 delete mCalendarView; 0119 } 0120 0121 void ActionManager::toggleMenubar(bool dontShowWarning) 0122 { 0123 if (mMenuBar) { 0124 if (mShowMenuBarAction->isChecked()) { 0125 mMenuBar->show(); 0126 } else { 0127 if (!dontShowWarning && (!mToolBar->isVisible() || !mToolBar->actions().contains(mHamburgerMenu))) { 0128 const QString accel = mShowMenuBarAction->shortcut().toString(); 0129 KMessageBox::information(mCalendarView, 0130 i18n("<qt>This will hide the menu bar completely." 0131 " You can show it again by typing %1.</qt>", 0132 accel), 0133 i18n("Hide menu bar"), 0134 QStringLiteral("HideMenuBarWarning")); 0135 } 0136 mMenuBar->hide(); 0137 } 0138 KOPrefs::instance()->setShowMenuBar(mShowMenuBarAction->isChecked()); 0139 } 0140 } 0141 0142 // see the Note: below for why this method is necessary 0143 void ActionManager::init() 0144 { 0145 // add this instance of the window to the static list. 0146 if (!mWindowList) { 0147 mWindowList = new KOWindowList; 0148 } 0149 0150 // Note: We need this ActionManager to be fully constructed, and 0151 // parent() to have a valid reference to it before the following 0152 // addWindow is called. 0153 mWindowList->addWindow(mMainWindow); 0154 0155 // initialize the QAction instances 0156 initActions(); 0157 0158 // set up autoSaving stuff 0159 mAutoArchiveTimer = new QTimer(this); 0160 mAutoArchiveTimer->setSingleShot(true); 0161 connect(mAutoArchiveTimer, &QTimer::timeout, this, &ActionManager::slotAutoArchive); 0162 0163 // First auto-archive should be in 5 minutes (like in kmail). 0164 if (CalendarSupport::KCalPrefs::instance()->mAutoArchive) { 0165 mAutoArchiveTimer->start(5 * 60 * 1000); // singleshot 0166 } 0167 0168 setTitle(); 0169 0170 connect(mCalendarView, &CalendarView::modifiedChanged, this, &ActionManager::setTitle); 0171 connect(mCalendarView, &CalendarView::configChanged, this, &ActionManager::updateConfig); 0172 0173 connect(mCalendarView, &CalendarView::incidenceSelected, this, &ActionManager::processIncidenceSelection); 0174 0175 processIncidenceSelection(Akonadi::Item(), QDate()); 0176 0177 // Update state of paste action 0178 mCalendarView->checkClipboard(); 0179 } 0180 0181 Akonadi::ETMCalendar::Ptr ActionManager::calendar() const 0182 { 0183 return mCalendarView->calendar(); 0184 } 0185 0186 void ActionManager::createCalendarAkonadi() 0187 { 0188 Q_ASSERT(calendar()); 0189 0190 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0191 mCollectionSelectionModelStateSaver = new KViewStateMaintainer<Akonadi::ETMViewStateSaver>(config->group(QStringLiteral("GlobalCollectionSelection"))); 0192 mCollectionSelectionModelStateSaver->setSelectionModel(calendar()->checkableProxyModel()->selectionModel()); 0193 0194 AkonadiCollectionViewFactory factory(mCalendarView); 0195 mCalendarView->addExtension(&factory); 0196 mCollectionView = factory.collectionView(); 0197 mCollectionView->setObjectName(QLatin1StringView("Resource View")); 0198 connect(mCollectionView, &AkonadiCollectionView::resourcesAddedRemoved, this, &ActionManager::slotResourcesAddedRemoved); 0199 0200 connect(mCollectionView, &AkonadiCollectionView::defaultResourceChanged, this, &ActionManager::slotDefaultResourceChanged); 0201 0202 connect(mCollectionView, &AkonadiCollectionView::colorsChanged, mCalendarView, qOverload<>(&CalendarView::updateConfig)); 0203 0204 mCollectionViewStateSaver = new KViewStateMaintainer<Akonadi::ETMViewStateSaver>(config->group(QStringLiteral("GlobalCollectionView"))); 0205 mCollectionViewStateSaver->setView(mCollectionView->view()); 0206 0207 KCheckableProxyModel *checkableProxy = calendar()->checkableProxyModel(); 0208 QItemSelectionModel *selectionModel = checkableProxy->selectionModel(); 0209 0210 mCollectionView->setCollectionSelectionProxyModel(checkableProxy); 0211 0212 auto collectionSelection = new CalendarSupport::CollectionSelection(selectionModel); 0213 EventViews::EventView::setGlobalCollectionSelection(collectionSelection); 0214 0215 mCalendarView->readSettings(); 0216 0217 // connect(calendar().data(), &Akonadi::ETMCalendar::calendarChanged, mCalendarView, &CalendarView::resourcesChanged); 0218 connect(mCalendarView, &CalendarView::configChanged, this, &ActionManager::updateConfig); 0219 0220 calendar()->setOwner(KCalendarCore::Person(CalendarSupport::KCalPrefs::instance()->fullName(), CalendarSupport::KCalPrefs::instance()->email())); 0221 } 0222 0223 void ActionManager::initActions() 0224 { 0225 /*************************** FILE MENU **********************************/ 0226 0227 //~~~~~~~~~~~~~~~~~~~~~~~ LOADING / SAVING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0228 if (mIsPart) { 0229 if (mMainWindow->hasDocument()) { 0230 mACollection->addAction(KStandardAction::Open, QStringLiteral("korganizer_open"), this, qOverload<>(&ActionManager::file_open)); 0231 } 0232 mACollection->addAction(KStandardAction::Print, QStringLiteral("korganizer_print"), mCalendarView, &CalendarView::print); 0233 mACollection->addAction(KStandardAction::PrintPreview, QStringLiteral("korganizer_print_preview"), mCalendarView, &CalendarView::printPreview); 0234 } else { 0235 KStandardAction::open(this, qOverload<>(&ActionManager::file_open), mACollection); 0236 KStandardAction::print(mCalendarView, &CalendarView::print, mACollection); 0237 KStandardAction::printPreview(mCalendarView, &CalendarView::printPreview, mACollection); 0238 } 0239 0240 //~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT / EXPORT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0241 /** Import Action **/ 0242 // TODO: Icon 0243 mImportAction = new QAction(i18n("Import &Calendar..."), this); 0244 mImportAction->setStatusTip(i18nc("@info:status", "Import a calendar")); 0245 mImportAction->setToolTip(i18nc("@info:tooltip", "Import an iCalendar or vCalendar file")); 0246 mImportAction->setWhatsThis(i18nc("@info:whatsthis", 0247 "Select this menu entry if you would like to import the contents of an " 0248 "iCalendar or vCalendar file into your current calendar collection.")); 0249 mACollection->addAction(QStringLiteral("import_icalendar"), mImportAction); 0250 connect(mImportAction, &QAction::triggered, this, &ActionManager::file_import); 0251 0252 /** Get Hot New Stuff Action **/ 0253 auto knsAction = new KNSWidgets::Action(i18n("Get New Calendars..."), QStringLiteral("korganizer.knsrc"), this); 0254 knsAction->setStatusTip(i18nc("@info:status", "Load a calendar from \"Get Hot New Stuff\"")); 0255 knsAction->setToolTip(i18nc("@info:tooltip", "Search \"Get Hot New Stuff\" for calendars to import")); 0256 knsAction->setWhatsThis(i18nc("@info:whatsthis", 0257 "This menu entry opens the \"Get Hot New Stuff\" dialog that allows you " 0258 "to search and import fun and useful calendars donated to the community.")); 0259 mACollection->addAction(QStringLiteral("downloadnewstuff"), knsAction); 0260 connect(knsAction, &KNSWidgets::Action::dialogFinished, this, [this](auto changedEntries) { 0261 for (const auto &e : changedEntries) { 0262 qCDebug(KORGANIZER_LOG) << " downloadNewStuff :"; 0263 const QStringList lstFile = e.installedFiles(); 0264 if (lstFile.count() != 1) { 0265 continue; 0266 } 0267 const QString file = lstFile.at(0); 0268 const QUrl filename = QUrl::fromLocalFile(file); 0269 qCDebug(KORGANIZER_LOG) << "filename :" << filename; 0270 if (!filename.isValid()) { 0271 continue; 0272 } 0273 0274 KCalendarCore::FileStorage storage(calendar()); 0275 storage.setFileName(file); 0276 storage.setSaveFormat(new KCalendarCore::ICalFormat); 0277 if (!storage.load()) { 0278 KMessageBox::error(mCalendarView, i18n("Could not load calendar %1.", file)); 0279 } else { 0280 QStringList eventSummaries; 0281 const KCalendarCore::Event::List events = calendar()->events(); 0282 eventSummaries.reserve(events.count()); 0283 for (const KCalendarCore::Event::Ptr &event : events) { 0284 eventSummaries.append(event->summary()); 0285 } 0286 0287 const int result = KMessageBox::warningContinueCancelList(mCalendarView, 0288 i18n("The downloaded events will be merged into your current calendar."), 0289 eventSummaries); 0290 0291 if (result != KMessageBox::Continue) { 0292 // FIXME (KNS2): hm, no way out here :-) 0293 } 0294 0295 if (importURL(QUrl::fromLocalFile(file), true)) { 0296 // FIXME (KNS2): here neither 0297 } 0298 } 0299 } 0300 }); 0301 0302 QAction *action = nullptr; 0303 /** Export Action **/ 0304 // TODO: Icon 0305 action = new QAction(i18n("Export as &iCalendar..."), this); 0306 action->setStatusTip(i18nc("@info:status", "Export calendar to file")); 0307 action->setToolTip(i18nc("@info:tooltip", "Export your calendar to an iCalendar file")); 0308 action->setWhatsThis(i18nc("@info:whatsthis", "Allows you to export your entire calendar collection to one iCalendar file.")); 0309 mACollection->addAction(QStringLiteral("export_icalendar"), action); 0310 connect(action, &QAction::triggered, mCalendarView, &CalendarView::exportICalendar); 0311 0312 /** Archive Action **/ 0313 // TODO: Icon 0314 action = new QAction(i18n("Archive O&ld Incidences..."), this); 0315 action->setStatusTip(i18nc("@info:status", "Archive events and to-dos to a file")); 0316 action->setToolTip(i18nc("@info:tooltip", "Archive old events and to-dos to an iCalendar file")); 0317 action->setWhatsThis(i18nc("@info:whatsthis", 0318 "This menu entry opens a dialog that allows you to select old events and to-dos " 0319 "that you can archive into an iCalendar file. They will " 0320 "be removed from your existing calendar collection.")); 0321 mACollection->addAction(QStringLiteral("file_archive"), action); 0322 connect(action, &QAction::triggered, this, &ActionManager::file_archive); 0323 0324 /** Purge Todos Action **/ 0325 // TODO: Icon 0326 action = new QAction(i18n("Pur&ge Completed To-dos"), mACollection); 0327 action->setStatusTip(i18nc("@info:status", "Purge completed to-dos")); 0328 action->setToolTip(i18nc("@info:tooltip", "Remove completed to-dos from your calendar")); 0329 action->setWhatsThis(i18nc("@info:whatsthis", 0330 "Allows you to remove all completed to-dos from your calendar collection. " 0331 "This action cannot be undone!")); 0332 mACollection->addAction(QStringLiteral("purge_completed"), action); 0333 connect(action, &QAction::triggered, mCalendarView, &CalendarView::purgeCompleted); 0334 0335 /************************** EDIT MENU *********************************/ 0336 0337 QAction *pasteAction = nullptr; 0338 Akonadi::History *history = mCalendarView->history(); 0339 if (mIsPart) { 0340 // edit menu 0341 mCutAction = mACollection->addAction(KStandardAction::Cut, QStringLiteral("korganizer_cut"), mCalendarView, &CalendarView::edit_cut); 0342 mCopyAction = mACollection->addAction(KStandardAction::Copy, QStringLiteral("korganizer_copy"), mCalendarView, &CalendarView::edit_copy); 0343 pasteAction = mACollection->addAction(KStandardAction::Paste, QStringLiteral("korganizer_paste"), mCalendarView, &CalendarView::edit_paste); 0344 mUndoAction = mACollection->addAction(KStandardAction::Undo, QStringLiteral("korganizer_undo"), this, [history]() { 0345 history->undo(); 0346 }); 0347 mRedoAction = mACollection->addAction(KStandardAction::Redo, QStringLiteral("korganizer_redo"), this, [history]() { 0348 history->redo(); 0349 }); 0350 } else { 0351 mCutAction = KStandardAction::cut(mCalendarView, &CalendarView::edit_cut, mACollection); 0352 mCopyAction = KStandardAction::copy(mCalendarView, &CalendarView::edit_copy, mACollection); 0353 pasteAction = KStandardAction::paste(mCalendarView, &CalendarView::edit_paste, mACollection); 0354 mUndoAction = KStandardAction::undo( 0355 this, 0356 [history]() { 0357 history->undo(); 0358 }, 0359 mACollection); 0360 mRedoAction = KStandardAction::redo( 0361 this, 0362 [history]() { 0363 history->redo(); 0364 }, 0365 mACollection); 0366 } 0367 mDeleteAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("&Delete"), this); 0368 mACollection->addAction(QStringLiteral("edit_delete"), mDeleteAction); 0369 connect(mDeleteAction, &QAction::triggered, mCalendarView, &CalendarView::appointment_delete); 0370 if (mIsPart) { 0371 mACollection->addAction(KStandardAction::Find, QStringLiteral("korganizer_find"), mCalendarView->dialogManager(), &KODialogManager::showSearchDialog); 0372 } else { 0373 KStandardAction::find(mCalendarView->dialogManager(), &KODialogManager::showSearchDialog, mACollection); 0374 } 0375 pasteAction->setEnabled(false); 0376 mUndoAction->setEnabled(false); 0377 mRedoAction->setEnabled(false); 0378 connect(mCalendarView, &CalendarView::pasteEnabled, pasteAction, &QAction::setEnabled); 0379 connect(history, &Akonadi::History::changed, this, &ActionManager::updateUndoRedoActions); 0380 0381 /************************** VIEW MENU *********************************/ 0382 0383 /** What's Next View Action **/ 0384 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-upcoming-events")), i18n("What's &Next"), this); 0385 action->setStatusTip(i18nc("@info:status", "What's Next View")); 0386 action->setToolTip(i18nc("@info:tooltip", "Switch to the What's Next View")); 0387 action->setWhatsThis(i18nc("@info:whatsthis", 0388 "Switches to the \"What's Next\" View, which shows your events and to-dos " 0389 "that are \"coming soon\" in a short list for quick reading. All open to-dos " 0390 "will be displayed, but only the events from the days selected in the " 0391 "Date Navigator sidebar will be shown.")); 0392 mACollection->addAction(QStringLiteral("view_whatsnext"), action); 0393 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::showWhatsNextView); 0394 0395 /** Month View Action **/ 0396 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-month")), i18n("&Month"), this); 0397 action->setStatusTip(i18nc("@info:status", "Month View")); 0398 action->setToolTip(i18nc("@info:tooltip", "Switch to the Month View")); 0399 action->setWhatsThis(i18nc("@info:whatsthis", 0400 "Switches to the Month View, which shows all the events and due to-dos " 0401 "in a familiar monthly calendar layout.")); 0402 mACollection->addAction(QStringLiteral("view_month"), action); 0403 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::showMonthView); 0404 0405 /** Agenda View Action **/ 0406 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-agenda")), i18n("&Agenda"), this); 0407 action->setStatusTip(i18nc("@info:status", "Agenda View")); 0408 action->setToolTip(i18nc("@info:tooltip", "Switch to the Agenda View")); 0409 action->setWhatsThis(i18nc("@info:whatsthis", 0410 "Switches to the Agenda View, which presents your events or due to-dos " 0411 "for one or more days, sorted chronologically. You can also see the length " 0412 "of each event in the day timetable.")); 0413 mACollection->addAction(QStringLiteral("view_agenda"), action); 0414 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::showAgendaView); 0415 0416 /** List View Action **/ 0417 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-list")), i18n("&Event List"), this); 0418 action->setStatusTip(i18nc("@info:status", "List View")); 0419 action->setToolTip(i18nc("@info:tooltip", "Switch to the List View")); 0420 action->setWhatsThis(i18nc("@info:whatsthis", 0421 "Switches to the List View, which displays all your to-dos, events and " 0422 "journal entries for the dates selected in the Date Navigator as a list.")); 0423 mACollection->addAction(QStringLiteral("view_list"), action); 0424 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::showListView); 0425 0426 /** Todo View Action **/ 0427 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-tasks")), i18n("&To-do List"), this); 0428 action->setStatusTip(i18nc("@info:status", "To-do List View")); 0429 action->setToolTip(i18nc("@info:tooltip", "Switch to the To-do List View")); 0430 action->setWhatsThis(i18nc("@info:whatsthis", 0431 "Switches to the To-do List view, which provides a place for you to " 0432 "track tasks that need to be done.")); 0433 mACollection->addAction(QStringLiteral("view_todo"), action); 0434 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::showTodoView); 0435 0436 /** Journal View Action **/ 0437 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-journal")), i18n("&Journal"), this); 0438 action->setStatusTip(i18nc("@info:status", "Journal View")); 0439 action->setToolTip(i18nc("@info:tooltip", "Switch to the Journal View")); 0440 action->setWhatsThis(i18nc("@info:whatsthis", 0441 "Switches to the Journal View, which provides a place for you to record " 0442 "your reflections, occurrences or experiences.")); 0443 mACollection->addAction(QStringLiteral("view_journal"), action); 0444 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::showJournalView); 0445 0446 /** Timeline View Action **/ 0447 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-timeline")), i18n("Time&line"), this); 0448 action->setStatusTip(i18nc("@info:status", "Timeline View")); 0449 action->setToolTip(i18nc("@info:tooltip", "Switch to the Timeline View")); 0450 action->setWhatsThis(i18nc("@info:whatsthis", 0451 "Switches to the Timeline View, which shows all events for the selected " 0452 "timespan in a Gantt view. Each calendar is displayed in a separate line.")); 0453 mACollection->addAction(QStringLiteral("view_timeline"), action); 0454 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::showTimeLineView); 0455 0456 //~~~~~~~~~~~~~~~~~~~~~~~~~~~ REFRESH ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0457 0458 /** Refresh Action **/ 0459 // TODO: icon 0460 action = new QAction(i18n("&Refresh"), this); 0461 action->setStatusTip(i18nc("@info:status", "Refresh")); 0462 action->setToolTip(i18nc("@info:tooltip", "Refresh the display")); 0463 action->setWhatsThis(i18nc("@info:whatsthis", 0464 "This action will refresh and redraw the current calendar view. " 0465 "It does not sync or update any calendar folders.")); 0466 mACollection->addAction(QStringLiteral("update"), action); 0467 connect(action, &QAction::triggered, mCalendarView, qOverload<>(&CalendarView::updateView)); 0468 0469 //~~~~~~~~~~~~~~~~~~~~~~~~~~~ FILTER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0470 0471 /** Filter Action **/ 0472 // TODO: icon 0473 mFilterAction = new KSelectAction(i18n("F&ilter"), this); 0474 mFilterAction->setStatusTip(i18nc("@info:status", "Filter incidences")); 0475 mFilterAction->setToolTip(i18nc("@info:tooltip", "Filter incidences from the calendar")); 0476 mFilterAction->setWhatsThis(i18nc("@info:whatsthis", 0477 "Runs user-defined view filters on the calendar collection. Filters must be " 0478 "created first. See \"Manage View Filters\" option in the Settings menu.")); 0479 mFilterAction->setToolBarMode(KSelectAction::MenuMode); 0480 mACollection->addAction(QStringLiteral("filter_select"), mFilterAction); 0481 mFilterAction->setEditable(false); 0482 0483 connect(mFilterAction, &KSelectAction::indexTriggered, mCalendarView, &CalendarView::filterActivated); 0484 connect(mCalendarView, &CalendarView::filtersUpdated, this, &ActionManager::setItems); 0485 connect(mCalendarView, &CalendarView::filterChanged, this, &ActionManager::setTitle); 0486 0487 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ZOOM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0488 // TODO: try to find / create better icons for the following 4 actions 0489 action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-in")), i18n("In Horizontally"), this); 0490 action->setEnabled(mCalendarView->currentView()->supportsZoom()); 0491 mACollection->addAction(QStringLiteral("zoom_in_horizontally"), action); 0492 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::zoomInHorizontally); 0493 0494 action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-out")), i18n("Out Horizontally"), this); 0495 action->setEnabled(mCalendarView->currentView()->supportsZoom()); 0496 mACollection->addAction(QStringLiteral("zoom_out_horizontally"), action); 0497 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::zoomOutHorizontally); 0498 0499 action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-in")), i18n("In Vertically"), this); 0500 action->setEnabled(mCalendarView->currentView()->supportsZoom()); 0501 mACollection->addAction(QStringLiteral("zoom_in_vertically"), action); 0502 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::zoomInVertically); 0503 0504 action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-out")), i18n("Out Vertically"), this); 0505 action->setEnabled(mCalendarView->currentView()->supportsZoom()); 0506 mACollection->addAction(QStringLiteral("zoom_out_vertically"), action); 0507 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::zoomOutVertically); 0508 0509 /************************** Actions MENU *********************************/ 0510 bool isRTL = QApplication::isRightToLeft(); 0511 0512 /** Scroll to Today Action **/ 0513 action = new QAction(QIcon::fromTheme(QStringLiteral("go-jump-today")), i18nc("@action Jump to today", "To &Today"), this); 0514 action->setIconText(i18n("Today")); 0515 action->setStatusTip(i18nc("@info:status", "Scroll to Today")); 0516 action->setToolTip(i18nc("@info:tooltip", "Scroll the view to today")); 0517 action->setWhatsThis(i18nc("@info:whatsthis", "Scrolls the current view to the today's date.")); 0518 mACollection->addAction(QStringLiteral("go_today"), action); 0519 connect(action, &QAction::triggered, mCalendarView, &CalendarView::goToday); 0520 0521 /** Scroll Backward Action **/ 0522 action = new QAction(QIcon::fromTheme(isRTL ? QStringLiteral("go-next") : QStringLiteral("go-previous")), i18nc("scroll backward", "&Backward"), this); 0523 action->setIconText(i18nc("scroll backward", "Back")); 0524 action->setStatusTip(i18nc("@info:status", "Scroll Backward")); 0525 action->setToolTip(i18nc("@info:tooltip", "Scroll the view backward")); 0526 action->setWhatsThis(i18nc("@info:whatsthis", 0527 "Scrolls backward by a day, week, month or year, depending on the " 0528 "current calendar view.")); 0529 mACollection->addAction(QStringLiteral("go_previous"), action); 0530 connect(action, &QAction::triggered, mCalendarView, &CalendarView::goPrevious); 0531 0532 /** Scroll Forward Action **/ 0533 action = new QAction(QIcon::fromTheme(isRTL ? QStringLiteral("go-previous") : QStringLiteral("go-next")), i18nc("scroll forward", "&Forward"), this); 0534 action->setIconText(i18nc("scroll forward", "Forward")); 0535 action->setStatusTip(i18nc("@info:status", "Scroll Forward")); 0536 action->setToolTip(i18nc("@info:tooltip", "Scroll the view forward")); 0537 action->setWhatsThis(i18nc("@info:whatsthis", 0538 "Scrolls forward by a day, week, month or year, depending on the " 0539 "current calendar view.")); 0540 mACollection->addAction(QStringLiteral("go_next"), action); 0541 connect(action, &QAction::triggered, mCalendarView, &CalendarView::goNext); 0542 0543 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-day")), i18n("&Day"), this); 0544 mACollection->addAction(QStringLiteral("select_day"), action); 0545 action->setEnabled(mCalendarView->currentView()->supportsDateRangeSelection()); 0546 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::selectDay); 0547 0548 mNextXDays = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-upcoming-days")), QString(), this); 0549 mNextXDays->setEnabled(mCalendarView->currentView()->supportsDateRangeSelection()); 0550 mACollection->addAction(QStringLiteral("select_nextx"), mNextXDays); 0551 connect(mNextXDays, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::selectNextX); 0552 mNextXDays->setText(i18np("&Next Day", "&Next %1 Days", KOPrefs::instance()->mNextXDays)); 0553 0554 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-workweek")), i18n("W&ork Week"), this); 0555 action->setEnabled(mCalendarView->currentView()->supportsDateRangeSelection()); 0556 mACollection->addAction(QStringLiteral("select_workweek"), action); 0557 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::selectWorkWeek); 0558 0559 action = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-week")), i18n("&Week"), this); 0560 action->setEnabled(mCalendarView->currentView()->supportsDateRangeSelection()); 0561 mACollection->addAction(QStringLiteral("select_week"), action); 0562 connect(action, &QAction::triggered, mCalendarView->viewManager(), &KOViewManager::selectWeek); 0563 0564 /************************** Actions MENU *********************************/ 0565 /** New Event Action **/ 0566 mNewEventAction = new QAction(QIcon::fromTheme(QStringLiteral("appointment-new")), i18n("New E&vent..."), this); 0567 mNewEventAction->setStatusTip(i18nc("@info:status", "Create a new Event")); 0568 mNewEventAction->setToolTip(i18nc("@info:tooltip", "Create a new Event")); 0569 mNewEventAction->setWhatsThis(i18nc("@info:whatsthis", 0570 "Starts a dialog that allows you to create a new Event with reminders, " 0571 "attendees, recurrences and much more.")); 0572 mACollection->addAction(QStringLiteral("new_event"), mNewEventAction); 0573 connect(mNewEventAction, &QAction::triggered, this, &ActionManager::slotNewEvent); 0574 0575 /** New To-do Action **/ 0576 mNewTodoAction = new QAction(QIcon::fromTheme(QStringLiteral("task-new")), i18n("New &To-do..."), this); 0577 mNewTodoAction->setStatusTip(i18nc("@info:status", "Create a new To-do")); 0578 mNewTodoAction->setToolTip(i18nc("@info:tooltip", "Create a new To-do")); 0579 mNewTodoAction->setWhatsThis(i18nc("@info:whatsthis", 0580 "Starts a dialog that allows you to create a new To-do with reminders, " 0581 "attendees, recurrences and much more.")); 0582 mACollection->addAction(QStringLiteral("new_todo"), mNewTodoAction); 0583 connect(mNewTodoAction, &QAction::triggered, this, &ActionManager::slotNewTodo); 0584 0585 /** New Sub-To-do Action **/ 0586 // TODO: icon 0587 mNewSubtodoAction = new QAction(i18n("New Su&b-to-do..."), this); 0588 // TODO: statustip, tooltip, whatsthis 0589 mACollection->addAction(QStringLiteral("new_subtodo"), mNewSubtodoAction); 0590 connect(mNewSubtodoAction, &QAction::triggered, this, &ActionManager::slotNewSubTodo); 0591 mNewSubtodoAction->setEnabled(false); 0592 connect(mCalendarView, &CalendarView::todoSelected, mNewSubtodoAction, &QAction::setEnabled); 0593 0594 /** New Journal Action **/ 0595 mNewJournalAction = new QAction(QIcon::fromTheme(QStringLiteral("journal-new")), i18n("New &Journal..."), this); 0596 mNewJournalAction->setStatusTip(i18nc("@info:status", "Create a new Journal")); 0597 mNewJournalAction->setToolTip(i18nc("@info:tooltip", "Create a new Journal")); 0598 mNewJournalAction->setWhatsThis(i18nc("@info:whatsthis", "Starts a dialog that allows you to create a new Journal entry.")); 0599 mACollection->addAction(QStringLiteral("new_journal"), mNewJournalAction); 0600 connect(mNewJournalAction, &QAction::triggered, this, &ActionManager::slotNewJournal); 0601 0602 /** Configure Current View Action **/ 0603 mConfigureViewAction = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure View..."), this); 0604 mConfigureViewAction->setIconText(i18n("Configure")); 0605 mConfigureViewAction->setStatusTip(i18nc("@info:status", "Configure the view")); 0606 mConfigureViewAction->setToolTip(i18nc("@info:tooltip", "Configure the current view")); 0607 mConfigureViewAction->setWhatsThis(i18nc("@info:whatsthis", 0608 "Starts a configuration dialog that allows you to change the settings " 0609 "for the current calendar view.")); 0610 mConfigureViewAction->setEnabled(mCalendarView->currentView() && mCalendarView->currentView()->hasConfigurationDialog()); 0611 mACollection->addAction(QStringLiteral("configure_view"), mConfigureViewAction); 0612 connect(mConfigureViewAction, &QAction::triggered, mCalendarView, &CalendarView::configureCurrentView); 0613 0614 mShowIncidenceAction = new QAction(QIcon::fromTheme(QStringLiteral("document-preview")), i18n("&Show"), this); 0615 mACollection->addAction(QStringLiteral("show_incidence"), mShowIncidenceAction); 0616 connect(mShowIncidenceAction, &QAction::triggered, mCalendarView, qOverload<>(&CalendarView::showIncidence)); 0617 0618 mEditIncidenceAction = new QAction(QIcon::fromTheme(QStringLiteral("document-edit")), i18n("&Edit..."), this); 0619 mACollection->addAction(QStringLiteral("edit_incidence"), mEditIncidenceAction); 0620 connect(mEditIncidenceAction, &QAction::triggered, mCalendarView, qOverload<>(&CalendarView::editIncidence)); 0621 0622 mDeleteIncidenceAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("&Delete"), this); 0623 mACollection->addAction(QStringLiteral("delete_incidence"), mDeleteIncidenceAction); 0624 connect(mDeleteIncidenceAction, &QAction::triggered, mCalendarView, qOverload<>(&CalendarView::deleteIncidence)); 0625 mACollection->setDefaultShortcut(mDeleteIncidenceAction, QKeySequence(Qt::Key_Delete)); 0626 0627 action = new QAction(i18n("&Make Sub-to-do Independent"), this); 0628 mACollection->addAction(QStringLiteral("unsub_todo"), action); 0629 connect(action, &QAction::triggered, mCalendarView, &CalendarView::todo_unsub); 0630 action->setEnabled(false); 0631 connect(mCalendarView, &CalendarView::subtodoSelected, action, &QAction::setEnabled); 0632 0633 // TODO: Add item to quickly toggle the reminder of a given incidence 0634 // mToggleAlarmAction = new KToggleAction( i18n( "&Activate Reminder" ), 0, 0635 // mCalendarView, SLOT(toggleAlarm()), 0636 // mACollection, "activate_alarm" ); 0637 0638 /************************** SCHEDULE MENU ********************************/ 0639 mPublishEvent = new QAction(QIcon::fromTheme(QStringLiteral("mail-send")), i18n("&Publish Item Information..."), this); 0640 mACollection->addAction(QStringLiteral("schedule_publish"), mPublishEvent); 0641 connect(mPublishEvent, &QAction::triggered, this, [this](bool) { 0642 mCalendarView->schedule_publish(); 0643 }); 0644 mPublishEvent->setEnabled(false); 0645 0646 mSendInvitation = new QAction(QIcon::fromTheme(QStringLiteral("mail-send")), i18n("Send &Invitation to Attendees"), this); 0647 mACollection->addAction(QStringLiteral("schedule_request"), mSendInvitation); 0648 connect(mSendInvitation, &QAction::triggered, this, [this](bool) { 0649 mCalendarView->schedule_request(); 0650 }); 0651 mSendInvitation->setEnabled(false); 0652 connect(mCalendarView, &CalendarView::organizerEventsSelected, mSendInvitation, &QAction::setEnabled); 0653 0654 mRequestUpdate = new QAction(i18n("Re&quest Update"), this); 0655 mACollection->addAction(QStringLiteral("schedule_refresh"), mRequestUpdate); 0656 connect(mRequestUpdate, &QAction::triggered, this, [this](bool) { 0657 mCalendarView->schedule_refresh(); 0658 }); 0659 mRequestUpdate->setEnabled(false); 0660 connect(mCalendarView, &CalendarView::groupEventsSelected, mRequestUpdate, &QAction::setEnabled); 0661 0662 mSendCancel = new QAction(i18n("Send &Cancellation to Attendees"), this); 0663 mACollection->addAction(QStringLiteral("schedule_cancel"), mSendCancel); 0664 connect(mSendCancel, &QAction::triggered, this, [this](bool) { 0665 mCalendarView->schedule_cancel(); 0666 }); 0667 mSendCancel->setEnabled(false); 0668 connect(mCalendarView, &CalendarView::organizerEventsSelected, mSendCancel, &QAction::setEnabled); 0669 0670 mSendStatusUpdate = new QAction(QIcon::fromTheme(QStringLiteral("mail-reply-sender")), i18n("Send Status &Update"), this); 0671 mACollection->addAction(QStringLiteral("schedule_reply"), mSendStatusUpdate); 0672 connect(mSendStatusUpdate, &QAction::triggered, this, [this](bool) { 0673 mCalendarView->schedule_reply(); 0674 }); 0675 mSendStatusUpdate->setEnabled(false); 0676 connect(mCalendarView, &CalendarView::groupEventsSelected, mSendStatusUpdate, &QAction::setEnabled); 0677 0678 mRequestChange = new QAction(i18nc("counter proposal", "Request Chan&ge"), this); 0679 mACollection->addAction(QStringLiteral("schedule_counter"), mRequestChange); 0680 connect(mRequestChange, &QAction::triggered, this, [this](bool) { 0681 mCalendarView->schedule_counter(); 0682 }); 0683 mRequestChange->setEnabled(false); 0684 connect(mCalendarView, &CalendarView::groupEventsSelected, mRequestChange, &QAction::setEnabled); 0685 0686 action = new QAction(i18n("&Mail Free Busy Information..."), this); 0687 mACollection->addAction(QStringLiteral("mail_freebusy"), action); 0688 connect(action, &QAction::triggered, mCalendarView, &CalendarView::mailFreeBusy); 0689 action->setEnabled(true); 0690 0691 mForwardEvent = new QAction(QIcon::fromTheme(QStringLiteral("mail-forward")), i18n("&Send as iCalendar..."), this); 0692 mACollection->addAction(QStringLiteral("schedule_forward"), mForwardEvent); 0693 connect(mForwardEvent, &QAction::triggered, this, [this](bool) { 0694 mCalendarView->schedule_forward(); 0695 }); 0696 mForwardEvent->setEnabled(false); 0697 0698 action = new QAction(i18n("&Upload Free Busy Information"), this); 0699 mACollection->addAction(QStringLiteral("upload_freebusy"), action); 0700 connect(action, &QAction::triggered, mCalendarView, &CalendarView::uploadFreeBusy); 0701 action->setEnabled(true); 0702 0703 if (!mIsPart) { 0704 action = new QAction(QIcon::fromTheme(QStringLiteral("help-contents")), i18n("&Address Book"), this); 0705 mACollection->addAction(QStringLiteral("addressbook"), action); 0706 connect(action, &QAction::triggered, mCalendarView, &CalendarView::openAddressbook); 0707 } 0708 0709 /************************** SETTINGS MENU ********************************/ 0710 0711 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIDEBAR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0712 mDateNavigatorShowAction = new KToggleAction(i18n("Show Date Navigator"), this); 0713 mACollection->addAction(QStringLiteral("show_datenavigator"), mDateNavigatorShowAction); 0714 connect(mDateNavigatorShowAction, &KToggleAction::triggered, this, &ActionManager::toggleDateNavigator); 0715 0716 mTodoViewShowAction = new KToggleAction(i18n("Show To-do View"), this); 0717 mACollection->addAction(QStringLiteral("show_todoview"), mTodoViewShowAction); 0718 connect(mTodoViewShowAction, &KToggleAction::triggered, this, &ActionManager::toggleTodoView); 0719 0720 mEventViewerShowAction = new KToggleAction(i18n("Show Item Viewer"), this); 0721 mACollection->addAction(QStringLiteral("show_eventviewer"), mEventViewerShowAction); 0722 connect(mEventViewerShowAction, &KToggleAction::triggered, this, &ActionManager::toggleEventViewer); 0723 0724 KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Settings")); 0725 mDateNavigatorShowAction->setChecked(config.readEntry("DateNavigatorVisible", true)); 0726 // if we are a kpart, then let's not show the todo in the left pane by 0727 // default since there's also a Todo part and we'll assume they'll be 0728 // using that as well, so let's not duplicate it (by default) here 0729 mTodoViewShowAction->setChecked(config.readEntry("TodoViewVisible", false)); // mIsPart ? false : true ) ); 0730 mEventViewerShowAction->setChecked(config.readEntry("EventViewerVisible", true)); 0731 toggleDateNavigator(); 0732 toggleTodoView(); 0733 toggleEventViewer(); 0734 0735 if (!mMainWindow->hasDocument()) { 0736 mCollectionViewShowAction = new KToggleAction(i18n("Show Calendar Manager"), this); 0737 mACollection->addAction(QStringLiteral("show_resourceview"), mCollectionViewShowAction); 0738 connect(mCollectionViewShowAction, &KToggleAction::triggered, this, &ActionManager::toggleResourceView); 0739 mCollectionViewShowAction->setChecked(config.readEntry("ResourceViewVisible", true)); 0740 0741 toggleResourceView(); 0742 } 0743 0744 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIDEBAR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0745 mShowMenuBarAction = KStandardAction::showMenubar(this, &ActionManager::toggleMenubar, mACollection); 0746 mShowMenuBarAction->setChecked(KOPrefs::instance()->showMenuBar()); 0747 toggleMenubar(true); 0748 0749 action = new QAction(i18n("Configure &Date && Time..."), this); 0750 mACollection->addAction(QStringLiteral("conf_datetime"), action); 0751 connect(action, &QAction::triggered, this, &ActionManager::configureDateTime); 0752 0753 action = new QAction(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("Manage View &Filters..."), this); 0754 mACollection->addAction(QStringLiteral("edit_filters"), action); 0755 connect(action, &QAction::triggered, mCalendarView, &CalendarView::editFilters); 0756 0757 action = new QAction(i18n("Manage T&ags..."), this); 0758 mACollection->addAction(QStringLiteral("edit_categories"), action); 0759 connect(action, &QAction::triggered, mCalendarView->dialogManager(), &KODialogManager::showCategoryEditDialog); 0760 0761 auto manager = new KColorSchemeManager(this); 0762 mACollection->addAction(QStringLiteral("colorscheme_menu"), KColorSchemeMenu::createMenu(manager, this)); 0763 0764 if (mIsPart) { 0765 action = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("&Configure KOrganizer..."), this); 0766 mACollection->addAction(QStringLiteral("korganizer_configure"), action); 0767 connect(action, &QAction::triggered, mCalendarView, &CalendarView::edit_options); 0768 mACollection->addAction(KStandardAction::KeyBindings, QStringLiteral("korganizer_configure_shortcuts"), this, &ActionManager::keyBindings); 0769 } else { 0770 KStandardAction::preferences(mCalendarView, &CalendarView::edit_options, mACollection); 0771 KStandardAction::keyBindings(this, &ActionManager::keyBindings, mACollection); 0772 } 0773 if (mMenuBar) { 0774 mHamburgerMenu = KStandardAction::hamburgerMenu(nullptr, nullptr, mACollection); 0775 mHamburgerMenu->setShowMenuBarAction(mShowMenuBarAction); 0776 mHamburgerMenu->setMenuBar(mMenuBar); 0777 connect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, [this]() { 0778 updateHamburgerMenu(); 0779 // Immediately disconnect. We only need to run this once, but on demand. 0780 // NOTE: The nullptr at the end disconnects all connections between 0781 // q and mHamburgerMenu's aboutToShowMenu signal. 0782 disconnect(mHamburgerMenu, &KHamburgerMenu::aboutToShowMenu, this, nullptr); 0783 }); 0784 } 0785 } 0786 0787 void ActionManager::updateHamburgerMenu() 0788 { 0789 auto menu = new QMenu; 0790 0791 menu->addAction(mACollection->action(QStringLiteral("conf_datetime"))); 0792 menu->addSeparator(); 0793 menu->addAction(mACollection->action(KStandardAction::name(KStandardAction::Print))); 0794 menu->addSeparator(); 0795 menu->addAction(mACollection->action(KStandardAction::name(KStandardAction::Quit))); 0796 mHamburgerMenu->setMenu(menu); 0797 } 0798 0799 void ActionManager::setItems(const QStringList &lst, int idx) 0800 { 0801 mFilterAction->setItems(lst); 0802 mFilterAction->setCurrentItem(idx); 0803 } 0804 0805 void ActionManager::slotResourcesAddedRemoved() 0806 { 0807 restoreCollectionViewSetting(); 0808 } 0809 0810 void ActionManager::slotDefaultResourceChanged(const Akonadi::Collection &collection) 0811 { 0812 mCalendarView->incidenceChanger()->setDefaultCollection(collection); 0813 } 0814 0815 void ActionManager::slotNewEvent() 0816 { 0817 mCalendarView->newEvent(); 0818 } 0819 0820 void ActionManager::slotNewTodo() 0821 { 0822 mCalendarView->newTodo(selectedCollection()); 0823 } 0824 0825 void ActionManager::slotNewSubTodo() 0826 { 0827 mCalendarView->newSubTodo(selectedCollection()); 0828 } 0829 0830 void ActionManager::slotNewJournal() 0831 { 0832 mCalendarView->newJournal(selectedCollection()); 0833 } 0834 0835 void ActionManager::slotMergeFinished(bool success, int total) 0836 { 0837 Q_ASSERT(sender()); 0838 mImportAction->setEnabled(true); 0839 auto importer = qobject_cast<Akonadi::ICalImporter *>(sender()); 0840 0841 if (success) { 0842 mCalendarView->showMessage(i18np("1 incidence was imported successfully.", "%1 incidences were imported successfully.", total), 0843 KMessageWidget::Information); 0844 } else { 0845 mCalendarView->showMessage(i18n("There was an error while merging the calendar: %1", importer->errorMessage()), KMessageWidget::Error); 0846 } 0847 sender()->deleteLater(); 0848 } 0849 0850 void ActionManager::slotNewResourceFinished(bool success) 0851 { 0852 Q_ASSERT(sender()); 0853 auto importer = qobject_cast<Akonadi::ICalImporter *>(sender()); 0854 mImportAction->setEnabled(true); 0855 if (success) { 0856 mCalendarView->showMessage(i18n("New calendar added successfully"), KMessageWidget::Information); 0857 } else { 0858 mCalendarView->showMessage(i18n("Could not add a calendar. Error: %1", importer->errorMessage()), KMessageWidget::Error); 0859 } 0860 sender()->deleteLater(); 0861 } 0862 0863 void ActionManager::readSettings() 0864 { 0865 // read settings from the KConfig, supplying reasonable 0866 // defaults where none are to be found 0867 0868 mCalendarView->readSettings(); 0869 restoreCollectionViewSetting(); 0870 } 0871 0872 void ActionManager::restoreCollectionViewSetting() 0873 { 0874 mCollectionSelectionModelStateSaver->restoreState(); 0875 mCollectionViewStateSaver->restoreState(); 0876 } 0877 0878 void ActionManager::writeSettings() 0879 { 0880 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0881 KConfigGroup group = config->group(QStringLiteral("Settings")); 0882 mCalendarView->writeSettings(); 0883 0884 if (mDateNavigatorShowAction) { 0885 group.writeEntry("DateNavigatorVisible", mDateNavigatorShowAction->isChecked()); 0886 } 0887 0888 if (mTodoViewShowAction) { 0889 group.writeEntry("TodoViewVisible", mTodoViewShowAction->isChecked()); 0890 } 0891 0892 if (mCollectionViewShowAction) { 0893 group.writeEntry("ResourceViewVisible", mCollectionViewShowAction->isChecked()); 0894 } 0895 0896 if (mEventViewerShowAction) { 0897 group.writeEntry("EventViewerVisible", mEventViewerShowAction->isChecked()); 0898 } 0899 0900 mCollectionViewStateSaver->saveState(); 0901 mCollectionSelectionModelStateSaver->saveState(); 0902 0903 KConfigGroup selectionViewGroup = config->group(QStringLiteral("GlobalCollectionView")); 0904 KConfigGroup selectionGroup = config->group(QStringLiteral("GlobalCollectionSelection")); 0905 selectionGroup.sync(); 0906 selectionViewGroup.sync(); 0907 config->sync(); 0908 } 0909 0910 void ActionManager::file_open() 0911 { 0912 const QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); 0913 const QUrl dir = QUrl::fromLocalFile(defaultPath + QLatin1StringView("/korganizer/")); 0914 const QUrl url = 0915 QFileDialog::getOpenFileUrl(dialogParent(), i18nc("@title:window", "Select Calendar File to Open"), dir, QStringLiteral("text/calendar (*.ics *.vcs)")); 0916 0917 if (!url.isEmpty()) { // isEmpty if user canceled the dialog 0918 file_open(url); 0919 } 0920 } 0921 0922 void ActionManager::file_open(const QUrl &url) 0923 { 0924 // is that URL already opened somewhere else? Activate that window 0925 KOrg::MainWindow *korg = ActionManager::findInstance(url); 0926 if ((nullptr != korg) && (korg != mMainWindow)) { 0927 #if KDEPIM_HAVE_X11 0928 KWindowSystem::activateWindow(korg->topLevelWidget()->windowHandle()); 0929 #endif 0930 return; 0931 } 0932 0933 qCDebug(KORGANIZER_LOG) << url.toDisplayString(); 0934 0935 importCalendar(url); 0936 } 0937 0938 void ActionManager::file_import() 0939 { 0940 const QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); 0941 const QUrl dir = QUrl::fromLocalFile(defaultPath + QLatin1StringView("/korganizer/")); 0942 const QUrl url = QFileDialog::getOpenFileUrl(dialogParent(), 0943 i18nc("@title:window", "Select Calendar File to Import"), 0944 dir, 0945 QStringLiteral("text/calendar (*.ics *.vcs)")); 0946 0947 if (!url.isEmpty()) { // isEmpty if user canceled the dialog 0948 importCalendar(url); 0949 } 0950 } 0951 0952 void ActionManager::file_archive() 0953 { 0954 mCalendarView->archiveCalendar(); 0955 } 0956 0957 bool ActionManager::importURL(const QUrl &url, bool merge) 0958 { 0959 auto importer = new Akonadi::ICalImporter(); 0960 bool jobStarted; 0961 if (merge) { 0962 connect(importer, &Akonadi::ICalImporter::importIntoExistingFinished, this, &ActionManager::slotMergeFinished); 0963 jobStarted = importer->importIntoExistingResource(url, Akonadi::Collection()); 0964 } else { 0965 connect(importer, &Akonadi::ICalImporter::importIntoNewFinished, this, &ActionManager::slotNewResourceFinished); 0966 jobStarted = importer->importIntoNewResource(url.path()); 0967 } 0968 0969 if (jobStarted) { 0970 mImportAction->setEnabled(false); 0971 } else { 0972 // empty error message means user canceled. 0973 if (!importer->errorMessage().isEmpty()) { 0974 mCalendarView->showMessage(i18n("An error occurred: %1", importer->errorMessage()), KMessageWidget::Error); 0975 } 0976 } 0977 0978 return jobStarted; 0979 } 0980 0981 bool ActionManager::saveURL() 0982 { 0983 if (!mCalendarView->saveCalendar(mFile)) { 0984 qCDebug(KORGANIZER_LOG) << "calendar view save failed."; 0985 return false; 0986 } 0987 0988 if (!mURL.isLocalFile()) { 0989 auto job = KIO::file_copy(QUrl::fromLocalFile(mFile), mURL); 0990 KJobWidgets::setWindow(job, view()); 0991 if (!job->exec()) { 0992 const QString msg = i18n("Cannot upload calendar to '%1'", mURL.toDisplayString()); 0993 KMessageBox::error(dialogParent(), msg); 0994 return false; 0995 } 0996 } 0997 0998 mMainWindow->showStatusMessage(i18n("Saved calendar '%1'.", mURL.toDisplayString())); 0999 1000 return true; 1001 } 1002 1003 bool ActionManager::saveAsURL(const QUrl &url) 1004 { 1005 qCDebug(KORGANIZER_LOG) << url.toDisplayString(); 1006 1007 if (url.isEmpty()) { 1008 qCDebug(KORGANIZER_LOG) << "Empty URL."; 1009 return false; 1010 } 1011 if (!url.isValid()) { 1012 qCDebug(KORGANIZER_LOG) << "Malformed URL."; 1013 return false; 1014 } 1015 1016 QString fileOrig = mFile; 1017 QUrl URLOrig = mURL; 1018 1019 QTemporaryFile *tempFile = nullptr; 1020 if (url.isLocalFile()) { 1021 mFile = url.toLocalFile(); 1022 } else { 1023 tempFile = new QTemporaryFile; 1024 tempFile->setAutoRemove(false); 1025 tempFile->open(); 1026 mFile = tempFile->fileName(); 1027 } 1028 mURL = url; 1029 1030 bool success = saveURL(); // Save local file and upload local file 1031 if (success) { 1032 delete mTempFile; 1033 mTempFile = tempFile; 1034 setTitle(); 1035 } else { 1036 KMessageBox::error(dialogParent(), i18n("Unable to save calendar to the file %1.", mFile), i18nc("@title:window", "Error")); 1037 qCDebug(KORGANIZER_LOG) << "failed"; 1038 mURL = URLOrig; 1039 mFile = fileOrig; 1040 delete tempFile; 1041 } 1042 1043 return success; 1044 } 1045 1046 void ActionManager::saveProperties(KConfigGroup &config) 1047 { 1048 config.writeEntry("UseResourceCalendar", !mMainWindow->hasDocument()); 1049 if (mMainWindow->hasDocument()) { 1050 config.writePathEntry("Calendar", mURL.url()); 1051 } 1052 } 1053 1054 void ActionManager::readProperties(const KConfigGroup &) 1055 { 1056 mMainWindow->init(false); 1057 } 1058 1059 // Configuration changed as a result of the options dialog. 1060 void ActionManager::updateConfig() 1061 { 1062 mNextXDays->setText(i18np("&Next Day", "&Next %1 Days", KOPrefs::instance()->mNextXDays)); 1063 1064 KOCore::self()->reloadPlugins(); 1065 1066 #ifdef AKONADI_PORT_DISABLED // shouldn't be required anymore 1067 if (mCollectionView) { 1068 mCollectionView->updateView(); 1069 } 1070 #endif 1071 } 1072 1073 void ActionManager::configureDateTime() 1074 { 1075 QProcess proc; 1076 const QString program = QStringLiteral("kcmshell6"); 1077 QStringList arguments; 1078 arguments << QStringLiteral("formats") << QStringLiteral("translations") << QStringLiteral("clock"); 1079 1080 if (!proc.startDetached(program, arguments)) { 1081 KMessageBox::error(dialogParent(), i18n("Could not start control module for date and time format.")); 1082 } 1083 } 1084 1085 KOrg::MainWindow *ActionManager::findInstance(const QUrl &url) 1086 { 1087 if (mWindowList) { 1088 if (url.isEmpty()) { 1089 return mWindowList->defaultInstance(); 1090 } else { 1091 return mWindowList->findInstance(url); 1092 } 1093 } else { 1094 return nullptr; 1095 } 1096 } 1097 1098 bool ActionManager::openURL(const QString &url) 1099 { 1100 importCalendar(QUrl::fromLocalFile(url)); 1101 return true; 1102 } 1103 1104 void ActionManager::dumpText(const QString &str) 1105 { 1106 qCDebug(KORGANIZER_LOG) << str; 1107 } 1108 1109 void ActionManager::toggleDateNavigator() 1110 { 1111 bool visible = mDateNavigatorShowAction->isChecked(); 1112 if (mCalendarView) { 1113 mCalendarView->showDateNavigator(visible); 1114 } 1115 } 1116 1117 void ActionManager::toggleTodoView() 1118 { 1119 bool visible = mTodoViewShowAction->isChecked(); 1120 if (mCalendarView) { 1121 mCalendarView->showTodoView(visible); 1122 } 1123 } 1124 1125 void ActionManager::toggleEventViewer() 1126 { 1127 bool visible = mEventViewerShowAction->isChecked(); 1128 if (mCalendarView) { 1129 mCalendarView->showEventViewer(visible); 1130 } 1131 } 1132 1133 void ActionManager::toggleResourceView() 1134 { 1135 const bool visible = mCollectionViewShowAction->isChecked(); 1136 if (mCollectionView) { 1137 if (visible) { 1138 mCollectionView->show(); 1139 } else { 1140 mCollectionView->hide(); 1141 } 1142 } 1143 } 1144 1145 bool ActionManager::mergeURL(const QString &url) 1146 { 1147 return importURL(QUrl::fromLocalFile(url), true); 1148 } 1149 1150 bool ActionManager::saveAsURL(const QString &url) 1151 { 1152 return saveAsURL(QUrl::fromLocalFile(url)); 1153 } 1154 1155 QString ActionManager::getCurrentURLasString() const 1156 { 1157 return mURL.url(); 1158 } 1159 1160 bool ActionManager::editIncidence(Akonadi::Item::Id id) 1161 { 1162 return mCalendarView->editIncidence(id); 1163 } 1164 1165 bool ActionManager::showIncidence(Akonadi::Item::Id id) 1166 { 1167 return mCalendarView->showIncidence(id); 1168 } 1169 1170 bool ActionManager::showIncidenceContext(Akonadi::Item::Id id) 1171 { 1172 return mCalendarView->showIncidenceContext(id); 1173 } 1174 1175 void ActionManager::showIncidenceByUid(const QString &uid, const QDateTime &occurrence, const QString &xdgActivationToken) 1176 { 1177 mCalendarView->showIncidenceByUid(uid, occurrence.date()); 1178 mCalendarView->showDate(occurrence.date()); 1179 1180 KWindowSystem::setCurrentXdgActivationToken(xdgActivationToken); 1181 KOrg::MainWindow *mainWindow = ActionManager::findInstance(QUrl()); 1182 if (mainWindow) { 1183 KWindowSystem::activateWindow(mainWindow->topLevelWidget()->windowHandle()); 1184 mainWindow->topLevelWidget()->show(); 1185 mainWindow->topLevelWidget()->windowHandle()->raise(); 1186 } 1187 } 1188 1189 bool ActionManager::handleCommandLine(const QStringList &args) 1190 { 1191 QCommandLineParser parser; 1192 korganizer_options(&parser); 1193 parser.process(args); 1194 1195 KOrg::MainWindow *mainWindow = ActionManager::findInstance(QUrl()); 1196 1197 bool ret = true; 1198 1199 if (!mainWindow) { 1200 qCCritical(KORGANIZER_LOG) << "Unable to find default calendar resources view."; 1201 ret = false; 1202 } else if (parser.positionalArguments().isEmpty()) { 1203 // No filenames given => all other args are meaningless, show main Window 1204 mainWindow->topLevelWidget()->show(); 1205 } else { 1206 // Import, merge, or ask => we need the resource calendar window anyway. 1207 mainWindow->topLevelWidget()->show(); 1208 1209 // Check for import, merge or ask 1210 const QStringList argList = parser.positionalArguments(); 1211 if (parser.isSet(QStringLiteral("import"))) { 1212 for (const QString &url : argList) { 1213 importURL(QUrl::fromUserInput(url), /*merge=*/false); 1214 } 1215 } else if (parser.isSet(QStringLiteral("merge"))) { 1216 for (const QString &url : argList) { 1217 importURL(QUrl::fromUserInput(url), /*merge=*/true); 1218 } 1219 } else { 1220 for (const QString &url : argList) { 1221 mainWindow->actionManager()->importCalendar(QUrl::fromUserInput(url)); 1222 } 1223 } 1224 } 1225 return ret; 1226 } 1227 1228 bool ActionManager::deleteIncidence(Akonadi::Item::Id id, bool force) 1229 { 1230 return mCalendarView->deleteIncidence(id, force); 1231 } 1232 1233 bool ActionManager::addIncidence(const QString &ical) 1234 { 1235 return mCalendarView->addIncidence(ical); 1236 } 1237 1238 QString ActionManager::localFileName() const 1239 { 1240 return mFile; 1241 } 1242 1243 class ActionManager::ActionStringsVisitor : public KCalendarCore::Visitor 1244 { 1245 public: 1246 ActionStringsVisitor() = default; 1247 1248 bool act(KCalendarCore::IncidenceBase::Ptr incidence, QAction *show, QAction *edit, QAction *del) 1249 { 1250 mShow = show; 1251 mEdit = edit; 1252 mDelete = del; 1253 return incidence->accept(*this, incidence); 1254 } 1255 1256 protected: 1257 bool visit(const KCalendarCore::Event::Ptr &) override 1258 { 1259 if (mShow) { 1260 mShow->setText(i18n("&Show Event")); 1261 } 1262 if (mEdit) { 1263 mEdit->setText(i18n("&Edit Event...")); 1264 } 1265 if (mDelete) { 1266 mDelete->setText(i18n("&Delete Event")); 1267 } 1268 return true; 1269 } 1270 1271 bool visit(const KCalendarCore::Todo::Ptr &) override 1272 { 1273 if (mShow) { 1274 mShow->setText(i18n("&Show To-do")); 1275 } 1276 if (mEdit) { 1277 mEdit->setText(i18n("&Edit To-do...")); 1278 } 1279 if (mDelete) { 1280 mDelete->setText(i18n("&Delete To-do")); 1281 } 1282 return true; 1283 } 1284 1285 bool visit(const KCalendarCore::Journal::Ptr &) override 1286 { 1287 return assignDefaultStrings(); 1288 } 1289 1290 bool visit(const KCalendarCore::FreeBusy::Ptr &) override // to inhibit hidden virtual compile warning 1291 { 1292 return false; 1293 } 1294 1295 protected: 1296 bool assignDefaultStrings() 1297 { 1298 if (mShow) { 1299 mShow->setText(i18n("&Show")); 1300 } 1301 if (mEdit) { 1302 mEdit->setText(i18n("&Edit...")); 1303 } 1304 if (mDelete) { 1305 mDelete->setText(i18n("&Delete")); 1306 } 1307 return true; 1308 } 1309 1310 QAction *mShow = nullptr; 1311 QAction *mEdit = nullptr; 1312 QAction *mDelete = nullptr; 1313 }; 1314 1315 void ActionManager::processIncidenceSelection(const Akonadi::Item &item, QDate date) 1316 { 1317 // qCDebug(KORGANIZER_LOG) << "ActionManager::processIncidenceSelection()"; 1318 Q_UNUSED(date) 1319 1320 if (!item.isValid()) { 1321 enableIncidenceActions(false); 1322 return; 1323 } 1324 1325 const KCalendarCore::Incidence::Ptr incidence = Akonadi::CalendarUtils::incidence(item); 1326 if (!incidence) { 1327 enableIncidenceActions(false); 1328 return; 1329 } 1330 1331 enableIncidenceActions(true); 1332 1333 if (!mCalendarView->calendar()->hasRight(item, Akonadi::Collection::CanDeleteItem)) { 1334 mCutAction->setEnabled(false); 1335 mDeleteAction->setEnabled(false); 1336 } 1337 1338 ActionStringsVisitor v; 1339 if (!v.act(incidence, mShowIncidenceAction, mEditIncidenceAction, mDeleteIncidenceAction)) { 1340 mShowIncidenceAction->setText(i18n("&Show")); 1341 mEditIncidenceAction->setText(i18n("&Edit...")); 1342 mDeleteIncidenceAction->setText(i18n("&Delete")); 1343 } 1344 } 1345 1346 void ActionManager::enableIncidenceActions(bool enabled) 1347 { 1348 mShowIncidenceAction->setEnabled(enabled); 1349 mEditIncidenceAction->setEnabled(enabled); 1350 mDeleteIncidenceAction->setEnabled(enabled); 1351 1352 mCutAction->setEnabled(enabled); 1353 mCopyAction->setEnabled(enabled); 1354 mDeleteAction->setEnabled(enabled); 1355 mPublishEvent->setEnabled(enabled); 1356 mForwardEvent->setEnabled(enabled); 1357 mSendInvitation->setEnabled(enabled); 1358 mSendCancel->setEnabled(enabled); 1359 mSendStatusUpdate->setEnabled(enabled); 1360 mRequestChange->setEnabled(enabled); 1361 mRequestUpdate->setEnabled(enabled); 1362 } 1363 1364 Akonadi::Collection ActionManager::selectedCollection() const 1365 { 1366 const QModelIndex index = mCollectionView->view()->currentIndex(); 1367 if (!index.isValid()) { 1368 return {}; 1369 } 1370 1371 return index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>(); 1372 } 1373 1374 void ActionManager::keyBindings() 1375 { 1376 KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsDisallowed, view()); 1377 if (mMainWindow) { 1378 dlg.addCollection(mMainWindow->getActionCollection()); 1379 } 1380 1381 dlg.configure(); 1382 } 1383 1384 void ActionManager::setTitle() 1385 { 1386 mMainWindow->setTitle(); 1387 } 1388 1389 void ActionManager::openEventEditor(const QString &summary) 1390 { 1391 mCalendarView->newEvent(summary); 1392 } 1393 1394 void ActionManager::openEventEditor(const QString &summary, const QString &description, const QStringList &attachments) 1395 { 1396 mCalendarView->newEvent(summary, description, attachments); 1397 } 1398 1399 void ActionManager::openEventEditor(const QString &summary, const QString &description, const QStringList &attachments, const QStringList &attendees) 1400 { 1401 mCalendarView->newEvent(summary, description, attachments, attendees); 1402 } 1403 1404 void ActionManager::openEventEditor(const QString &summary, 1405 const QString &description, 1406 const QString &uri, 1407 const QString &file, 1408 const QStringList &attendees, 1409 const QString &attachmentMimetype) 1410 { 1411 int action = IncidenceEditorNG::IncidenceEditorSettings::self()->defaultEmailAttachMethod(); 1412 if (attachmentMimetype != QLatin1StringView("message/rfc822")) { 1413 action = IncidenceEditorNG::IncidenceEditorSettings::Link; 1414 } else if (file.isEmpty()) { 1415 action = KOPrefs::TodoAttachLink; 1416 } else if (IncidenceEditorNG::IncidenceEditorSettings::self()->defaultEmailAttachMethod() == IncidenceEditorNG::IncidenceEditorSettings::Ask) { 1417 auto menu = new QMenu(nullptr); 1418 QAction *attachLink = menu->addAction(i18n("Attach as &link")); 1419 QAction *attachInline = menu->addAction(i18n("Attach &inline")); 1420 QAction *attachBody = menu->addAction(i18n("Attach inline &without attachments")); 1421 menu->addSeparator(); 1422 menu->addAction(QIcon::fromTheme(QStringLiteral("dialog-cancel")), i18n("C&ancel")); 1423 1424 QAction *ret = menu->exec(QCursor::pos()); 1425 delete menu; 1426 1427 if (ret == attachLink) { 1428 action = IncidenceEditorNG::IncidenceEditorSettings::Link; 1429 } else if (ret == attachInline) { 1430 action = IncidenceEditorNG::IncidenceEditorSettings::InlineFull; 1431 } else if (ret == attachBody) { 1432 action = IncidenceEditorNG::IncidenceEditorSettings::InlineBody; 1433 } else { 1434 return; 1435 } 1436 } 1437 1438 QString attData; 1439 QTemporaryFile tf; 1440 tf.setAutoRemove(true); 1441 switch (action) { 1442 case IncidenceEditorNG::IncidenceEditorSettings::Link: 1443 attData = uri; 1444 break; 1445 case IncidenceEditorNG::IncidenceEditorSettings::InlineFull: 1446 attData = file; 1447 break; 1448 case IncidenceEditorNG::IncidenceEditorSettings::InlineBody: { 1449 QFile f(file); 1450 if (!f.open(QFile::ReadOnly)) { 1451 return; 1452 } 1453 auto msg = new KMime::Message(); 1454 msg->setContent(f.readAll()); 1455 msg->parse(); 1456 if (msg == msg->textContent() || msg->textContent() == nullptr) { // no attachments 1457 attData = file; 1458 } else { 1459 if (KMessageBox::warningContinueCancel(nullptr, 1460 i18n("Removing attachments from an email might invalidate its signature."), 1461 i18nc("@title:window", "Remove Attachments"), 1462 KStandardGuiItem::cont(), 1463 KStandardGuiItem::cancel(), 1464 QStringLiteral("BodyOnlyInlineAttachment")) 1465 != KMessageBox::Continue) { 1466 delete msg; 1467 return; 1468 } 1469 auto newMsg = new KMime::Message(); 1470 newMsg->setHead(msg->head()); 1471 newMsg->setBody(msg->textContent()->body()); 1472 newMsg->parse(); 1473 newMsg->contentTransferEncoding()->from7BitString(msg->textContent()->contentTransferEncoding()->as7BitString()); 1474 newMsg->contentType()->from7BitString(msg->textContent()->contentType()->as7BitString()); 1475 newMsg->assemble(); 1476 tf.write(newMsg->encodedContent()); 1477 attData = tf.fileName(); 1478 } 1479 tf.close(); 1480 delete msg; 1481 break; 1482 } 1483 default: 1484 return; 1485 } 1486 1487 mCalendarView->newEvent(summary, 1488 description, 1489 QStringList(attData), 1490 attendees, 1491 QStringList(attachmentMimetype), 1492 action != IncidenceEditorNG::IncidenceEditorSettings::Link); 1493 } 1494 1495 void ActionManager::openTodoEditor(const QString &text) 1496 { 1497 mCalendarView->newTodo(text); 1498 } 1499 1500 void ActionManager::openTodoEditor(const QString &summary, const QString &description, const QStringList &attachments) 1501 { 1502 mCalendarView->newTodo(summary, description, attachments); 1503 } 1504 1505 void ActionManager::openTodoEditor(const QString &summary, const QString &description, const QStringList &attachments, const QStringList &attendees) 1506 { 1507 mCalendarView->newTodo(summary, description, attachments, attendees); 1508 } 1509 1510 void ActionManager::openTodoEditor(const QString &summary, 1511 const QString &description, 1512 const QString &uri, 1513 const QString &file, 1514 const QStringList &attendees, 1515 const QString &attachmentMimetype) 1516 { 1517 int action = KOPrefs::instance()->defaultTodoAttachMethod(); 1518 if (attachmentMimetype != QLatin1StringView("message/rfc822")) { 1519 action = KOPrefs::TodoAttachLink; 1520 } else if (file.isEmpty()) { 1521 action = KOPrefs::TodoAttachLink; 1522 } else if (KOPrefs::instance()->defaultTodoAttachMethod() == KOPrefs::TodoAttachAsk) { 1523 auto menu = new QMenu(nullptr); 1524 QAction *attachLink = menu->addAction(i18n("Attach as &link")); 1525 QAction *attachInline = menu->addAction(i18n("Attach &inline")); 1526 menu->addSeparator(); 1527 menu->addAction(QIcon::fromTheme(QStringLiteral("dialog-cancel")), i18n("C&ancel")); 1528 1529 QAction *ret = menu->exec(QCursor::pos()); 1530 delete menu; 1531 1532 if (ret == attachLink) { 1533 action = KOPrefs::TodoAttachLink; 1534 } else if (ret == attachInline) { 1535 action = KOPrefs::TodoAttachInlineFull; 1536 } else { 1537 return; 1538 } 1539 } 1540 1541 QString attData; 1542 switch (action) { 1543 case KOPrefs::TodoAttachLink: 1544 attData = uri; 1545 break; 1546 case KOPrefs::TodoAttachInlineFull: 1547 attData = file; 1548 break; 1549 default: 1550 return; 1551 } 1552 1553 mCalendarView->newTodo(summary, description, QStringList(attData), attendees, QStringList(attachmentMimetype), action != KOPrefs::TodoAttachLink); 1554 } 1555 1556 void ActionManager::openJournalEditor(QDate date) 1557 { 1558 mCalendarView->newJournal(date); 1559 } 1560 1561 void ActionManager::openJournalEditor(const QString &text, QDate date) 1562 { 1563 mCalendarView->newJournal(text, date); 1564 } 1565 1566 void ActionManager::openJournalEditor(const QString &text) 1567 { 1568 mCalendarView->newJournal(text); 1569 } 1570 1571 void ActionManager::showJournalView() 1572 { 1573 mCalendarView->viewManager()->showJournalView(); 1574 } 1575 1576 void ActionManager::showTodoView() 1577 { 1578 mCalendarView->viewManager()->showTodoView(); 1579 } 1580 1581 void ActionManager::showEventView() 1582 { 1583 mCalendarView->viewManager()->showEventView(); 1584 } 1585 1586 void ActionManager::goDate(QDate date) 1587 { 1588 mCalendarView->goDate(date); 1589 } 1590 1591 void ActionManager::goDate(const QString &date) 1592 { 1593 goDate(QLocale().toDate(date)); 1594 } 1595 1596 void ActionManager::showDate(QDate date) 1597 { 1598 mCalendarView->showDate(date); 1599 } 1600 1601 void ActionManager::updateUndoRedoActions() 1602 { 1603 Akonadi::History *history = mCalendarView->incidenceChanger()->history(); 1604 1605 if (history->undoAvailable()) { 1606 mUndoAction->setEnabled(true); 1607 QString nextUndoDescription = history->nextUndoDescription(); 1608 if (nextUndoDescription.length() > 30) { 1609 nextUndoDescription.truncate(30); 1610 nextUndoDescription += QStringLiteral("..."); 1611 } 1612 mUndoAction->setText(i18n("Undo: %1", nextUndoDescription)); 1613 } else { 1614 mUndoAction->setEnabled(false); 1615 mUndoAction->setText(i18n("Undo")); 1616 } 1617 1618 if (history->redoAvailable()) { 1619 mRedoAction->setEnabled(true); 1620 QString nextRedoDescription = history->nextRedoDescription(); 1621 if (nextRedoDescription.length() > 30) { 1622 nextRedoDescription.truncate(30); 1623 nextRedoDescription += QStringLiteral("..."); 1624 } 1625 mRedoAction->setText(i18n("Redo: %1", nextRedoDescription)); 1626 } else { 1627 mRedoAction->setEnabled(false); 1628 mRedoAction->setText(i18n("Redo")); 1629 } 1630 1631 mUndoAction->setIconText(i18n("Undo")); 1632 } 1633 1634 bool ActionManager::queryClose() 1635 { 1636 return true; 1637 } 1638 1639 void ActionManager::importCalendar(const QUrl &url) 1640 { 1641 if (!url.isValid()) { 1642 KMessageBox::error(dialogParent(), i18n("URL '%1' is invalid.", url.toDisplayString())); 1643 return; 1644 } 1645 1646 const QString questionText = i18nc("@info", 1647 "<p>Would you like to merge this calendar item into an existing calendar " 1648 "or use it to create a brand new calendar?</p>" 1649 "<p>If you select merge, then you will be given the opportunity to select " 1650 "the destination calendar.</p>" 1651 "<p>If you select add, then a new calendar will be created for you automatically.</p>"); 1652 1653 const int answer = KMessageBox::questionTwoActionsCancel(dialogParent(), 1654 questionText, 1655 i18nc("@title:window", "Import Calendar"), 1656 KGuiItem(i18n("Merge into existing calendar")), 1657 KGuiItem(i18n("Add as new calendar"))); 1658 1659 switch (answer) { 1660 case KMessageBox::ButtonCode::PrimaryAction: // merge 1661 importURL(url, true); 1662 break; 1663 case KMessageBox::ButtonCode::SecondaryAction: // import 1664 importURL(url, false); 1665 break; 1666 default: 1667 return; 1668 } 1669 } 1670 1671 void ActionManager::slotAutoArchivingSettingsModified() 1672 { 1673 if (CalendarSupport::KCalPrefs::instance()->mAutoArchive) { 1674 mAutoArchiveTimer->start(4 * 60 * 60 * 1000); // check again in 4 hours 1675 } else { 1676 mAutoArchiveTimer->stop(); 1677 } 1678 } 1679 1680 void ActionManager::slotAutoArchive() 1681 { 1682 if (!mCalendarView->calendar()) { // can this happen? 1683 return; 1684 } 1685 1686 mAutoArchiveTimer->stop(); 1687 CalendarSupport::EventArchiver archiver; 1688 1689 archiver.runAuto(calendar(), mCalendarView->incidenceChanger(), mCalendarView, false /*no gui*/); 1690 1691 // restart timer with the correct delay ( especially useful for the first time ) 1692 slotAutoArchivingSettingsModified(); 1693 } 1694 1695 QWidget *ActionManager::dialogParent() 1696 { 1697 return mCalendarView->topLevelWidget(); 1698 } 1699 1700 void ActionManager::openTodoEditor(const QString &summary, 1701 const QString &description, 1702 const QStringList &attachmentUris, 1703 const QStringList &attendees, 1704 const QStringList &attachmentMimetypes, 1705 bool attachmentIsInline) 1706 { 1707 Q_UNUSED(summary) 1708 Q_UNUSED(description) 1709 Q_UNUSED(attachmentUris) 1710 Q_UNUSED(attendees) 1711 Q_UNUSED(attachmentMimetypes) 1712 Q_UNUSED(attachmentIsInline) 1713 qCWarning(KORGANIZER_LOG) << "Not implemented in korg-desktop"; 1714 } 1715 1716 void ActionManager::openEventEditor(const QString &summary, 1717 const QString &description, 1718 const QStringList &attachmentUris, 1719 const QStringList &attendees, 1720 const QStringList &attachmentMimetypes, 1721 bool attachmentIsInline) 1722 { 1723 Q_UNUSED(summary) 1724 Q_UNUSED(description) 1725 Q_UNUSED(attachmentUris) 1726 Q_UNUSED(attendees) 1727 Q_UNUSED(attachmentMimetypes) 1728 Q_UNUSED(attachmentIsInline) 1729 qCWarning(KORGANIZER_LOG) << "Not implemented in korg-desktop"; 1730 } 1731 1732 #include "moc_actionmanager.cpp"