1 /*
2   SPDX-FileCopyrightText: 2010-2012 Sérgio Martins <iamsergio@gmail.com>
3 
4   SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #include "history.h"
10 #include "incidencechanger.h"
11 #include <Akonadi/Collection>
12 #include <KCalendarCore/Incidence>
13 
14 #include <QPointer>
15 #include <QStack>
16 #include <QVector>
17 
18 using namespace Akonadi;
19 using namespace KCalendarCore;
20 
21 namespace Akonadi
22 {
23 class History;
24 
25 enum OperationType { TypeNone, TypeUndo, TypeRedo };
26 
27 class Entry : public QObject
28 {
29     Q_OBJECT
30 public:
31     using Ptr = QSharedPointer<Entry>;
32     using List = QVector<Entry::Ptr>;
33     Entry(const Akonadi::Item &item, const QString &description, History *qq);
34     Entry(const Akonadi::Item::List &items, const QString &description, History *qq);
35     virtual void updateIds(Item::Id oldId, Item::Id newId);
36     void doIt(OperationType);
37 
38     Akonadi::Item::List mItems;
39     QString mDescription;
40 Q_SIGNALS:
41     void finished(Akonadi::IncidenceChanger::ResultCode, const QString &errorString);
42 
43 protected:
44     virtual bool undo() = 0;
45     virtual bool redo() = 0;
46     void updateIdsGlobaly(Item::Id oldId, Item::Id newId);
47     QWidget *currentParent() const;
48     IncidenceChanger *mChanger = nullptr;
49     QHash<Akonadi::Item::Id, int> mLatestRevisionByItemId;
50     History *q = nullptr;
51     QVector<int> mChangeIds;
52 
53 private:
54     void init(const QString &description, History *qq);
55     Q_DISABLE_COPY(Entry)
56 };
57 
58 class AKONADI_CALENDAR_EXPORT HistoryPrivate : public QObject
59 {
60     Q_OBJECT
61 public:
62     explicit HistoryPrivate(History *qq);
~HistoryPrivate()63     ~HistoryPrivate() override
64     {
65     }
66 
67     void doIt(OperationType);
68     void stackEntry(const Entry::Ptr &entry, uint atomicOperationId);
69     void updateIds(Item::Id oldId, Item::Id newId);
70     QStack<Entry::Ptr> &destinationStack();
71     QStack<Entry::Ptr> &stack(OperationType);
72     QStack<Entry::Ptr> &stack();
73     void undoOrRedo(OperationType, QWidget *parent);
74 
75     void emitDone(OperationType, History::ResultCode);
76     void setEnabled(bool enabled);
77 
78 
79     int redoCount() const;
80     int undoCount() const;
81 
82     IncidenceChanger *const mChanger;
83 
84     QStack<Entry::Ptr> mUndoStack;
85     QStack<Entry::Ptr> mRedoStack;
86 
87     OperationType mOperationTypeInProgress;
88 
89     Entry::Ptr mEntryInProgress;
90 
91     QString mLastErrorString;
92     bool mUndoAllInProgress = false;
93 
94     /**
95      * When recordCreation/Deletion/Modification is called and an undo operation is already in progress
96      * the entry is added here.
97      */
98     QVector<Entry::Ptr> mQueuedEntries;
99     bool mEnabled = true;
100     QPointer<QWidget> mCurrentParent;
101 
102 public Q_SLOTS:
103     void handleFinished(Akonadi::IncidenceChanger::ResultCode, const QString &errorString);
104 
105 private:
106     History *const q;
107 };
108 
109 class CreationEntry : public Entry
110 {
111     Q_OBJECT
112 public:
113     using Ptr = QSharedPointer<CreationEntry>;
114     CreationEntry(const Akonadi::Item &item, const QString &description, History *q);
115 
116     bool undo() override;
117     bool redo() override;
118 
119 private Q_SLOTS:
120     void
121     onDeleteFinished(int changeId, const QVector<Akonadi::Item::Id> &deletedIds, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString);
122 
123     void onCreateFinished(int changeId, const Akonadi::Item &item, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString);
124 
125 private:
126     Q_DISABLE_COPY(CreationEntry)
127 };
128 
129 class DeletionEntry : public Entry
130 {
131     Q_OBJECT
132 public:
133     DeletionEntry(const Akonadi::Item::List &items, const QString &description, History *q);
134     bool undo() override;
135     bool redo() override;
136 
137 private Q_SLOTS:
138     void
139     onDeleteFinished(int changeId, const QVector<Akonadi::Item::Id> &deletedIds, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString);
140 
141     void onCreateFinished(int changeId, const Akonadi::Item &item, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString);
142 
143 private:
144     IncidenceChanger::ResultCode mResultCode;
145     QString mErrorString;
146     QHash<int, Akonadi::Item::Id> mOldIdByChangeId;
147     int mNumPendingCreations;
148     Q_DISABLE_COPY(DeletionEntry)
149 };
150 
151 class ModificationEntry : public Entry
152 {
153     Q_OBJECT
154 public:
155     ModificationEntry(const Akonadi::Item &item, const Incidence::Ptr &originalPayload, const QString &description, History *q);
156 
157     bool undo() override;
158     bool redo() override;
159 
160 private Q_SLOTS:
161     void onModifyFinished(int changeId, const Akonadi::Item &item, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString);
162 
163 private:
164     Q_DISABLE_COPY(ModificationEntry)
165     Incidence::Ptr mOriginalPayload;
166 };
167 
168 class MultiEntry : public Entry
169 {
170     Q_OBJECT
171 public:
172     using Ptr = QSharedPointer<MultiEntry>;
173     MultiEntry(int id, const QString &description, History *q);
174 
175     void addEntry(const Entry::Ptr &entry);
176     void updateIds(Item::Id oldId, Item::Id newId) override;
177 
178 protected:
179     bool undo() override;
180     bool redo() override;
181 
182 private Q_SLOTS:
183     void onEntryFinished(Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString);
184 
185 public:
186     const uint mAtomicOperationId;
187 
188 private:
189     Entry::List mEntries;
190     int mFinishedEntries;
191     OperationType mOperationInProgress;
192     Q_DISABLE_COPY(MultiEntry)
193 };
194 }
195 
196