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