Logo ROOT   6.08/07
Reference Guide
TQCommand.cxx
Go to the documentation of this file.
1 // @(#)root/base:$Id$
2 // Author: Valeriy Onuchin 04/27/2004
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TQCommand
13 \ingroup Base
14 
15 The Command design pattern is based on the idea, that all editing
16 in an application is done by creating instances of command objects.
17 Command objects apply changes to the edited object and then are
18 stored on a command stack. Furthermore, each command knows how to
19 undo its changes to bring the edited object back to its previous
20 state. As long as the application only uses command objects to
21 change the state of the edited object, it is possible to undo
22 a sequence of commands by traversing the command stack downwards and
23 calling the "undo" method of each command in turn. It is also
24 possible to redo a sequence of commands by traversing the command
25 stack upwards and calling the "redo" method of each command.
26 
27 
28 Examples:
29 
30 1. Create a new command
31 ~~~ {.cpp}
32  TQCommand *com = new TQCommand("TH1", hpx, "SetFillColor(Color_t)"
33  "SetFillColor(Color_t)");
34 ~~~
35  - 1st parameter - the name of class
36  - 2nd parameter - object
37  - 3rd parameter - the name of do/redo method
38  - 4th parameter - the name of undo method
39  Since redo,undo methods are the same, undo name can be omitted, e.g.
40 ~~~ {.cpp}
41  TQCommand *com = new TQCommand("TH1", hpx, "SetFillColor(Color_t)");
42 ~~~
43  For objects derived from TObject class name can be omitted, e.g.
44 ~~~ {.cpp}
45  TQCommand *com = new TQCommand(hpx, "SetFillColor(Color_t)");
46 ~~~
47 
48 2. Setting undo, redo parameters.
49 ~~~ {.cpp}
50  Color_t old_color = hpx->GetFillColor();
51  Color_t new_color = 4; // blue color
52 
53  com->SetRedoArgs(1, new_color);
54  com->SetUndoArgs(1, old_color);
55 ~~~
56  1st argument - the number of undo, redo parameters
57  the other arguments - undo, redo values
58  Since the number of undo,redo parameters is the same one can use
59 ~~~ {.cpp}
60  com->SetArgs(1, new_color, old_color);
61 ~~~
62 
63 3. Undo, redo method execution
64 ~~~ {.cpp}
65  com->Redo(); // execute redo method
66  com->Undo(); // execute undo method
67 ~~~
68 
69 4. Merged commands
70  It possible to group several commands together so an end user
71  can undo and redo them with one command.
72 ~~~ {.cpp}
73  TQCommand *update = new TQCommand(gPad, "Modified()");
74  com->Add(update);
75 ~~~
76 
77 5. Macro commands
78  "Merging" allows to create macro commands, e.g.
79 ~~~ {.cpp}
80  TQCommand *macro = new TQCommand("my macro");
81  macro->Add(com1);
82  macro->Add(com2);
83  ...
84 ~~~
85  During Redo operation commands composing macro command are executed
86  sequentially in direct order (first in first out). During Undo,
87  they are executed in reverse order (last in first out).
88 
89 6. Undo manager.
90  TQUndoManager is recorder of undo and redo operations. This is
91  command history list which can be traversed backwards and upwards
92  performing undo and redo operations.
93  To register command TQUndoManager::Add(TObject*) method is used.
94 ~~~ {.cpp}
95  TQUndoManager *history = new TQUndoManager();
96  history->Add(com);
97 ~~~
98  TQUndoManager::Add automatically invokes execution of command's Redo method.
99 
100 Use TQUndoManager::Undo to undo commands in history list.
101 Redo is Undo for undo action. Use TQUndoManager::Redo method for that
102 */
103 
104 #include "Varargs.h"
105 #include "TQCommand.h"
106 #include "TQConnection.h"
107 #include "TDataType.h"
108 #include "stdarg.h"
109 #include "TROOT.h"
110 
113 
115 
116 ////////////////////////////////////////////////////////////////////////////////
117 /// Common protected method used in several constructors
118 
119 void TQCommand::Init(const char *clname, void *obj, const char *redo, const char *undo)
120 {
121  TString credo( CompressName(redo) );
122  TString cundo( CompressName(undo) );
123 
124  fNRargs = fNUargs = -1;
125  fNewDelete = kFALSE;
126  fObject = obj;
127 
128  fRedo = redo ? new TQConnection(clname, obj, credo) : 0;
129  fUndo = undo ? new TQConnection(clname, obj, cundo) : fRedo;
130 
131  fRedoArgs = 0;
132  fUndoArgs = 0;
133  fStatus = 0;
134  fState = 0;
135 
136  if (!obj && !redo && !undo) { // macros
137  fName = clname;
138  }
139 }
140 
141 ////////////////////////////////////////////////////////////////////////////////
142 /// Constructor.
143 ///
144 /// Input parameters:
145 /// 1. clname - class name.
146 /// 2. obj - an object
147 /// 3. redo - method or function to do/redo operation
148 /// 4. undo - method or function to undo operation
149 ///
150 /// Comments:
151 /// - if either clname or obj is NULL that means that redo/undo is function
152 /// - to specify default arguments for redo/undo method/function
153 /// '=' must precede to argument value.
154 ///
155 /// Example:
156 /// ~~~ {.cpp}
157 /// TQCommand("TPad", gPad, "SetEditable(=kTRUE)", "SetEditable(=kFALSE)");
158 /// ~~~
159 /// undo method can be same as redo one. In that case undo parameter
160 /// can be omitted.
161 ///
162 /// Example:
163 /// ~~~ {.cpp}
164 /// TQCommand("TPad", gPad, "SetFillStyle(Style_t)");
165 /// ~~~
166 
167 TQCommand::TQCommand(const char *clname, void *obj, const char *redo,
168  const char *undo) : TList(), TQObject()
169 {
170  Init(clname, obj, redo, undo);
171 }
172 
173 ////////////////////////////////////////////////////////////////////////////////
174 /// Constructor.
175 ///
176 /// Input parameters:
177 /// 1. obj - an object
178 /// 2. redo - method or function to do/redo operation
179 /// 3. undo - method or function to undo operation
180 ///
181 /// Comments:
182 /// to specify default arguments for redo/undo method/function
183 /// '=' must precede to argument value.
184 ///
185 /// Example:
186 /// ~~~ {.cpp}
187 /// TQCommand(gPad, "SetEditable(=kTRUE)", "SetEditable(=kFALSE)");
188 /// ~~~
189 ///
190 /// undo method can be same as redo one. In that case "undo"
191 /// can parameter be omitted.
192 ///
193 /// Example:
194 /// ~~~ {.cpp}
195 /// TQCommand(gPad, "SetFillStyle(Style_t)");
196 /// ~~~
197 
198 TQCommand::TQCommand(TObject *obj, const char *redo, const char *undo) :
199  TList(), TQObject()
200 {
201  if (obj) Init(obj->ClassName(), obj, redo, undo);
202  else Init(0, 0, redo, undo);
203 }
204 
205 ////////////////////////////////////////////////////////////////////////////////
206 /// Copy constructor.
207 
209 {
210  fRedo = new TQConnection(*(com.fRedo));
211  fUndo = new TQConnection(*(com.fUndo));
212 
213  fRedoArgs = 0;
214  fUndoArgs = 0;
215  fNRargs = com.fNRargs;
216  fNUargs = com.fNUargs;
217 
218  if (fNRargs > 0) {
219  fRedoArgs = new Long_t[fNRargs];
220  for (int i = 0; i< fNRargs; i++) {
221  fRedoArgs[i] = com.fRedoArgs[i];
222  }
223  }
224  if (fNUargs > 0) {
225  fUndoArgs = new Long_t[fNUargs];
226  for (int i = 0; i < fNUargs; i++) {
227  fUndoArgs[i] = com.fUndoArgs[i];
228  }
229  }
230  fStatus = com.fStatus;
231  fNewDelete = com.fNewDelete;
232  fName = com.fName;
233  fTitle = com.fTitle;
234  fObject = com.fObject;
235  fState = com.fState;
236 
237  // copy merged commands
238  TIter next(&com);
239  TQCommand *obj;
240  while ((obj = (TQCommand*)next())) {
241  TList::Add(new TQCommand(*obj));
242  }
243 }
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 /// dtor.
247 
249 {
250  if (fRedo != fUndo) delete fUndo;
251 
252  delete fRedo;
253  delete fRedoArgs;
254  delete fUndoArgs;
255 
256  Delete();
257 }
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 /// Return a command which is doing redo/undo action.
261 ///
262 /// This static method allows to set undo parameters dynamically, i.e.
263 /// during execution of Redo function.
264 ///
265 /// Example:
266 /// For redo actions like TGTextEdit::DelChar() it is not possible to
267 /// know ahead what character will be deleted.
268 /// To set arguments for undo action ( e.g. TGTextEdit::InsChar(char)),
269 /// one needs to call TQCommand::SetUndoArgs(1, character) from
270 /// inside of TGTextEdit::DelChar() method, i.e.
271 /// ~~~ {.cpp}
272 /// TQCommand::GetCommand()->SetUndoArgs(1, somechar);
273 /// ~~~
274 
276 {
277  return gActiveCommand;
278 }
279 
280 ////////////////////////////////////////////////////////////////////////////////
281 /// If "opt" is not zero delete every merged command which option string is
282 /// equal to "opt". If "opt" is zero - delete all merged commands.
283 
285 {
286  if (!opt) {
287  TList::Delete();
288  return;
289  }
290 
291  TObjLink *lnk = fFirst;
292  TObjLink *sav;
293 
294  while (lnk) {
295  sav = lnk->Next();
296  TString ostr = lnk->GetOption();
297  if (ostr.Contains(opt)) { // remove command
298  delete lnk->GetObject();
299  Remove(lnk);
300  }
301  lnk = sav;
302  }
303 }
304 
305 ////////////////////////////////////////////////////////////////////////////////
306 /// Two commands can be merged if they can be composed into
307 /// a single command (Macro command).
308 ///
309 /// To allow merging commands user might override this function.
310 
312 {
313  return (!fRedo && !fUndo);
314 }
315 
316 ////////////////////////////////////////////////////////////////////////////////
317 /// Add command to the list of merged commands.
318 /// This make it possible to group complex actions together so an end user
319 /// can undo and redo them with one command. Execution of TQUndoManager::Undo(),
320 /// TQUndoManager::Redo() methods only invokes the top level command as a whole.
321 ///
322 /// Merge method is analogous to logical join operation.
323 ///
324 /// Note: Merge method invokes redo action.
325 
327 {
328  Add(c, "merge");
329 }
330 
331 ////////////////////////////////////////////////////////////////////////////////
332 /// Merge a collection of TQCommand.
333 
335 {
336  TIter next(collection);
337  while (TObject* o = next()) {
338  TQCommand *command = dynamic_cast<TQCommand*> (o);
339  if (!command) {
340  Error("Merge",
341  "Cannot merge - an object which doesn't inherit from TQCommand found in the list");
342  return -1;
343  }
344  Merge(command);
345  }
346  return GetEntries();
347 }
348 
349 ////////////////////////////////////////////////////////////////////////////////
350 /// Add command to the list of merged commands.
351 ///
352 /// Option string can contain substrings:
353 /// - "compress" - try to compress input command
354 /// - "radd" - execute redo action of input command
355 /// - "uadd" - execute undo action of input command
356 
358 {
359  if (!obj->InheritsFrom(TQCommand::Class())) return;
360 
361  TQCommand *o = (TQCommand *)obj;
362  TQCommand *c = (TQCommand *)Last();
363  TString ostr = opt;
364 
365  if (c) {
366  if (c->CanCompress(o) || (c->IsEqual(o) && ostr.Contains("compress"))) {
367  c->Compress(o);
368  return;
369  }
370  }
371  TList::AddLast(o, opt);
372  if (o->CanRedo() && ostr.Contains("radd")) o->Redo();
373  if (o->CanUndo() && ostr.Contains("uadd")) o->Undo();
374 }
375 
376 ////////////////////////////////////////////////////////////////////////////////
377 /// By default, commands can be compressed if they are:
378 ///
379 /// - equal
380 /// - setter commands
381 ///
382 /// More complicated commands might want to override this function.
383 
385 {
386  return (IsEqual(c) && IsSetter());
387 }
388 
389 ////////////////////////////////////////////////////////////////////////////////
390 /// Compress command. Compression is analogous to arithmetic "addition operation".
391 ///
392 /// Note:
393 /// - The compressed command will be deleted.
394 /// - Execution Compress method invokes Redo action with new redo arguments
395 /// inherited from compressed command.
396 ///
397 /// More complicated commands might want to override this function.
398 
400 {
401  for (int i = 0; i < fNRargs; i++) {
402  fRedoArgs[i] = c->fRedoArgs[i];
403  }
404  Redo();
405  fStatus--; //do not change the state of command
406  delete c;
407 }
408 
409 ////////////////////////////////////////////////////////////////////////////////
410 /// Equal comparison. The commands are equal if they are
411 /// applied to the same object and have the same Redo/Undo actions
412 ///
413 /// More complicated commands might want to override this function.
414 
416 {
417  if (!obj->InheritsFrom(TQCommand::Class())) return kFALSE;
418  TQCommand *c = (TQCommand *)obj;
419  if (!fRedo || !fUndo || (c->GetObject() != fObject)) return kFALSE;
420 
421  TString cname = fRedo->GetClassName();
422  TString rname = fRedo->GetName();
423 
424  return ((cname == c->GetRedo()->GetClassName()) &&
425  (rname == c->GetRedo()->GetName()));
426 }
427 
428 ////////////////////////////////////////////////////////////////////////////////
429 /// Returns kTRUE is command if Redo is the same as Undo function
430 /// and is the setter action.
431 ///
432 /// By default, all functions with names like "SetXXX" or "setXXX"
433 /// considered as setters. Another type of setters are Move, Resize operations
434 ///
435 /// More complicated commands might want to override this function.
436 
438 {
439  TString redo = GetRedoName();
440  TString undo = GetUndoName();
441 
442  if (!redo || !undo || (redo != undo)) return kFALSE;
443 
444  return (redo.BeginsWith("Set") ||
445  redo.BeginsWith("set") ||
446  redo.BeginsWith("Move") ||
447  redo.BeginsWith("move") ||
448  redo.BeginsWith("Resize") ||
449  redo.BeginsWith("resize"));
450 }
451 
452 ////////////////////////////////////////////////////////////////////////////////
453 /// Set do/redo and undo parameters. The format is
454 /// SetArgs(number_of_params, redo_params, undo_params)
455 ///
456 /// Example:
457 /// ~~~ {.cpp}
458 /// move_command->SetArgs(2, 100, 100, 200, 200);
459 /// ~~~
460 /// 2 params, (100,100) - do/redo position, (200,200) - undo position
461 
462 void TQCommand::SetArgs(Int_t narg, ...)
463 {
464  if (narg < 0) {
465  return;
466  } else if (!narg) { // no arguments
467  fNRargs = fNUargs = narg;
468  return;
469  }
470 
471  va_list ap;
472  va_start(ap, narg);
473 
474  if (fNRargs != narg ) {
475  delete fRedoArgs;
476  }
477  fRedoArgs = new Long_t[narg];
478 
479  if (fNUargs != narg ) {
480  delete fUndoArgs;
481  }
482  fUndoArgs = new Long_t[narg];
483 
484  fNRargs = fNUargs = narg;
485 
486  Int_t i;
487  for (i = 0; i < fNRargs; i++) {
488  fRedoArgs[i] = va_arg(ap, Long_t);
489  }
490  for (i = 0; i < fNUargs; i++) {
491  fUndoArgs[i] = va_arg(ap, Long_t);
492  }
493  va_end(ap);
494 }
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 /// Set redo parameters. The format is
498 /// SetRedoArgs(number_of_params, params)
499 ///
500 /// Example:
501 /// ~~~ {.cpp}
502 /// move_command->SetRedoArgs(2, 100, 100);
503 /// ~~~
504 
506 {
507  if (narg < 0) {
508  return;
509  } else if (!narg) { // no arguments
510  fNRargs = 0;
511  return;
512  }
513 
514  va_list ap;
515  va_start(ap, narg);
516 
517  if (fNRargs != narg ) {
518  delete fRedoArgs;
519  }
520  fRedoArgs = new Long_t[narg];
521 
522  fNRargs = narg;
523 
524  for (int i = 0; i < fNRargs; i++) {
525  fRedoArgs[i] = va_arg(ap, Long_t);
526  }
527  va_end(ap);
528 }
529 
530 ////////////////////////////////////////////////////////////////////////////////
531 /// Set undo parameters. The format is
532 /// SetUndoArgs(number_of_params, params)
533 ///
534 /// Example:
535 /// ~~~ {.cpp}
536 /// move_command->SetUndoArgs(2, 200, 200);
537 /// ~~~
538 
540 {
541  if (narg < 0) {
542  return;
543  } else if (!narg) { // no arguments
544  fNUargs = narg;
545  return;
546  }
547 
548  va_list ap;
549  va_start(ap, narg);
550 
551  if (fNUargs != narg ) {
552  delete fUndoArgs;
553  }
554  fUndoArgs = new Long_t[narg];
555 
556  fNUargs = narg;
557 
558  for (int i = 0; i < fNUargs; i++) {
559  fUndoArgs[i] = va_arg(ap, Long_t);
560  }
561  va_end(ap);
562 }
563 
564 ////////////////////////////////////////////////////////////////////////////////
565 /// Returns kTRUE if Redo action is possible, kFALSE if it's not.
566 /// By default, only single sequential redo action is possible.
567 
569 {
570  return (fStatus <= 0);
571 }
572 
573 ////////////////////////////////////////////////////////////////////////////////
574 /// Returns kTRUE if Undo action is possible, kFALSE if it's not.
575 /// By default, only single trial undo action is possible.
576 
578 {
579  return (fStatus > 0);
580 }
581 
582 ////////////////////////////////////////////////////////////////////////////////
583 /// Execute command and then merge commands
584 
586 {
587  Bool_t done = kFALSE;
588  fState = 1;
589 
590  gActiveCommand = this;
591 
592  if (fNRargs > 0) {
593  if (fRedo) {
595  done = kTRUE;
596  }
597  } else if (!fNRargs) {
598  if (fRedo) {
599  fRedo->ExecuteMethod();
600  done = kTRUE;
601  }
602  }
603 
604  // execute merged commands
605  TObjLink *lnk = fFirst;
606  while (lnk) {
607  TQCommand *c = (TQCommand *)lnk->GetObject();
608  c->Redo();
609  done = kTRUE;
610  lnk = lnk->Next();
611  }
612 
613  if (done) Emit("Redo()");
614  fStatus++;
615  fState = 0;
616  gActiveCommand = 0;
617 }
618 
619 ////////////////////////////////////////////////////////////////////////////////
620 /// Un-execute all merged commands and the command.
621 /// Merged commands are executed in reverse order.
622 
624 {
625  Bool_t done = kFALSE;
626  fState = -1;
627 
628  gActiveCommand = this;
629 
630  // unexecute merged commands
631  TObjLink *lnk = fLast;
632  while (lnk) {
633  TQCommand *c = (TQCommand *)lnk->GetObject();
634  TString opt = lnk->GetOption();
635  TObjLink *sav = lnk->Prev();
636  c->Undo();
637  done = kTRUE;
638  if (opt.Contains("remove")) { // remove command
639  delete lnk->GetObject();
640  Remove(lnk);
641  }
642  lnk = sav;
643  }
644  if (fNUargs > 0) {
645  if (fUndo) {
647  done = kTRUE;
648  }
649  } else if (!fNUargs) {
650  if (fUndo) {
651  fUndo->ExecuteMethod();
652  done = kTRUE;
653  }
654  }
655 
656  if (done) Emit("Undo()");
657  fStatus--;
658  fState = 0;
659  gActiveCommand = 0;
660 }
661 
662 ////////////////////////////////////////////////////////////////////////////////
663 /// Returns the command name. Default name is "ClassName::RedoName(args)"
664 /// If list of merged commands is not empty the name is
665 /// "ClassName::RedoName(args):cname1:cname2 ..."
666 
667 const char *TQCommand::GetName() const
668 {
669  const Int_t maxname = 100;
670 
671  if (!fName.IsNull()) return fName.Data();
672 
673  TString name;
674 
675  if (fRedo) {
676  if (fRedo->GetClassName()) {
677  name = fRedo->GetClassName();
678  }
679  name += "::";
680  name += fRedo->GetName();
681  }
682  TQCommand *c;
683  TObjLink *lnk = fFirst;
684 
685  while (lnk && (fName.Length() < maxname)) {
686  c = (TQCommand *)lnk->GetObject();
687  name += ":";
688  name += c->GetName();
689  lnk = lnk->Next();
690  }
691 
692  // trick against "constness"
693  TQCommand *m = (TQCommand *)this;
694  m->fName = name;
695 
696  return name.Data();
697 }
698 
699 ////////////////////////////////////////////////////////////////////////////////
700 /// Returns command description.
701 /// By default, "ClassName::RedoName(args)_ClassName::UndoName(args)"
702 
703 const char *TQCommand::GetTitle() const
704 {
705  if (!fTitle.IsNull()) return fTitle.Data();
706 
707  TString title = GetName();
708 
709  if (fUndo) {
710  title += "_";
711  title += fUndo->GetClassName();
712  title += "::";
713  if (fUndo->GetName()) title += fUndo->GetName();
714  }
715  return title.Data();
716 }
717 
718 ////////////////////////////////////////////////////////////////////////////////
719 /// Returns the name of redo command
720 
721 const char *TQCommand::GetRedoName() const
722 {
723  return (fRedo ? fRedo->GetName() : 0);
724 }
725 
726 ////////////////////////////////////////////////////////////////////////////////
727 /// Returns the name of undo command
728 
729 const char *TQCommand::GetUndoName() const
730 {
731  return (fUndo ? fUndo->GetName() : 0);
732 }
733 
734 ////////////////////////////////////////////////////////////////////////////////
735 /// Returns a pointer to array of redo arguments
736 
738 {
739  return fRedoArgs;
740 }
741 
742 ////////////////////////////////////////////////////////////////////////////////
743 /// Returns a pointer to array of undo arguments
744 
746 {
747  return fUndoArgs;
748 }
749 
750 ////////////////////////////////////////////////////////////////////////////////
751 /// Returns a number of redo arguments
752 
754 {
755  return fNRargs;
756 }
757 
758 ////////////////////////////////////////////////////////////////////////////////
759 /// Returns a number of undo arguments
760 
762 {
763  return fNUargs;
764 }
765 
766 ////////////////////////////////////////////////////////////////////////////////
767 /// Returns an object for which undo redo actions are applied
768 
769 void *TQCommand::GetObject() const
770 {
771  return fObject;
772 }
773 
774 ////////////////////////////////////////////////////////////////////////////////
775 /// Returns a number of sequential undo or redo operations
776 
778 {
779  return fStatus;
780 }
781 
782 ////////////////////////////////////////////////////////////////////////////////
783 /// Returns kTRUE if neither redo nor undo action specified
784 
786 {
787  return (!fRedo && !fUndo);
788 }
789 
790 ////////////////////////////////////////////////////////////////////////////////
791 /// Undo action is in progress
792 
794 {
795  return (fState < 0);
796 }
797 
798 ////////////////////////////////////////////////////////////////////////////////
799 /// Redo action is in progress
800 
802 {
803  return (fState > 0);
804 }
805 
806 ////////////////////////////////////////////////////////////////////////////////
807 /// Returns kTRUE if command execution is in progress
808 
810 {
811  return fState;
812 }
813 
814 ////////////////////////////////////////////////////////////////////////////////
815 /// Sets name of the command
816 
817 void TQCommand::SetName(const char *name)
818 {
819  fName = name;
820 }
821 
822 ////////////////////////////////////////////////////////////////////////////////
823 /// Sets description of the command
824 
825 void TQCommand::SetTitle(const char *title)
826 {
827  fTitle = title;
828 }
829 
830 ////////////////////////////////////////////////////////////////////////////////
831 /// ls this command and merged commands
832 
833 void TQCommand::ls(Option_t *) const
834 {
835  TString name = GetName();
836  printf("%d %s\n", fStatus, name.Data());
837 
838  TObjLink *lnk = fFirst;
839  while (lnk) {
840  printf("\t");
841  lnk->GetObject()->ls();
842  lnk = lnk->Next();
843  }
844 }
845 
846 ////////////////////////////////////////////////////////////////////////////////
847 /// Print collection header.
848 
850 {
852  printf("%d %s\n", fStatus, GetName());
853 }
854 
855 /** \class TQUndoManager
856 Recorder of operations for undo and redo
857 */
858 
859 ////////////////////////////////////////////////////////////////////////////////
860 /// Constructor
861 
863 {
864  fCursor = 0;
865  fLimit = kMaxUInt; // maximum value for UInt_t
866  fLogging = kFALSE;
867  fLogBook = 0;
868  fCurrent = 0;
869 }
870 
871 ////////////////////////////////////////////////////////////////////////////////
872 /// Destructor
873 
875 {
876  Delete();
877 
878  if (fLogBook) {
879  delete fLogBook;
880  }
881 }
882 
883 ////////////////////////////////////////////////////////////////////////////////
884 /// Lists all commands in stack
885 
886 void TQUndoManager::ls(Option_t *option) const
887 {
888  if (!IsEmpty()) {
889  TObjLink *lnk = fFirst;
890  while (lnk) {
891  if (lnk == fCursor) {
892  printf("->");
893  } else {
894  printf(" ");
895  }
896  TQCommand *com = (TQCommand*)lnk->GetObject();
897  com->ls(option);
898  lnk = lnk->Next();
899  }
900  }
901 }
902 
903 ////////////////////////////////////////////////////////////////////////////////
904 /// Print collection entry.
905 
907  Int_t /*recurse*/) const
908 {
909  TQCommand *com = (TQCommand*) entry;
911  if (fCursor && fCursor->GetObject() == entry) {
912  printf("->");
913  } else {
914  printf(" ");
915  }
916  com->ls(option);
917 }
918 
919 ////////////////////////////////////////////////////////////////////////////////
920 /// Start logging. Delete all previous log records
921 /// Note: logging is not implemented yet
922 
924 {
925  fLogging = on;
926 
927  if (fLogging) {
928  if (fLogBook) {
929  fLogBook->Delete();
930  } else {
931  fLogBook = new TList();
932  }
933  }
934 }
935 
936 ////////////////////////////////////////////////////////////////////////////////
937 /// Add command to the stack of commands.
938 /// Command's redo action will be executed.
939 ///
940 /// option string can contain the following substrings:
941 /// - "merge" - input command will be merged
942 /// - "compress" - input command will be compressed
943 
945 {
946  if (!obj->InheritsFrom(TQCommand::Class())) return;
947 
948  TQCommand *o = (TQCommand *)obj;
949  TQCommand *c;
950  Bool_t onredo = fCursor && fCursor->Next();
951  TString ostr = onredo ? "1radd" : "0radd"; // execute redo on add
952  if (opt) ostr += opt;
953 
954  if (fState) { // undo/redo in progress
955  c = fCurrent;
956  if (c) {
957  fCurrent = o;
958  c->Add(o, "remove"); // add nested command
959  }
960  return;
961  }
962 
963  // delete all commands after cursor position
964  if (fCursor && fCursor->Next()) {
965  TObjLink *lnk = fCursor->Next();
966  TObjLink *sav;
967  while (lnk) {
968  sav = lnk->Next();
969  delete lnk->GetObject();
970  Remove(lnk);
971  lnk = sav;
972  }
973  }
974 
975  c = GetCursor();
976  if (c) {
977  if (c->CanCompress(o) || c->CanMerge(o) ||
978  ostr.Contains("merge") || ostr.Contains("compress")) {
979  fState = 1;
980  c->Add(o, ostr.Data());
981  fState = 0;
982  return;
983  }
984  }
985 
986  TList::AddLast(obj, ostr.Data());
987  fCursor = fLast;
988  Redo(ostr.Data());
989 
990  if ((fSize > 0) && ((UInt_t)fSize > fLimit)) {
991  Remove(fFirst);
992  }
993 }
994 
995 ////////////////////////////////////////////////////////////////////////////////
996 /// emit signal
997 
999 {
1000  Emit("CurrentChanged(TQCommand*)", (long)c);
1001 }
1002 
1003 ////////////////////////////////////////////////////////////////////////////////
1004 /// Performs undo action. Move cursor position backward in history stack
1005 
1007 {
1008  Bool_t done = kFALSE;
1009  if (!CanUndo()) return;
1010 
1011  TQCommand *sav = fCurrent;
1013 
1014  if (c->CanUndo()) {
1015  fState = -1;
1016  fCurrent = c;
1017  fCurrent->Undo(option);
1018  fState = 0;
1019  done = kTRUE;
1020  fCursor = fCursor->Prev() ? fCursor->Prev() : fFirst;
1021  } else {
1022  fCursor = fCursor->Prev();
1024  fState = -1;
1025  fCurrent->Undo(option);
1026  fState = 0;
1027  done = kTRUE;
1028  }
1029  if (done && fLogging && fLogBook) {
1030  fLogBook->Add(new TQCommand(*fCurrent));
1031  }
1032  if (sav != fCurrent) CurrentChanged(fCurrent);
1033 }
1034 
1035 ////////////////////////////////////////////////////////////////////////////////
1036 /// Performs redo action. Move cursor position forward in history stack
1037 
1039 {
1040  Bool_t done = kFALSE;
1041  if (!CanRedo()) return;
1042 
1043  TQCommand *sav = fCurrent;
1045 
1046  if (c->CanRedo()) {
1047  fState = 1;
1048  fCurrent = c;
1049  fCurrent->Redo(option);
1050  fState = 0;
1051  done = kTRUE;
1052  fCursor = fCursor->Next() ? fCursor->Next() : fLast;
1053  } else {
1054  fCursor = fCursor->Next();
1056  fState = 1;
1057  fCurrent->Redo(option);
1058  fState = 0;
1059  done = kTRUE;
1060  }
1061  if (done && fLogging && fLogBook) {
1062  fLogBook->Add(new TQCommand(*fCurrent));
1063  }
1064  if (sav != fCurrent) CurrentChanged(fCurrent);
1065 }
1066 
1067 ////////////////////////////////////////////////////////////////////////////////
1068 /// Returns kTRUE if redo action is possible
1069 
1071 {
1072  if (!fCursor) return kFALSE;
1073 
1075  if (c->CanRedo()) return kTRUE;
1076 
1077  c = fCursor->Next() ? (TQCommand*)fCursor->Next()->GetObject() : 0;
1078  return (c && c->CanRedo());
1079 }
1080 
1081 ////////////////////////////////////////////////////////////////////////////////
1082 /// Returns kTRUE if undo action is possible
1083 
1085 {
1086  if (!fCursor) return kFALSE;
1087 
1089  if (c->CanUndo()) return kTRUE;
1090 
1091  c = fCursor->Prev() ? (TQCommand*)fCursor->Prev()->GetObject() : 0;
1092  return (c && c->CanUndo());
1093 }
1094 
1095 ////////////////////////////////////////////////////////////////////////////////
1096 /// Returns kTRUE if logging is ON
1097 
1099 {
1100  return fLogging;
1101 }
1102 
1103 ////////////////////////////////////////////////////////////////////////////////
1104 /// Returns the last executed command
1105 
1107 {
1108  return fCurrent;
1109 }
1110 
1111 ////////////////////////////////////////////////////////////////////////////////
1112 /// Returns a command correspondent to the current cursor position in stack
1113 
1115 {
1116  return (TQCommand*)(fCursor ? fCursor->GetObject() : 0);
1117 }
1118 
1119 ////////////////////////////////////////////////////////////////////////////////
1120 /// Returns a maximum number of commands which could be located in stack
1121 
1123 {
1124  fLimit = limit;
1125 }
1126 
1127 ////////////////////////////////////////////////////////////////////////////////
1128 /// Returns a maximum number of commands which could be located in stack
1129 
1131 {
1132  return fLimit;
1133 }
virtual Bool_t CanUndo() const
Returns kTRUE if undo action is possible.
Definition: TQCommand.cxx:1084
virtual void SetUndoArgs(Int_t nargs,...)
Set undo parameters.
Definition: TQCommand.cxx:539
virtual void Merge(TQCommand *c)
Add command to the list of merged commands.
Definition: TQCommand.cxx:326
TString fName
Definition: TQCommand.h:43
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:405
Int_t fNRargs
Definition: TQCommand.h:38
long long Long64_t
Definition: RtypesCore.h:69
Int_t fNUargs
Definition: TQCommand.h:39
virtual void SetLogging(Bool_t on=kTRUE)
Start logging.
Definition: TQCommand.cxx:923
Int_t fState
Definition: TQCommand.h:40
Long_t * GetUndoArgs() const
Returns a pointer to array of undo arguments.
Definition: TQCommand.cxx:745
Bool_t IsUndoing() const
Undo action is in progress.
Definition: TQCommand.cxx:793
return c
TQConnection * fUndo
Definition: TQCommand.h:35
const char Option_t
Definition: RtypesCore.h:62
virtual void Add(TObject *obj, Option_t *opt)
Add command to the stack of commands.
Definition: TQCommand.cxx:944
TQCommand * fCurrent
Definition: TQCommand.h:109
Bool_t IsRedoing() const
Redo action is in progress.
Definition: TQCommand.cxx:801
const char * GetUndoName() const
Returns the name of undo command.
Definition: TQCommand.cxx:729
Long_t * fUndoArgs
Definition: TQCommand.h:37
virtual void Compress(TQCommand *c)
Compress command.
Definition: TQCommand.cxx:399
virtual Int_t GetEntries() const
Definition: TCollection.h:92
virtual TObject * Last() const
Return the last object in the list. Returns 0 when list is empty.
Definition: TList.cxx:581
TList * fLogBook
Definition: TQCommand.h:111
TQUndoManager()
Constructor.
Definition: TQCommand.cxx:862
This is the ROOT implementation of the Qt object communication mechanism (see also http://www...
Definition: TQObject.h:53
Long_t * GetRedoArgs() const
Returns a pointer to array of redo arguments.
Definition: TQCommand.cxx:737
virtual Bool_t CanMerge(TQCommand *c) const
Two commands can be merged if they can be composed into a single command (Macro command).
Definition: TQCommand.cxx:311
virtual void Init(const char *cl, void *object, const char *redo, const char *undo)
Common protected method used in several constructors.
Definition: TQCommand.cxx:119
Long_t * fRedoArgs
Definition: TQCommand.h:36
TQConnection * GetRedo() const
Definition: TQCommand.h:77
Basic string class.
Definition: TString.h:137
virtual Bool_t IsEqual(const TObject *obj) const
Equal comparison.
Definition: TQCommand.cxx:415
int Int_t
Definition: RtypesCore.h:41
TQCommand * GetCursor() const
Returns a command correspondent to the current cursor position in stack.
Definition: TQCommand.cxx:1114
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
virtual void Undo(Option_t *option="")
Performs undo action. Move cursor position backward in history stack.
Definition: TQCommand.cxx:1006
const char * Class
Definition: TXMLSetup.cxx:64
virtual Bool_t IsSetter() const
Returns kTRUE is command if Redo is the same as Undo function and is the setter action.
Definition: TQCommand.cxx:437
const UInt_t kMaxUInt
Definition: Rtypes.h:102
virtual Bool_t CanRedo() const
Returns kTRUE if Redo action is possible, kFALSE if it&#39;s not.
Definition: TQCommand.cxx:568
virtual void AddLast(TObject *obj)
Add object at the end of the list.
Definition: TList.cxx:137
virtual ~TQCommand()
dtor.
Definition: TQCommand.cxx:248
virtual void Redo(Option_t *option="")
Execute command and then merge commands.
Definition: TQCommand.cxx:585
virtual ~TQUndoManager()
Destructor.
Definition: TQCommand.cxx:874
Int_t GetNRargs() const
Returns a number of redo arguments.
Definition: TQCommand.cxx:753
Int_t GetNUargs() const
Returns a number of undo arguments.
Definition: TQCommand.cxx:761
virtual void ls(Option_t *option="") const
Lists all commands in stack.
Definition: TQCommand.cxx:886
virtual void Redo(Option_t *option="")
Performs redo action. Move cursor position forward in history stack.
Definition: TQCommand.cxx:1038
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:188
virtual void SetArgs(Int_t nargs,...)
Set do/redo and undo parameters.
Definition: TQCommand.cxx:462
UInt_t GetLimit() const
Returns a maximum number of commands which could be located in stack.
Definition: TQCommand.cxx:1130
void Init(TClassEdit::TInterpreterLookupHelper *helper)
Definition: TClassEdit.cxx:119
TString fTitle
Definition: TQCommand.h:44
Bool_t fNewDelete
Definition: TQCommand.h:42
TQCommand(const char *cl=0, void *object=0, const char *redo=0, const char *undo=0)
Constructor.
Definition: TQCommand.cxx:167
TQConnection * fRedo
Definition: TQCommand.h:34
Bool_t IsExecuting() const
Returns kTRUE if command execution is in progress.
Definition: TQCommand.cxx:809
void Emit(const char *signal)
Acitvate signal without args.
Definition: TQObject.cxx:561
UInt_t fLimit
Definition: TQCommand.h:110
A doubly linked list.
Definition: TList.h:47
static TQCommand * gActiveCommand
Definition: TQCommand.cxx:114
void * GetObject() const
Returns an object for which undo redo actions are applied.
Definition: TQCommand.cxx:769
TQConnection class is an internal class, used in the object communication mechanism.
Definition: TQConnection.h:46
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:675
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:488
virtual void CurrentChanged(TQCommand *c)
emit signal
Definition: TQCommand.cxx:998
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:558
Collection abstract base class.
Definition: TCollection.h:48
TObjLink * fLast
pointer to first entry in linked list
Definition: TList.h:53
unsigned int UInt_t
Definition: RtypesCore.h:42
TMarker * m
Definition: textangle.C:8
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
virtual Bool_t CanCompress(TQCommand *c) const
By default, commands can be compressed if they are:
Definition: TQCommand.cxx:384
Ssiz_t Length() const
Definition: TString.h:390
friend class TQConnection
Definition: TQObject.h:55
virtual void Delete(Option_t *option="")
If "opt" is not zero delete every merged command which option string is equal to "opt".
Definition: TQCommand.cxx:284
Int_t GetStatus() const
Returns a number of sequential undo or redo operations.
Definition: TQCommand.cxx:777
virtual Bool_t CanUndo() const
Returns kTRUE if Undo action is possible, kFALSE if it&#39;s not.
Definition: TQCommand.cxx:577
Int_t fSize
Definition: TCollection.h:63
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition: TROOT.cxx:2618
Bool_t fLogging
Definition: TQCommand.h:112
void ExecuteMethod()
Apply slot-method to the fReceiver object without arguments.
TObjLink * fFirst
Definition: TList.h:52
virtual void SetTitle(const char *title)
Sets description of the command.
Definition: TQCommand.cxx:825
virtual void PrintCollectionEntry(TObject *entry, Option_t *option, Int_t recurse) const
Print collection entry.
Definition: TQCommand.cxx:906
virtual void ls(Option_t *option="") const
ls this command and merged commands
Definition: TQCommand.cxx:833
long Long_t
Definition: RtypesCore.h:50
virtual Bool_t IsEmpty() const
Definition: TCollection.h:99
#define ClassImp(name)
Definition: Rtypes.h:279
virtual Bool_t CanRedo() const
Returns kTRUE if redo action is possible.
Definition: TQCommand.cxx:1070
Bool_t IsMacro() const
Returns kTRUE if neither redo nor undo action specified.
Definition: TQCommand.cxx:785
virtual void SetName(const char *name)
Sets name of the command.
Definition: TQCommand.cxx:817
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
virtual void Add(TObject *obj, Option_t *opt)
Add command to the list of merged commands.
Definition: TQCommand.cxx:357
virtual const char * GetTitle() const
Returns command description.
Definition: TQCommand.cxx:703
Bool_t IsNull() const
Definition: TString.h:387
virtual void SetRedoArgs(Int_t nargs,...)
Set redo parameters.
Definition: TQCommand.cxx:505
virtual void Undo(Option_t *option="")
Un-execute all merged commands and the command.
Definition: TQCommand.cxx:623
Mother of all ROOT objects.
Definition: TObject.h:37
TList()
Definition: TList.h:72
virtual void Add(TObject *obj)
Definition: TList.h:81
Recorder of operations for undo and redo.
Definition: TQCommand.h:105
Bool_t IsLogging() const
Returns kTRUE if logging is ON.
Definition: TQCommand.cxx:1098
static TQCommand * GetCommand()
Return a command which is doing redo/undo action.
Definition: TQCommand.cxx:275
void * fObject
Definition: TQCommand.h:45
virtual const char * GetName() const
Returns the command name.
Definition: TQCommand.cxx:667
const char * GetName() const
Returns name of connection (aka name of slot)
The Command design pattern is based on the idea, that all editing in an application is done by creati...
Definition: TQCommand.h:29
const char * GetRedoName() const
Returns the name of redo command.
Definition: TQCommand.cxx:721
TQCommand * GetCurrent() const
Returns the last executed command.
Definition: TQCommand.cxx:1106
const Bool_t kTRUE
Definition: Rtypes.h:91
const char * GetClassName() const
Definition: TQConnection.h:72
TObjLink * fCursor
Definition: TQCommand.h:108
virtual void PrintCollectionHeader(Option_t *option) const
Print collection header.
Definition: TQCommand.cxx:849
Int_t fStatus
Definition: TQCommand.h:41
char name[80]
Definition: TGX11.cxx:109
virtual void SetLimit(UInt_t limit)
Returns a maximum number of commands which could be located in stack.
Definition: TQCommand.cxx:1122
const char * Data() const
Definition: TString.h:349