kalarm

undo.cpp
1/*
2 * undo.cpp - undo/redo facility
3 * Program: kalarm
4 * Copyright © 2005,2006 by David Jarvie <software@astrojar.org.uk>
5 *
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.
10 *
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.
15 *
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.
19 */
20
21#include "kalarm.h"
22
23#include <tqobject.h>
24#include <tqstringlist.h>
25
26#include <tdeapplication.h>
27#include <tdelocale.h>
28#include <tdemessagebox.h>
29#include <kdebug.h>
30
31#include "alarmcalendar.h"
32#include "alarmevent.h"
33#include "alarmtext.h"
34#include "functions.h"
35#include "undo.moc"
36
37static int maxCount = 12;
38
39
40class UndoItem
41{
42 public:
43 enum Operation { ADD, EDIT, DELETE, REACTIVATE, DEACTIVATE, MULTI };
44 UndoItem(); // needed by TQValueList
45 virtual ~UndoItem();
46 virtual Operation operation() const = 0;
47 virtual TQString actionText() const = 0;
48 virtual TQString description() const { return TQString(); }
49 virtual TQString eventID() const { return TQString(); }
50 virtual TQString oldEventID() const { return TQString(); }
51 virtual TQString newEventID() const { return TQString(); }
52 int id() const { return mId; }
53 Undo::Type type() const { return mType; }
54 void setType(Undo::Type t) { mType = t; }
55 KAEvent::Status calendar() const { return mCalendar; }
56 virtual void setCalendar(KAEvent::Status s) { mCalendar = s; }
57 virtual UndoItem* restore() = 0;
58 virtual bool deleteID(const TQString& /*id*/) { return false; }
59
60 enum Error { ERR_NONE, ERR_PROG, ERR_NOT_FOUND, ERR_CREATE, ERR_TEMPLATE, ERR_EXPIRED };
61 enum Warning { WARN_NONE, WARN_KORG_ADD, WARN_KORG_MODIFY, WARN_KORG_DELETE };
62 static int mLastId;
63 static Error mRestoreError; // error code valid only if restore() returns 0
64 static Warning mRestoreWarning; // warning code set by restore()
65 static int mRestoreWarningCount; // item count for mRestoreWarning (to allow i18n messages to work correctly)
66
67 protected:
68 UndoItem(Undo::Type);
69 static TQString addDeleteActionText(KAEvent::Status, bool add);
70 TQString description(const KAEvent&) const;
71 void replaceWith(UndoItem* item) { Undo::replace(this, item); }
72
73 int mId; // unique identifier (only for mType = UNDO, REDO)
74 Undo::Type mType; // which list (if any) the object is in
75 KAEvent::Status mCalendar;
76};
77
78class UndoMultiBase : public UndoItem
79{
80 public:
81 UndoMultiBase(Undo::Type t) : UndoItem(t) { }
82 UndoMultiBase(Undo::Type t, Undo::List& undos) : UndoItem(t), mUndos(undos) { }
83 ~UndoMultiBase();
84 const Undo::List& undos() const { return mUndos; }
85 protected:
86 Undo::List mUndos; // this list must always have >= 2 entries
87};
88
89template <class T> class UndoMulti : public UndoMultiBase
90{
91 public:
92 UndoMulti(Undo::Type, const TQValueList<KAEvent>&);
93 UndoMulti(Undo::Type t, Undo::List& undos) : UndoMultiBase(t, undos) { }
94 virtual Operation operation() const { return MULTI; }
95 virtual UndoItem* restore();
96 virtual bool deleteID(const TQString& id);
97 virtual UndoItem* createRedo(Undo::List&) = 0;
98};
99
100class UndoAdd : public UndoItem
101{
102 public:
103 UndoAdd(Undo::Type, const KAEvent&);
104 UndoAdd(Undo::Type, const KAEvent&, KAEvent::Status);
105 virtual Operation operation() const { return ADD; }
106 virtual TQString actionText() const;
107 virtual TQString description() const { return mDescription; }
108 virtual TQString eventID() const { return mEventID; }
109 virtual TQString newEventID() const { return mEventID; }
110 virtual UndoItem* restore() { return doRestore(); }
111 protected:
112 UndoItem* doRestore(bool setArchive = false);
113 virtual UndoItem* createRedo(const KAEvent&);
114 private:
115 TQString mEventID;
116 TQString mDescription;
117};
118
119class UndoEdit : public UndoItem
120{
121 public:
122 UndoEdit(Undo::Type, const KAEvent& oldEvent, const TQString& newEventID, const TQString& description);
123 ~UndoEdit();
124 virtual Operation operation() const { return EDIT; }
125 virtual TQString actionText() const;
126 virtual TQString description() const { return mDescription; }
127 virtual TQString eventID() const { return mNewEventID; }
128 virtual TQString oldEventID() const { return mOldEvent->id(); }
129 virtual TQString newEventID() const { return mNewEventID; }
130 virtual UndoItem* restore();
131 private:
132 KAEvent* mOldEvent;
133 TQString mNewEventID;
134 TQString mDescription;
135};
136
137class UndoDelete : public UndoItem
138{
139 public:
140 UndoDelete(Undo::Type, const KAEvent&);
141 ~UndoDelete();
142 virtual Operation operation() const { return DELETE; }
143 virtual TQString actionText() const;
144 virtual TQString description() const { return UndoItem::description(*mEvent); }
145 virtual TQString eventID() const { return mEvent->id(); }
146 virtual TQString oldEventID() const { return mEvent->id(); }
147 virtual UndoItem* restore();
148 KAEvent* event() const { return mEvent; }
149 protected:
150 virtual UndoItem* createRedo(const KAEvent&);
151 private:
152 KAEvent* mEvent;
153};
154
155class UndoReactivate : public UndoAdd
156{
157 public:
158 UndoReactivate(Undo::Type t, const KAEvent& e) : UndoAdd(t, e, KAEvent::ACTIVE) { }
159 virtual Operation operation() const { return REACTIVATE; }
160 virtual TQString actionText() const;
161 virtual UndoItem* restore();
162 protected:
163 virtual UndoItem* createRedo(const KAEvent&);
164};
165
166class UndoDeactivate : public UndoDelete
167{
168 public:
169 UndoDeactivate(Undo::Type t, const KAEvent& e) : UndoDelete(t, e) { }
170 virtual Operation operation() const { return DEACTIVATE; }
171 virtual TQString actionText() const;
172 virtual UndoItem* restore();
173 protected:
174 virtual UndoItem* createRedo(const KAEvent&);
175};
176
177class UndoDeletes : public UndoMulti<UndoDelete>
178{
179 public:
180 UndoDeletes(Undo::Type t, const TQValueList<KAEvent>& events)
181 : UndoMulti<UndoDelete>(t, events) { } // UNDO only
182 UndoDeletes(Undo::Type t, Undo::List& undos)
183 : UndoMulti<UndoDelete>(t, undos) { }
184 virtual TQString actionText() const;
185 virtual UndoItem* createRedo(Undo::List&);
186};
187
188class UndoReactivates : public UndoMulti<UndoReactivate>
189{
190 public:
191 UndoReactivates(Undo::Type t, const TQValueList<KAEvent>& events)
192 : UndoMulti<UndoReactivate>(t, events) { } // UNDO only
193 UndoReactivates(Undo::Type t, Undo::List& undos)
194 : UndoMulti<UndoReactivate>(t, undos) { }
195 virtual TQString actionText() const;
196 virtual UndoItem* createRedo(Undo::List&);
197};
198
199Undo* Undo::mInstance = 0;
200Undo::List Undo::mUndoList;
201Undo::List Undo::mRedoList;
202
203
204/******************************************************************************
205* Create the one and only instance of the Undo class.
206*/
207Undo* Undo::instance()
208{
209 if (!mInstance)
210 mInstance = new Undo(tdeApp);
211 return mInstance;
212}
213
214/******************************************************************************
215* Clear the lists of undo and redo items.
216*/
217void Undo::clear()
218{
219 if (!mUndoList.isEmpty() || !mRedoList.isEmpty())
220 {
221 mInstance->blockSignals(true);
222 while (mUndoList.count())
223 delete mUndoList.first(); // N.B. 'delete' removes the object from the list
224 while (mRedoList.count())
225 delete mRedoList.first(); // N.B. 'delete' removes the object from the list
226 mInstance->blockSignals(false);
227 emitChanged();
228 }
229}
230
231/******************************************************************************
232* Create an undo item and add it to the list of undos.
233* N.B. The base class constructor adds the object to the undo list.
234*/
235void Undo::saveAdd(const KAEvent& event)
236{
237 new UndoAdd(UNDO, event);
238 emitChanged();
239}
240
241void Undo::saveEdit(const KAEvent& oldEvent, const KAEvent& newEvent)
242{
243 new UndoEdit(UNDO, oldEvent, newEvent.id(), AlarmText::summary(newEvent));
244 removeRedos(oldEvent.id()); // remove any redos which are made invalid by this edit
245 emitChanged();
246}
247
248void Undo::saveDelete(const KAEvent& event)
249{
250 new UndoDelete(UNDO, event);
251 removeRedos(event.id()); // remove any redos which are made invalid by this deletion
252 emitChanged();
253}
254
255void Undo::saveDeletes(const TQValueList<KAEvent>& events)
256{
257 int count = events.count();
258 if (count == 1)
259 saveDelete(events.first());
260 else if (count > 1)
261 {
262 new UndoDeletes(UNDO, events);
263 for (TQValueList<KAEvent>::ConstIterator it = events.begin(); it != events.end(); ++it)
264 removeRedos((*it).id()); // remove any redos which are made invalid by these deletions
265 emitChanged();
266 }
267}
268
269void Undo::saveReactivate(const KAEvent& event)
270{
271 new UndoReactivate(UNDO, event);
272 emitChanged();
273}
274
275void Undo::saveReactivates(const TQValueList<KAEvent>& events)
276{
277 int count = events.count();
278 if (count == 1)
279 saveReactivate(events.first());
280 else if (count > 1)
281 {
282 new UndoReactivates(UNDO, events);
283 emitChanged();
284 }
285}
286
287/******************************************************************************
288* Remove any redos which are made invalid by a new undo.
289*/
290void Undo::removeRedos(const TQString& eventID)
291{
292 TQString id = eventID;
293 for (Iterator it = mRedoList.begin(); it != mRedoList.end(); )
294 {
295 UndoItem* item = *it;
296//kdDebug(5950)<<"removeRedos(): "<<item->eventID()<<" (looking for "<<id<<")"<<endl;
297 if (item->operation() == UndoItem::MULTI)
298 {
299 if (item->deleteID(id))
300 {
301 // The old multi-redo was replaced with a new single redo
302 delete item;
303 }
304 ++it;
305 }
306 else if (item->eventID() == id)
307 {
308 if (item->operation() == UndoItem::EDIT)
309 id = item->oldEventID(); // continue looking for its post-edit ID
310 item->setType(NONE); // prevent the destructor removing it from the list
311 delete item;
312 it = mRedoList.remove(it);
313 }
314 else
315 ++it;
316 }
317}
318
319/******************************************************************************
320* Undo or redo a specified item.
321* Reply = true if success, or if the item no longer exists.
322*/
323bool Undo::undo(Undo::Iterator it, Undo::Type type, TQWidget* parent, const TQString& action)
324{
325 UndoItem::mRestoreError = UndoItem::ERR_NONE;
326 UndoItem::mRestoreWarning = UndoItem::WARN_NONE;
327 UndoItem::mRestoreWarningCount = 0;
328 if (it != mUndoList.end() && it != mRedoList.end() && (*it)->type() == type)
329 {
330 (*it)->restore();
331 delete *it; // N.B. 'delete' removes the object from its list
332 emitChanged();
333 }
334
335 TQString err;
336 switch (UndoItem::mRestoreError)
337 {
338 case UndoItem::ERR_NONE:
339 {
341 switch (UndoItem::mRestoreWarning)
342 {
343 case UndoItem::WARN_KORG_ADD: errcode = KAlarm::KORG_ERR_ADD; break;
344 case UndoItem::WARN_KORG_MODIFY: errcode = KAlarm::KORG_ERR_MODIFY; break;
345 case UndoItem::WARN_KORG_DELETE: errcode = KAlarm::KORG_ERR_DELETE; break;
346 case UndoItem::WARN_NONE:
347 default:
348 return true;
349 }
350 KAlarm::displayKOrgUpdateError(parent, errcode, UndoItem::mRestoreWarningCount);
351 return true;
352 }
353 case UndoItem::ERR_NOT_FOUND: err = i18n("Alarm not found"); break;
354 case UndoItem::ERR_CREATE: err = i18n("Error recreating alarm"); break;
355 case UndoItem::ERR_TEMPLATE: err = i18n("Error recreating alarm template"); break;
356 case UndoItem::ERR_EXPIRED: err = i18n("Cannot reactivate expired alarm"); break;
357 case UndoItem::ERR_PROG: err = i18n("Program error"); break;
358 default: err = i18n("Unknown error"); break;
359 }
360 KMessageBox::sorry(parent, i18n("Undo-action: message", "%1: %2").arg(action).arg(err));
361 return false;
362}
363
364/******************************************************************************
365* Add an undo item to the start of one of the lists.
366*/
367void Undo::add(UndoItem* item, bool undo)
368{
369 if (item)
370 {
371 // Limit the number of items stored
372 int undoCount = mUndoList.count();
373 int redoCount = mRedoList.count();
374 if (undoCount + redoCount >= maxCount - 1)
375 {
376 if (undoCount)
377 mUndoList.pop_back();
378 else
379 mRedoList.pop_back();
380 }
381
382 // Append the new item
383 List* list = undo ? &mUndoList : &mRedoList;
384 list->prepend(item);
385 }
386}
387
388/******************************************************************************
389* Remove an undo item from one of the lists.
390*/
391void Undo::remove(UndoItem* item, bool undo)
392{
393 List* list = undo ? &mUndoList : &mRedoList;
394 if (!list->isEmpty())
395 list->remove(item);
396}
397
398/******************************************************************************
399* Replace an undo item in one of the lists.
400*/
401void Undo::replace(UndoItem* old, UndoItem* New)
402{
403 Type type = old->type();
404 List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : 0;
405 if (!list)
406 return;
407 Iterator it = list->find(old);
408 if (it != list->end())
409 {
410 New->setType(type); // ensure the item points to the correct list
411 *it = New;
412 old->setType(NONE); // mark the old item as no longer being in a list
413 }
414}
415
416/******************************************************************************
417* Return the action description of the latest undo/redo item.
418*/
419TQString Undo::actionText(Undo::Type type)
420{
421 List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : 0;
422 return (list && !list->isEmpty()) ? list->first()->actionText() : TQString();
423}
424
425/******************************************************************************
426* Return the action description of the undo/redo item with the specified ID.
427*/
428TQString Undo::actionText(Undo::Type type, int id)
429{
430 UndoItem* undo = getItem(id, type);
431 return undo ? undo->actionText() : TQString();
432}
433
434/******************************************************************************
435* Return the alarm description of the undo/redo item with the specified ID.
436*/
437TQString Undo::description(Undo::Type type, int id)
438{
439 UndoItem* undo = getItem(id, type);
440 return undo ? undo->description() : TQString();
441}
442
443/******************************************************************************
444* Return the descriptions of all undo or redo items, in order latest first.
445* For alarms which have undergone more than one change, only the first one is
446* listed, to force dependent undos to be executed in their correct order.
447* If 'ids' is non-null, also returns a list of their corresponding IDs.
448*/
449TQValueList<int> Undo::ids(Undo::Type type)
450{
451 TQValueList<int> ids;
452 TQStringList ignoreIDs;
453//int n=0;
454 List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : 0;
455 if (!list)
456 return ids;
457 for (Iterator it = list->begin(); it != list->end(); ++it)
458 {
459 // Check whether this item should be ignored because it is a
460 // deendent undo. If not, add this item's ID to the ignore list.
461 UndoItem* item = *it;
462 bool omit = false;
463 if (item->operation() == UndoItem::MULTI)
464 {
465 // If any item in a multi-undo is disqualified, omit the whole multi-undo
466 TQStringList newIDs;
467 const Undo::List& undos = ((UndoMultiBase*)item)->undos();
468 for (Undo::List::ConstIterator u = undos.begin(); u != undos.end(); ++u)
469 {
470 TQString evid = (*u)->eventID();
471 if (ignoreIDs.find(evid) != ignoreIDs.end())
472 omit = true;
473 else if (omit)
474 ignoreIDs.append(evid);
475 else
476 newIDs.append(evid);
477 }
478 if (omit)
479 {
480 for (TQStringList::ConstIterator i = newIDs.begin(); i != newIDs.end(); ++i)
481 ignoreIDs.append(*i);
482 }
483 }
484 else
485 {
486 omit = (ignoreIDs.find(item->eventID()) != ignoreIDs.end());
487 if (!omit)
488 ignoreIDs.append(item->eventID());
489 if (item->operation() == UndoItem::EDIT)
490 ignoreIDs.append(item->oldEventID()); // continue looking for its post-edit ID
491 }
492 if (!omit)
493 ids.append(item->id());
494//else kdDebug(5950)<<"Undo::ids(): omit "<<item->actionText()<<": "<<item->description()<<endl;
495 }
496//kdDebug(5950)<<"Undo::ids(): "<<n<<" -> "<<ids.count()<<endl;
497 return ids;
498}
499
500/******************************************************************************
501* Emit the appropriate 'changed' signal.
502*/
503void Undo::emitChanged()
504{
505 if (mInstance)
506 mInstance->emitChanged(actionText(UNDO), actionText(REDO));
507}
508
509/******************************************************************************
510* Return the item with the specified ID.
511*/
512UndoItem* Undo::getItem(int id, Undo::Type type)
513{
514 List* list = (type == UNDO) ? &mUndoList : (type == REDO) ? &mRedoList : 0;
515 if (list)
516 {
517 for (Iterator it = list->begin(); it != list->end(); ++it)
518 {
519 if ((*it)->id() == id)
520 return *it;
521 }
522 }
523 return 0;
524}
525
526/******************************************************************************
527* Find an item with the specified ID.
528*/
529Undo::Iterator Undo::findItem(int id, Undo::Type type)
530{
531 List* list = (type == UNDO) ? &mUndoList : &mRedoList;
532 Iterator it;
533 for (it = list->begin(); it != list->end(); ++it)
534 {
535 if ((*it)->id() == id)
536 break;
537 }
538 return it;
539}
540
541
542/*=============================================================================
543= Class: UndoItem
544= A single undo action.
545=============================================================================*/
546int UndoItem::mLastId = 0;
547UndoItem::Error UndoItem::mRestoreError;
548UndoItem::Warning UndoItem::mRestoreWarning;
549int UndoItem::mRestoreWarningCount;
550
551/******************************************************************************
552* Constructor.
553* Optionally appends the undo to the list of undos.
554*/
555UndoItem::UndoItem(Undo::Type type)
556 : mId(0),
557 mType(type)
558{
559 if (type != Undo::NONE)
560 {
561 mId = ++mLastId;
562 if (mId < 0)
563 mId = mLastId = 1; // wrap round if we reach a negative number
564 Undo::add(this, (mType == Undo::UNDO));
565 }
566}
567
568/******************************************************************************
569* Destructor.
570* Removes the undo from the list (if it's in the list).
571*/
572UndoItem::~UndoItem()
573{
574 if (mType != Undo::NONE)
575 Undo::remove(this, (mType == Undo::UNDO));
576}
577
578/******************************************************************************
579* Return the description of an event.
580*/
581TQString UndoItem::description(const KAEvent& event) const
582{
583 return (mCalendar == KAEvent::TEMPLATE) ? event.templateName() : AlarmText::summary(event);
584}
585
586/******************************************************************************
587* Return the action description of an add or delete Undo/Redo item for displaying.
588*/
589TQString UndoItem::addDeleteActionText(KAEvent::Status calendar, bool add)
590{
591 switch (calendar)
592 {
593 case KAEvent::ACTIVE:
594 if (add)
595 return i18n("Action to create a new alarm", "New alarm");
596 else
597 return i18n("Action to delete an alarm", "Delete alarm");
598 case KAEvent::TEMPLATE:
599 if (add)
600 return i18n("Action to create a new alarm template", "New template");
601 else
602 return i18n("Action to delete an alarm template", "Delete template");
603 case KAEvent::EXPIRED:
604 return i18n("Delete expired alarm");
605 default:
606 break;
607 }
608 return TQString();
609}
610
611
612/*=============================================================================
613= Class: UndoMultiBase
614= Undo item for multiple alarms.
615=============================================================================*/
616
617template <class T>
618UndoMulti<T>::UndoMulti(Undo::Type type, const TQValueList<KAEvent>& events)
619 : UndoMultiBase(type) // UNDO only
620{
621 for (TQValueList<KAEvent>::ConstIterator it = events.begin(); it != events.end(); ++it)
622 mUndos.append(new T(Undo::NONE, *it));
623}
624
625UndoMultiBase::~UndoMultiBase()
626{
627 for (Undo::List::Iterator it = mUndos.begin(); it != mUndos.end(); ++it)
628 delete *it;
629}
630
631/******************************************************************************
632* Undo the item, i.e. restore multiple alarms which were deleted (or delete
633* alarms which were restored).
634* Create a redo item to delete (or restore) the alarms again.
635* Reply = redo item.
636*/
637template <class T>
638UndoItem* UndoMulti<T>::restore()
639{
640 Undo::List newUndos;
641 for (Undo::List::Iterator it = mUndos.begin(); it != mUndos.end(); ++it)
642 {
643 UndoItem* undo = (*it)->restore();
644 if (undo)
645 newUndos.append(undo);
646 }
647 if (newUndos.isEmpty())
648 return 0;
649
650 // Create a redo item to delete the alarm again
651 return createRedo(newUndos);
652}
653
654/******************************************************************************
655* If one of the multiple items has the specified ID, delete it.
656* If an item is deleted and there is only one item left, the UndoMulti
657* instance is removed from its list and replaced by the remaining UndoItem instead.
658* Reply = true if this instance was replaced. The caller must delete it.
659* = false otherwise.
660*/
661template <class T>
662bool UndoMulti<T>::deleteID(const TQString& id)
663{
664 for (Undo::List::Iterator it = mUndos.begin(); it != mUndos.end(); ++it)
665 {
666 UndoItem* item = *it;
667 if (item->eventID() == id)
668 {
669 // Found a matching entry - remove it
670 mUndos.remove(it);
671 if (mUndos.count() == 1)
672 {
673 // There is only one entry left after removal.
674 // Replace 'this' multi instance with the remaining single entry.
675 replaceWith(item);
676 return true;
677 }
678 else
679 {
680 delete item;
681 return false;
682 }
683 }
684 }
685 return false;
686}
687
688
689/*=============================================================================
690= Class: UndoAdd
691= Undo item for alarm creation.
692=============================================================================*/
693
694UndoAdd::UndoAdd(Undo::Type type, const KAEvent& event)
695 : UndoItem(type),
696 mEventID(event.id())
697{
698 setCalendar(KAEvent::uidStatus(mEventID));
699 mDescription = UndoItem::description(event); // calendar must be set before calling this
700}
701
702UndoAdd::UndoAdd(Undo::Type type, const KAEvent& event, KAEvent::Status cal)
703 : UndoItem(type),
704 mEventID(KAEvent::uid(event.id(), cal))
705{
706 setCalendar(cal);
707 mDescription = UndoItem::description(event); // calendar must be set before calling this
708}
709
710/******************************************************************************
711* Undo the item, i.e. delete the alarm which was added.
712* Create a redo item to add the alarm back again.
713* Reply = redo item.
714*/
715UndoItem* UndoAdd::doRestore(bool setArchive)
716{
717 // Retrieve the current state of the alarm
718 kdDebug(5950) << "UndoAdd::doRestore(" << mEventID << ")\n";
719 const KCal::Event* kcalEvent = AlarmCalendar::getEvent(mEventID);
720 if (!kcalEvent)
721 {
722 mRestoreError = ERR_NOT_FOUND; // alarm is no longer in calendar
723 return 0;
724 }
725 KAEvent event(*kcalEvent);
726
727 // Create a redo item to recreate the alarm.
728 // Do it now, since 'event' gets modified by KAlarm::deleteEvent()
729 UndoItem* undo = createRedo(event);
730
731 switch (calendar())
732 {
733 case KAEvent::ACTIVE:
734 if (setArchive)
735 event.setArchive();
736 // Archive it if it has already triggered
737 switch (KAlarm::deleteEvent(event, true))
738 {
739 case KAlarm::UPDATE_ERROR:
740 case KAlarm::UPDATE_FAILED:
741 case KAlarm::SAVE_FAILED:
742 mRestoreError = ERR_CREATE;
743 break;
744 case KAlarm::UPDATE_KORG_ERR:
745 mRestoreWarning = WARN_KORG_DELETE;
746 ++mRestoreWarningCount;
747 break;
748 default:
749 break;
750 }
751 break;
752 case KAEvent::TEMPLATE:
753 if (KAlarm::deleteTemplate(event) != KAlarm::UPDATE_OK)
754 mRestoreError = ERR_TEMPLATE;
755 break;
756 case KAEvent::EXPIRED: // redoing the deletion of an expired alarm
757 KAlarm::deleteEvent(event);
758 break;
759 default:
760 delete undo;
761 mRestoreError = ERR_PROG;
762 return 0;
763 }
764 return undo;
765}
766
767/******************************************************************************
768* Create a redo item to add the alarm back again.
769*/
770UndoItem* UndoAdd::createRedo(const KAEvent& event)
771{
772 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
773 return new UndoDelete(t, event);
774}
775
776/******************************************************************************
777* Return the action description of the Undo item for displaying.
778*/
779TQString UndoAdd::actionText() const
780{
781 return addDeleteActionText(calendar(), (type() == Undo::UNDO));
782}
783
784
785/*=============================================================================
786= Class: UndoEdit
787= Undo item for alarm edit.
788=============================================================================*/
789
790UndoEdit::UndoEdit(Undo::Type type, const KAEvent& oldEvent, const TQString& newEventID, const TQString& description)
791 : UndoItem(type),
792 mOldEvent(new KAEvent(oldEvent)),
793 mNewEventID(newEventID),
794 mDescription(description)
795{
796 setCalendar(KAEvent::uidStatus(mNewEventID));
797}
798
799UndoEdit::~UndoEdit()
800{
801 delete mOldEvent;
802}
803
804/******************************************************************************
805* Undo the item, i.e. undo an edit to a previously existing alarm.
806* Create a redo item to reapply the edit.
807* Reply = redo item.
808*/
809UndoItem* UndoEdit::restore()
810{
811 kdDebug(5950) << "UndoEdit::restore(" << mNewEventID << ")\n";
812 // Retrieve the current state of the alarm
813 const KCal::Event* kcalEvent = AlarmCalendar::getEvent(mNewEventID);
814 if (!kcalEvent)
815 {
816 mRestoreError = ERR_NOT_FOUND; // alarm is no longer in calendar
817 return 0;
818 }
819 KAEvent newEvent(*kcalEvent);
820
821 // Create a redo item to restore the edit
822 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
823 UndoItem* undo = new UndoEdit(t, newEvent, mOldEvent->id(), mDescription);
824
825 switch (calendar())
826 {
827 case KAEvent::ACTIVE:
828 switch (KAlarm::modifyEvent(newEvent, *mOldEvent, 0))
829 {
830 case KAlarm::UPDATE_ERROR:
831 case KAlarm::UPDATE_FAILED:
832 case KAlarm::SAVE_FAILED:
833 mRestoreError = ERR_CREATE;
834 break;
835 case KAlarm::UPDATE_KORG_ERR:
836 mRestoreWarning = WARN_KORG_MODIFY;
837 ++mRestoreWarningCount;
838 break;
839 default:
840 break;
841 }
842 break;
843 case KAEvent::TEMPLATE:
844 if (KAlarm::updateTemplate(*mOldEvent, 0) != KAlarm::UPDATE_OK)
845 mRestoreError = ERR_TEMPLATE;
846 break;
847 case KAEvent::EXPIRED: // editing of expired events is not allowed
848 default:
849 delete undo;
850 mRestoreError = ERR_PROG;
851 return 0;
852 }
853 return undo;
854}
855
856/******************************************************************************
857* Return the action description of the Undo item for displaying.
858*/
859TQString UndoEdit::actionText() const
860{
861 switch (calendar())
862 {
863 case KAEvent::ACTIVE:
864 return i18n("Action to edit an alarm", "Edit alarm");
865 case KAEvent::TEMPLATE:
866 return i18n("Action to edit an alarm template", "Edit template");
867 default:
868 break;
869 }
870 return TQString();
871}
872
873
874/*=============================================================================
875= Class: UndoDelete
876= Undo item for alarm deletion.
877=============================================================================*/
878
879UndoDelete::UndoDelete(Undo::Type type, const KAEvent& event)
880 : UndoItem(type),
881 mEvent(new KAEvent(event))
882{
883 setCalendar(KAEvent::uidStatus(mEvent->id()));
884}
885
886UndoDelete::~UndoDelete()
887{
888 delete mEvent;
889}
890
891/******************************************************************************
892* Undo the item, i.e. restore an alarm which was deleted.
893* Create a redo item to delete the alarm again.
894* Reply = redo item.
895*/
896UndoItem* UndoDelete::restore()
897{
898 kdDebug(5950) << "UndoDelete::restore(" << mEvent->id() << ")\n";
899 // Restore the original event
900 switch (calendar())
901 {
902 case KAEvent::ACTIVE:
903 if (mEvent->toBeArchived())
904 {
905 // It was archived when it was deleted
906 mEvent->setUid(KAEvent::EXPIRED);
907 switch (KAlarm::reactivateEvent(*mEvent, 0, true))
908 {
909 case KAlarm::UPDATE_KORG_ERR:
910 mRestoreWarning = WARN_KORG_ADD;
911 ++mRestoreWarningCount;
912 break;
913 case KAlarm::UPDATE_ERROR:
914 case KAlarm::UPDATE_FAILED:
915 case KAlarm::SAVE_FAILED:
916 mRestoreError = ERR_EXPIRED;
917 return 0;
918 case KAlarm::UPDATE_OK:
919 break;
920 }
921 }
922 else
923 {
924 switch (KAlarm::addEvent(*mEvent, 0, 0, true))
925 {
926 case KAlarm::UPDATE_KORG_ERR:
927 mRestoreWarning = WARN_KORG_ADD;
928 ++mRestoreWarningCount;
929 break;
930 case KAlarm::UPDATE_ERROR:
931 case KAlarm::UPDATE_FAILED:
932 case KAlarm::SAVE_FAILED:
933 mRestoreError = ERR_CREATE;
934 return 0;
935 case KAlarm::UPDATE_OK:
936 break;
937 }
938 }
939 break;
940 case KAEvent::TEMPLATE:
941 if (KAlarm::addTemplate(*mEvent, 0) != KAlarm::UPDATE_OK)
942 {
943 mRestoreError = ERR_CREATE;
944 return 0;
945 }
946 break;
947 case KAEvent::EXPIRED:
948 if (!KAlarm::addExpiredEvent(*mEvent))
949 {
950 mRestoreError = ERR_CREATE;
951 return 0;
952 }
953 break;
954 default:
955 mRestoreError = ERR_PROG;
956 return 0;
957 }
958
959 // Create a redo item to delete the alarm again
960 return createRedo(*mEvent);
961}
962
963/******************************************************************************
964* Create a redo item to archive the alarm again.
965*/
966UndoItem* UndoDelete::createRedo(const KAEvent& event)
967{
968 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
969 return new UndoAdd(t, event);
970}
971
972/******************************************************************************
973* Return the action description of the Undo item for displaying.
974*/
975TQString UndoDelete::actionText() const
976{
977 return addDeleteActionText(calendar(), (type() == Undo::REDO));
978}
979
980
981/*=============================================================================
982= Class: UndoDeletes
983= Undo item for multiple alarm deletion.
984=============================================================================*/
985
986/******************************************************************************
987* Create a redo item to delete the alarms again.
988*/
989UndoItem* UndoDeletes::createRedo(Undo::List& undos)
990{
991 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
992 return new UndoDeletes(t, undos);
993}
994
995/******************************************************************************
996* Return the action description of the Undo item for displaying.
997*/
998TQString UndoDeletes::actionText() const
999{
1000 if (mUndos.isEmpty())
1001 return TQString();
1002 for (Undo::List::ConstIterator it = mUndos.begin(); it != mUndos.end(); ++it)
1003 {
1004 switch ((*it)->calendar())
1005 {
1006 case KAEvent::ACTIVE:
1007 return i18n("Delete multiple alarms");
1008 case KAEvent::TEMPLATE:
1009 return i18n("Delete multiple templates");
1010 case KAEvent::EXPIRED:
1011 break; // check if they are ALL expired
1012 default:
1013 return TQString();
1014 }
1015 }
1016 return i18n("Delete multiple expired alarms");
1017}
1018
1019
1020/*=============================================================================
1021= Class: UndoReactivate
1022= Undo item for alarm reactivation.
1023=============================================================================*/
1024
1025/******************************************************************************
1026* Undo the item, i.e. re-archive the alarm which was reactivated.
1027* Create a redo item to reactivate the alarm back again.
1028* Reply = redo item.
1029*/
1030UndoItem* UndoReactivate::restore()
1031{
1032 kdDebug(5950) << "UndoReactivate::restore()\n";
1033 // Validate the alarm's calendar
1034 switch (calendar())
1035 {
1036 case KAEvent::ACTIVE:
1037 break;
1038 default:
1039 mRestoreError = ERR_PROG;
1040 return 0;
1041 }
1042 return UndoAdd::doRestore(true); // restore alarm, ensuring that it is re-archived
1043}
1044
1045/******************************************************************************
1046* Create a redo item to add the alarm back again.
1047*/
1048UndoItem* UndoReactivate::createRedo(const KAEvent& event)
1049{
1050 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
1051 return new UndoDeactivate(t, event);
1052}
1053
1054/******************************************************************************
1055* Return the action description of the Undo item for displaying.
1056*/
1057TQString UndoReactivate::actionText() const
1058{
1059 return i18n("Reactivate alarm");
1060}
1061
1062
1063/*=============================================================================
1064= Class: UndoDeactivate
1065= Redo item for alarm reactivation.
1066=============================================================================*/
1067
1068/******************************************************************************
1069* Undo the item, i.e. reactivate an alarm which was archived.
1070* Create a redo item to archive the alarm again.
1071* Reply = redo item.
1072*/
1073UndoItem* UndoDeactivate::restore()
1074{
1075 kdDebug(5950) << "UndoDeactivate::restore()\n";
1076 // Validate the alarm's calendar
1077 switch (calendar())
1078 {
1079 case KAEvent::ACTIVE:
1080 break;
1081 default:
1082 mRestoreError = ERR_PROG;
1083 return 0;
1084 }
1085
1086 return UndoDelete::restore();
1087}
1088
1089/******************************************************************************
1090* Create a redo item to archive the alarm again.
1091*/
1092UndoItem* UndoDeactivate::createRedo(const KAEvent& event)
1093{
1094 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
1095 return new UndoReactivate(t, event);
1096}
1097
1098/******************************************************************************
1099* Return the action description of the Undo item for displaying.
1100*/
1101TQString UndoDeactivate::actionText() const
1102{
1103 return i18n("Reactivate alarm");
1104}
1105
1106
1107/*=============================================================================
1108= Class: UndoReactivates
1109= Undo item for multiple alarm reactivation.
1110=============================================================================*/
1111
1112/******************************************************************************
1113* Create a redo item to reactivate the alarms again.
1114*/
1115UndoItem* UndoReactivates::createRedo(Undo::List& undos)
1116{
1117 Undo::Type t = (type() == Undo::UNDO) ? Undo::REDO : (type() == Undo::REDO) ? Undo::UNDO : Undo::NONE;
1118 return new UndoReactivates(t, undos);
1119}
1120
1121/******************************************************************************
1122* Return the action description of the Undo item for displaying.
1123*/
1124TQString UndoReactivates::actionText() const
1125{
1126 return i18n("Reactivate multiple alarms");
1127}
represents calendar alarms and events
KAEvent corresponds to a KCal::Event instance.
Definition: alarmevent.h:232
Status
The category of an event, indicated by the middle part of its UID.
Definition: alarmevent.h:270
miscellaneous functions
KOrgUpdateError
Error codes supplied as parameter to displayKOrgUpdateError()
Definition: functions.h:61