summaryrefslogtreecommitdiffstats
path: root/kalarm/undo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kalarm/undo.cpp')
-rw-r--r--kalarm/undo.cpp1127
1 files changed, 1127 insertions, 0 deletions
diff --git a/kalarm/undo.cpp b/kalarm/undo.cpp
new file mode 100644
index 00000000..bab085ae
--- /dev/null
+++ b/kalarm/undo.cpp
@@ -0,0 +1,1127 @@
+/*
+ * undo.cpp - undo/redo facility
+ * Program: kalarm
+ * Copyright © 2005,2006 by David Jarvie <software@astrojar.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "kalarm.h"
+
+#include <qobject.h>
+#include <qstringlist.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+#include "alarmcalendar.h"
+#include "alarmevent.h"
+#include "alarmtext.h"
+#include "functions.h"
+#include "undo.moc"
+
+static int maxCount = 12;
+
+
+class UndoItem
+{
+ public:
+ enum Operation { ADD, EDIT, DELETE, REACTIVATE, DEACTIVATE, MULTI };
+ UndoItem(); // needed by QValueList
+ virtual ~UndoItem();
+ virtual Operation operation() const = 0;
+ virtual QString actionText() const = 0;
+ virtual QString description() const { return QString::null; }
+ virtual QString eventID() const { return QString::null; }
+ virtual QString oldEventID() const { return QString::null; }
+ virtual QString newEventID() const { return QString::null; }
+ int id() const { return mId; }
+ Undo::Type type() const { return mType; }
+ void setType(Undo::Type t) { mType = t; }
+ KAEvent::Status calendar() const { return mCalendar; }
+ virtual void setCalendar(KAEvent::Status s) { mCalendar = s; }
+ virtual UndoItem* restore() = 0;
+ virtual bool deleteID(const QString& /*id*/) { return false; }
+
+ enum Error { ERR_NONE, ERR_PROG, ERR_NOT_FOUND, ERR_CREATE, ERR_TEMPLATE, ERR_EXPIRED };
+ enum Warning { WARN_NONE, WARN_KORG_ADD, WARN_KORG_MODIFY, WARN_KORG_DELETE };
+ static int mLastId;
+ static Error mRestoreError; // error code valid only if restore() returns 0
+ static Warning mRestoreWarning; // warning code set by restore()
+ static int mRestoreWarningCount; // item count for mRestoreWarning (to allow i18n messages to work correctly)
+
+ protected:
+ UndoItem(Undo::Type);
+ static QString addDeleteActionText(KAEvent::Status, bool add);
+ QString description(const KAEvent&) const;
+ void replaceWith(UndoItem* item) { Undo::replace(this, item); }
+
+ int mId; // unique identifier (only for mType = UNDO, REDO)
+ Undo::Type mType; // which list (if any) the object is in
+ KAEvent::Status mCalendar;
+};
+
+class UndoMultiBase : public UndoItem
+{
+ public:
+ UndoMultiBase(Undo::Type t) : UndoItem(t) { }
+ UndoMultiBase(Undo::Type t, Undo::List& undos) : UndoItem(t), mUndos(undos) { }
+ ~UndoMultiBase();
+ const Undo::List& undos() const { return mUndos; }
+ protected:
+ Undo::List mUndos; // this list must always have >= 2 entries
+};
+
+template <class T> class UndoMulti : public UndoMultiBase
+{
+ public:
+ UndoMulti(Undo::Type, const QValueList<KAEvent>&);
+ UndoMulti(Undo::Type t, Undo::List& undos) : UndoMultiBase(t, undos) { }
+ virtual Operation operation() const { return MULTI; }
+ virtual UndoItem* restore();
+ virtual bool deleteID(const QString& id);
+ virtual UndoItem* createRedo(Undo::List&) = 0;
+};
+
+class UndoAdd : public UndoItem
+{
+ public:
+ UndoAdd(Undo::Type, const KAEvent&);
+ UndoAdd(Undo::Type, const KAEvent&, KAEvent::Status);
+ virtual Operation operation() const { return ADD; }
+ virtual QString actionText() const;
+ virtual QString description() const { return mDescription; }
+ virtual QString eventID() const { return mEventID; }
+ virtual QString newEventID() const { return mEventID; }
+ virtual UndoItem* restore() { return doRestore(); }
+ protected:
+ UndoItem* doRestore(bool setArchive = false);
+ virtual UndoItem* createRedo(const KAEvent&);
+ private:
+ QString mEventID;
+ QString mDescription;
+};
+
+class UndoEdit : public UndoItem
+{
+ public:
+ UndoEdit(Undo::Type, const KAEvent& oldEvent, const QString& newEventID, const QString& description);
+ ~UndoEdit();
+ virtual Operation operation() const { return EDIT; }
+ virtual QString actionText() const;
+ virtual QString description() const { return mDescription; }
+ virtual QString eventID() const { return mNewEventID; }
+ virtual QString oldEventID() const { return mOldEvent->id(); }
+ virtual QString newEventID() const { return mNewEventID; }
+ virtual UndoItem* restore();
+ private:
+ KAEvent* mOldEvent;
+ QString mNewEventID;
+ QString mDescription;
+};
+
+class UndoDelete : public UndoItem
+{
+ public:
+ UndoDelete(Undo::Type, const KAEvent&);
+ ~UndoDelete();
+ virtual Operation operation() const { return DELETE; }
+ virtual QString actionText() const;
+ virtual QString description() const { return UndoItem::description(*mEvent); }
+ virtual QString eventID() const { return mEvent->id(); }
+ virtual QString oldEventID() const { return mEvent->id(); }
+ virtual UndoItem* restore();
+ KAEvent* event() const { return mEvent; }
+ protected:
+ virtual UndoItem* createRedo(const KAEvent&);
+ private:
+ KAEvent* mEvent;
+};
+
+class UndoReactivate : public UndoAdd
+{
+ public:
+ UndoReactivate(Undo::Type t, const KAEvent& e) : UndoAdd(t, e, KAEvent::ACTIVE) { }
+ virtual Operation operation() const { return REACTIVATE; }
+ virtual QString actionText() const;
+ virtual UndoItem* restore();
+ protected:
+ virtual UndoItem* createRedo(const KAEvent&);
+};
+
+class UndoDeactivate : public UndoDelete
+{
+ public:
+ UndoDeactivate(Undo::Type t, const KAEvent& e) : UndoDelete(t, e) { }
+ virtual Operation operation() const { return DEACTIVATE; }
+ virtual QString actionText() const;
+ virtual UndoItem* restore();
+ protected:
+ virtual UndoItem* createRedo(const KAEvent&);
+};
+
+class UndoDeletes : public UndoMulti<UndoDelete>
+{
+ public:
+ UndoDeletes(Undo::Type t, const QValueList<KAEvent>& events)
+ : UndoMulti<UndoDelete>(t, events) { } // UNDO only
+ UndoDeletes(Undo::Type t, Undo::List& undos)
+ : UndoMulti<UndoDelete>(t, undos) { }
+ virtual QString actionText() const;
+ virtual UndoItem* createRedo(Undo::List&);
+};
+
+class UndoReactivates : public UndoMulti<UndoReactivate>
+{
+ public:
+ UndoReactivates(Undo::Type t, const QValueList<KAEvent>& events)
+ : UndoMulti<UndoReactivate>(t, events) { } // UNDO only
+ UndoReactivates(Undo::Type t, Undo::List& undos)
+ : UndoMulti<UndoReactivate>(t, undos) { }
+ virtual QString actionText() const;
+ virtual UndoItem* createRedo(Undo::List&);
+};
+
+Undo* Undo::mInstance = 0;
+Undo::List Undo::mUndoList;
+Undo::List Undo::mRedoList;
+
+
+/******************************************************************************
+* Create the one and only instance of the Undo class.
+*/
+Undo* Undo::instance()
+{
+ if (!mInstance)
+ mInstance = new Undo(kapp);
+ return mInstance;
+}
+
+/******************************************************************************
+* Clear the lists of undo and redo items.
+*/
+void Undo::clear()
+{
+ if (!mUndoList.isEmpty() || !mRedoList.isEmpty())
+ {
+ mInstance->blockSignals(true);
+ while (mUndoList.count())
+ delete mUndoList.first(); // N.B. 'delete' removes the object from the list
+ while (mRedoList.count())
+ delete mRedoList.first(); // N.B. 'delete' removes the object from the list
+ mInstance->blockSignals(false);
+ emitChanged();
+ }
+}
+
+/******************************************************************************
+* Create an undo item and add it to the list of undos.
+* N.B. The base class constructor adds the object to the undo list.
+*/
+void Undo::saveAdd(const KAEvent& event)
+{
+ new UndoAdd(UNDO, event);
+ emitChanged();
+}
+
+void Undo::saveEdit(const KAEvent& oldEvent, const KAEvent& newEvent)
+{
+ new UndoEdit(UNDO, oldEvent, newEvent.id(), AlarmText::summary(newEvent));
+ removeRedos(oldEvent.id()); // remove any redos which are made invalid by this edit
+ emitChanged();
+}
+
+void Undo::saveDelete(const KAEvent& event)
+{
+ new UndoDelete(UNDO, event);
+ removeRedos(event.id()); // remove any redos which are made invalid by this deletion
+ emitChanged();
+}
+
+void Undo::saveDeletes(const QValueList<KAEvent>& events)
+{
+ int count = events.count();
+ if (count == 1)
+ saveDelete(events.first());
+ else if (count > 1)
+ {
+ new UndoDeletes(UNDO, events);
+ for (QValueList<KAEvent>::ConstIterator it = events.begin(); it != events.end(); ++it)
+ removeRedos((*it).id()); // remove any redos which are made invalid by these deletions
+ emitChanged();
+ }
+}
+
+void Undo::saveReactivate(const KAEvent& event)
+{
+ new UndoReactivate(UNDO, event);
+ emitChanged();
+}
+
+void Undo::saveReactivates(const QValueList<KAEvent>& events)
+{
+ int count = events.count();
+ if (count == 1)
+ saveReactivate(events.first());
+ else if (count > 1)
+ {
+ new UndoReactivates(UNDO, events);
+ emitChanged();
+ }
+}
+
+/******************************************************************************
+* Remove any redos which are made invalid by a new undo.
+*/
+void Undo::removeRedos(const QString& eventID)
+{
+ QString id = eventID;
+ for (Iterator it = mRedoList.begin(); it != mRedoList.end(); )
+ {
+ UndoItem* item = *it;
+//kdDebug(5950)<<"removeRedos(): "<<item->eventID()<<" (looking for "<<id<<")"<<endl;
+ if (item->operation() == UndoItem::MULTI)
+ {
+ if (item->deleteID(id))
+ {
+ // The old multi-redo was replaced with a new single redo
+ delete item;
+ }
+ ++it;
+ }
+ else if (item->eventID() == id)
+ {
+ if (item->operation() == UndoItem::EDIT)
+ id = item->oldEventID(); // continue looking for its post-edit ID
+ item->setType(NONE); // prevent the destructor removing it from the list
+ delete item;
+ it = mRedoList.remove(it);
+ }
+ else
+ ++it;
+ }
+}
+
+/******************************************************************************
+* Undo or redo a specified item.
+* Reply = true if success, or if the item no longer exists.
+*/
+bool Undo::undo(Undo::Iterator it, Undo::Type type, QWidget* parent, const QString& action)
+{
+ UndoItem::mRestoreError = UndoItem::ERR_NONE;
+ UndoItem::mRestoreWarning = UndoItem::WARN_NONE;
+ UndoItem::mRestoreWarningCount = 0;
+ if (it != mUndoList.end() && it != mRedoList.end() && (*it)->type() == type)
+ {
+ (*it)->restore();
+ delete *it; // N.B. 'delete' removes the object from its list
+ emitChanged();
+ }
+
+ QString err;
+ switch (UndoItem::mRestoreError)
+ {
+ case UndoItem::ERR_NONE:
+ {
+ KAlarm::KOrgUpdateError errcode;
+ switch (UndoItem::mRestoreWarning)
+ {
+ case UndoItem::WARN_KORG_ADD: errcode = KAlarm::KORG_ERR_ADD; break;
+ case UndoItem::WARN_KORG_MODIFY: errcode = KAlarm::KORG_ERR_MODIFY; break;
+ case UndoItem::WARN_KORG_DELETE: errcode = KAlarm::KORG_ERR_DELETE; break;
+ case UndoItem::WARN_NONE:
+ default:
+ return true;
+ }
+ KAlarm::displayKOrgUpdateError(parent, errcode, UndoItem::mRestoreWarningCount);
+ return true;
+ }
+ case UndoItem::ERR_NOT_FOUND: err = i18n("Alarm not found"); break;
+ case UndoItem::ERR_CREATE: err = i18n("Error recreating alarm"); break;
+ case UndoItem::ERR_TEMPLATE: err = i18n("Error recreating alarm template"); break;
+ case UndoItem::ERR_EXPIRED: err = i18n("Cannot reactivate expired alarm"); break;
+ case UndoItem::ERR_PROG: err = i18n("Program error"); break;
+ default: err = i18n("Unknown error"); break;
+ }
+ KMessageBox::sorry(parent, i18n("Undo-action: message", "%1: %2").arg(action).arg(err));
+ return false;
+}
+
+/******************************************************************************
+* Add an undo item to the start of one of the lists.
+*/
+void Undo::add(UndoItem* item, bool undo)
+{
+ if (item)
+ {
+ // Limit the number of items stored
+ int undoCount = mUndoList.count();
+ int redoCount = mRedoList.count();
+ if (undoCount + redoCount >= maxCount - 1)
+ {
+ if (undoCount)
+ mUndoList.pop_back();
+ else
+ mRedoList.pop_back();
+ }
+
+ // Append the new item
+ List* list = undo ? &mUndoList : &mRedoList;
+ list->prepend(item);
+ }
+}
+
+/******************************************************************************
+* Remove an undo item from one of the lists.
+*/
+void Undo::remove(UndoItem* item, bool undo)
+{
+ List* list = undo ? &mUndoList : &mRedoList;
+ if (!list->isEmpty())
+ list->remove(item);
+}
+
+/******************************************************************************
+* Replace an undo item in one of the lists.
+*/
+void Undo::replace(UndoItem* old, UndoItem* New)
+{
+ Type type = old->type();
+ List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : 0;
+ if (!list)
+ return;
+ Iterator it = list->find(old);
+ if (it != list->end())
+ {
+ New->setType(type); // ensure the item points to the correct list
+ *it = New;
+ old->setType(NONE); // mark the old item as no longer being in a list
+ }
+}
+
+/******************************************************************************
+* Return the action description of the latest undo/redo item.
+*/
+QString Undo::actionText(Undo::Type type)
+{
+ List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : 0;
+ return (list && !list->isEmpty()) ? list->first()->actionText() : QString::null;
+}
+
+/******************************************************************************
+* Return the action description of the undo/redo item with the specified ID.
+*/
+QString Undo::actionText(Undo::Type type, int id)
+{
+ UndoItem* undo = getItem(id, type);
+ return undo ? undo->actionText() : QString::null;
+}
+
+/******************************************************************************
+* Return the alarm description of the undo/redo item with the specified ID.
+*/
+QString Undo::description(Undo::Type type, int id)
+{
+ UndoItem* undo = getItem(id, type);
+ return undo ? undo->description() : QString::null;
+}
+
+/******************************************************************************
+* Return the descriptions of all undo or redo items, in order latest first.
+* For alarms which have undergone more than one change, only the first one is
+* listed, to force dependent undos to be executed in their correct order.
+* If 'ids' is non-null, also returns a list of their corresponding IDs.
+*/
+QValueList<int> Undo::ids(Undo::Type type)
+{
+ QValueList<int> ids;
+ QStringList ignoreIDs;
+//int n=0;
+ List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : 0;
+ if (!list)
+ return ids;
+ for (Iterator it = list->begin(); it != list->end(); ++it)
+ {
+ // Check whether this item should be ignored because it is a
+ // deendent undo. If not, add this item's ID to the ignore list.
+ UndoItem* item = *it;
+ bool omit = false;
+ if (item->operation() == UndoItem::MULTI)
+ {
+ // If any item in a multi-undo is disqualified, omit the whole multi-undo
+ QStringList newIDs;
+ const Undo::List& undos = ((UndoMultiBase*)item)->undos();
+ for (Undo::List::ConstIterator u = undos.begin(); u != undos.end(); ++u)
+ {
+ QString evid = (*u)->eventID();
+ if (ignoreIDs.find(evid) != ignoreIDs.end())
+ omit = true;
+ else if (omit)
+ ignoreIDs.append(evid);
+ else
+ newIDs.append(evid);
+ }
+ if (omit)
+ {
+ for (QStringList::ConstIterator i = newIDs.begin(); i != newIDs.end(); ++i)
+ ignoreIDs.append(*i);
+ }
+ }
+ else
+ {
+ omit = (ignoreIDs.find(item->eventID()) != ignoreIDs.end());
+ if (!omit)
+ ignoreIDs.append(item->eventID());
+ if (item->operation() == UndoItem::EDIT)
+ ignoreIDs.append(item->oldEventID()); // continue looking for its post-edit ID
+ }
+ if (!omit)
+ ids.append(item->id());
+//else kdDebug(5950)<<"Undo::ids(): omit "<<item->actionText()<<": "<<item->description()<<endl;
+ }
+//kdDebug(5950)<<"Undo::ids(): "<<n<<" -> "<<ids.count()<<endl;
+ return ids;
+}
+
+/******************************************************************************
+* Emit the appropriate 'changed' signal.
+*/
+void Undo::emitChanged()
+{
+ if (mInstance)
+ mInstance->emitChanged(actionText(UNDO), actionText(REDO));
+}
+
+/******************************************************************************
+* Return the item with the specified ID.
+*/
+UndoItem* Undo::getItem(int id, Undo::Type type)
+{
+ List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : 0;
+ if (list)
+ {
+ for (Iterator it = list->begin(); it != list->end(); ++it)
+ {
+ if ((*it)->id() == id)
+ return *it;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Find an item with the specified ID.
+*/
+Undo::Iterator Undo::findItem(int id, Undo::Type type)
+{
+ List* list = (type == UNDO) ? &mUndoList : &mRedoList;
+ Iterator it;
+ for (it = list->begin(); it != list->end(); ++it)
+ {
+ if ((*it)->id() == id)
+ break;
+ }
+ return it;
+}
+
+
+/*=============================================================================
+= Class: UndoItem
+= A single undo action.
+=============================================================================*/
+int UndoItem::mLastId = 0;
+UndoItem::Error UndoItem::mRestoreError;
+UndoItem::Warning UndoItem::mRestoreWarning;
+int UndoItem::mRestoreWarningCount;
+
+/******************************************************************************
+* Constructor.
+* Optionally appends the undo to the list of undos.
+*/
+UndoItem::UndoItem(Undo::Type type)
+ : mId(0),
+ mType(type)
+{
+ if (type != Undo::NONE)
+ {
+ mId = ++mLastId;
+ if (mId < 0)
+ mId = mLastId = 1; // wrap round if we reach a negative number
+ Undo::add(this, (mType == Undo::UNDO));
+ }
+}
+
+/******************************************************************************
+* Destructor.
+* Removes the undo from the list (if it's in the list).
+*/
+UndoItem::~UndoItem()
+{
+ if (mType != Undo::NONE)
+ Undo::remove(this, (mType == Undo::UNDO));
+}
+
+/******************************************************************************
+* Return the description of an event.
+*/
+QString UndoItem::description(const KAEvent& event) const
+{
+ return (mCalendar == KAEvent::TEMPLATE) ? event.templateName() : AlarmText::summary(event);
+}
+
+/******************************************************************************
+* Return the action description of an add or delete Undo/Redo item for displaying.
+*/
+QString UndoItem::addDeleteActionText(KAEvent::Status calendar, bool add)
+{
+ switch (calendar)
+ {
+ case KAEvent::ACTIVE:
+ if (add)
+ return i18n("Action to create a new alarm", "New alarm");
+ else
+ return i18n("Action to delete an alarm", "Delete alarm");
+ case KAEvent::TEMPLATE:
+ if (add)
+ return i18n("Action to create a new alarm template", "New template");
+ else
+ return i18n("Action to delete an alarm template", "Delete template");
+ case KAEvent::EXPIRED:
+ return i18n("Delete expired alarm");
+ default:
+ break;
+ }
+ return QString::null;
+}
+
+
+/*=============================================================================
+= Class: UndoMultiBase
+= Undo item for multiple alarms.
+=============================================================================*/
+
+template <class T>
+UndoMulti<T>::UndoMulti(Undo::Type type, const QValueList<KAEvent>& events)
+ : UndoMultiBase(type) // UNDO only
+{
+ for (QValueList<KAEvent>::ConstIterator it = events.begin(); it != events.end(); ++it)
+ mUndos.append(new T(Undo::NONE, *it));
+}
+
+UndoMultiBase::~UndoMultiBase()
+{
+ for (Undo::List::Iterator it = mUndos.begin(); it != mUndos.end(); ++it)
+ delete *it;
+}
+
+/******************************************************************************
+* Undo the item, i.e. restore multiple alarms which were deleted (or delete
+* alarms which were restored).
+* Create a redo item to delete (or restore) the alarms again.
+* Reply = redo item.
+*/
+template <class T>
+UndoItem* UndoMulti<T>::restore()
+{
+ Undo::List newUndos;
+ for (Undo::List::Iterator it = mUndos.begin(); it != mUndos.end(); ++it)
+ {
+ UndoItem* undo = (*it)->restore();
+ if (undo)
+ newUndos.append(undo);
+ }
+ if (newUndos.isEmpty())
+ return 0;
+
+ // Create a redo item to delete the alarm again
+ return createRedo(newUndos);
+}
+
+/******************************************************************************
+* If one of the multiple items has the specified ID, delete it.
+* If an item is deleted and there is only one item left, the UndoMulti
+* instance is removed from its list and replaced by the remaining UndoItem instead.
+* Reply = true if this instance was replaced. The caller must delete it.
+* = false otherwise.
+*/
+template <class T>
+bool UndoMulti<T>::deleteID(const QString& id)
+{
+ for (Undo::List::Iterator it = mUndos.begin(); it != mUndos.end(); ++it)
+ {
+ UndoItem* item = *it;
+ if (item->eventID() == id)
+ {
+ // Found a matching entry - remove it
+ mUndos.remove(it);
+ if (mUndos.count() == 1)
+ {
+ // There is only one entry left after removal.
+ // Replace 'this' multi instance with the remaining single entry.
+ replaceWith(item);
+ return true;
+ }
+ else
+ {
+ delete item;
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+
+/*=============================================================================
+= Class: UndoAdd
+= Undo item for alarm creation.
+=============================================================================*/
+
+UndoAdd::UndoAdd(Undo::Type type, const KAEvent& event)
+ : UndoItem(type),
+ mEventID(event.id())
+{
+ setCalendar(KAEvent::uidStatus(mEventID));
+ mDescription = UndoItem::description(event); // calendar must be set before calling this
+}
+
+UndoAdd::UndoAdd(Undo::Type type, const KAEvent& event, KAEvent::Status cal)
+ : UndoItem(type),
+ mEventID(KAEvent::uid(event.id(), cal))
+{
+ setCalendar(cal);
+ mDescription = UndoItem::description(event); // calendar must be set before calling this
+}
+
+/******************************************************************************
+* Undo the item, i.e. delete the alarm which was added.
+* Create a redo item to add the alarm back again.
+* Reply = redo item.
+*/
+UndoItem* UndoAdd::doRestore(bool setArchive)
+{
+ // Retrieve the current state of the alarm
+ kdDebug(5950) << "UndoAdd::doRestore(" << mEventID << ")\n";
+ const KCal::Event* kcalEvent = AlarmCalendar::getEvent(mEventID);
+ if (!kcalEvent)
+ {
+ mRestoreError = ERR_NOT_FOUND; // alarm is no longer in calendar
+ return 0;
+ }
+ KAEvent event(*kcalEvent);
+
+ // Create a redo item to recreate the alarm.
+ // Do it now, since 'event' gets modified by KAlarm::deleteEvent()
+ UndoItem* undo = createRedo(event);
+
+ switch (calendar())
+ {
+ case KAEvent::ACTIVE:
+ if (setArchive)
+ event.setArchive();
+ // Archive it if it has already triggered
+ switch (KAlarm::deleteEvent(event, true))
+ {
+ case KAlarm::UPDATE_ERROR:
+ case KAlarm::UPDATE_FAILED:
+ case KAlarm::SAVE_FAILED:
+ mRestoreError = ERR_CREATE;
+ break;
+ case KAlarm::UPDATE_KORG_ERR:
+ mRestoreWarning = WARN_KORG_DELETE;
+ ++mRestoreWarningCount;
+ break;
+ default:
+ break;
+ }
+ break;
+ case KAEvent::TEMPLATE:
+ if (KAlarm::deleteTemplate(event) != KAlarm::UPDATE_OK)
+ mRestoreError = ERR_TEMPLATE;
+ break;
+ case KAEvent::EXPIRED: // redoing the deletion of an expired alarm
+ KAlarm::deleteEvent(event);
+ break;
+ default:
+ delete undo;
+ mRestoreError = ERR_PROG;
+ return 0;
+ }
+ return undo;
+}
+
+/******************************************************************************
+* Create a redo item to add the alarm back again.
+*/
+UndoItem* UndoAdd::createRedo(const KAEvent& event)
+{
+ Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
+ return new UndoDelete(t, event);
+}
+
+/******************************************************************************
+* Return the action description of the Undo item for displaying.
+*/
+QString UndoAdd::actionText() const
+{
+ return addDeleteActionText(calendar(), (type() == Undo::UNDO));
+}
+
+
+/*=============================================================================
+= Class: UndoEdit
+= Undo item for alarm edit.
+=============================================================================*/
+
+UndoEdit::UndoEdit(Undo::Type type, const KAEvent& oldEvent, const QString& newEventID, const QString& description)
+ : UndoItem(type),
+ mOldEvent(new KAEvent(oldEvent)),
+ mNewEventID(newEventID),
+ mDescription(description)
+{
+ setCalendar(KAEvent::uidStatus(mNewEventID));
+}
+
+UndoEdit::~UndoEdit()
+{
+ delete mOldEvent;
+}
+
+/******************************************************************************
+* Undo the item, i.e. undo an edit to a previously existing alarm.
+* Create a redo item to reapply the edit.
+* Reply = redo item.
+*/
+UndoItem* UndoEdit::restore()
+{
+ kdDebug(5950) << "UndoEdit::restore(" << mNewEventID << ")\n";
+ // Retrieve the current state of the alarm
+ const KCal::Event* kcalEvent = AlarmCalendar::getEvent(mNewEventID);
+ if (!kcalEvent)
+ {
+ mRestoreError = ERR_NOT_FOUND; // alarm is no longer in calendar
+ return 0;
+ }
+ KAEvent newEvent(*kcalEvent);
+
+ // Create a redo item to restore the edit
+ Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
+ UndoItem* undo = new UndoEdit(t, newEvent, mOldEvent->id(), mDescription);
+
+ switch (calendar())
+ {
+ case KAEvent::ACTIVE:
+ switch (KAlarm::modifyEvent(newEvent, *mOldEvent, 0))
+ {
+ case KAlarm::UPDATE_ERROR:
+ case KAlarm::UPDATE_FAILED:
+ case KAlarm::SAVE_FAILED:
+ mRestoreError = ERR_CREATE;
+ break;
+ case KAlarm::UPDATE_KORG_ERR:
+ mRestoreWarning = WARN_KORG_MODIFY;
+ ++mRestoreWarningCount;
+ break;
+ default:
+ break;
+ }
+ break;
+ case KAEvent::TEMPLATE:
+ if (KAlarm::updateTemplate(*mOldEvent, 0) != KAlarm::UPDATE_OK)
+ mRestoreError = ERR_TEMPLATE;
+ break;
+ case KAEvent::EXPIRED: // editing of expired events is not allowed
+ default:
+ delete undo;
+ mRestoreError = ERR_PROG;
+ return 0;
+ }
+ return undo;
+}
+
+/******************************************************************************
+* Return the action description of the Undo item for displaying.
+*/
+QString UndoEdit::actionText() const
+{
+ switch (calendar())
+ {
+ case KAEvent::ACTIVE:
+ return i18n("Action to edit an alarm", "Edit alarm");
+ case KAEvent::TEMPLATE:
+ return i18n("Action to edit an alarm template", "Edit template");
+ default:
+ break;
+ }
+ return QString::null;
+}
+
+
+/*=============================================================================
+= Class: UndoDelete
+= Undo item for alarm deletion.
+=============================================================================*/
+
+UndoDelete::UndoDelete(Undo::Type type, const KAEvent& event)
+ : UndoItem(type),
+ mEvent(new KAEvent(event))
+{
+ setCalendar(KAEvent::uidStatus(mEvent->id()));
+}
+
+UndoDelete::~UndoDelete()
+{
+ delete mEvent;
+}
+
+/******************************************************************************
+* Undo the item, i.e. restore an alarm which was deleted.
+* Create a redo item to delete the alarm again.
+* Reply = redo item.
+*/
+UndoItem* UndoDelete::restore()
+{
+ kdDebug(5950) << "UndoDelete::restore(" << mEvent->id() << ")\n";
+ // Restore the original event
+ switch (calendar())
+ {
+ case KAEvent::ACTIVE:
+ if (mEvent->toBeArchived())
+ {
+ // It was archived when it was deleted
+ mEvent->setUid(KAEvent::EXPIRED);
+ switch (KAlarm::reactivateEvent(*mEvent, 0, true))
+ {
+ case KAlarm::UPDATE_KORG_ERR:
+ mRestoreWarning = WARN_KORG_ADD;
+ ++mRestoreWarningCount;
+ break;
+ case KAlarm::UPDATE_ERROR:
+ case KAlarm::UPDATE_FAILED:
+ case KAlarm::SAVE_FAILED:
+ mRestoreError = ERR_EXPIRED;
+ return 0;
+ case KAlarm::UPDATE_OK:
+ break;
+ }
+ }
+ else
+ {
+ switch (KAlarm::addEvent(*mEvent, 0, 0, true))
+ {
+ case KAlarm::UPDATE_KORG_ERR:
+ mRestoreWarning = WARN_KORG_ADD;
+ ++mRestoreWarningCount;
+ break;
+ case KAlarm::UPDATE_ERROR:
+ case KAlarm::UPDATE_FAILED:
+ case KAlarm::SAVE_FAILED:
+ mRestoreError = ERR_CREATE;
+ return 0;
+ case KAlarm::UPDATE_OK:
+ break;
+ }
+ }
+ break;
+ case KAEvent::TEMPLATE:
+ if (KAlarm::addTemplate(*mEvent, 0) != KAlarm::UPDATE_OK)
+ {
+ mRestoreError = ERR_CREATE;
+ return 0;
+ }
+ break;
+ case KAEvent::EXPIRED:
+ if (!KAlarm::addExpiredEvent(*mEvent))
+ {
+ mRestoreError = ERR_CREATE;
+ return 0;
+ }
+ break;
+ default:
+ mRestoreError = ERR_PROG;
+ return 0;
+ }
+
+ // Create a redo item to delete the alarm again
+ return createRedo(*mEvent);
+}
+
+/******************************************************************************
+* Create a redo item to archive the alarm again.
+*/
+UndoItem* UndoDelete::createRedo(const KAEvent& event)
+{
+ Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
+ return new UndoAdd(t, event);
+}
+
+/******************************************************************************
+* Return the action description of the Undo item for displaying.
+*/
+QString UndoDelete::actionText() const
+{
+ return addDeleteActionText(calendar(), (type() == Undo::REDO));
+}
+
+
+/*=============================================================================
+= Class: UndoDeletes
+= Undo item for multiple alarm deletion.
+=============================================================================*/
+
+/******************************************************************************
+* Create a redo item to delete the alarms again.
+*/
+UndoItem* UndoDeletes::createRedo(Undo::List& undos)
+{
+ Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
+ return new UndoDeletes(t, undos);
+}
+
+/******************************************************************************
+* Return the action description of the Undo item for displaying.
+*/
+QString UndoDeletes::actionText() const
+{
+ if (mUndos.isEmpty())
+ return QString::null;
+ for (Undo::List::ConstIterator it = mUndos.begin(); it != mUndos.end(); ++it)
+ {
+ switch ((*it)->calendar())
+ {
+ case KAEvent::ACTIVE:
+ return i18n("Delete multiple alarms");
+ case KAEvent::TEMPLATE:
+ return i18n("Delete multiple templates");
+ case KAEvent::EXPIRED:
+ break; // check if they are ALL expired
+ default:
+ return QString::null;
+ }
+ }
+ return i18n("Delete multiple expired alarms");
+}
+
+
+/*=============================================================================
+= Class: UndoReactivate
+= Undo item for alarm reactivation.
+=============================================================================*/
+
+/******************************************************************************
+* Undo the item, i.e. re-archive the alarm which was reactivated.
+* Create a redo item to reactivate the alarm back again.
+* Reply = redo item.
+*/
+UndoItem* UndoReactivate::restore()
+{
+ kdDebug(5950) << "UndoReactivate::restore()\n";
+ // Validate the alarm's calendar
+ switch (calendar())
+ {
+ case KAEvent::ACTIVE:
+ break;
+ default:
+ mRestoreError = ERR_PROG;
+ return 0;
+ }
+ return UndoAdd::doRestore(true); // restore alarm, ensuring that it is re-archived
+}
+
+/******************************************************************************
+* Create a redo item to add the alarm back again.
+*/
+UndoItem* UndoReactivate::createRedo(const KAEvent& event)
+{
+ Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
+ return new UndoDeactivate(t, event);
+}
+
+/******************************************************************************
+* Return the action description of the Undo item for displaying.
+*/
+QString UndoReactivate::actionText() const
+{
+ return i18n("Reactivate alarm");
+}
+
+
+/*=============================================================================
+= Class: UndoDeactivate
+= Redo item for alarm reactivation.
+=============================================================================*/
+
+/******************************************************************************
+* Undo the item, i.e. reactivate an alarm which was archived.
+* Create a redo item to archive the alarm again.
+* Reply = redo item.
+*/
+UndoItem* UndoDeactivate::restore()
+{
+ kdDebug(5950) << "UndoDeactivate::restore()\n";
+ // Validate the alarm's calendar
+ switch (calendar())
+ {
+ case KAEvent::ACTIVE:
+ break;
+ default:
+ mRestoreError = ERR_PROG;
+ return 0;
+ }
+
+ return UndoDelete::restore();
+}
+
+/******************************************************************************
+* Create a redo item to archive the alarm again.
+*/
+UndoItem* UndoDeactivate::createRedo(const KAEvent& event)
+{
+ Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
+ return new UndoReactivate(t, event);
+}
+
+/******************************************************************************
+* Return the action description of the Undo item for displaying.
+*/
+QString UndoDeactivate::actionText() const
+{
+ return i18n("Reactivate alarm");
+}
+
+
+/*=============================================================================
+= Class: UndoReactivates
+= Undo item for multiple alarm reactivation.
+=============================================================================*/
+
+/******************************************************************************
+* Create a redo item to reactivate the alarms again.
+*/
+UndoItem* UndoReactivates::createRedo(Undo::List& undos)
+{
+ Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
+ return new UndoReactivates(t, undos);
+}
+
+/******************************************************************************
+* Return the action description of the Undo item for displaying.
+*/
+QString UndoReactivates::actionText() const
+{
+ return i18n("Reactivate multiple alarms");
+}