TQCommand.cxx

Go to the documentation of this file.
00001 // @(#)root/base:$Id: TQCommand.cxx 25128 2008-08-12 17:59:19Z pcanal $
00002 // Author: Valeriy Onuchin 04/27/2004
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // The Command design pattern is based on the idea, that all editing    //
00015 // in an application is done by creating instances of command objects.  //
00016 // Command objects apply changes to the edited object and then are      //
00017 // stored  on a command stack. Furthermore, each command knows how to   //
00018 // undo its changes to bring the edited object back to its previous     //
00019 // state. As long as the application only uses command objects to       //
00020 // change the state of the edited object, it is possible to undo        //
00021 // a sequence of commands by traversing the command stack downwards and //
00022 // calling the "undo" method of each command in turn. It is also        //
00023 // possible to redo a sequence of commands by traversing the command    //
00024 // stack upwards and calling the "redo" method of each command.         //
00025 //                                                                      //
00026 //                                                                      //
00027 // Examples:                                                            //
00028 //                                                                      //
00029 // 1. Create a new command                                              //
00030 //                                                                      //
00031 // TQCommand *com = new TQCommand("TH1", hpx, "SetFillColor(Color_t)"   //
00032 //                                "SetFillColor(Color_t)");             //
00033 //                                                                      //
00034 // 1st parameter - the name of class                                    //
00035 // 2nd parameter - object                                               //
00036 // 3rd parameter - the name of do/redo method                           //
00037 // 4th parameter - the name of undo method                              //
00038 //                                                                      //
00039 // Since redo,undo methods are the same, undo name can be omitted, e.g. //
00040 //                                                                      //
00041 // TQCommand *com = new TQCommand("TH1", hpx, "SetFillColor(Color_t)"); //
00042 //                                                                      //
00043 // For objects derived from TObject class name can be omitted, e.g.     //
00044 //                                                                      //
00045 //    TQCommand *com = new TQCommand(hpx, "SetFillColor(Color_t)");     //
00046 //                                                                      //
00047 // 2. Setting undo, redo parameters.                                    //
00048 //                                                                      //
00049 //    Color_t old_color = hpx->GetFillColor();                          //
00050 //    Color_t new_color = 4;  // blue color                             //
00051 //                                                                      //
00052 //    com->SetRedoArgs(1, new_color);                                   //
00053 //    com->SetUndoArgs(1, old_color);                                   //
00054 //                                                                      //
00055 // 1st argument - the number of undo, redo parameters                   //
00056 // the other arguments - undo, redo values                              //
00057 //                                                                      //
00058 // Since the number of undo,redo parameters is the same one can use     //
00059 //                                                                      //
00060 //    com->SetArgs(1, new_color, old_color);                            //
00061 //                                                                      //
00062 // 3. Undo, redo method execution                                       //
00063 //                                                                      //
00064 //    com->Redo(); // execute redo method                               //
00065 //    com->Undo(); // execute undo method                               //
00066 //                                                                      //
00067 // 4. Merged commands                                                   //
00068 //                                                                      //
00069 // It possible to group several commands together so an end user        //
00070 // can undo and redo them with one command.                             //
00071 //                                                                      //
00072 //    TQCommand *update = new TQCommand(gPad, "Modified()");            //
00073 //    com->Add(update);                                                 //
00074 //                                                                      //
00075 // 5. Macro commands                                                    //
00076 //                                                                      //
00077 // "Merging" allows to create macro commands, e.g.                      //
00078 //                                                                      //
00079 //    TQCommand *macro = new TQCommand("my macro");                     //
00080 //    macro->Add(com1);                                                 //
00081 //    macro->Add(com2);                                                 //
00082 //    ...                                                               //
00083 //                                                                      //
00084 // During Redo operation commands composing macro command are executed  //
00085 // sequentially in direct  order (first in first out). During Undo,     //
00086 // they are executed in reverse order (last in first out).              //
00087 //                                                                      //
00088 // 6. Undo manager.                                                     //
00089 //                                                                      //
00090 // TQUndoManager is recorder of undo and redo operations. This is       //
00091 // command history list which can be traversed backwards and upwards    //
00092 // performing undo and redo operations.                                 //
00093 // To register command TQUndoManager::Add(TObject*) method is used.     //
00094 //                                                                      //
00095 //    TQUndoManager *history = new TQUndoManager();                     //
00096 //    history->Add(com);                                                //
00097 //                                                                      //
00098 // TQUndoManager::Add automatically invokes execution of command's      //
00099 // Redo method.                                                         //
00100 //                                                                      //
00101 // Use TQUndoManager::Undo to undo commands in  history list.           //
00102 // Redo is Undo for undo action. Use TQUndoManager::Redo method for that//
00103 //                                                                      //
00104 //////////////////////////////////////////////////////////////////////////
00105 
00106 #include "Varargs.h"
00107 #include "TQCommand.h"
00108 #include "TQConnection.h"
00109 #include "TDataType.h"
00110 #include "stdarg.h"
00111 #include "TROOT.h"
00112 
00113 ClassImp(TQCommand)
00114 ClassImp(TQUndoManager)
00115 
00116 static TQCommand *gActiveCommand = 0;
00117 
00118 //////////////////////// auxilary private functions ////////////////////////////
00119 //______________________________________________________________________________
00120 static char *ResolveTypes(const char *method)
00121 {
00122    // Resolve any typedefs in the method signature. For example:
00123    // func(Float_t,Int_t) becomes func(float,int).
00124    // The returned string must be deleted by the user.
00125 
00126    if (!method || !*method) return 0;
00127 
00128    char *str = new char[strlen(method)+1];
00129    if (str) strcpy(str, method);
00130 
00131    TString res;
00132 
00133    char *s = strtok(str, "(");
00134    res = s;
00135    res += "(";
00136 
00137    Bool_t first = kTRUE;
00138    while ((s = strtok(0, ",)"))) {
00139       char *s1, s2 = 0;
00140       if ((s1 = strchr(s, '*'))) {
00141          *s1 = 0;
00142          s2  = '*';
00143       }
00144       if (!s1 && (s1 = strchr(s, '&'))) {
00145          *s1 = 0;
00146          s2  = '&';
00147       }
00148       TDataType *dt = gROOT->GetType(s);
00149       if (s1) *s1 = s2;
00150       if (!first) res += ",";
00151       if (dt) {
00152          res += dt->GetFullTypeName();
00153          if (s1) res += s1;
00154       } else
00155          res += s;
00156       first = kFALSE;
00157    }
00158 
00159    res += ")";
00160 
00161    delete [] str;
00162    str = new char[res.Length()+1];
00163    strcpy(str, res.Data());
00164 
00165    return str;
00166 }
00167 
00168 //______________________________________________________________________________
00169 static char *CompressName(const char *method_name)
00170 {
00171    // Removes "const" words and blanks from full (with prototype)
00172    // method name.
00173    //
00174    //  Example: CompressName(" Draw(const char *, const char *,
00175    //                               Option_t * , Int_t , Int_t)")
00176    //
00177    // Returns the string "Draw(char*,char*,char*,int,int)"
00178    // The returned string must be deleted by the user.
00179 
00180    if (!method_name || !*method_name) return 0;
00181 
00182    char *str = new char[strlen(method_name)+1];
00183    if (str) strcpy(str, method_name);
00184 
00185    char *tmp = str;
00186 
00187    // substitute "const" with white spaces
00188    while ((tmp = strstr(tmp,"const"))) {
00189       for (int i = 0; i < 5; i++) *(tmp+i) = ' ';
00190    }
00191 
00192    tmp = str;
00193    char *s;
00194    s = str;
00195 
00196    Bool_t quote = kFALSE;
00197    while (*tmp) {
00198       if (*tmp == '\"')
00199          quote = quote ? kFALSE : kTRUE;
00200       if (*tmp != ' ' || quote)
00201          *s++ = *tmp;
00202       tmp++;
00203    }
00204    *s = '\0';
00205 
00206    s = ResolveTypes(str);
00207 
00208    delete [] str;
00209 
00210    return s;
00211 }
00212 
00213 ////////////////////////////////////////////////////////////////////////////////
00214 //______________________________________________________________________________
00215 void TQCommand::Init(const char *clname, void *obj, const char *redo, const char *undo)
00216 {
00217    // common protected method used in several constructors
00218 
00219    char *credo = CompressName(redo);
00220    char *cundo = CompressName(undo);
00221 
00222    fNRargs = fNUargs = -1;
00223    fNewDelete = kFALSE;
00224    fObject = obj;
00225 
00226    fRedo = redo ? new TQConnection(clname, obj, credo) : 0;
00227    fUndo = undo ? new TQConnection(clname, obj, cundo) : fRedo;
00228 
00229    fRedoArgs = 0;
00230    fUndoArgs = 0;
00231    fStatus = 0;
00232    fState = 0;
00233 
00234    delete [] credo;
00235    delete [] cundo;
00236 
00237    if (!obj && !redo && !undo) { // macros
00238       fName = clname;
00239    }
00240 }
00241 
00242 //______________________________________________________________________________
00243 TQCommand::TQCommand(const char *clname, void *obj, const char *redo,
00244                      const char *undo) : TList(), TQObject()
00245 {
00246    // Constructor.
00247    //
00248    //   Input parameters:
00249    //     1. clname - class name.
00250    //     2. obj - an object
00251    //     3. redo - method or function to do/redo operation
00252    //     4. undo - method or function to undo operation
00253    //
00254    // Comments:
00255    //    - if either clname or obj is NULL that means that redo/undo is function
00256    //    - to specify default arguments for redo/undo method/function
00257    //       '=' must precede to argument value.
00258    //
00259    //  Example:
00260    //    TQCommand("TPad", gPad, "SetEditable(=kTRUE)", "SetEditable(=kFALSE)");
00261    //
00262    //    - undo method can be same as redo one. In that case undo parameter
00263    //       can be omitted.
00264    //
00265    //  Example:
00266    //    TQCommand("TPad", gPad, "SetFillStyle(Style_t)");
00267 
00268    Init(clname, obj, redo, undo);
00269 }
00270 
00271 //______________________________________________________________________________
00272 TQCommand::TQCommand(TObject *obj, const char *redo, const char *undo) :
00273            TList(), TQObject()
00274 {
00275    // Constructor.
00276    //
00277    //   Input parameters:
00278    //     1. obj - an object
00279    //     2. redo - method or function to do/redo operation
00280    //     3. undo - method or function to undo operation
00281    //
00282    // Comments:
00283    //    - to specify default arguments for redo/undo method/function
00284    //       '=' must precede to argument value.
00285    //
00286    //  Example:
00287    //    TQCommand(gPad, "SetEditable(=kTRUE)", "SetEditable(=kFALSE)");
00288    //
00289    //    - undo method can be same as redo one. In that case "undo"
00290    //       can parameter be omitted.
00291    //
00292    //  Example:
00293    //    TQCommand(gPad, "SetFillStyle(Style_t)");
00294 
00295    if (obj) Init(obj->ClassName(), obj, redo, undo);
00296    else Init(0, 0, redo, undo);
00297 }
00298 
00299 //______________________________________________________________________________
00300 TQCommand::TQCommand(const TQCommand &com) : TList(), TQObject()
00301 {
00302    // Copy constructor.
00303    
00304    fRedo = new TQConnection(*(com.fRedo));
00305    fUndo = new TQConnection(*(com.fUndo));
00306    
00307    fRedoArgs = 0;
00308    fUndoArgs = 0;
00309    fNRargs = com.fNRargs;
00310    fNUargs = com.fNUargs;
00311    
00312    if (fNRargs > 0) {
00313       fRedoArgs = new Long_t[fNRargs];
00314       for (int i = 0; i< fNRargs; i++) {
00315          fRedoArgs[i] = com.fRedoArgs[i];
00316       }
00317    }
00318    if (fNUargs > 0) {
00319       fUndoArgs = new Long_t[fNUargs];
00320       for (int i = 0; i < fNUargs; i++) {
00321          fUndoArgs[i] = com.fUndoArgs[i];
00322       }
00323    }
00324    fStatus = com.fStatus;
00325    fNewDelete = com.fNewDelete;
00326    fName = com.fName;
00327    fTitle = com.fTitle;
00328    fObject = com.fObject;
00329    fState = com.fState;
00330    
00331    // copy merged commands
00332    TIter next(&com);
00333    TQCommand *obj;
00334    while ((obj = (TQCommand*)next())) {
00335       TList::Add(new TQCommand(*obj));
00336    }
00337 }
00338 
00339 //______________________________________________________________________________
00340 TQCommand::~TQCommand()
00341 {
00342    // dtor.
00343 
00344    if (fRedo != fUndo) delete fUndo;
00345 
00346    delete fRedo;
00347    delete fRedoArgs;
00348    delete fUndoArgs;
00349 
00350    Delete();
00351 }
00352 
00353 //______________________________________________________________________________
00354 TQCommand *TQCommand::GetCommand()
00355 {
00356    // Return a command which is doing redo/undo action.
00357    //
00358    // This static method allows to set undo parameters dynamically, i.e.
00359    // during execution of Redo function.
00360    //
00361    // Example:
00362    //    For redo actions like TGTextEdit::DelChar() it is not possible to
00363    //    know ahead what character will be deleted.
00364    //    To set arguments for undo action ( e.g. TGTextEdit::InsChar(char)),
00365    //    one needs to call TQCommand::SetUndoArgs(1, character) from
00366    //    inside of TGTextEdit::DelChar() method, i.e.
00367    //
00368    //    TQCommand::GetCommand()->SetUndoArgs(1, somechar);
00369 
00370    return gActiveCommand;
00371 }
00372 
00373 //______________________________________________________________________________
00374 void TQCommand::Delete(Option_t *opt)
00375 {
00376    // If "opt" is not zero delete every merged command which option string is
00377    // equal to "opt". If "opt" is zero - delete all merged commands.
00378 
00379    if (!opt) {
00380       TList::Delete();
00381       return;
00382    }
00383 
00384    TObjLink *lnk = fFirst;
00385    TObjLink *sav;
00386 
00387    while (lnk) {
00388       sav = lnk->Next();
00389       TString ostr = lnk->GetOption();
00390       if (ostr.Contains(opt)) {   // remove command
00391          delete lnk->GetObject();
00392          Remove(lnk);
00393       }
00394       lnk = sav;
00395    }
00396 }
00397 
00398 //______________________________________________________________________________
00399 Bool_t TQCommand::CanMerge(TQCommand *) const
00400 {
00401    // Two commands can be merged if they can be composed into
00402    // a single command (Macro command).
00403    //
00404    // To allow merging commands user might override this function.
00405 
00406    return (!fRedo && !fUndo);
00407 }
00408 
00409 //______________________________________________________________________________
00410 void TQCommand::Merge(TQCommand *c)
00411 {
00412    // Add command to the list of merged commands.
00413    // This make it possible to group complex actions together so an end user
00414    // can undo and redo them with one command. Execution of TQUndoManager::Undo(),
00415    // TQUndoManager::Redo() methods only invokes the top level command as a whole.
00416    //
00417    // Merge method is analogous to logical join operation.
00418    //
00419    // Note:  Merge method invokes redo action.
00420 
00421    Add(c, "merge");
00422 }
00423 
00424 //______________________________________________________________________________
00425 void TQCommand::Add(TObject *obj, Option_t *opt)
00426 {
00427    // Add command to the list of merged commands.
00428    //
00429    // Option string can contain substrings:
00430    //  "compress" - try to compress input command
00431    //  "radd" - execute redo action of input command
00432    //  "uadd" - execute undo action of input command
00433 
00434    if (!obj->InheritsFrom(TQCommand::Class())) return;
00435 
00436    TQCommand *o = (TQCommand *)obj;
00437    TQCommand *c = (TQCommand *)Last();
00438    TString ostr = opt;
00439 
00440    if (c) {
00441       if (c->CanCompress(o) || (c->IsEqual(o) && ostr.Contains("compress"))) {
00442          c->Compress(o);
00443          return;
00444       }
00445    }
00446    TList::AddLast(o, opt);
00447    if (o->CanRedo() && ostr.Contains("radd")) o->Redo();
00448    if (o->CanUndo() && ostr.Contains("uadd")) o->Undo();
00449 }
00450 
00451 //______________________________________________________________________________
00452 Bool_t TQCommand::CanCompress(TQCommand *c) const
00453 {
00454    // By default, commands can be compressed if they are:
00455    //
00456    //  - equal
00457    //  - setter commands
00458    //
00459    // More complicated commands might want to override this function.
00460 
00461    return (IsEqual(c) && IsSetter());
00462 }
00463 
00464 //______________________________________________________________________________
00465 void TQCommand::Compress(TQCommand *c)
00466 {
00467    // Compress command. Compression is analogous to arithmetic "addition operation".
00468    //
00469    // Note:
00470    //    - The compressed command will be deleted.
00471    //    - Execution Compress method invokes Redo action with new redo arguments
00472    //      inheritied from compressed command.
00473    //
00474    // More complicated commands might want to override this function.
00475 
00476    for (int i = 0; i < fNRargs; i++) {
00477       fRedoArgs[i] = c->fRedoArgs[i];
00478    }
00479    Redo();
00480    fStatus--;   //do not change the state of command
00481    delete c;
00482 }
00483 
00484 //______________________________________________________________________________
00485 Bool_t TQCommand::IsEqual(const TObject* obj) const
00486 {
00487    // Equal comparison. The commands are equal if they are
00488    // applied to the same object and have the same Redo/Undo actions
00489    //
00490    // More complicated commands might want to override this function.
00491 
00492    if (!obj->InheritsFrom(TQCommand::Class())) return kFALSE;
00493    TQCommand *c = (TQCommand *)obj;
00494    if (!fRedo || !fUndo || (c->GetObject() != fObject)) return kFALSE;
00495 
00496    TString cname = fRedo->GetClassName();
00497    TString rname = fRedo->GetName();
00498 
00499    return ((cname == c->GetRedo()->GetClassName()) &&
00500            (rname == c->GetRedo()->GetName()));
00501 }
00502 
00503 //______________________________________________________________________________
00504 Bool_t TQCommand::IsSetter() const
00505 {
00506    // Returns kTRUE is command if Redo is the same as Undo function
00507    // and is the setter action.
00508    //
00509    // By default, all functions with names like "SetXXX" or "setXXX"
00510    // considered as setters. Another type of setters are Move, Resize operations
00511    //
00512    // More complicated commands might want to override this function.
00513 
00514    TString redo = GetRedoName();
00515    TString undo = GetUndoName();
00516 
00517    if (!redo || !undo || (redo != undo)) return kFALSE;
00518 
00519    return (redo.BeginsWith("Set") ||
00520            redo.BeginsWith("set") ||
00521            redo.BeginsWith("Move") ||
00522            redo.BeginsWith("move") ||
00523            redo.BeginsWith("Resize") ||
00524            redo.BeginsWith("resize"));
00525 }
00526 
00527 //______________________________________________________________________________
00528 void TQCommand::SetArgs(Int_t narg, ...)
00529 {
00530    // Set do/redo and undo parameters. The format is
00531    //    SetArgs(number_of_params, redo_params, undo_params)
00532    //
00533    // Example:
00534    //     move_command->SetArgs(2, 100, 100, 200, 200);
00535    //      2 params, (100,100) - do/redo position, (200,200) - undo position
00536 
00537    if (narg < 0) {
00538       return;
00539    } else if (!narg) {  // no arguments
00540       fNRargs = fNUargs = narg;
00541       return;
00542    }
00543 
00544    va_list ap;
00545    va_start(ap, narg);
00546 
00547    if (fNRargs != narg ) {
00548       delete fRedoArgs;
00549    }
00550    fRedoArgs = new Long_t[narg];
00551 
00552    if (fNUargs != narg ) {
00553       delete fUndoArgs;
00554    }
00555    fUndoArgs = new Long_t[narg];
00556 
00557    fNRargs = fNUargs = narg;
00558 
00559    Int_t i;
00560    for (i = 0; i < fNRargs; i++) {
00561       fRedoArgs[i] = va_arg(ap, Long_t);
00562    }
00563    for (i = 0; i < fNUargs; i++) {
00564       fUndoArgs[i] = va_arg(ap, Long_t);
00565    }
00566    va_end(ap);
00567 }
00568 
00569 //______________________________________________________________________________
00570 void TQCommand::SetRedoArgs(Int_t narg, ...)
00571 {
00572    // Set redo parameters. The format is
00573    //    SetRedoArgs(number_of_params, params)
00574    //
00575    // Example:
00576    //     move_command->SetRedoArgs(2, 100, 100);
00577 
00578    if (narg < 0) {
00579       return;
00580    } else if (!narg) {  // no arguments
00581       fNRargs = 0;
00582       return;
00583    }
00584 
00585    va_list ap;
00586    va_start(ap, narg);
00587 
00588    if (fNRargs != narg ) {
00589       delete fRedoArgs;
00590    }
00591    fRedoArgs = new Long_t[narg];
00592 
00593    fNRargs = narg;
00594 
00595    for (int i = 0; i < fNRargs; i++) {
00596       fRedoArgs[i] = va_arg(ap, Long_t);
00597    }
00598    va_end(ap);
00599 }
00600 
00601 //______________________________________________________________________________
00602 void TQCommand::SetUndoArgs(Int_t narg, ...)
00603 {
00604    // Set undo parameters. The format is
00605    //    SetUndoArgs(number_of_params, params)
00606    //
00607    // Example:
00608    //     move_command->SetUndoArgs(2, 200, 200);
00609 
00610    if (narg < 0) {
00611       return;
00612    } else if (!narg) {  // no arguments
00613       fNUargs = narg;
00614       return;
00615    }
00616 
00617    va_list ap;
00618    va_start(ap, narg);
00619 
00620    if (fNUargs != narg ) {
00621       delete fUndoArgs;
00622    }
00623    fUndoArgs = new Long_t[narg];
00624 
00625    fNUargs = narg;
00626 
00627    for (int i = 0; i < fNUargs; i++) {
00628       fUndoArgs[i] = va_arg(ap, Long_t);
00629    }
00630    va_end(ap);
00631 }
00632 
00633 //______________________________________________________________________________
00634 Bool_t TQCommand::CanRedo() const
00635 {
00636    // Returns kTRUE if Redo action is possible, kFALSE if it's not.
00637    // By default, only single sequential redo action is possible.
00638 
00639    return (fStatus <= 0);
00640 }
00641 
00642 //______________________________________________________________________________
00643 Bool_t TQCommand::CanUndo() const
00644 {
00645    // Returns kTRUE if Undo action is possible, kFALSE if it's not.
00646    // By default, only single tial undo action is possible.
00647 
00648    return (fStatus > 0);
00649 }
00650 
00651 //______________________________________________________________________________
00652 void TQCommand::Redo(Option_t *)
00653 {
00654    // Execute command and then smerged commands
00655 
00656    Bool_t done = kFALSE;
00657    fState = 1;
00658 
00659    gActiveCommand = this;
00660 
00661    if (fNRargs > 0) {
00662       if (fRedo) {
00663          fRedo->ExecuteMethod(fRedoArgs, fNRargs);
00664          done = kTRUE;
00665       }
00666    } else if (!fNRargs) {
00667       if (fRedo) {
00668          fRedo->ExecuteMethod();
00669          done = kTRUE;
00670       }
00671    }
00672 
00673    // execute merged commands
00674    TObjLink *lnk = fFirst;
00675    while (lnk) {
00676       TQCommand *c = (TQCommand *)lnk->GetObject();
00677       c->Redo();
00678       done = kTRUE;
00679       lnk = lnk->Next();
00680    }
00681 
00682    if (done) Emit("Redo()");
00683    fStatus++;
00684    fState = 0;
00685    gActiveCommand = 0;
00686 }
00687 
00688 //______________________________________________________________________________
00689 void TQCommand::Undo(Option_t *)
00690 {
00691    // Unexecute all merged commands and the command.
00692    // Merged commands are executed in reverse order.
00693 
00694    Bool_t done = kFALSE;
00695    fState = -1;
00696 
00697    gActiveCommand = this;
00698 
00699    // unexecute merged commands
00700    TObjLink *lnk = fLast;
00701    while (lnk) {
00702       TQCommand *c = (TQCommand *)lnk->GetObject();
00703       TString opt = lnk->GetOption();
00704       TObjLink *sav = lnk->Prev();
00705       c->Undo();
00706       done = kTRUE;
00707       if (opt.Contains("remove")) {   // remove  command
00708          delete lnk->GetObject();
00709          Remove(lnk);
00710       }
00711       lnk = sav;
00712    }
00713    if (fNUargs > 0) {
00714       if (fUndo) {
00715          fUndo->ExecuteMethod(fUndoArgs, fNUargs);
00716          done = kTRUE;
00717       }
00718    } else if (!fNUargs) {
00719       if (fUndo) {
00720          fUndo->ExecuteMethod();
00721          done = kTRUE;
00722       }
00723    }
00724 
00725    if (done) Emit("Undo()");
00726    fStatus--;
00727    fState = 0;
00728    gActiveCommand = 0;
00729 }
00730 
00731 //______________________________________________________________________________
00732 const char *TQCommand::GetName() const
00733 {
00734    // Returns the command name. Default name is "ClassName::RedoName(args)"
00735    // If list of merged commands is not empty the name is
00736    // "ClassName::RedoName(args):cname1:cname2 ..."
00737 
00738    const Int_t maxname = 100;
00739 
00740    if (!fName.IsNull()) return fName.Data();
00741 
00742    TString name;
00743 
00744    if (fRedo) {
00745       if (fRedo->GetClassName()) {
00746          name = fRedo->GetClassName();
00747       }
00748       name += "::";
00749       name += fRedo->GetName();
00750    }
00751    TQCommand *c;
00752    TObjLink *lnk = fFirst;
00753 
00754    while (lnk && (fName.Length() < maxname)) {
00755       c = (TQCommand *)lnk->GetObject();
00756       name += ":";
00757       name += c->GetName();
00758       lnk = lnk->Next();
00759    }
00760 
00761    // trick against "constness"
00762    TQCommand *m = (TQCommand *)this;
00763    m->fName = name;
00764 
00765    return name.Data();
00766 }
00767 
00768 //______________________________________________________________________________
00769 const char *TQCommand::GetTitle() const
00770 {
00771    // Returns command description.
00772    // By default, "ClassName::RedoName(args)_ClassName::UndoName(args)"
00773 
00774    if (!fTitle.IsNull()) return fTitle.Data();
00775 
00776    TString title = GetName();
00777 
00778    if (fUndo) {
00779       title += "_";
00780       title += fUndo->GetClassName();
00781       title += "::";
00782       if (fUndo->GetName())  title += fUndo->GetName();
00783    }
00784    return title.Data();
00785 }
00786 
00787 //______________________________________________________________________________
00788 const char *TQCommand::GetRedoName() const
00789 {
00790    // Returns the name of redo command
00791 
00792    return (fRedo ? fRedo->GetName() : 0);
00793 }
00794 
00795 //______________________________________________________________________________
00796 const char *TQCommand::GetUndoName() const
00797 {
00798    // Returns the name of undo command
00799 
00800    return (fUndo ? fUndo->GetName() : 0);
00801 }
00802 
00803 //______________________________________________________________________________
00804 Long_t *TQCommand::GetRedoArgs() const
00805 {
00806    // Returns a pointer to array of redo arguments
00807 
00808    return fRedoArgs;
00809 }
00810 
00811 //______________________________________________________________________________
00812 Long_t *TQCommand::GetUndoArgs() const
00813 {
00814    // Returns a pointer to array of undo arguments
00815 
00816    return fUndoArgs;
00817 }
00818 
00819 //______________________________________________________________________________
00820 Int_t TQCommand::GetNRargs() const
00821 {
00822    // Returns a number of redo arguments
00823 
00824    return fNRargs;
00825 }
00826 
00827 //______________________________________________________________________________
00828 Int_t TQCommand::GetNUargs() const
00829 {
00830    // Returns a number of undo arguments
00831 
00832    return fNUargs;
00833 }
00834 
00835 //______________________________________________________________________________
00836 void *TQCommand::GetObject() const
00837 {
00838    // Returns an object for which undo redo acions are applied
00839 
00840    return fObject;
00841 }
00842 
00843 //______________________________________________________________________________
00844 Int_t TQCommand::GetStatus() const
00845 {
00846    // Returns a number of sequential undo or redo operations
00847 
00848    return fStatus;
00849 }
00850 
00851 //______________________________________________________________________________
00852 Bool_t TQCommand::IsMacro() const
00853 {
00854    // Returns kTRUE if neither redo nor undo action specified
00855 
00856    return (!fRedo && !fUndo);
00857 }
00858 
00859 //______________________________________________________________________________
00860 Bool_t TQCommand::IsUndoing() const
00861 {
00862    // Undo action is in progress
00863 
00864    return (fState < 0);
00865 }
00866 
00867 //______________________________________________________________________________
00868 Bool_t TQCommand::IsRedoing() const
00869 {
00870    // Redo action is in progress
00871 
00872    return (fState > 0);
00873 }
00874 
00875 //______________________________________________________________________________
00876 Bool_t TQCommand::IsExecuting() const
00877 {
00878    // Returns kTRUE if command execution is in progress
00879 
00880    return fState;
00881 }
00882 
00883 //______________________________________________________________________________
00884 void TQCommand::SetName(const char *name)
00885 {
00886    // Sets name of the command
00887 
00888    fName = name;
00889 }
00890 
00891 //______________________________________________________________________________
00892 void TQCommand::SetTitle(const char *title)
00893 {
00894    // Sets description of the command
00895 
00896    fTitle = title;
00897 }
00898 
00899 //______________________________________________________________________________
00900 void TQCommand::ls(Option_t *) const
00901 {
00902    // ls this command and merged commands
00903 
00904    TString name = GetName();
00905    printf("%d %s\n", fStatus, name.Data());
00906 
00907    TObjLink *lnk = fFirst;
00908    while (lnk) {
00909       printf("\t");
00910       lnk->GetObject()->ls();
00911       lnk = lnk->Next();
00912    }
00913 }
00914 
00915 //______________________________________________________________________________
00916 void TQCommand::PrintCollectionHeader(Option_t* /*option*/) const
00917 {
00918    // Print collection header.
00919 
00920    TROOT::IndentLevel();
00921    printf("%d %s\n", fStatus, GetName()); 
00922 }
00923 
00924 ///////////////////////////////////////////////////////////////////////////////
00925 //______________________________________________________________________________
00926 TQUndoManager::TQUndoManager() : TQCommand(0, 0, 0, 0)
00927 {
00928    // Constructor
00929 
00930    fCursor = 0;
00931    fLimit = kMaxUInt;   // maximum value for UInt_t
00932    fLogging = kFALSE;
00933    fLogBook = 0;
00934    fCurrent = 0;
00935 }
00936 
00937 //______________________________________________________________________________
00938 TQUndoManager::~TQUndoManager()
00939 {
00940    // Destructor
00941 
00942    Delete();
00943 
00944    if (fLogBook) {
00945       delete fLogBook;
00946    }
00947 }
00948 
00949 //______________________________________________________________________________
00950 void TQUndoManager::ls(Option_t *option) const
00951 {
00952    // Lists all commands in stack
00953 
00954    if (!IsEmpty()) {
00955       TObjLink *lnk = fFirst;
00956       while (lnk) {
00957          if (lnk == fCursor) {
00958             printf("->");
00959          } else {
00960             printf("  ");
00961          }
00962          TQCommand *com = (TQCommand*)lnk->GetObject();
00963          com->ls(option);
00964          lnk = lnk->Next();
00965       }
00966    }
00967 }
00968 
00969 //______________________________________________________________________________
00970 void TQUndoManager::PrintCollectionEntry(TObject* entry, Option_t* option,
00971                                          Int_t /*recurse*/) const
00972 {
00973    // Print collection entry.
00974 
00975    TQCommand *com = (TQCommand*) entry;
00976    TROOT::IndentLevel();
00977    if (fCursor && fCursor->GetObject() == entry) {
00978       printf("->");
00979    } else {
00980       printf("  ");
00981    }
00982    com->ls(option);
00983 }
00984 
00985 //______________________________________________________________________________
00986 void  TQUndoManager::SetLogging(Bool_t on)
00987 {
00988    // Start logging. Delete all previous log records
00989    // Note: logging is not implemented yet
00990 
00991    fLogging = on;
00992 
00993    if (fLogging) {
00994       if (fLogBook) {
00995          fLogBook->Delete();
00996       } else {
00997          fLogBook = new TList();
00998       }
00999    }
01000 }
01001 
01002 //______________________________________________________________________________
01003 void TQUndoManager::Add(TObject *obj, Option_t *opt)
01004 {
01005    // Add command to the stack of commands.
01006    // Command's redo action will be executed.
01007    //
01008    // option string can contain the following substrings:
01009    //    "merge" - input command will be merged
01010    //    "compress" - input command will be compressed
01011 
01012    if (!obj->InheritsFrom(TQCommand::Class())) return;
01013 
01014    TQCommand *o = (TQCommand *)obj;
01015    TQCommand *c;
01016    Bool_t onredo = fCursor && fCursor->Next();
01017    TString ostr = onredo ? "1radd" : "0radd"; // execute redo on add
01018    if (opt) ostr += opt;
01019 
01020    if (fState) { // undo/redo in progress
01021       c = fCurrent;
01022       if (c) {
01023          fCurrent = o;
01024          c->Add(o, "remove");   // add nested command
01025       }
01026       return;
01027    }
01028 
01029    // delete all commands after cursor position
01030    if (fCursor && fCursor->Next()) {
01031       TObjLink *lnk = fCursor->Next();
01032       TObjLink *sav;
01033       while (lnk) {
01034          sav = lnk->Next();
01035          delete lnk->GetObject();
01036          Remove(lnk);
01037          lnk = sav;
01038       }
01039    }
01040 
01041    c = GetCursor();
01042    if (c) {
01043       if (c->CanCompress(o) || c->CanMerge(o) ||
01044           ostr.Contains("merge") || ostr.Contains("compress")) {
01045          fState = 1;
01046          c->Add(o, ostr.Data());
01047          fState = 0;
01048          return;
01049       }
01050    }
01051 
01052    TList::AddLast(obj, ostr.Data());
01053    fCursor = fLast;
01054    Redo(ostr.Data());
01055 
01056    if ((fSize > 0) && ((UInt_t)fSize > fLimit)) {
01057       Remove(fFirst);
01058    }
01059 }
01060 
01061 //______________________________________________________________________________
01062 void TQUndoManager::CurrentChanged(TQCommand *c)
01063 {
01064    // emit signal
01065 
01066    Emit("CurrentChanged(TQCommand*)", (long)c);
01067 }
01068 
01069 //______________________________________________________________________________
01070 void TQUndoManager::Undo(Option_t *option)
01071 {
01072    // Performs undo action. Move cursor position backward in history stack
01073 
01074    Bool_t done = kFALSE;
01075    if (!CanUndo()) return;
01076 
01077    TQCommand *sav = fCurrent;
01078    TQCommand *c = (TQCommand*)fCursor->GetObject();
01079 
01080    if (c->CanUndo()) {
01081       fState = -1;
01082       fCurrent = c;
01083       fCurrent->Undo(option);
01084       fState = 0;
01085       done = kTRUE;
01086       fCursor = fCursor->Prev() ? fCursor->Prev() : fFirst;
01087    } else {
01088       fCursor = fCursor->Prev();
01089       fCurrent = (TQCommand*)fCursor->GetObject();
01090       fState = -1;
01091       fCurrent->Undo(option);
01092       fState = 0;
01093       done = kTRUE;
01094    }
01095    if (done && fLogging && fLogBook) {
01096       fLogBook->Add(new TQCommand(*fCurrent));
01097    }
01098    if (sav != fCurrent) CurrentChanged(fCurrent);
01099 }
01100 
01101 //______________________________________________________________________________
01102 void TQUndoManager::Redo(Option_t *option)
01103 {
01104    // Performs redo action. Move cursor position forward in history stack
01105 
01106    Bool_t done = kFALSE;
01107    if (!CanRedo()) return;
01108 
01109    TQCommand *sav = fCurrent;
01110    TQCommand *c = (TQCommand*)fCursor->GetObject();
01111 
01112    if (c->CanRedo()) {
01113       fState = 1;
01114       fCurrent = c;
01115       fCurrent->Redo(option);
01116       fState = 0;
01117       done = kTRUE;
01118       fCursor = fCursor->Next() ? fCursor->Next() : fLast;
01119    } else {
01120       fCursor = fCursor->Next();
01121       fCurrent = (TQCommand*)fCursor->GetObject();
01122       fState = 1;
01123       fCurrent->Redo(option);
01124       fState = 0;
01125       done = kTRUE;
01126    }
01127    if (done && fLogging && fLogBook) {
01128       fLogBook->Add(new TQCommand(*fCurrent));
01129    }
01130    if (sav != fCurrent) CurrentChanged(fCurrent);
01131 }
01132 
01133 //______________________________________________________________________________
01134 Bool_t TQUndoManager::CanRedo() const
01135 {
01136    // Returns kTRUE if redo action is possible
01137 
01138    if (!fCursor) return kFALSE;
01139 
01140    TQCommand *c = (TQCommand*)fCursor->GetObject();
01141    if (c->CanRedo()) return kTRUE;
01142 
01143    c = fCursor->Next() ? (TQCommand*)fCursor->Next()->GetObject() : 0;
01144    return (c && c->CanRedo());
01145 }
01146 
01147 //______________________________________________________________________________
01148 Bool_t TQUndoManager::CanUndo() const
01149 {
01150    // Returns kTRUE if undo action is possible
01151 
01152    if (!fCursor) return kFALSE;
01153 
01154    TQCommand *c = (TQCommand*)fCursor->GetObject();
01155    if (c->CanUndo()) return kTRUE;
01156 
01157    c = fCursor->Prev() ? (TQCommand*)fCursor->Prev()->GetObject() : 0;
01158    return (c && c->CanUndo());
01159 }
01160 
01161 //_____________________________________________________________________________
01162 Bool_t TQUndoManager::IsLogging() const
01163 {
01164    // Returns kTRUE if logging is ON
01165 
01166    return fLogging;
01167 }
01168 
01169 //_____________________________________________________________________________
01170 TQCommand *TQUndoManager::GetCurrent() const
01171 {
01172    // Returns the last executed command
01173 
01174    return fCurrent;
01175 }
01176 
01177 //_____________________________________________________________________________
01178 TQCommand *TQUndoManager::GetCursor() const
01179 {
01180    // Returns a command correspondent to the current cursor position in stack
01181 
01182    return (TQCommand*)(fCursor ? fCursor->GetObject() : 0);
01183 }
01184 
01185 //_____________________________________________________________________________
01186 void TQUndoManager::SetLimit(UInt_t limit)
01187 {
01188    // Returns a maximum number of commands which could be located in stack
01189 
01190    fLimit = limit;
01191 }
01192 
01193 //_____________________________________________________________________________
01194 UInt_t TQUndoManager::GetLimit() const
01195 {
01196    // Returns a maximum number of commands which  could be located in stack
01197 
01198    return fLimit;
01199 }

Generated on Tue Jul 5 14:11:22 2011 for ROOT_528-00b_version by  doxygen 1.5.1