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"