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 
37 static int maxCount = 12;
38 
39 
40 class 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 
78 class 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 
89 template <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 
100 class 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 
119 class 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 
137 class 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 
155 class 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 
166 class 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 
177 class 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 
188 class 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 
199 Undo* Undo::mInstance = 0;
200 Undo::List Undo::mUndoList;
201 Undo::List Undo::mRedoList;
202 
203 
204 /******************************************************************************
205 * Create the one and only instance of the Undo class.
206 */
207 Undo* Undo::instance()
208 {
209  if (!mInstance)
210  mInstance = new Undo(kapp);
211  return mInstance;
212 }
213 
214 /******************************************************************************
215 * Clear the lists of undo and redo items.
216 */
217 void 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 */
235 void Undo::saveAdd(const KAEvent& event)
236 {
237  new UndoAdd(UNDO, event);
238  emitChanged();
239 }
240 
241 void 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 
248 void 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 
255 void 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 
269 void Undo::saveReactivate(const KAEvent& event)
270 {
271  new UndoReactivate(UNDO, event);
272  emitChanged();
273 }
274 
275 void 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 */
290 void 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 */
323 bool 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  {
340  KAlarm::KOrgUpdateError errcode;
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 */
367 void 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 */
391 void 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 */
401 void 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 */
419 TQString 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 */
428 TQString 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 */
437 TQString 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 */
449 TQValueList<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 */
503 void 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 */
512 UndoItem* 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 */
529 Undo::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 =============================================================================*/
546 int UndoItem::mLastId = 0;
547 UndoItem::Error UndoItem::mRestoreError;
548 UndoItem::Warning UndoItem::mRestoreWarning;
549 int UndoItem::mRestoreWarningCount;
550 
551 /******************************************************************************
552 * Constructor.
553 * Optionally appends the undo to the list of undos.
554 */
555 UndoItem::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 */
572 UndoItem::~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 */
581 TQString 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 */
589 TQString 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 
617 template <class T>
618 UndoMulti<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 
625 UndoMultiBase::~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 */
637 template <class T>
638 UndoItem* 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 */
661 template <class T>
662 bool 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 
694 UndoAdd::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 
702 UndoAdd::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 */
715 UndoItem* 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 */
770 UndoItem* 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 */
779 TQString 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 
790 UndoEdit::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 
799 UndoEdit::~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 */
809 UndoItem* 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 */
859 TQString 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 
879 UndoDelete::UndoDelete(Undo::Type type, const KAEvent& event)
880  : UndoItem(type),
881  mEvent(new KAEvent(event))
882 {
883  setCalendar(KAEvent::uidStatus(mEvent->id()));
884 }
885 
886 UndoDelete::~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 */
896 UndoItem* 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 */
966 UndoItem* 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 */
975 TQString 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 */
989 UndoItem* 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 */
998 TQString 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 */
1030 UndoItem* 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 */
1048 UndoItem* 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 */
1057 TQString 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 */
1073 UndoItem* 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 */
1092 UndoItem* 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 */
1101 TQString 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 */
1115 UndoItem* 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 */
1124 TQString 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