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