Fix dnd email
[kdepim.git] / kalarm / undo.cpp
blob8ae834d2bee92cc2fe82393b967a5981f0199762
1 /*
2 * undo.cpp - undo/redo facility
3 * Program: kalarm
4 * Copyright © 2005-2014 by David Jarvie <djarvie@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "kalarm.h" //krazy:exclude=includes (kalarm.h must be first)
22 #include "undo.h"
24 #include "alarmcalendar.h"
25 #include "functions.h"
26 #include "messagebox.h"
28 #include <kalarmcal/alarmtext.h>
29 #include <kalarmcal/kaevent.h>
31 #include <QApplication>
32 #include <KLocalizedString>
33 #include "kalarm_debug.h"
35 static int maxCount = 12;
37 #ifdef DELETE
38 #undef DELETE // conflicting Windows macro
39 #endif
41 // Simplify access to Undo::Event struct
42 #define RESOURCE_PARAM_TYPE const Collection&
43 #define EVENT_RESOURCE collection
45 using namespace Akonadi;
47 class UndoItem
49 public:
50 enum Operation { ADD, EDIT, DELETE, REACTIVATE, DEACTIVATE, MULTI };
51 UndoItem(); // needed by QList
52 virtual ~UndoItem();
53 virtual Operation operation() const = 0;
54 virtual QString actionText() const { return !mName.isEmpty() ? mName : defaultActionText(); }
55 virtual QString defaultActionText() const = 0;
56 virtual QString description() const { return QString(); }
57 virtual QString eventID() const { return QString(); }
58 virtual QString oldEventID() const { return QString(); }
59 virtual QString newEventID() const { return QString(); }
60 virtual Collection collection() const { return Collection(); }
61 int id() const { return mId; }
62 Undo::Type type() const { return mType; }
63 void setType(Undo::Type t) { mType = t; }
64 CalEvent::Type calendar() const { return mCalendar; }
65 virtual void setCalendar(CalEvent::Type s) { mCalendar = s; }
66 virtual UndoItem* restore() = 0;
67 virtual bool deleteID(const QString& /*id*/) { return false; }
69 enum Error { ERR_NONE, ERR_PROG, ERR_NOT_FOUND, ERR_CREATE, ERR_TEMPLATE, ERR_ARCHIVED };
70 enum Warning { WARN_NONE, WARN_KORG_ADD, WARN_KORG_MODIFY, WARN_KORG_DELETE };
71 static int mLastId;
72 static Error mRestoreError; // error code valid only if restore() returns 0
73 static Warning mRestoreWarning; // warning code set by restore()
74 static KAlarm::UpdateResult mRestoreWarningKorg; // KOrganizer error status set by restore()
75 static int mRestoreWarningCount; // item count for mRestoreWarning (to allow i18n messages to work correctly)
77 protected:
78 UndoItem(Undo::Type, const QString& name = QString());
79 static QString addDeleteActionText(CalEvent::Type, bool add);
80 QString description(const KAEvent&) const;
81 void replaceWith(UndoItem* item) { Undo::replace(this, item); }
83 QString mName; // specified action name (overrides default)
84 int mId; // unique identifier (only for mType = UNDO, REDO)
85 Undo::Type mType; // which list (if any) the object is in
86 CalEvent::Type mCalendar;
89 class UndoMultiBase : public UndoItem
91 public:
92 UndoMultiBase(Undo::Type t, const QString& name)
93 : UndoItem(t, name), mUndos(new Undo::List) {}
94 UndoMultiBase(Undo::Type t, Undo::List* undos, const QString& name)
95 : UndoItem(t, name), mUndos(undos) {}
96 ~UndoMultiBase() { delete mUndos; }
97 const Undo::List* undos() const { return mUndos; }
98 protected:
99 Undo::List* mUndos; // this list must always have >= 2 entries
102 template <class T> class UndoMulti : public UndoMultiBase
104 public:
105 UndoMulti(Undo::Type, const Undo::EventList&, const QString& name);
106 UndoMulti(Undo::Type t, Undo::List* undos, const QString& name) : UndoMultiBase(t, undos, name) {}
107 Operation operation() const Q_DECL_OVERRIDE { return MULTI; }
108 UndoItem* restore() Q_DECL_OVERRIDE;
109 bool deleteID(const QString& id) Q_DECL_OVERRIDE;
110 virtual UndoItem* createRedo(Undo::List*) = 0;
113 class UndoAdd : public UndoItem
115 public:
116 UndoAdd(Undo::Type, const Undo::Event&, const QString& name = QString());
117 UndoAdd(Undo::Type, const KAEvent&, RESOURCE_PARAM_TYPE, const QString& name = QString());
118 UndoAdd(Undo::Type, const KAEvent&, RESOURCE_PARAM_TYPE, const QString& name, CalEvent::Type);
119 Operation operation() const Q_DECL_OVERRIDE { return ADD; }
120 QString defaultActionText() const Q_DECL_OVERRIDE;
121 QString description() const Q_DECL_OVERRIDE { return mDescription; }
122 Collection collection() const Q_DECL_OVERRIDE { return mResource; }
123 QString eventID() const Q_DECL_OVERRIDE { return mEventId; }
124 QString newEventID() const Q_DECL_OVERRIDE { return mEventId; }
125 UndoItem* restore() Q_DECL_OVERRIDE { return doRestore(); }
126 protected:
127 UndoItem* doRestore(bool setArchive = false);
128 virtual UndoItem* createRedo(const KAEvent&, RESOURCE_PARAM_TYPE);
129 private:
130 Collection mResource; // collection containing the event
131 QString mEventId;
132 QString mDescription;
135 class UndoEdit : public UndoItem
137 public:
138 UndoEdit(Undo::Type, const KAEvent& oldEvent, const QString& newEventID,
139 RESOURCE_PARAM_TYPE, const QStringList& dontShowErrors, const QString& description);
140 ~UndoEdit();
141 Operation operation() const Q_DECL_OVERRIDE { return EDIT; }
142 QString defaultActionText() const Q_DECL_OVERRIDE;
143 QString description() const Q_DECL_OVERRIDE { return mDescription; }
144 Collection collection() const Q_DECL_OVERRIDE { return mResource; }
145 QString eventID() const Q_DECL_OVERRIDE { return mNewEventId; }
146 QString oldEventID() const Q_DECL_OVERRIDE { return mOldEvent->id(); }
147 QString newEventID() const Q_DECL_OVERRIDE { return mNewEventId; }
148 UndoItem* restore() Q_DECL_OVERRIDE;
149 private:
150 Collection mResource; // collection containing the event
151 KAEvent* mOldEvent;
152 QString mNewEventId;
153 QString mDescription;
154 QStringList mDontShowErrors;
157 class UndoDelete : public UndoItem
159 public:
160 UndoDelete(Undo::Type, const Undo::Event&, const QString& name = QString());
161 UndoDelete(Undo::Type, const KAEvent&, RESOURCE_PARAM_TYPE, const QStringList& dontShowErrors, const QString& name = QString());
162 ~UndoDelete();
163 Operation operation() const Q_DECL_OVERRIDE { return DELETE; }
164 QString defaultActionText() const Q_DECL_OVERRIDE;
165 QString description() const Q_DECL_OVERRIDE { return UndoItem::description(*mEvent); }
166 Collection collection() const Q_DECL_OVERRIDE { return mResource; }
167 QString eventID() const Q_DECL_OVERRIDE { return mEvent->id(); }
168 QString oldEventID() const Q_DECL_OVERRIDE { return mEvent->id(); }
169 UndoItem* restore() Q_DECL_OVERRIDE;
170 KAEvent* event() const { return mEvent; }
171 protected:
172 virtual UndoItem* createRedo(const KAEvent&, RESOURCE_PARAM_TYPE);
173 private:
174 Collection mResource; // collection containing the event
175 KAEvent* mEvent;
176 QStringList mDontShowErrors;
179 class UndoReactivate : public UndoAdd
181 public:
182 UndoReactivate(Undo::Type t, const Undo::Event& e, const QString& name = QString())
183 : UndoAdd(t, e.event, e.EVENT_RESOURCE, name, CalEvent::ACTIVE) {}
184 UndoReactivate(Undo::Type t, const KAEvent& e, RESOURCE_PARAM_TYPE r, const QString& name = QString())
185 : UndoAdd(t, e, r, name, CalEvent::ACTIVE) {}
186 Operation operation() const Q_DECL_OVERRIDE { return REACTIVATE; }
187 QString defaultActionText() const Q_DECL_OVERRIDE;
188 UndoItem* restore() Q_DECL_OVERRIDE;
189 protected:
190 UndoItem* createRedo(const KAEvent&, RESOURCE_PARAM_TYPE) Q_DECL_OVERRIDE;
193 class UndoDeactivate : public UndoDelete
195 public:
196 UndoDeactivate(Undo::Type t, const KAEvent& e, RESOURCE_PARAM_TYPE r, const QString& name = QString())
197 : UndoDelete(t, e, r, QStringList(), name) {}
198 Operation operation() const Q_DECL_OVERRIDE { return DEACTIVATE; }
199 QString defaultActionText() const Q_DECL_OVERRIDE;
200 UndoItem* restore() Q_DECL_OVERRIDE;
201 protected:
202 UndoItem* createRedo(const KAEvent&, RESOURCE_PARAM_TYPE) Q_DECL_OVERRIDE;
205 class UndoAdds : public UndoMulti<UndoAdd>
207 public:
208 UndoAdds(Undo::Type t, const Undo::EventList& events, const QString& name = QString())
209 : UndoMulti<UndoAdd>(t, events, name) {} // UNDO only
210 UndoAdds(Undo::Type t, Undo::List* undos, const QString& name)
211 : UndoMulti<UndoAdd>(t, undos, name) {}
212 QString defaultActionText() const Q_DECL_OVERRIDE;
213 UndoItem* createRedo(Undo::List*) Q_DECL_OVERRIDE;
216 class UndoDeletes : public UndoMulti<UndoDelete>
218 public:
219 UndoDeletes(Undo::Type t, const Undo::EventList& events, const QString& name = QString())
220 : UndoMulti<UndoDelete>(t, events, name) {} // UNDO only
221 UndoDeletes(Undo::Type t, Undo::List* undos, const QString& name)
222 : UndoMulti<UndoDelete>(t, undos, name) {}
223 QString defaultActionText() const Q_DECL_OVERRIDE;
224 UndoItem* createRedo(Undo::List*) Q_DECL_OVERRIDE;
227 class UndoReactivates : public UndoMulti<UndoReactivate>
229 public:
230 UndoReactivates(Undo::Type t, const Undo::EventList& events, const QString& name = QString())
231 : UndoMulti<UndoReactivate>(t, events, name) {} // UNDO only
232 UndoReactivates(Undo::Type t, Undo::List* undos, const QString& name)
233 : UndoMulti<UndoReactivate>(t, undos, name) {}
234 QString defaultActionText() const Q_DECL_OVERRIDE;
235 UndoItem* createRedo(Undo::List*) Q_DECL_OVERRIDE;
238 Undo* Undo::mInstance = Q_NULLPTR;
239 Undo::List Undo::mUndoList;
240 Undo::List Undo::mRedoList;
243 /******************************************************************************
244 * Create the one and only instance of the Undo class.
246 Undo* Undo::instance()
248 if (!mInstance)
249 mInstance = new Undo(qApp);
250 return mInstance;
253 /******************************************************************************
254 * Clear the lists of undo and redo items.
256 void Undo::clear()
258 if (!mUndoList.isEmpty() || !mRedoList.isEmpty())
260 mInstance->blockSignals(true);
261 while (!mUndoList.isEmpty())
262 delete mUndoList.first(); // N.B. 'delete' removes the object from the list
263 while (!mRedoList.isEmpty())
264 delete mRedoList.first(); // N.B. 'delete' removes the object from the list
265 mInstance->blockSignals(false);
266 emitChanged();
270 /******************************************************************************
271 * Create an undo item and add it to the list of undos.
272 * N.B. The base class constructor adds the object to the undo list.
274 void Undo::saveAdd(const KAEvent& event, RESOURCE_PARAM_TYPE resource, const QString& name)
276 new UndoAdd(UNDO, event, resource, name);
277 emitChanged();
280 void Undo::saveAdds(const Undo::EventList& events, const QString& name)
282 int count = events.count();
283 if (count == 1)
284 saveAdd(events.first().event, events.first().EVENT_RESOURCE, name);
285 else if (count > 1)
287 new UndoAdds(UNDO, events, name);
288 emitChanged();
292 void Undo::saveEdit(const Undo::Event& oldEvent, const KAEvent& newEvent)
294 new UndoEdit(UNDO, oldEvent.event, newEvent.id(), oldEvent.EVENT_RESOURCE, oldEvent.dontShowErrors, AlarmText::summary(newEvent));
295 removeRedos(oldEvent.event.id()); // remove any redos which are made invalid by this edit
296 emitChanged();
299 void Undo::saveDelete(const Undo::Event& event, const QString& name)
301 new UndoDelete(UNDO, event.event, event.EVENT_RESOURCE, event.dontShowErrors, name);
302 removeRedos(event.event.id()); // remove any redos which are made invalid by this deletion
303 emitChanged();
306 void Undo::saveDeletes(const Undo::EventList& events, const QString& name)
308 int count = events.count();
309 if (count == 1)
310 saveDelete(events[0], name);
311 else if (count > 1)
313 new UndoDeletes(UNDO, events, name);
314 for (int i = 0, end = events.count(); i < end; ++i)
315 removeRedos(events[i].event.id()); // remove any redos which are made invalid by these deletions
316 emitChanged();
320 void Undo::saveReactivate(const KAEvent& event, RESOURCE_PARAM_TYPE resource, const QString& name)
322 new UndoReactivate(UNDO, event, resource, name);
323 emitChanged();
326 void Undo::saveReactivates(const EventList& events, const QString& name)
328 int count = events.count();
329 if (count == 1)
330 saveReactivate(events[0].event, events[0].EVENT_RESOURCE, name);
331 else if (count > 1)
333 new UndoReactivates(UNDO, events, name);
334 emitChanged();
338 /******************************************************************************
339 * Remove any redos which are made invalid by a new undo.
341 void Undo::removeRedos(const QString& eventID)
343 QString id = eventID;
344 for (int i = 0; i < mRedoList.count(); )
346 UndoItem* item = mRedoList[i];
347 //qCDebug(KALARM_LOG)<<item->eventID()<<" (looking for"<<id<<")";
348 if (item->operation() == UndoItem::MULTI)
350 if (item->deleteID(id))
352 // The old multi-redo was replaced with a new single redo
353 delete item; // N.B. 'delete' removes the object from the list
356 else if (item->eventID() == id)
358 if (item->operation() == UndoItem::EDIT)
359 id = item->oldEventID(); // continue looking for its post-edit ID
360 delete item; // N.B. 'delete' removes the object from the list
362 else
363 ++i;
367 /******************************************************************************
368 * Undo or redo a specified item.
369 * Reply = true if success, or if the item no longer exists.
371 bool Undo::undo(int i, Undo::Type type, QWidget* parent, const QString& action)
373 UndoItem::mRestoreError = UndoItem::ERR_NONE;
374 UndoItem::mRestoreWarning = UndoItem::WARN_NONE;
375 UndoItem::mRestoreWarningKorg = KAlarm::UPDATE_OK;
376 UndoItem::mRestoreWarningCount = 0;
377 List& list = (type == UNDO) ? mUndoList : mRedoList;
378 if (i < list.count() && list[i]->type() == type)
380 list[i]->restore();
381 delete list[i]; // N.B. 'delete' removes the object from its list
382 emitChanged();
385 QString err;
386 switch (UndoItem::mRestoreError)
388 case UndoItem::ERR_NONE:
390 KAlarm::UpdateError errcode;
391 switch (UndoItem::mRestoreWarning)
393 case UndoItem::WARN_KORG_ADD: errcode = KAlarm::ERR_ADD; break;
394 case UndoItem::WARN_KORG_MODIFY: errcode = KAlarm::ERR_MODIFY; break;
395 case UndoItem::WARN_KORG_DELETE: errcode = KAlarm::ERR_DELETE; break;
396 case UndoItem::WARN_NONE:
397 default:
398 return true;
400 KAlarm::displayKOrgUpdateError(parent, errcode, UndoItem::mRestoreWarningKorg, UndoItem::mRestoreWarningCount);
401 return true;
403 case UndoItem::ERR_NOT_FOUND: err = i18nc("@info", "Alarm not found"); break;
404 case UndoItem::ERR_CREATE: err = i18nc("@info", "Error recreating alarm"); break;
405 case UndoItem::ERR_TEMPLATE: err = i18nc("@info", "Error recreating alarm template"); break;
406 case UndoItem::ERR_ARCHIVED: err = i18nc("@info", "Cannot reactivate archived alarm"); break;
407 case UndoItem::ERR_PROG: err = i18nc("@info", "Program error"); break;
408 default: err = i18nc("@info", "Unknown error"); break;
410 KAMessageBox::sorry(parent, i18nc("@info Undo-action: message", "%1: %2", action, err));
411 return false;
414 /******************************************************************************
415 * Add an undo item to the start of one of the lists.
417 void Undo::add(UndoItem* item, bool undo)
419 if (item)
421 // Limit the number of items stored
422 int undoCount = mUndoList.count();
423 int redoCount = mRedoList.count();
424 if (undoCount + redoCount >= maxCount - 1)
426 if (undoCount)
427 mUndoList.pop_back();
428 else
429 mRedoList.pop_back();
432 // Append the new item
433 List* list = undo ? &mUndoList : &mRedoList;
434 list->prepend(item);
438 /******************************************************************************
439 * Remove an undo item from one of the lists.
441 void Undo::remove(UndoItem* item, bool undo)
443 List* list = undo ? &mUndoList : &mRedoList;
444 if (!list->isEmpty())
445 list->removeAt(list->indexOf(item));
448 /******************************************************************************
449 * Replace an undo item in one of the lists.
451 void Undo::replace(UndoItem* old, UndoItem* New)
453 Type type = old->type();
454 List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : Q_NULLPTR;
455 if (!list)
456 return;
457 int i = list->indexOf(old);
458 if (i >= 0)
460 New->setType(type); // ensure the item points to the correct list
461 (*list)[i] = New;
462 old->setType(NONE); // mark the old item as no longer being in a list
466 /******************************************************************************
467 * Return the action description of the latest undo/redo item.
469 QString Undo::actionText(Undo::Type type)
471 List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : Q_NULLPTR;
472 return (list && !list->isEmpty()) ? (*list)[0]->actionText() : QString();
475 /******************************************************************************
476 * Return the action description of the undo/redo item with the specified ID.
478 QString Undo::actionText(Undo::Type type, int id)
480 UndoItem* undo = getItem(id, type);
481 return undo ? undo->actionText() : QString();
484 /******************************************************************************
485 * Return the alarm description of the undo/redo item with the specified ID.
487 QString Undo::description(Undo::Type type, int id)
489 UndoItem* undo = getItem(id, type);
490 return undo ? undo->description() : QString();
493 /******************************************************************************
494 * Return the descriptions of all undo or redo items, in order latest first.
495 * For alarms which have undergone more than one change, only the first one is
496 * listed, to force dependent undos to be executed in their correct order.
497 * If 'ids' is non-null, also returns a list of their corresponding IDs.
499 QList<int> Undo::ids(Undo::Type type)
501 QList<int> ids;
502 QStringList ignoreIDs;
503 //int n=0;
504 List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : Q_NULLPTR;
505 if (!list)
506 return ids;
507 for (int i = 0, end = list->count(); i < end; ++i)
509 // Check whether this item should be ignored because it is a
510 // dependent undo. If not, add this item's ID to the ignore list.
511 UndoItem* item = (*list)[i];
512 bool omit = false;
513 if (item->operation() == UndoItem::MULTI)
515 // If any item in a multi-undo is disqualified, omit the whole multi-undo
516 QStringList newIDs;
517 const Undo::List* undos = ((UndoMultiBase*)item)->undos();
518 for (int u = 0, uend = undos->count(); u < uend; ++u)
520 QString evid = (*undos)[u]->eventID();
521 if (ignoreIDs.contains(evid))
522 omit = true;
523 else if (omit)
524 ignoreIDs.append(evid);
525 else
526 newIDs.append(evid);
528 if (omit)
530 for (int i = 0, iend = newIDs.count(); i < iend; ++i)
531 ignoreIDs.append(newIDs[i]);
534 else
536 omit = ignoreIDs.contains(item->eventID());
537 if (!omit)
538 ignoreIDs.append(item->eventID());
539 if (item->operation() == UndoItem::EDIT)
540 ignoreIDs.append(item->oldEventID()); // continue looking for its post-edit ID
542 if (!omit)
543 ids.append(item->id());
544 //else qCDebug(KALARM_LOG)<<"Undo::ids(): omit"<<item->actionText()<<":"<<item->description();
546 //qCDebug(KALARM_LOG)<<"Undo::ids():"<<n<<" ->"<<ids.count();
547 return ids;
550 /******************************************************************************
551 * Emit the appropriate 'changed' signal.
553 void Undo::emitChanged()
555 if (mInstance)
556 mInstance->emitChanged(actionText(UNDO), actionText(REDO));
559 /******************************************************************************
560 * Return the item with the specified ID.
562 UndoItem* Undo::getItem(int id, Undo::Type type)
564 List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : Q_NULLPTR;
565 if (list)
567 for (int i = 0, end = list->count(); i < end; ++i)
569 if ((*list)[i]->id() == id)
570 return (*list)[i];
573 return Q_NULLPTR;
576 /******************************************************************************
577 * Find an item with the specified ID.
579 int Undo::findItem(int id, Undo::Type type)
581 List& list = (type == UNDO) ? mUndoList : mRedoList;
582 int i = 0;
583 for (int end = list.count(); i < end; ++i)
585 if (list[i]->id() == id)
586 break;
588 return i;
592 /*=============================================================================
593 = Class: UndoItem
594 = A single undo action.
595 =============================================================================*/
596 int UndoItem::mLastId = 0;
597 UndoItem::Error UndoItem::mRestoreError;
598 UndoItem::Warning UndoItem::mRestoreWarning;
599 KAlarm::UpdateResult UndoItem::mRestoreWarningKorg;
600 int UndoItem::mRestoreWarningCount;
602 /******************************************************************************
603 * Constructor.
604 * Optionally appends the undo to the list of undos.
606 UndoItem::UndoItem(Undo::Type type, const QString& name)
607 : mName(name),
608 mId(0),
609 mType(type),
610 mCalendar(CalEvent::EMPTY)
612 if (type != Undo::NONE)
614 mId = ++mLastId;
615 if (mId < 0)
616 mId = mLastId = 1; // wrap round if we reach a negative number
617 Undo::add(this, (mType == Undo::UNDO));
621 /******************************************************************************
622 * Destructor.
623 * Removes the undo from the list (if it's in the list).
625 UndoItem::~UndoItem()
627 if (mType != Undo::NONE)
628 Undo::remove(this, (mType == Undo::UNDO));
631 /******************************************************************************
632 * Return the description of an event.
634 QString UndoItem::description(const KAEvent& event) const
636 return (mCalendar == CalEvent::TEMPLATE) ? event.templateName() : AlarmText::summary(event);
639 /******************************************************************************
640 * Return the action description of an add or delete Undo/Redo item for displaying.
642 QString UndoItem::addDeleteActionText(CalEvent::Type calendar, bool add)
644 switch (calendar)
646 case CalEvent::ACTIVE:
647 if (add)
648 return i18nc("@info Action to create a new alarm", "New alarm");
649 else
650 return i18nc("@info Action to delete an alarm", "Delete alarm");
651 case CalEvent::TEMPLATE:
652 if (add)
653 return i18nc("@info Action to create a new alarm template", "New template");
654 else
655 return i18nc("@info Action to delete an alarm template", "Delete template");
656 case CalEvent::ARCHIVED:
657 return i18nc("@info", "Delete archived alarm");
658 default:
659 break;
661 return QString();
665 /*=============================================================================
666 = Class: UndoMultiBase
667 = Undo item for multiple alarms.
668 =============================================================================*/
670 template <class T>
671 UndoMulti<T>::UndoMulti(Undo::Type type, const Undo::EventList& events, const QString& name)
672 : UndoMultiBase(type, name) // UNDO only
674 for (int i = 0, end = events.count(); i < end; ++i)
675 mUndos->append(new T(Undo::NONE, events[i]));
678 /******************************************************************************
679 * Undo the item, i.e. restore multiple alarms which were deleted (or delete
680 * alarms which were restored).
681 * Create a redo item to delete (or restore) the alarms again.
682 * Reply = redo item.
684 template <class T>
685 UndoItem* UndoMulti<T>::restore()
687 Undo::List* newUndos = new Undo::List;
688 for (int i = 0, end = mUndos->count(); i < end; ++i)
690 UndoItem* undo = (*mUndos)[i]->restore();
691 if (undo)
692 newUndos->append(undo);
694 if (newUndos->isEmpty())
696 delete newUndos;
697 return Q_NULLPTR;
700 // Create a redo item to delete the alarm again
701 return createRedo(newUndos);
704 /******************************************************************************
705 * If one of the multiple items has the specified ID, delete it.
706 * If an item is deleted and there is only one item left, the UndoMulti
707 * instance is removed from its list and replaced by the remaining UndoItem instead.
708 * Reply = true if this instance was replaced. The caller must delete it.
709 * = false otherwise.
711 template <class T>
712 bool UndoMulti<T>::deleteID(const QString& id)
714 for (int i = 0, end = mUndos->count(); i < end; ++i)
716 UndoItem* item = (*mUndos)[i];
717 if (item->eventID() == id)
719 // Found a matching entry - remove it
720 mUndos->removeAt(i);
721 if (mUndos->count() == 1)
723 // There is only one entry left after removal.
724 // Replace 'this' multi instance with the remaining single entry.
725 replaceWith(item);
726 return true;
728 else
730 delete item;
731 return false;
735 return false;
739 /*=============================================================================
740 = Class: UndoAdd
741 = Undo item for alarm creation.
742 =============================================================================*/
744 UndoAdd::UndoAdd(Undo::Type type, const Undo::Event& undo, const QString& name)
745 : UndoItem(type, name),
746 mResource(undo.EVENT_RESOURCE),
747 mEventId(undo.event.id())
749 setCalendar(undo.event.category());
750 mDescription = UndoItem::description(undo.event); // calendar must be set before calling this
753 UndoAdd::UndoAdd(Undo::Type type, const KAEvent& event, RESOURCE_PARAM_TYPE resource, const QString& name)
754 : UndoItem(type, name),
755 mResource(resource),
756 mEventId(event.id())
758 setCalendar(event.category());
759 mDescription = UndoItem::description(event); // calendar must be set before calling this
762 UndoAdd::UndoAdd(Undo::Type type, const KAEvent& event, RESOURCE_PARAM_TYPE resource, const QString& name, CalEvent::Type cal)
763 : UndoItem(type, name),
764 mResource(resource),
765 mEventId(CalEvent::uid(event.id(), cal)) // convert if old-style event ID
767 setCalendar(cal);
768 mDescription = UndoItem::description(event); // calendar must be set before calling this
771 /******************************************************************************
772 * Undo the item, i.e. delete the alarm which was added.
773 * Create a redo item to add the alarm back again.
774 * Reply = redo item.
776 UndoItem* UndoAdd::doRestore(bool setArchive)
778 // Retrieve the current state of the alarm
779 qCDebug(KALARM_LOG) << mEventId;
780 const KAEvent* ev = AlarmCalendar::getEvent(EventId(mResource.id(), mEventId));
781 if (!ev)
783 mRestoreError = ERR_NOT_FOUND; // alarm is no longer in calendar
784 return Q_NULLPTR;
786 KAEvent event(*ev);
788 // Create a redo item to recreate the alarm.
789 // Do it now, since 'event' gets modified by KAlarm::deleteEvent()
790 UndoItem* undo = createRedo(event, mResource);
792 switch (calendar())
794 case CalEvent::ACTIVE:
796 if (setArchive)
797 event.setArchive();
798 // Archive it if it has already triggered
799 KAlarm::UpdateResult status = KAlarm::deleteEvent(event, true);
800 switch (status.status)
802 case KAlarm::UPDATE_ERROR:
803 case KAlarm::UPDATE_FAILED:
804 case KAlarm::SAVE_FAILED:
805 mRestoreError = ERR_CREATE;
806 break;
807 case KAlarm::UPDATE_KORG_FUNCERR:
808 case KAlarm::UPDATE_KORG_ERRINIT:
809 case KAlarm::UPDATE_KORG_ERRSTART:
810 case KAlarm::UPDATE_KORG_ERR:
811 mRestoreWarning = WARN_KORG_DELETE;
812 ++mRestoreWarningCount;
813 if (status.status > mRestoreWarningKorg.status)
814 mRestoreWarningKorg = status;
815 break;
816 default:
817 break;
819 break;
821 case CalEvent::TEMPLATE:
822 if (KAlarm::deleteTemplate(event) != KAlarm::UPDATE_OK)
823 mRestoreError = ERR_TEMPLATE;
824 break;
825 case CalEvent::ARCHIVED: // redoing the deletion of an archived alarm
826 KAlarm::deleteEvent(event);
827 break;
828 default:
829 delete undo;
830 mRestoreError = ERR_PROG;
831 return Q_NULLPTR;
833 return undo;
836 /******************************************************************************
837 * Create a redo item to add the alarm back again.
839 UndoItem* UndoAdd::createRedo(const KAEvent& event, RESOURCE_PARAM_TYPE resource)
841 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
842 return new UndoDelete(t, event, resource, QStringList(), mName);
845 /******************************************************************************
846 * Return the action description of the Undo item for displaying.
848 QString UndoAdd::defaultActionText() const
850 return addDeleteActionText(calendar(), (type() == Undo::UNDO));
854 /*=============================================================================
855 = Class: UndoAdds
856 = Undo item for multiple alarm creation.
857 =============================================================================*/
859 /******************************************************************************
860 * Create a redo item to add the alarms again.
862 UndoItem* UndoAdds::createRedo(Undo::List* undos)
864 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
865 return new UndoAdds(t, undos, mName);
868 /******************************************************************************
869 * Return the action description of the Undo item for displaying.
871 QString UndoAdds::defaultActionText() const
873 return i18nc("@info", "Create multiple alarms");
877 /*=============================================================================
878 = Class: UndoEdit
879 = Undo item for alarm edit.
880 =============================================================================*/
882 UndoEdit::UndoEdit(Undo::Type type, const KAEvent& oldEvent, const QString& newEventID,
883 RESOURCE_PARAM_TYPE resource, const QStringList& dontShowErrors, const QString& description)
884 : UndoItem(type),
885 mResource(resource),
886 mOldEvent(new KAEvent(oldEvent)),
887 mNewEventId(newEventID),
888 mDescription(description),
889 mDontShowErrors(dontShowErrors)
891 setCalendar(oldEvent.category());
894 UndoEdit::~UndoEdit()
896 delete mOldEvent;
899 /******************************************************************************
900 * Undo the item, i.e. undo an edit to a previously existing alarm.
901 * Create a redo item to reapply the edit.
902 * Reply = redo item.
904 UndoItem* UndoEdit::restore()
906 qCDebug(KALARM_LOG) << mNewEventId;
907 // Retrieve the current state of the alarm
908 const KAEvent* event = AlarmCalendar::getEvent(EventId(mResource.id(), mNewEventId));
909 if (!event)
911 mRestoreError = ERR_NOT_FOUND; // alarm is no longer in calendar
912 return Q_NULLPTR;
914 KAEvent newEvent(*event);
916 // Create a redo item to restore the edit
917 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
918 UndoItem* undo = new UndoEdit(t, newEvent, mOldEvent->id(), mResource, KAlarm::dontShowErrors(EventId(newEvent)), mDescription);
920 switch (calendar())
922 case CalEvent::ACTIVE:
924 KAlarm::UpdateResult status = KAlarm::modifyEvent(newEvent, *mOldEvent);
925 switch (status.status)
927 case KAlarm::UPDATE_ERROR:
928 case KAlarm::UPDATE_FAILED:
929 case KAlarm::SAVE_FAILED:
930 mRestoreError = ERR_CREATE;
931 break;
932 case KAlarm::UPDATE_KORG_FUNCERR:
933 case KAlarm::UPDATE_KORG_ERRINIT:
934 case KAlarm::UPDATE_KORG_ERRSTART:
935 case KAlarm::UPDATE_KORG_ERR:
936 mRestoreWarning = WARN_KORG_MODIFY;
937 ++mRestoreWarningCount;
938 if (status.status > mRestoreWarningKorg.status)
939 mRestoreWarningKorg = status;
940 // fall through to default
941 default:
942 KAlarm::setDontShowErrors(EventId(*mOldEvent), mDontShowErrors);
943 break;
945 break;
947 case CalEvent::TEMPLATE:
948 if (KAlarm::updateTemplate(*mOldEvent) != KAlarm::UPDATE_OK)
949 mRestoreError = ERR_TEMPLATE;
950 break;
951 case CalEvent::ARCHIVED: // editing of archived events is not allowed
952 default:
953 delete undo;
954 mRestoreError = ERR_PROG;
955 return Q_NULLPTR;
957 return undo;
960 /******************************************************************************
961 * Return the action description of the Undo item for displaying.
963 QString UndoEdit::defaultActionText() const
965 switch (calendar())
967 case CalEvent::ACTIVE:
968 return i18nc("@info Action to edit an alarm", "Edit alarm");
969 case CalEvent::TEMPLATE:
970 return i18nc("@info Action to edit an alarm template", "Edit template");
971 default:
972 break;
974 return QString();
978 /*=============================================================================
979 = Class: UndoDelete
980 = Undo item for alarm deletion.
981 =============================================================================*/
983 UndoDelete::UndoDelete(Undo::Type type, const Undo::Event& undo, const QString& name)
984 : UndoItem(type, name),
985 mResource(undo.EVENT_RESOURCE),
986 mEvent(new KAEvent(undo.event)),
987 mDontShowErrors(undo.dontShowErrors)
989 setCalendar(mEvent->category());
992 UndoDelete::UndoDelete(Undo::Type type, const KAEvent& event, RESOURCE_PARAM_TYPE resource, const QStringList& dontShowErrors, const QString& name)
993 : UndoItem(type, name),
994 mResource(resource),
995 mEvent(new KAEvent(event)),
996 mDontShowErrors(dontShowErrors)
998 setCalendar(mEvent->category());
1001 UndoDelete::~UndoDelete()
1003 delete mEvent;
1006 /******************************************************************************
1007 * Undo the item, i.e. restore an alarm which was deleted.
1008 * Create a redo item to delete the alarm again.
1009 * Reply = redo item.
1011 UndoItem* UndoDelete::restore()
1013 qCDebug(KALARM_LOG) << mEvent->id();
1014 // Restore the original event
1015 switch (calendar())
1017 case CalEvent::ACTIVE:
1018 if (mEvent->toBeArchived())
1020 // It was archived when it was deleted
1021 mEvent->setCategory(CalEvent::ARCHIVED);
1022 KAlarm::UpdateResult status = KAlarm::reactivateEvent(*mEvent, &mResource);
1023 switch (status.status)
1025 case KAlarm::UPDATE_KORG_FUNCERR:
1026 case KAlarm::UPDATE_KORG_ERRINIT:
1027 case KAlarm::UPDATE_KORG_ERRSTART:
1028 case KAlarm::UPDATE_KORG_ERR:
1029 mRestoreWarning = WARN_KORG_ADD;
1030 ++mRestoreWarningCount;
1031 if (status.status > mRestoreWarningKorg.status)
1032 mRestoreWarningKorg = status;
1033 break;
1034 case KAlarm::UPDATE_ERROR:
1035 case KAlarm::UPDATE_FAILED:
1036 case KAlarm::SAVE_FAILED:
1037 mRestoreError = ERR_ARCHIVED;
1038 return Q_NULLPTR;
1039 case KAlarm::UPDATE_OK:
1040 break;
1043 else
1045 KAlarm::UpdateResult status = KAlarm::addEvent(*mEvent, &mResource, Q_NULLPTR, true);
1046 switch (status.status)
1048 case KAlarm::UPDATE_KORG_FUNCERR:
1049 case KAlarm::UPDATE_KORG_ERRINIT:
1050 case KAlarm::UPDATE_KORG_ERRSTART:
1051 case KAlarm::UPDATE_KORG_ERR:
1052 mRestoreWarning = WARN_KORG_ADD;
1053 ++mRestoreWarningCount;
1054 if (status.status > mRestoreWarningKorg.status)
1055 mRestoreWarningKorg = status;
1056 break;
1057 case KAlarm::UPDATE_ERROR:
1058 case KAlarm::UPDATE_FAILED:
1059 case KAlarm::SAVE_FAILED:
1060 mRestoreError = ERR_CREATE;
1061 return Q_NULLPTR;
1062 case KAlarm::UPDATE_OK:
1063 break;
1066 KAlarm::setDontShowErrors(EventId(*mEvent), mDontShowErrors);
1067 break;
1068 case CalEvent::TEMPLATE:
1069 if (KAlarm::addTemplate(*mEvent, &mResource) != KAlarm::UPDATE_OK)
1071 mRestoreError = ERR_CREATE;
1072 return Q_NULLPTR;
1074 break;
1075 case CalEvent::ARCHIVED:
1076 if (!KAlarm::addArchivedEvent(*mEvent, &mResource))
1078 mRestoreError = ERR_CREATE;
1079 return Q_NULLPTR;
1081 break;
1082 default:
1083 mRestoreError = ERR_PROG;
1084 return Q_NULLPTR;
1087 // Create a redo item to delete the alarm again
1088 return createRedo(*mEvent, mResource);
1091 /******************************************************************************
1092 * Create a redo item to archive the alarm again.
1094 UndoItem* UndoDelete::createRedo(const KAEvent& event, RESOURCE_PARAM_TYPE resource)
1096 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
1097 return new UndoAdd(t, event, resource, mName);
1100 /******************************************************************************
1101 * Return the action description of the Undo item for displaying.
1103 QString UndoDelete::defaultActionText() const
1105 return addDeleteActionText(calendar(), (type() == Undo::REDO));
1109 /*=============================================================================
1110 = Class: UndoDeletes
1111 = Undo item for multiple alarm deletion.
1112 =============================================================================*/
1114 /******************************************************************************
1115 * Create a redo item to delete the alarms again.
1117 UndoItem* UndoDeletes::createRedo(Undo::List* undos)
1119 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
1120 return new UndoDeletes(t, undos, mName);
1123 /******************************************************************************
1124 * Return the action description of the Undo item for displaying.
1126 QString UndoDeletes::defaultActionText() const
1128 if (mUndos->isEmpty())
1129 return QString();
1130 for (int i = 0, end = mUndos->count(); i < end; ++i)
1132 switch ((*mUndos)[i]->calendar())
1134 case CalEvent::ACTIVE:
1135 return i18nc("@info", "Delete multiple alarms");
1136 case CalEvent::TEMPLATE:
1137 return i18nc("@info", "Delete multiple templates");
1138 case CalEvent::ARCHIVED:
1139 break; // check if they are ALL archived
1140 default:
1141 return QString();
1144 return i18nc("@info", "Delete multiple archived alarms");
1148 /*=============================================================================
1149 = Class: UndoReactivate
1150 = Undo item for alarm reactivation.
1151 =============================================================================*/
1153 /******************************************************************************
1154 * Undo the item, i.e. re-archive the alarm which was reactivated.
1155 * Create a redo item to reactivate the alarm back again.
1156 * Reply = redo item.
1158 UndoItem* UndoReactivate::restore()
1160 qCDebug(KALARM_LOG);
1161 // Validate the alarm's calendar
1162 switch (calendar())
1164 case CalEvent::ACTIVE:
1165 break;
1166 default:
1167 mRestoreError = ERR_PROG;
1168 return Q_NULLPTR;
1170 return UndoAdd::doRestore(true); // restore alarm, ensuring that it is re-archived
1173 /******************************************************************************
1174 * Create a redo item to add the alarm back again.
1176 UndoItem* UndoReactivate::createRedo(const KAEvent& event, RESOURCE_PARAM_TYPE resource)
1178 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
1179 return new UndoDeactivate(t, event, resource, mName);
1182 /******************************************************************************
1183 * Return the action description of the Undo item for displaying.
1185 QString UndoReactivate::defaultActionText() const
1187 return i18nc("@info", "Reactivate alarm");
1191 /*=============================================================================
1192 = Class: UndoDeactivate
1193 = Redo item for alarm reactivation.
1194 =============================================================================*/
1196 /******************************************************************************
1197 * Undo the item, i.e. reactivate an alarm which was archived.
1198 * Create a redo item to archive the alarm again.
1199 * Reply = redo item.
1201 UndoItem* UndoDeactivate::restore()
1203 qCDebug(KALARM_LOG);
1204 // Validate the alarm's calendar
1205 switch (calendar())
1207 case CalEvent::ACTIVE:
1208 break;
1209 default:
1210 mRestoreError = ERR_PROG;
1211 return Q_NULLPTR;
1214 return UndoDelete::restore();
1217 /******************************************************************************
1218 * Create a redo item to archive the alarm again.
1220 UndoItem* UndoDeactivate::createRedo(const KAEvent& event, RESOURCE_PARAM_TYPE resource)
1222 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
1223 return new UndoReactivate(t, event, resource, mName);
1226 /******************************************************************************
1227 * Return the action description of the Undo item for displaying.
1229 QString UndoDeactivate::defaultActionText() const
1231 return i18nc("@info", "Reactivate alarm");
1235 /*=============================================================================
1236 = Class: UndoReactivates
1237 = Undo item for multiple alarm reactivation.
1238 =============================================================================*/
1240 /******************************************************************************
1241 * Create a redo item to reactivate the alarms again.
1243 UndoItem* UndoReactivates::createRedo(Undo::List* undos)
1245 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
1246 return new UndoReactivates(t, undos, mName);
1249 /******************************************************************************
1250 * Return the action description of the Undo item for displaying.
1252 QString UndoReactivates::defaultActionText() const
1254 return i18nc("@info", "Reactivate multiple alarms");
1258 /*=============================================================================
1259 = Class: Event
1260 = Event details for external calls.
1261 =============================================================================*/
1262 Undo::Event::Event(const KAEvent& e, RESOURCE_PARAM_TYPE r)
1263 : event(e),
1264 EVENT_RESOURCE(r)
1266 if (e.category() == CalEvent::ACTIVE)
1267 dontShowErrors = KAlarm::dontShowErrors(EventId(e));
1270 // vim: et sw=4: