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