[pim/eventviews] src: Move KCalUtils::RecurrenceAcctions here

Volker Krause <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 8dfdefbf47428b4dbd4e04775eb7e35c69fd5f05 by Volker Krause.
Committed on 02/08/2026 at 07:49.
Pushed by vkrause into branch 'master'.

Move KCalUtils::RecurrenceAcctions here

This is the only user.

M  +1    -0    src/CMakeLists.txt
M  +5    -6    src/agenda/agenda.cpp
M  +14   -15   src/eventview.cpp
M  +5    -5    src/month/monthitem.cpp
A  +116  -0    src/recurrenceactions.cpp     [License: LGPL(v2.0+)]
A  +125  -0    src/recurrenceactions.h     [License: LGPL(v2.0+)]

https://invent.kde.org/pim/eventviews/-/commit/8dfdefbf47428b4dbd4e04775eb7e35c69fd5f05

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fdc4f2b7..a32d687b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -17,6 +17,7 @@ target_sources(
         eventview.cpp
         helper.cpp
         prefs.cpp
+        recurrenceactions.cpp
         # Agenda view specific code.
         agenda/agenda.cpp
         agenda/agendaitem.cpp
diff --git a/src/agenda/agenda.cpp b/src/agenda/agenda.cpp
index 4980e39a..385fad7e 100644
--- a/src/agenda/agenda.cpp
+++ b/src/agenda/agenda.cpp
@@ -13,6 +13,7 @@
 #include "agenda.h"
 #include "agendaview.h"
 #include "prefs.h"
+#include "recurrenceactions.h"
 
 #include <Akonadi/CalendarUtils>
 #include <Akonadi/IncidenceChanger>
@@ -23,8 +24,6 @@
 #include <KCalendarCore/MimeData>
 #endif
 
-#include <KCalUtils/RecurrenceActions>
-
 #include "calendarview_debug.h"
 #include <KMessageBox>
 
@@ -1168,13 +1167,13 @@ void Agenda::endItemAction()
             }
 
             switch (res) {
-            case KCalUtils::RecurrenceActions::AllOccurrences: // All occurrences
+            case RecurrenceActions::AllOccurrences: // All occurrences
                 // Moving the whole sequence of events is handled by the itemModified below.
                 modify = true;
                 break;
-            case KCalUtils::RecurrenceActions::SelectedOccurrence:
-            case KCalUtils::RecurrenceActions::FutureOccurrences: {
-                const bool thisAndFuture = (res == KCalUtils::RecurrenceActions::FutureOccurrences);
+            case RecurrenceActions::SelectedOccurrence:
+            case RecurrenceActions::FutureOccurrences: {
+                const bool thisAndFuture = (res == RecurrenceActions::FutureOccurrences);
                 modify = true;
                 multiModify = true;
                 d->mChanger->startAtomicOperation(i18nc("@info/plain", "Dissociate event from recurrence"));
diff --git a/src/eventview.cpp b/src/eventview.cpp
index 9c405411..5c0e42f4 100644
--- a/src/eventview.cpp
+++ b/src/eventview.cpp
@@ -9,9 +9,9 @@
 */
 
 #include "eventview_p.h"
-using namespace Qt::Literals::StringLiterals;
 
 #include "prefs.h"
+#include "recurrenceactions.h"
 
 #include <CalendarSupport/CollectionSelection>
 #include <CalendarSupport/KCalPrefs>
@@ -23,8 +23,6 @@ using namespace Qt::Literals::StringLiterals;
 
 #include <KCalendarCore/CalFilter>
 
-#include <KCalUtils/RecurrenceActions>
-
 #include <KHolidays/HolidayCategories>
 #include <KHolidays/HolidayRegion>
 
@@ -40,6 +38,7 @@ using namespace Qt::Literals::StringLiterals;
 #include <QKeyEvent>
 #include <QSortFilterProxyModel>
 
+using namespace Qt::Literals::StringLiterals;
 using namespace KCalendarCore;
 using namespace EventViews;
 using namespace Akonadi;
@@ -116,7 +115,7 @@ int EventView::showMoveRecurDialog(const Incidence::Ptr &inc, QDate date)
 {
     QDateTime const dateTime(date, {}, QTimeZone::LocalTime);
 
-    int const availableOccurrences = KCalUtils::RecurrenceActions::availableOccurrences(inc, dateTime);
+    int const availableOccurrences = RecurrenceActions::availableOccurrences(inc, dateTime);
 
     const QString caption = i18nc("@title:window", "Changing Recurring Item");
     KGuiItem const itemFuture(i18n("Also &Future Items"));
@@ -124,39 +123,39 @@ int EventView::showMoveRecurDialog(const Incidence::Ptr &inc, QDate date)
     KGuiItem const itemAll(i18n("&All Occurrences"));
 
     switch (availableOccurrences) {
-    case KCalUtils::RecurrenceActions::NoOccurrence:
-        return KCalUtils::RecurrenceActions::NoOccurrence;
+    case RecurrenceActions::NoOccurrence:
+        return RecurrenceActions::NoOccurrence;
 
-    case KCalUtils::RecurrenceActions::SelectedOccurrence:
-        return KCalUtils::RecurrenceActions::SelectedOccurrence;
+    case RecurrenceActions::SelectedOccurrence:
+        return RecurrenceActions::SelectedOccurrence;
 
-    case KCalUtils::RecurrenceActions::AllOccurrences:
-        Q_ASSERT(availableOccurrences & KCalUtils::RecurrenceActions::SelectedOccurrence);
+    case RecurrenceActions::AllOccurrences:
+        Q_ASSERT(availableOccurrences & RecurrenceActions::SelectedOccurrence);
 
         // if there are all kinds of ooccurrences (i.e. past present and future) the user might
         // want the option only apply to current and future occurrences, leaving the past ones
         // provide a third choice for that ("Also future")
-        if (availableOccurrences == KCalUtils::RecurrenceActions::AllOccurrences) {
+        if (availableOccurrences == RecurrenceActions::AllOccurrences) {
             const QString message = i18n(
                 "The item you are trying to change is a recurring item. "
                 "Should the changes be applied only to this single occurrence, "
                 "also to future items, or to all items in the recurrence?");
-            return KCalUtils::RecurrenceActions::questionSelectedFutureAllCancel(message, caption, itemSelected, itemFuture, itemAll, this);
+            return RecurrenceActions::questionSelectedFutureAllCancel(message, caption, itemSelected, itemFuture, itemAll, this);
         }
         [[fallthrough]];
 
     default:
-        Q_ASSERT(availableOccurrences & KCalUtils::RecurrenceActions::SelectedOccurrence);
+        Q_ASSERT(availableOccurrences & RecurrenceActions::SelectedOccurrence);
         // selected occurrence and either past or future occurrences
         const QString message = i18n(
             "The item you are trying to change is a recurring item. "
             "Should the changes be applied only to this single occurrence "
             "or to all items in the recurrence?");
-        return KCalUtils::RecurrenceActions::questionSelectedAllCancel(message, caption, itemSelected, itemAll, this);
+        return RecurrenceActions::questionSelectedAllCancel(message, caption, itemSelected, itemAll, this);
         break;
     }
 
-    return KCalUtils::RecurrenceActions::NoOccurrence;
+    return RecurrenceActions::NoOccurrence;
 }
 
 void EventView::addCalendar(const Akonadi::CollectionCalendar::Ptr &calendar)
diff --git a/src/month/monthitem.cpp b/src/month/monthitem.cpp
index 65913768..f6a6cd25 100644
--- a/src/month/monthitem.cpp
+++ b/src/month/monthitem.cpp
@@ -11,6 +11,7 @@
 #include "monthview.h"
 #include "prefs.h"
 #include "prefs_base.h" // Ugly, but needed for the Enums
+#include "recurrenceactions.h"
 
 #include <Akonadi/CalendarUtils>
 #include <Akonadi/EntityTreeModel>
@@ -20,7 +21,6 @@
 #include <CalendarSupport/Utils>
 
 #include <KCalUtils/IncidenceFormatter>
-#include <KCalUtils/RecurrenceActions>
 
 #include "calendarview_debug.h"
 #include <KMessageBox>
@@ -426,16 +426,16 @@ void IncidenceMonthItem::updateDates(int startOffset, int endOffset)
     if (mIncidence->recurs()) {
         const int res = monthScene()->mMonthView->showMoveRecurDialog(mIncidence, startDate());
         switch (res) {
-        case KCalUtils::RecurrenceActions::AllOccurrences: {
+        case RecurrenceActions::AllOccurrences: {
             // All occurrences
             KCalendarCore::Incidence::Ptr const oldIncidence(mIncidence->clone());
             setNewDates(mIncidence, startOffset, endOffset);
             changer->modifyIncidence(item, oldIncidence);
             break;
         }
-        case KCalUtils::RecurrenceActions::SelectedOccurrence: // Just this occurrence
-        case KCalUtils::RecurrenceActions::FutureOccurrences: { // All future occurrences
-            const bool thisAndFuture = (res == KCalUtils::RecurrenceActions::FutureOccurrences);
+        case RecurrenceActions::SelectedOccurrence: // Just this occurrence
+        case RecurrenceActions::FutureOccurrences: { // All future occurrences
+            const bool thisAndFuture = (res == RecurrenceActions::FutureOccurrences);
             QDateTime occurrenceDate(mIncidence->dtStart());
             occurrenceDate.setDate(startDate());
             KCalendarCore::Incidence::Ptr const newIncidence(KCalendarCore::Calendar::createException(mIncidence, occurrenceDate, thisAndFuture));
diff --git a/src/recurrenceactions.cpp b/src/recurrenceactions.cpp
new file mode 100644
index 00000000..d18132df
--- /dev/null
+++ b/src/recurrenceactions.cpp
@@ -0,0 +1,116 @@
+/*
+  This file is part of the kcal library.
+
+  SPDX-FileCopyrightText: Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
+  SPDX-FileContributor: Kevin Krammer <[email protected]>
+
+  SPDX-FileCopyrightText: 2015 Sérgio Martins <[email protected]>
+
+  SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "recurrenceactions.h"
+
+#include <KGuiItem>
+#include <KLocalizedString>
+#include <KMessageBox>
+
+#include <QDialog>
+#include <QDialogButtonBox>
+#include <QPointer>
+#include <QPushButton>
+
+using namespace EventViews;
+using namespace KCalendarCore;
+
+int RecurrenceActions::availableOccurrences(const Incidence::Ptr &incidence, const QDateTime &selectedOccurrence)
+{
+    int result = NoOccurrence;
+
+    if (incidence->recurrence()->recursOn(selectedOccurrence.date(), selectedOccurrence.timeZone())) {
+        result |= SelectedOccurrence;
+    }
+
+    if (incidence->recurrence()->getPreviousDateTime(selectedOccurrence).isValid()) {
+        result |= PastOccurrences;
+    }
+
+    if (incidence->recurrence()->getNextDateTime(selectedOccurrence).isValid()) {
+        result |= FutureOccurrences;
+    }
+
+    return result;
+}
+
+int RecurrenceActions::questionSelectedAllCancel(const QString &message,
+                                                 const QString &caption,
+                                                 const KGuiItem &actionSelected,
+                                                 const KGuiItem &actionAll,
+                                                 QWidget *parent)
+{
+    QPointer<QDialog> const dialog = new QDialog(parent);
+    dialog->setWindowTitle(caption);
+    auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::No | QDialogButtonBox::Yes, parent);
+    dialog->setObjectName(QLatin1StringView("RecurrenceActions::questionSelectedAllCancel"));
+
+    KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), actionSelected);
+    KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), actionAll);
+
+    QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
+    okButton->setDefault(true);
+    okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
+    buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+
+    bool checkboxResult = false;
+    int const result =
+        KMessageBox::createKMessageBox(dialog, buttonBox, QMessageBox::Question, message, QStringList(), QString(), &checkboxResult, KMessageBox::Notify);
+
+    switch (result) {
+    case QDialogButtonBox::Yes:
+        return SelectedOccurrence;
+    case QDialogButtonBox::Ok:
+        return AllOccurrences;
+    default:
+        return NoOccurrence;
+    }
+}
+
+int RecurrenceActions::questionSelectedFutureAllCancel(const QString &message,
+                                                       const QString &caption,
+                                                       const KGuiItem &actionSelected,
+                                                       const KGuiItem &actionFuture,
+                                                       const KGuiItem &actionAll,
+                                                       QWidget *parent)
+{
+    QPointer<QDialog> const dialog = new QDialog(parent);
+    dialog->setWindowTitle(caption);
+
+    auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::No | QDialogButtonBox::Yes, parent);
+    dialog->setObjectName(QLatin1StringView("RecurrenceActions::questionSelectedFutureAllCancel"));
+    KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), actionSelected);
+    KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), actionFuture);
+    KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), actionAll);
+    QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
+    okButton->setDefault(true);
+    okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
+    buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+
+    bool checkboxResult = false;
+    QDialogButtonBox::StandardButton const result =
+        KMessageBox::createKMessageBox(dialog, buttonBox, QMessageBox::Question, message, QStringList(), QString(), &checkboxResult, KMessageBox::Notify);
+
+    switch (result) {
+    case QDialogButtonBox::Yes:
+        return SelectedOccurrence;
+    case QDialogButtonBox::No:
+        return FutureOccurrences;
+    case QDialogButtonBox::Ok:
+        return AllOccurrences;
+    default:
+        return NoOccurrence;
+    }
+
+    return NoOccurrence;
+}
+
+#include "moc_recurrenceactions.cpp"
diff --git a/src/recurrenceactions.h b/src/recurrenceactions.h
new file mode 100644
index 00000000..6d831536
--- /dev/null
+++ b/src/recurrenceactions.h
@@ -0,0 +1,125 @@
+/*
+  SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
+  SPDX-FileContributor: Kevin Krammer <[email protected]>
+
+  SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#pragma once
+
+#include <KCalendarCore/Incidence>
+
+class QDateTime;
+class KGuiItem;
+class QWidget;
+
+namespace EventViews
+{
+/*!
+  \brief Utility functions for dealing with recurrences
+
+  Incidences with recurrencies need to be treated differently than single independent ones.
+  For example the user might be given the choice to not only modify a selected occurrence
+  of an incidence but also all that follow that one, etc.
+
+  \author Kevin Krammer, [email protected]
+  \since 4.6
+*/
+namespace RecurrenceActions
+{
+/*!
+  \brief Flags for indicating on which occurrences to work on
+
+  Flags can be OR'ed together to get a combined scope.
+*/
+enum Scope {
+    /*!
+     Scope does not apply to any occurrence
+    */
+    NoOccurrence = 0,
+
+    /*!
+     Scope does include the given/selected occurrence
+    */
+    SelectedOccurrence = 1,
+
+    /*!
+     Scope does include occurrences before the given/selected occurrence
+    */
+    PastOccurrences = 2,
+
+    /*!
+     Scope does include occurrences after the given/selected occurrence
+    */
+    FutureOccurrences = 4,
+
+    /*!
+     Scope does include all occurrences (past, present and future)
+    */
+    AllOccurrences = PastOccurrences | SelectedOccurrence | FutureOccurrences
+};
+
+/*!
+  \brief Checks what scope an action could be applied on for a given incidence
+
+  Checks whether the incidence is occurring on the given date and whether there
+  are occurrences in the past and future.
+
+  \a incidence the incidence of which to check recurrences.
+  \a selectedOccurrence the date (including timespec) to use as the base occurrence,
+  i.e., from which to check for past and future occurrences.
+
+  Returns the #Scope to which actions on the given @incidence can be applied to
+*/
+[[nodiscard]] int availableOccurrences(const KCalendarCore::Incidence::Ptr &incidence, const QDateTime &selectedOccurrence);
+
+/*!
+  \brief Presents a message box with two action choices and cancel to the user
+
+  Shows a message box style question dialog with two action scope buttons and cancel.
+  This is for quick decisions like whether to only modify a single occurrence or all occurrences.
+
+  \a message the message which explains the change and available options.
+  \a caption the dialog's caption.
+  \a actionSelected the GUI item to use for the button representing the
+  #SelectedOccurrence scope.
+  \a actionAll the GUI item to use for the button representing the #AllOccurrences scope.
+  \a parent QWidget parent for the dialog.
+
+  \a #NoOccurrence on cancel, #SelectedOccurrence or #AllOccurrences on the respective action.
+*/
+[[nodiscard]] int
+questionSelectedAllCancel(const QString &message, const QString &caption, const KGuiItem &actionSelected, const KGuiItem &actionAll, QWidget *parent);
+
+/*!
+  \brief Presents a message box with three action choices and cancel to the user
+
+  Shows a message box style question dialog with three action scope buttons and cancel.
+  This is for quick decisions like whether to only modify a single occurrence, to include
+  future or all occurrences.
+
+  Note The calling application code can of course decide to word the future action text
+        in a way that it includes the selected occurrence, e.g. "Also Future Items".
+        The returned value will still just be #FutureOccurrences so the calling code
+        has to include #SelectedOccurrence itself if it passes the value further on
+
+  \a message the message which explains the change and available options.
+  \a caption the dialog's caption.
+  \a actionSelected the GUI item to use for the button representing the
+  #SelectedOccurrence scope.
+  \a actionSelected the GUI item to use for the button representing the
+  #FutureOccurrences scope.
+  \a actionAll the GUI item to use for the button representing the #AllOccurrences scope.
+  \a parent QWidget parent for the dialog.
+
+  \a #NoOccurrence on cancel, #SelectedOccurrence, #FutureOccurrences or #AllOccurrences
+  on the respective action.
+*/
+[[nodiscard]] int questionSelectedFutureAllCancel(const QString &message,
+                                                  const QString &caption,
+                                                  const KGuiItem &actionSelected,
+                                                  const KGuiItem &actionFuture,
+                                                  const KGuiItem &actionAll,
+                                                  QWidget *parent);
+}
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.