21 #include "history_p.h"
23 #include <kcalutils/stringify.h>
25 using namespace KCalCore;
28 History::History(QObject *parent) : QObject(parent), d(new Private(this))
30 d->mChanger =
new IncidenceChanger(
false,
this);
31 d->mChanger->setObjectName(
"changer");
32 d->mOperationTypeInProgress = TypeNone;
34 d->mUndoAllInProgress =
false;
42 History::Private::Private(
History *qq) : q(qq)
48 const QString &description,
49 const uint atomicOperationId)
51 Q_ASSERT_X(item.isValid(),
"History::recordCreation()",
52 "Item must be valid.");
54 Q_ASSERT_X(item.hasPayload<KCalCore::Incidence::Ptr>(),
"History::recordCreation()",
55 "Item must have Incidence::Ptr payload.");
57 Entry::Ptr entry(
new CreationEntry(item, description,
this));
59 d->stackEntry(entry, atomicOperationId);
63 const Akonadi::Item &newItem,
64 const QString &description,
65 const uint atomicOperationId)
67 Q_ASSERT_X(oldItem.isValid(),
"History::recordModification",
"old item must be valid");
68 Q_ASSERT_X(newItem.isValid(),
"History::recordModification",
"newItem item must be valid");
69 Q_ASSERT_X(oldItem.hasPayload<KCalCore::Incidence::Ptr>(),
"History::recordModification",
70 "old item must have Incidence::Ptr payload");
71 Q_ASSERT_X(newItem.hasPayload<KCalCore::Incidence::Ptr>(),
"History::recordModification",
72 "newItem item must have Incidence::Ptr payload");
74 Entry::Ptr entry(
new ModificationEntry(newItem, oldItem.payload<KCalCore::Incidence::Ptr>(),
77 Q_ASSERT(newItem.revision() >= oldItem.revision());
79 d->stackEntry(entry, atomicOperationId);
83 const QString &description,
84 const uint atomicOperationId)
86 Q_ASSERT_X(item.isValid(),
"History::recordDeletion",
"Item must be valid");
93 const QString &description,
94 const uint atomicOperationId)
96 Entry::Ptr entry(
new DeletionEntry(items, description,
this));
98 foreach(
const Akonadi::Item &item, items) {
100 Q_ASSERT_X(item.isValid(),
101 "History::recordDeletion()",
"Item must be valid.");
102 Q_ASSERT_X(item.hasPayload<Incidence::Ptr>(),
103 "History::recordDeletion()",
"Item must have an Incidence::Ptr payload.");
106 d->stackEntry(entry, atomicOperationId);
111 if (!d->mUndoStack.isEmpty())
112 return d->mUndoStack.top()->mDescription;
119 if (!d->mRedoStack.isEmpty())
120 return d->mRedoStack.top()->mDescription;
127 d->undoOrRedo(TypeUndo, parent);
132 d->undoOrRedo(TypeRedo, parent);
137 if (d->mOperationTypeInProgress != TypeNone) {
138 kWarning() <<
"Don't call History::undoAll() while an undo/redo/undoAll is in progress";
139 }
else if (d->mEnabled) {
140 d->mUndoAllInProgress =
true;
141 d->mCurrentParent = parent;
144 kWarning() <<
"Don't call undo/redo when History is disabled";
151 if (d->mOperationTypeInProgress == TypeNone) {
152 d->mRedoStack.clear();
153 d->mUndoStack.clear();
154 d->mLastErrorString.clear();
155 d->mQueuedEntries.clear();
165 return d->mLastErrorString;
170 return !d->mUndoStack.isEmpty() && d->mOperationTypeInProgress == TypeNone;
175 return !d->mRedoStack.isEmpty() && d->mOperationTypeInProgress == TypeNone;
178 void History::Private::updateIds(Item::Id oldId, Item::Id newId)
180 mEntryInProgress->updateIds(oldId, newId);
182 foreach(
const Entry::Ptr &entry, mUndoStack)
183 entry->updateIds(oldId, newId);
185 foreach(
const Entry::Ptr &entry, mRedoStack)
186 entry->updateIds(oldId, newId);
189 void History::Private::doIt(OperationType type)
191 mOperationTypeInProgress = type;
193 Q_ASSERT(!stack().isEmpty());
194 mEntryInProgress = stack().pop();
196 connect(mEntryInProgress.data(), SIGNAL(finished(Akonadi::IncidenceChanger::ResultCode,QString)),
197 SLOT(handleFinished(Akonadi::IncidenceChanger::ResultCode,QString)),
198 Qt::UniqueConnection);
199 mEntryInProgress->doIt(type);
202 void History::Private::handleFinished(IncidenceChanger::ResultCode changerResult,
203 const QString &errorString)
205 Q_ASSERT(mOperationTypeInProgress != TypeNone);
206 Q_ASSERT(!(mUndoAllInProgress && mOperationTypeInProgress == TypeRedo));
208 const bool success = (changerResult == IncidenceChanger::ResultCodeSuccess);
213 mLastErrorString.clear();
214 destinationStack().push(mEntryInProgress);
216 mLastErrorString = errorString;
217 stack().push(mEntryInProgress);
224 if (!mQueuedEntries.isEmpty()) {
226 foreach(
const Entry::Ptr &entry, mQueuedEntries) {
227 mUndoStack.push(entry);
229 mQueuedEntries.clear();
232 emitDone(mOperationTypeInProgress, resultCode);
233 mOperationTypeInProgress = TypeNone;
237 void History::Private::stackEntry(
const Entry::Ptr &entry, uint atomicOperationId)
239 const bool useMultiEntry = (atomicOperationId > 0);
241 Entry::Ptr entryToPush;
244 Entry::Ptr topEntry = (mOperationTypeInProgress == TypeNone) ?
245 (mUndoStack.isEmpty() ? Entry::Ptr() : mUndoStack.top()) :
246 (mQueuedEntries.isEmpty() ? Entry::Ptr() : mQueuedEntries.last());
248 const bool topIsMultiEntry = qobject_cast<MultiEntry*>(topEntry.data());
250 if (topIsMultiEntry) {
251 MultiEntry::Ptr multiEntry = topEntry.staticCast<MultiEntry>();
252 if (multiEntry->mAtomicOperationId != atomicOperationId) {
253 multiEntry = MultiEntry::Ptr(
new MultiEntry(atomicOperationId, entry->mDescription, q));
254 entryToPush = multiEntry;
256 multiEntry->addEntry(entry);
258 MultiEntry::Ptr multiEntry = MultiEntry::Ptr(
new MultiEntry(atomicOperationId,
259 entry->mDescription, q));
260 multiEntry->addEntry(entry);
261 entryToPush = multiEntry;
267 if (mOperationTypeInProgress == TypeNone) {
269 mUndoStack.push(entryToPush);
275 mQueuedEntries.append(entryToPush);
280 void History::Private::undoOrRedo(OperationType type, QWidget *parent)
283 Q_ASSERT(mOperationTypeInProgress == TypeNone);
285 if (!stack(type).isEmpty()) {
287 mCurrentParent = parent;
290 kWarning() <<
"Don't call undo/redo when History is disabled";
293 kWarning() <<
"Don't call undo/redo when the stack is empty.";
297 QStack<Entry::Ptr>& History::Private::stack(OperationType type)
300 return type == TypeUndo ? mUndoStack : mRedoStack;
303 void History::Private::setEnabled(
bool enabled)
305 if (enabled != mEnabled) {
310 int History::Private::redoCount()
const
312 return mRedoStack.count();
315 int History::Private::undoCount()
const
317 return mUndoStack.count();
320 QStack<Entry::Ptr>& History::Private::stack()
322 return stack(mOperationTypeInProgress);
325 QStack<Entry::Ptr>& History::Private::destinationStack()
328 return mOperationTypeInProgress == TypeRedo ? mUndoStack : mRedoStack;
333 if (type == TypeUndo) {
334 emit q->undone(resultCode);
335 }
else if (type == TypeRedo) {
336 emit q->redone(resultCode);
342 #include "moc_history.cpp"
343 #include "moc_history_p.cpp"