TClassTree.cxx

Go to the documentation of this file.
00001 // @(#)root/gpad:$Id: TClassTree.cxx 36657 2010-11-15 09:55:37Z rdm $
00002 // Author: Rene Brun   01/12/98
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, 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 #include "RConfigure.h"
00013 
00014 #include "TROOT.h"
00015 #include "TClassTree.h"
00016 #include "TClassTable.h"
00017 #include "TClass.h"
00018 #include "TBaseClass.h"
00019 #include "TDataMember.h"
00020 #include "TDataType.h"
00021 #include "TRealData.h"
00022 #include "TMethod.h"
00023 #include "TMethodArg.h"
00024 #include "TPad.h"
00025 #include "TPaveClass.h"
00026 #include "TArrow.h"
00027 #include "TText.h"
00028 #include "TSystem.h"
00029 #include "TObjString.h"
00030 #include "Riostream.h"
00031 
00032 const Int_t kIsClassTree = BIT(7);
00033 const Int_t kUsedByData  = BIT(11);
00034 const Int_t kUsedByFunc  = BIT(12);
00035 const Int_t kUsedByCode  = BIT(13);
00036 const Int_t kUsedByClass = BIT(14);
00037 const Int_t kUsingData   = BIT(15);
00038 const Int_t kUsingFunc   = BIT(16);
00039 const Int_t kUsingCode   = BIT(17);
00040 const Int_t kUsingClass  = BIT(18);
00041 const Int_t kUsedByCode1 = BIT(19);
00042 const Int_t kIsaPointer  = BIT(20);
00043 const Int_t kIsBasic     = BIT(21);
00044 
00045 static Float_t gXsize, gYsize, gDx, gDy, gLabdx, gLabdy, gDxx, gCsize;
00046 static Int_t *gNtsons, *gNsons;
00047 
00048 ClassImp(TClassTree)
00049 
00050 
00051 //______________________________________________________________________________
00052 //
00053 // Draw inheritance tree and their relations for a list of classes
00054 // The following options are supported
00055 //   - Direct inheritance (default)
00056 //   - Multiple inheritance
00057 //   - Composition
00058 //   - References by data members and member functions
00059 //   - References from Code
00060 //
00061 // The list of classes is specified:
00062 //   - either in the TClassTree constructor as a second argument
00063 //   - or the parameter to TClassTRee::Draw
00064 //
00065 // Note that the ClassTree viewer can also be started from the canvas
00066 // pull down menu "Classes".
00067 //
00068 // In the list of classes, class names are separated by a ":"
00069 // wildcarding is supported.
00070 // The following formats are supported, eg in TClassTree::Draw
00071 //   1- Draw("ClassA")
00072 //         Draw inheritance tree for ClassA
00073 //         Show all classes referenced by ClassA
00074 //   2- Draw("*ClassB")
00075 //         Draw inheritance tree for ClassB
00076 //         and all the classes deriving from ClassB
00077 //   3- Draw(">ClassC")
00078 //         Draw inheritance tree for ClassC
00079 //         Show classes referencing ClassC
00080 //   4- Draw("ClassD<")
00081 //         Draw inheritance tree for ClassD
00082 //         Show classes referenced by ClassD
00083 //         Show all classes referencing ClassD
00084 //   5- Draw("Cla*")
00085 //         Draw inheritance tree for all classes with name starting with "Cla"
00086 //         Show classes referenced by these classes
00087 //   6- Draw("ClassA:ClassB<")
00088 //         Draw inheritance tree for ClassA
00089 //         Show all classes referenced by ClassA
00090 //         Draw inheritance tree for ClassB
00091 //         Show classes referenced by ClassB
00092 //         Show all classes referencing ClassB
00093 //
00094 //  example;  Draw("TTree<")
00095 //         Draw inheritance tree for the Root class TTree
00096 //         Show all classes referenced by TTree
00097 //         Show all classes using TTree
00098 //
00099 // By default, only direct inheritance is drawn.
00100 // Use TClassTree::ShowLinks(option) to show additional references
00101 //   option = "H" to show links to embedded classes
00102 //   option = "M" to show multiple inheritance
00103 //   option = "R" to show pointers to other classes from data members
00104 //   option = "C" to show classes used by the code(implementation) of a class
00105 //
00106 // The following picture is produced directly by:
00107 //       TClassTree ct("ct","*TH1")
00108 // It shows all the classes derived from the base class TH1.
00109 //Begin_Html
00110 /*
00111 <img src="gif/th1_classtree.gif">
00112 */
00113 //End_Html
00114 //
00115 // The ClassTree class uses the services of the class TPaveClass to
00116 // show the class names. By clicking with the right mouse button in
00117 // one TPaveClass object, one can invoke the following functions of TClassTree:
00118 //   - ShowLinks(option) with by default option = "HMR"
00119 //   - Draw(classes). By default the class drawn is the one being pointed
00120 //   - ShowClassesUsedBy(classes) (by default the pointed class)
00121 //   - ShowClassesUsing(classes) (by default the pointed class)
00122 //
00123 //  The following picture has been generated with the following statements
00124 //       TClassTree tc1("tc1","TObject");
00125 //       tc1.SetShowLinks("HMR");
00126 //
00127 //Begin_Html
00128 /*
00129 <img src="gif/tobject_classtree.gif">
00130 */
00131 //End_Html
00132 //
00133 // Note that in case of embedded classes or pointers to classes,
00134 // the corresponding dashed lines or arrows respectively start
00135 // in the TPaveClass object at an X position reflecting the position
00136 // in the list of data members.
00137 //
00138 //  - References by data members to other classes are show with a full red line
00139 //  - Multiple inheritance is shown with a dashed blue line
00140 //  - "Has a" relation is shown with a dotted cyan line
00141 //  - References from code is shown by a full green line
00142 //
00143 //  Use TClassTree::SetSourceDir to specify the search path for source files.
00144 //  By default the search path includes the ROOTSYS/src directory, the current
00145 //  directory and the subdirectory src.
00146 //
00147 //  The first time TClassTree::Draw is invoked, all the classes in the
00148 //  current application are processed, including the parsing of the code
00149 //  to find all classes referenced by the include statements.
00150 //  This process may take a few seconds. The following commands will be
00151 //  much faster.
00152 //
00153 //  A TClassTree object may be saved in a Root file.
00154 //  This object can be processed later by a Root program that ignores
00155 //  the original classes. This interesting possibility allows to send
00156 //  the class structure of an application to a colleague who does not have
00157 //  your classes.
00158 //  Example:
00159 //    TFile f("myClasses.root","recreate")
00160 //    TClassTree *ct = new TClassTree("ct","ATLF*")
00161 //    ct->Write();
00162 //  You can send at this point the file myClass.root to a colleague who can
00163 //  run the following Root basic session
00164 //     TFile f("myClass.root"); //connect the file
00165 //     tt.ls();                 //to list all classes and titles
00166 //     tt.Draw("ATLFDisplay")   //show class ATLFDisplay with all its dependencies
00167 //  At this point, one has still access to all the classes present
00168 //  in the original session and select any combination of these classes
00169 //  to be displayed.
00170 
00171 
00172 //______________________________________________________________________________
00173 TClassTree::TClassTree()
00174 {
00175    // TClassTree default constructor.
00176 
00177    fShowCod  = 0;
00178    fShowHas  = 0;
00179    fShowMul  = 0;
00180    fShowRef  = 0;
00181    fNclasses = 0;
00182    fCstatus  = 0;
00183    fParents  = 0;
00184    fCparent  = 0;
00185    fCpointer = 0;
00186    fCnames   = 0;
00187    fCtitles  = 0;
00188    fOptions  = 0;
00189    fLinks    = 0;
00190    fDerived  = 0;
00191    fNdata    = 0;
00192    SetLabelDx();
00193    SetYoffset(0);
00194 #ifdef ROOTSRCDIR
00195    SetSourceDir(".:src:" ROOTSRCDIR);
00196 #else
00197    SetSourceDir(".:src:$ROOTSYS/src");
00198 #endif
00199 }
00200 
00201 
00202 //_____________________________________________________________________________
00203 TClassTree::TClassTree(const char *name, const char *classes)
00204            :TNamed(name,classes)
00205 {
00206    // TClassTree constructor.
00207 
00208    fShowCod  = 0;
00209    fShowHas  = 0;
00210    fShowMul  = 0;
00211    fShowRef  = 0;
00212    fNclasses = 0;
00213    fCstatus  = 0;
00214    fParents  = 0;
00215    fCparent  = 0;
00216    fCpointer = 0;
00217    fCnames   = 0;
00218    fCtitles  = 0;
00219    fOptions  = 0;
00220    fLinks    = 0;
00221    fDerived  = 0;
00222    fNdata    = 0;
00223    SetLabelDx();
00224    SetYoffset(0);
00225 #ifdef ROOTSRCDIR
00226    SetSourceDir(".:src:" ROOTSRCDIR);
00227 #else
00228    SetSourceDir(".:src:$ROOTSYS/src");
00229 #endif
00230 
00231    // draw list of classes (if specified)
00232    if (classes && strlen(classes)) {
00233       fClasses = classes;
00234       Draw();
00235    }
00236 }
00237 
00238 
00239 //______________________________________________________________________________
00240 TClassTree::~TClassTree()
00241 {
00242    // TClassTree default destructor.
00243 
00244    for (Int_t i=0;i<fNclasses;i++) {
00245       //delete fOptions[i];
00246       if (fLinks[i]) fLinks[i]->Delete();
00247       //delete fLinks[i];
00248       //if (fDerived[i]) {delete [] fDerived[i]; fDerived[i] = 0;}
00249    }
00250    delete [] fCnames;
00251    delete [] fCtitles;
00252    delete [] fCstatus;
00253    delete [] fParents;
00254    delete [] fCparent;
00255    delete [] fCpointer;
00256    delete [] fOptions;
00257    delete [] fLinks;
00258    delete [] fDerived;
00259    delete [] fNdata;
00260 }
00261 
00262 
00263 //______________________________________________________________________________
00264 void TClassTree::Draw(const char *classes)
00265 {
00266    // Draw the inheritance tree and relations for the list of classes
00267    // see this class header for the syntax and examples
00268 
00269    if (!gPad) {
00270       gROOT->MakeDefCanvas();
00271    }
00272    Init();
00273    if (classes && strlen(classes)) fClasses = classes;
00274    for (Int_t i=0;i<fNclasses;i++) {
00275       fCstatus[i]  = 0;
00276       fCparent[i] = -1;
00277    }
00278    Paint();
00279 }
00280 
00281 
00282 //______________________________________________________________________________
00283 Int_t TClassTree::FindClass(const char *classname)
00284 {
00285    //  Find class number corresponding to classname in list of local classes
00286 
00287    for (Int_t i=0;i<fNclasses;i++) {
00288       if(!fCnames[i]->CompareTo(classname)) return i;
00289    }
00290    return -1;
00291 }
00292 
00293 
00294 //______________________________________________________________________________
00295 void TClassTree::FindClassesUsedBy(Int_t iclass)
00296 {
00297    //  Select all classes used/referenced by the class number iclass
00298 
00299    fCstatus[iclass] = 1;
00300    Int_t i;
00301    TObjString *os;
00302    TList *los = fLinks[iclass];
00303    TIter next(los);
00304    while ((os = (TObjString*)next())) {
00305       i = FindClass(os->GetName());
00306       if (i < 0) continue;
00307       if (fCstatus[i]) continue;
00308       Int_t udata  = os->TestBit(kUsedByData);
00309       Int_t ufunc  = os->TestBit(kUsedByFunc);
00310       Int_t ucode  = os->TestBit(kUsedByCode);
00311       Int_t uclass = os->TestBit(kUsedByClass);
00312       if (udata || ufunc || ucode || uclass) {
00313          fCstatus[i] = 1;
00314       }
00315    }
00316 }
00317 
00318 
00319 //______________________________________________________________________________
00320 void TClassTree::FindClassesUsing(Int_t iclass)
00321 {
00322    //  Select all classes using/referencing the class number iclass
00323 
00324    // loop on all classes
00325    fCstatus[iclass] = 1;
00326    Int_t i;
00327    TObjString *os;
00328    TList *los = fLinks[iclass];
00329    TIter next(los);
00330    while ((os = (TObjString*)next())) {
00331       i = FindClass(os->GetName());
00332       if (i < 0) continue;
00333       if (fCstatus[i]) continue;
00334       Int_t udata  = os->TestBit(kUsingData);
00335       Int_t ufunc  = os->TestBit(kUsingFunc);
00336       Int_t ucode  = os->TestBit(kUsingCode);
00337       Int_t uclass = os->TestBit(kUsingClass);
00338       if (udata || ufunc || ucode || uclass) {
00339          fCstatus[i] = 1;
00340       }
00341    }
00342 }
00343 
00344 
00345 //______________________________________________________________________________
00346 void TClassTree::FindClassPosition(const char *classname, Float_t &x, Float_t &y)
00347 {
00348    // Search the TPaveClass object in the pad with label=classname
00349    // returns the x and y position of the center of the pave.
00350 
00351    TIter next(gPad->GetListOfPrimitives());
00352    TObject *obj;
00353    TPaveClass *pave;
00354    while((obj=next())) {
00355       if (obj->InheritsFrom(TPaveClass::Class())) {
00356          pave = (TPaveClass*)obj;
00357          if (!strcmp(pave->GetLabel(),classname)) {
00358             x = 0.5*(pave->GetX1() + pave->GetX2());
00359             y = 0.5*(pave->GetY1() + pave->GetY2());
00360             return;
00361          }
00362       }
00363    }
00364    x = y = 0;
00365 }
00366 
00367 
00368 //_____________________________________________________________________________
00369 void TClassTree::Init()
00370 {
00371    // Initialize the data structures
00372 
00373    if (fNclasses) return;
00374 
00375    // fill the classes structures
00376    gClassTable->Init();
00377    fNclasses   = gClassTable->Classes();   //number of classes in the application
00378    fCnames     = new TString*[fNclasses];  //class names
00379    fCtitles    = new TString*[fNclasses];  //class titles (given in ClassDef)
00380    fCstatus    = new Int_t[fNclasses];     //=0 if not used in current expression
00381    fParents    = new Int_t[fNclasses];     //parent number of classes (permanent)
00382    fCparent    = new Int_t[fNclasses];     //parent number of classes (local to expression)
00383    fNdata      = new Int_t[fNclasses];     //number of data members per class
00384    fCpointer   = new TClass*[fNclasses];   //pointers to the TClass
00385    fOptions    = new TString*[fNclasses];  //options per class
00386    fLinks      = new TList*[fNclasses];    //list of classes referencing/referenced
00387    fDerived    = new char*[fNclasses];     //derivation matrix
00388 
00389    Int_t i,j;
00390    for (i=0;i<fNclasses;i++) {
00391       fCnames[i]   = new TString(gClassTable->Next());
00392       fCpointer[i] = TClass::GetClass(fCnames[i]->Data());
00393       fCtitles[i]  = new TString(fCpointer[i]->GetTitle());
00394       fCstatus[i]  = 0;
00395       fOptions[i]  = new TString("ID");
00396       fLinks[i]    = new TList();
00397       fDerived[i]  = new char[fNclasses];
00398    }
00399    TBaseClass *clbase;
00400    TClass *cl;
00401    for (i=0;i<fNclasses;i++) {
00402       TList *lm = fCpointer[i]->GetListOfDataMembers();
00403       if (lm) fNdata[i] = lm->GetSize();
00404       else    fNdata[i] = 0;
00405       // build derivation matrix
00406       char *derived = fDerived[i];
00407       for (j=0;j<fNclasses;j++) {
00408          derived[j] = 0;
00409          if (fCpointer[i]->InheritsFrom(fCpointer[j])) {
00410             derived[j] = 1;
00411          }
00412       }
00413       //build list of class parent
00414       fParents[i] = -1;
00415       TList *lb = fCpointer[i]->GetListOfBases();
00416       if (!lb) continue;
00417       clbase = (TBaseClass*)lb->First();
00418       if (clbase == 0) continue;
00419       cl = (TClass*)clbase->GetClassPointer();
00420       for (j=0;j<fNclasses;j++) {
00421          if(cl == fCpointer[j]) {
00422             fParents[i] = j;
00423             break;
00424          }
00425       }
00426    }
00427    //now the real & hard stuff
00428    for (i=0;i<fNclasses;i++) {
00429       ScanClasses(i);
00430    }
00431 }
00432 
00433 
00434 //_____________________________________________________________________________
00435 void TClassTree::ls(Option_t *) const
00436 {
00437    // list classes names and titles
00438 
00439    char line[500];
00440    for (Int_t i=0;i<fNclasses;i++) {
00441       snprintf(line,500,"%s%s",fCnames[i]->Data(),"...........................");
00442       snprintf(&line[30],460,"%s",fCtitles[i]->Data());
00443       line[79] = 0;
00444       printf("%5d %s\n",i,line);
00445    }
00446 }
00447 
00448 
00449 //_____________________________________________________________________________
00450 TObjString *TClassTree::Mark(const char *classname, TList *los, Int_t abit)
00451 {
00452    // set bit abit in class classname in list los
00453 
00454    if (!los) return 0;
00455    TObjString *os = (TObjString*)los->FindObject(classname);
00456    if (!os) {
00457       os = new TObjString(classname);
00458       los->Add(os);
00459    }
00460    os->SetBit(abit);
00461    return os;
00462 }
00463 
00464 
00465 //______________________________________________________________________________
00466 void TClassTree::Paint(Option_t *)
00467 {
00468    // Draw the current class setting in fClasses and fStatus
00469 
00470    //delete primitives belonging to a previous paint
00471    if (gPad) {
00472       TIter next(gPad->GetListOfPrimitives());
00473       TObject *obj;
00474       while((obj=next())) {
00475          if (obj->TestBit(kIsClassTree)) delete obj;
00476       }
00477    }
00478 
00479    Int_t nch      = strlen(GetClasses());
00480    if (nch == 0) return;
00481    char *classes  = new char[nch+1];
00482    gNsons   = new Int_t[fNclasses];
00483    gNtsons  = new Int_t[fNclasses];
00484    strlcpy(classes,GetClasses(),nch+1);
00485    Int_t i,j;
00486    char *derived;
00487    char *ptr = strtok(classes,":");
00488     //mark referenced classes
00489    while (ptr) {
00490       nch = strlen(ptr);
00491       if (ptr[0] == '*') {
00492          j = FindClass(&ptr[1]);
00493          if (j >= 0) {
00494             for (i=0;i<fNclasses;i++) {
00495                derived = fDerived[i];
00496                if(derived[j]) fCstatus[i] = 1;
00497             }
00498          }
00499       } else if (ptr[0] == '>') {
00500          for (i=0;i<fNclasses;i++) {
00501             if(fCnames[i]->Contains(&ptr[1])) {
00502                FindClassesUsing(i);
00503                fCstatus[i] = 2;
00504                break;
00505             }
00506          }
00507       } else if (ptr[nch-1] == '<') {
00508          ptr[nch-1] = 0;
00509          for (i=0;i<fNclasses;i++) {
00510             if(fCnames[i]->Contains(ptr)) {
00511                FindClassesUsedBy(i);
00512                FindClassesUsing(i);
00513                fCstatus[i] = 2;
00514                break;
00515             }
00516          }
00517       } else if (ptr[nch-1] == '*') {
00518          ptr[nch-1] = 0;
00519          for (i=0;i<fNclasses;i++) {
00520             if(fCnames[i]->Contains(ptr)) fCstatus[i] = 1;
00521          }
00522       } else {
00523          for (i=0;i<fNclasses;i++) {
00524             if(!fCnames[i]->CompareTo(ptr)) {
00525                FindClassesUsedBy(i);
00526                fCstatus[i] = 2;
00527                break;
00528             }
00529          }
00530       }
00531       ptr = strtok(0,":");
00532    }
00533     //mark base classes of referenced classes
00534    for (i=0;i<fNclasses;i++) {
00535       gNsons[i] = gNtsons[i] = 0;
00536    }
00537    for (i=0;i<fNclasses;i++) {
00538       if (fCstatus[i] == 0) continue;
00539       derived = fDerived[i];
00540       for (j=0;j<fNclasses;j++) {
00541          if (j == i) continue;
00542          if(derived[j]) {
00543             fCstatus[j] = 1;
00544          }
00545       }
00546    }
00547     //find parent class number for selected classes
00548    for (i=0;i<fNclasses;i++) {
00549       if (fCstatus[i] == 0) continue;
00550       j = fParents[i];
00551       if (j >=0 ) {
00552          fCparent[i] = j;
00553          gNsons[j]++;
00554       }
00555    }
00556     //compute total number of sons for each node
00557    Int_t maxlev = 1;
00558    Int_t icl,ip;
00559    for (i=0;i<fNclasses;i++) {
00560       if (fCstatus[i] == 0) continue;
00561       if (gNsons[i] != 0) continue;
00562       icl = i;
00563       Int_t nlevel = 1;
00564       while (fCparent[icl] >= 0) {
00565          nlevel++;
00566          if (nlevel > maxlev) maxlev = nlevel;
00567          ip = fCparent[icl];
00568          gNtsons[ip]++;
00569          icl = ip;
00570       }
00571    }
00572 
00573     //compute levels, number and list of sons
00574    Int_t ndiv=0;
00575    Int_t nmore = 0;
00576    for (i=0;i<fNclasses;i++) {
00577       if (fCstatus[i] == 0) continue;
00578       if (fCparent[i] < 0) {
00579          ndiv += gNtsons[i]+1;
00580          nmore++;
00581       }
00582    }
00583    ndiv++;
00584 
00585    // We are now ready to draw the active nodes
00586    Float_t xmin = gPad->GetX1();
00587    Float_t xmax = gPad->GetX2();
00588    Float_t ymin = gPad->GetY1();
00589    Float_t ymax = gPad->GetY2();
00590    Float_t ytop = gYsize/20;
00591    gXsize = xmax - xmin;
00592    gYsize = ymax - ymin;
00593    gDy = (gYsize-ytop)/(ndiv);
00594    if (gDy > gYsize/10.) gDy = gYsize/10.;
00595    gDx = 0.9*gXsize/5;
00596    if (maxlev > 5) gDx = 0.97*gXsize/maxlev;
00597    Float_t y  = ymax -ytop;
00598    gLabdx = fLabelDx*gXsize;
00599    if (gLabdx > 0.95*gDx) gLabdx = 0.95*gDx;
00600    gLabdy = 0.3*gDy;
00601    gDxx = 0.5*gXsize/26.;
00602    Float_t xleft  = xmin +gDxx;
00603    Float_t ymore  = 0.5*nmore*gDy+fYoffset*gYsize;
00604    Int_t dxpixels = gPad->XtoAbsPixel(gLabdx) - gPad->XtoAbsPixel(0);
00605    Int_t dypixels = gPad->YtoAbsPixel(0)     - gPad->YtoAbsPixel(gLabdy);
00606    gCsize  = dxpixels/(10.*dypixels);
00607    gCsize = std::max(gCsize,Float_t(0.75));
00608    gCsize = std::min(gCsize,Float_t(1.1));
00609    // draw classes level 0
00610    for (i=0;i<fNclasses;i++) {
00611       if (fCstatus[i] == 0) continue;
00612       if (fCparent[i] < 0) {
00613          y -= gDy+0.5*gNtsons[i]*gDy;
00614          if (!fCnames[i]->CompareTo("TObject")) y += ymore;
00615          PaintClass(i,xleft,y);
00616          y -= 0.5*gNtsons[i]*gDy;
00617       }
00618    }
00619 
00620    // show all types of links corresponding to selected options
00621    if (fShowCod) ShowCod();
00622    if (fShowHas) ShowHas();
00623    if (fShowMul) ShowMul();
00624    if (fShowRef) ShowRef();
00625 
00626    nch      = strlen(GetClasses());
00627    xmax = 0.3;
00628    if (nch > 20) xmax = 0.5;
00629    if (nch > 50) xmax = 0.7;
00630    if (nch > 70) xmax = 0.9;
00631    TPaveClass *ptitle = new TPaveClass(xmin +0.1*gXsize/26.
00632                                       ,ymin+gYsize-0.9*gYsize/20.
00633                                       ,xmin+xmax*gXsize
00634                                       ,ymin+gYsize-0.1*gYsize/26.
00635                                       ,GetClasses(),this);
00636    ptitle->SetFillColor(42);
00637    ptitle->SetBit(kIsClassTree);
00638    ptitle->Draw();
00639 
00640    //cleanup
00641    delete [] classes;
00642    delete [] gNsons;
00643    delete [] gNtsons;
00644 }
00645 
00646 
00647 //______________________________________________________________________________
00648 void TClassTree::PaintClass(Int_t iclass, Float_t xleft, Float_t y)
00649 {
00650    // Paint one class level
00651 
00652    Float_t u[2],yu=0,yl=0;
00653    Int_t ns = gNsons[iclass];
00654    u[0] = xleft;
00655    u[1] = u[0]+gDxx;
00656    if(ns != 0) u[1] = u[0]+gDx;
00657    TLine *line = new TLine(u[0],y,u[1],y);
00658    line->SetBit(kIsClassTree);
00659    line->Draw();
00660    Int_t icobject = FindClass("TObject");
00661    TPaveClass *label = new TPaveClass(xleft+gDxx,y-gLabdy,xleft+gLabdx,y+gLabdy,fCnames[iclass]->Data(),this);
00662    char *derived = fDerived[iclass];
00663    if (icobject >= 0 && !derived[icobject]) label->SetFillColor(30);
00664    if (fCstatus[iclass] > 1) label->SetFillColor(kYellow);
00665    label->SetTextSize(gCsize);
00666    label->SetBit(kIsClassTree);
00667    label->SetToolTipText(fCtitles[iclass]->Data(),500);
00668    label->Draw();
00669    if (ns == 0) return;
00670 
00671    // drawing sons
00672    y +=  0.5*gNtsons[iclass]*gDy;
00673    Int_t first =0;
00674    for (Int_t i=0;i<fNclasses;i++) {
00675       if(fCparent[i] != iclass) continue;
00676       if (gNtsons[i] > 1) y -= 0.5*gNtsons[i]*gDy;
00677       else               y -= 0.5*gDy;
00678       if (!first) {first=1; yu = y;}
00679       PaintClass(i,u[1],y);
00680       yl = y;
00681       if (gNtsons[i] > 1) y -= 0.5*gNtsons[i]*gDy;
00682       else               y -= 0.5*gDy;
00683    }
00684    if (ns == 1) return;
00685    line = new TLine(u[1],yl,u[1],yu);
00686    line->SetBit(kIsClassTree);
00687    line->Draw();
00688 }
00689 
00690 
00691 //______________________________________________________________________________
00692 void TClassTree::SaveAs(const char *filename, Option_t *option) const
00693 {
00694    // save current configuration in a Root file
00695    // if filename is blank, the name of the file will be the current objectname.root
00696    // all the current settings are preserved
00697    // the Root file produced can be looked at by a another Root session
00698    // with no access to the original classes.
00699    // By default a message is printed. Specify option "Q" to remove the message
00700 
00701    if (gDirectory) gDirectory->SaveObjectAs(this,filename,option);
00702 }
00703 
00704 
00705 //______________________________________________________________________________
00706 void TClassTree::ScanClasses(Int_t iclass)
00707 {
00708    //  Select all classes used by/referenced/referencing the class number iclass
00709    //  and build the list of these classes
00710 
00711    Int_t ic, icl;
00712    TList *los = fLinks[iclass];
00713    TList *losref = 0;
00714    TObjString *os;
00715 
00716    // scan list of data members
00717    // =========================
00718    TClass *cl = fCpointer[iclass];
00719    TDataMember *dm;
00720    TList *lm = cl->GetListOfDataMembers();
00721    if (lm) {
00722       TIter      next(lm);
00723       Int_t imember = 0;
00724       while ((dm = (TDataMember *) next())) {
00725          imember++;
00726          ic = FindClass(dm->GetTypeName());
00727          if (ic < 0 || ic == iclass) continue;
00728          losref = fLinks[ic];
00729          os = Mark(fCnames[ic]->Data(),los,kUsedByData);
00730          os->SetBit(kIsaPointer,dm->IsaPointer());
00731          os->SetBit(kIsBasic,dm->IsBasic());
00732          os->SetUniqueID(imember);
00733          Mark(fCnames[iclass]->Data(),losref,kUsingData);
00734       }
00735    }
00736 
00737    // scan base classes
00738    // =================
00739    char *derived = fDerived[iclass];
00740    TBaseClass *clbase;
00741    Int_t numb = 0;
00742    TList *lb = fCpointer[iclass]->GetListOfBases();
00743    if (lb) {
00744       TIter nextb(lb);
00745       while ((clbase = (TBaseClass*)nextb())) {
00746          numb++;
00747          if (numb == 1) continue;
00748          ic = FindClass(clbase->GetName());
00749          derived[ic] = 2;
00750       }
00751       for (ic=0;ic<fNclasses;ic++) {
00752          if (ic == iclass) continue;
00753          if (derived[ic]) {
00754             losref = fLinks[ic];
00755             Mark(fCnames[ic]->Data(),los,kUsedByClass);
00756             Mark(fCnames[iclass]->Data(),losref,kUsingClass);
00757          }
00758       }
00759    }
00760 
00761    // scan member functions
00762    // =====================
00763    char *star, *cref;
00764    TMethod *method;
00765    TMethodArg *methodarg;
00766    TList *lf = cl->GetListOfMethods();
00767    if (lf) {
00768       TIter nextm(lf);
00769       TString name;
00770       while ((method = (TMethod*) nextm())) {
00771          // check return type
00772          name = method->GetReturnTypeName();
00773          star = strstr((char*)name.Data(),"*");
00774          if (star) *star = 0;
00775          cref = strstr((char*)name.Data(),"&");
00776          if (cref) *cref = 0;
00777          ic = FindClass(name);
00778          if (ic < 0 || ic == iclass) continue;
00779          losref = fLinks[ic];
00780          Mark(fCnames[ic]->Data(),los,kUsedByFunc);
00781          Mark(fCnames[iclass]->Data(),losref,kUsingFunc);
00782 
00783          // now loop on all method arguments
00784          // ================================
00785          TIter nexta(method->GetListOfMethodArgs());
00786          while ((methodarg = (TMethodArg*) nexta())) {
00787             name = methodarg->GetTypeName();
00788             star = strstr((char*)name.Data(),"*");
00789             if (star) *star = 0;
00790             cref = strstr((char*)name.Data(),"&");
00791             if (cref) *cref = 0;
00792             ic = FindClass(name);
00793             if (ic < 0 || ic == iclass) continue;
00794             losref = fLinks[ic];
00795             Mark(fCnames[ic]->Data(),los,kUsedByFunc);
00796             Mark(fCnames[iclass]->Data(),losref,kUsingFunc);
00797          }
00798       }
00799    }
00800 
00801    // Look into the source code to search the list of includes
00802    // here we assume that include file names are classes file names
00803    // we stop reading the code when
00804    //   - a class member function is found
00805    //   - any class constructor is found
00806    if (!cl->GetImplFileName() || !cl->GetImplFileName()[0])
00807       return;
00808 
00809    const char *source = gSystem->BaseName( gSystem->UnixPathName(cl->GetImplFileName()));
00810    char *sourceName = gSystem->Which( fSourceDir.Data(), source , kReadPermission );
00811    if (!sourceName) return;
00812    Int_t ncn = strlen(fCnames[iclass]->Data())+2;
00813    char *cname = new char[ncn+1];
00814    snprintf(cname,ncn,"%s::",fCnames[iclass]->Data());
00815        // open source file
00816    ifstream sourceFile;
00817    sourceFile.open( sourceName, ios::in );
00818    Int_t nlines = 0;
00819    if( sourceFile.good() ) {
00820       const Int_t kMAXLEN=1500;
00821       char line[kMAXLEN];
00822       while( !sourceFile.eof() ) {
00823          sourceFile.getline( line, kMAXLEN-1 );
00824          if( sourceFile.eof() ) break;
00825          Int_t nblank = strspn(line," ");
00826          if (!strncmp(&line[nblank],"//",2)) continue;
00827          char *cc = strstr(line,"::");
00828          if (cc) {
00829             *cc = 0;
00830             if (!strncmp(&line[nblank],cname,ncn)) break;  //reach class member function
00831             Int_t nl = strlen(&line[nblank]);
00832             if (!strncmp(&line[nblank],cc+2,nl))   break;  //reach any class constructor
00833          }
00834          nlines++; if (nlines > 1000) break;
00835          char *inc = strstr(line,"#include");
00836          if (inc) {
00837             char *ch = strstr(line,".h");
00838             if (!ch) continue;
00839             *ch = 0;
00840             char *start = strstr(line,"<");
00841             if (!start) start = strstr(line,"\"");
00842             if (!start) continue;
00843             start++;
00844             while ((start < ch) && (*start == ' ')) start++;
00845             icl = FindClass(start);
00846             if (icl < 0 || icl == iclass) continue;
00847             // mark this include being used by this class
00848             losref = fLinks[icl];
00849             Mark(fCnames[icl]->Data(),los,kUsedByCode1);
00850             Mark(fCnames[icl]->Data(),los,kUsedByCode);
00851             Mark(fCnames[iclass]->Data(),losref,kUsingCode);
00852             // and also the base classes of the class in the include
00853             derived = fDerived[icl];
00854             for (ic=0;ic<fNclasses;ic++) {
00855                if (ic == icl) continue;
00856                if (derived[ic]) {
00857                   losref = fLinks[ic];
00858                   Mark(fCnames[ic]->Data(),los,kUsedByCode);
00859                   Mark(fCnames[iclass]->Data(),losref,kUsingCode);
00860                }
00861             }
00862          }
00863       }
00864    }
00865    delete [] cname;
00866    sourceFile.close();
00867 }
00868 
00869 
00870 //______________________________________________________________________________
00871 void TClassTree::SetClasses(const char *classes, Option_t *)
00872 {
00873    // Set the list of classes for which the hierarchy is to be drawn
00874    // See Paint for the syntax
00875 
00876    if (classes == 0) return;
00877    fClasses = classes;
00878    for (Int_t i=0;i<fNclasses;i++) {
00879       fCstatus[i]  = 0;
00880       fCparent[i] = -1;
00881    }
00882    if (gPad) Paint();
00883 }
00884 
00885 
00886 //______________________________________________________________________________
00887 void TClassTree::SetLabelDx(Float_t labeldx)
00888 {
00889    // Set the size along x of the TPavellabel showing the class name
00890 
00891    fLabelDx = labeldx;
00892    if (gPad) Paint();
00893 }
00894 
00895 
00896 //______________________________________________________________________________
00897 void TClassTree::SetYoffset(Float_t offset)
00898 {
00899    // Set the offset at the top of the picture
00900    // The default offset is computed automatically taking into account
00901    // classes not inheriting from TObject.
00902 
00903    fYoffset = offset;
00904    if (gPad) Paint();
00905 }
00906 
00907 
00908 //______________________________________________________________________________
00909 void TClassTree::ShowClassesUsedBy(const char *classes)
00910 {
00911    // mark classes used by the list of classes in classes
00912 
00913    Int_t i,j;
00914    Int_t nch = strlen(classes);
00915    char *ptr = new char[nch+1];
00916    strlcpy(ptr,classes,nch+1);
00917    if (ptr[0] == '*') {
00918       i = FindClass(&ptr[1]);
00919       if (i >= 0) {
00920          char *derived = fDerived[i];
00921          for (j=0;j<fNclasses;j++) {
00922             if(derived[j]) FindClassesUsedBy(j);
00923          }
00924       }
00925    } else if (ptr[nch-1] == '*') {
00926       ptr[nch-1] = 0;
00927       for (j=0;j<fNclasses;j++) {
00928          if(fCnames[j]->Contains(ptr)) FindClassesUsedBy(j);
00929       }
00930    } else {
00931       for (j=0;j<fNclasses;j++) {
00932          if(!fCnames[j]->CompareTo(ptr)) FindClassesUsedBy(j);
00933       }
00934    }
00935    delete [] ptr;
00936    if (gPad) Paint();
00937 }
00938 
00939 
00940 //______________________________________________________________________________
00941 void TClassTree::ShowClassesUsing(const char *classes)
00942 {
00943    // mark classes using any class in the list of classes in classes
00944 
00945    Int_t i,j;
00946    Int_t nch = strlen(classes);
00947    char *ptr = new char[nch+1];
00948    strlcpy(ptr,classes,nch+1);
00949    if (ptr[0] == '*') {
00950       i = FindClass(&ptr[1]);
00951       if (i >= 0) {
00952          char *derived = fDerived[i];
00953          for (j=0;j<fNclasses;j++) {
00954             if(derived[j]) FindClassesUsing(j);
00955          }
00956       }
00957    } else if (ptr[nch-1] == '*') {
00958       ptr[nch-1] = 0;
00959       for (j=0;j<fNclasses;j++) {
00960          if(fCnames[j]->Contains(ptr)) FindClassesUsing(j);
00961       }
00962    } else {
00963       for (j=0;j<fNclasses;j++) {
00964          if(!fCnames[j]->CompareTo(ptr)) FindClassesUsing(j);
00965       }
00966    }
00967    delete [] ptr;
00968    if (gPad) Paint();
00969 }
00970 
00971 
00972 //______________________________________________________________________________
00973 void TClassTree::ShowCod()
00974 {
00975    // Draw the Code References relationships
00976 
00977    TIter next(gPad->GetListOfPrimitives());
00978    TObject *obj;
00979    TObjString *os;
00980    TPaveClass *pave;
00981    Int_t ic,icl;
00982    Float_t x,y,x1,y1;
00983    //iterate on all TPaveClass objects in the pad
00984    while((obj=next())) {
00985       if (obj->InheritsFrom(TPaveClass::Class())) {
00986          pave = (TPaveClass*)obj;
00987          icl = FindClass(pave->GetLabel());
00988          if (icl < 0) continue;
00989          char *derived = fDerived[icl];
00990          x  = 0.5*(pave->GetX1() + pave->GetX2());
00991          y  = 0.5*(pave->GetY1() + pave->GetY2());
00992          TIter nextos(fLinks[icl]);
00993          //iterate on all classes in the list of classes of this class
00994          while((os=(TObjString*)nextos())) {
00995             if (!os->TestBit(kUsedByCode1)) continue;
00996             ic = FindClass(os->GetName());
00997             if (derived[ic]) continue;
00998             FindClassPosition(os->GetName(),x1,y1);
00999             if (x1 == 0 || y1 == 0) continue; //may be pointed class was not drawn
01000             TArrow *arrow = new TArrow(x,y,x1,y1,0.008,"|>");
01001             arrow->SetLineColor(kGreen);
01002             arrow->SetFillColor(kGreen);
01003             arrow->SetBit(kIsClassTree);
01004             arrow->Draw();
01005          }
01006       }
01007    }
01008 }
01009 
01010 
01011 //______________________________________________________________________________
01012 void TClassTree::ShowHas()
01013 {
01014    // Draw the "Has a" relationships
01015 
01016    TIter next(gPad->GetListOfPrimitives());
01017    TObject *obj;
01018    TObjString *os;
01019    TPaveClass *pave;
01020    Int_t icl;
01021    Float_t y,x1,y1,dx;
01022    //iterate on all TPaveClass objects in the pad
01023    while((obj=next())) {
01024       if (obj->InheritsFrom(TPaveClass::Class())) {
01025          pave = (TPaveClass*)obj;
01026          icl = FindClass(pave->GetLabel());
01027          if (icl < 0) continue;
01028          y  = 0.5*(pave->GetY1() + pave->GetY2());
01029          Int_t nmembers = fNdata[icl];
01030          if (nmembers == 0) continue;
01031          dx = (pave->GetX2() - pave->GetX1())/nmembers;
01032          TIter nextos(fLinks[icl]);
01033          //iterate on all classes in the list of classes of this class
01034          while((os=(TObjString*)nextos())) {
01035             if (!os->TestBit(kUsedByData)) continue;
01036             if (os->TestBit(kIsaPointer)) continue;
01037             if (os->TestBit(kIsBasic)) continue;
01038             FindClassPosition(os->GetName(),x1,y1);
01039             if (x1 == 0 || y1 == 0) continue; //may be base class was not drawn
01040             Int_t imember = os->GetUniqueID();
01041             TLine *line = new TLine(pave->GetX1()+(imember+0.5)*dx,y,x1,y1);
01042             line->SetLineStyle(3);
01043             line->SetLineColor(6);
01044             line->SetBit(kIsClassTree);
01045             line->Draw();
01046          }
01047       }
01048    }
01049 }
01050 
01051 
01052 //______________________________________________________________________________
01053 void TClassTree::ShowLinks(Option_t *option)
01054 {
01055    // Set link options in the ClassTree object
01056    //
01057    //   "C"  show References from code
01058    //   "H"  show Has a relations
01059    //   "M"  show Multiple Inheritance
01060    //   "R"  show References from data members
01061 
01062    TString opt = option;
01063    opt.ToUpper();
01064    fShowCod = fShowHas = fShowMul = fShowRef = 0;
01065    if (opt.Contains("C")) fShowCod = 1;
01066    if (opt.Contains("H")) fShowHas = 1;
01067    if (opt.Contains("M")) fShowMul = 1;
01068    if (opt.Contains("R")) fShowRef = 1;
01069    if (gPad) Paint();
01070 }
01071 
01072 
01073 //______________________________________________________________________________
01074 void TClassTree::ShowMul()
01075 {
01076    // Draw the Multiple inheritance relationships
01077 
01078    TIter next(gPad->GetListOfPrimitives());
01079    TObject *obj;
01080    TObjString *os;
01081    TPaveClass *pave;
01082    Int_t ic,icl;
01083    Float_t x,y,x1,y1;
01084    //iterate on all TPaveClass objects in the pad
01085    while((obj=next())) {
01086       if (obj->InheritsFrom(TPaveClass::Class())) {
01087          pave = (TPaveClass*)obj;
01088          icl = FindClass(pave->GetLabel());
01089          if (icl < 0) continue;
01090          char *derived = fDerived[icl];
01091          x = 0.5*(pave->GetX1() + pave->GetX2());
01092          y = 0.5*(pave->GetY1() + pave->GetY2());
01093          TIter nextos(fLinks[icl]);
01094          //iterate on all classes in the list of classes of this class
01095          while((os=(TObjString*)nextos())) {
01096             if (!os->TestBit(kUsedByClass)) continue;
01097             ic = FindClass(os->GetName());
01098             if (derived[ic] != 2) continue; //keep only multiple inheritance
01099             FindClassPosition(os->GetName(),x1,y1);
01100             if (x1 == 0 || y1 == 0) continue; //may be base class was not drawn
01101             TLine *line = new TLine(x,y,x1,y1);
01102             line->SetBit(kIsClassTree);
01103             line->SetLineStyle(2);
01104             line->SetLineColor(kBlue);
01105             line->Draw();
01106          }
01107       }
01108    }
01109 }
01110 
01111 
01112 //______________________________________________________________________________
01113 void TClassTree::ShowRef()
01114 {
01115    // Draw the References relationships (other than inheritance or composition)
01116 
01117    TIter next(gPad->GetListOfPrimitives());
01118    TObject *obj;
01119    TObjString *os;
01120    TPaveClass *pave;
01121    Int_t ic,icl;
01122    Float_t y,x1,y1,dx;
01123    Int_t icc = FindClass("TClass");
01124    //iterate on all TPaveClass objects in the pad
01125    while((obj=next())) {
01126       if (obj->InheritsFrom(TPaveClass::Class())) {
01127          pave = (TPaveClass*)obj;
01128          icl = FindClass(pave->GetLabel());
01129          if (icl < 0) continue;
01130          y  = 0.5*(pave->GetY1() + pave->GetY2());
01131          Int_t nmembers = fNdata[icl];
01132          if (nmembers == 0) continue;
01133          dx = (pave->GetX2() - pave->GetX1())/nmembers;
01134          TIter nextos(fLinks[icl]);
01135          //iterate on all classes in the list of classes of this class
01136          while((os=(TObjString*)nextos())) {
01137             if (!os->TestBit(kUsedByData)) continue;
01138             ic = FindClass(os->GetName());
01139             if (!os->TestBit(kIsaPointer)) continue;
01140             if (os->TestBit(kIsBasic)) continue;
01141             if (ic == icc) continue; // do not show relations with TClass
01142             FindClassPosition(os->GetName(),x1,y1);
01143             if (x1 == 0 || y1 == 0) continue; //may be pointed class was not drawn
01144             Int_t imember = os->GetUniqueID();
01145             TArrow *arrow = new TArrow(pave->GetX1()+(imember+0.5)*dx,y,x1,y1,0.008,"|>");
01146             arrow->SetLineColor(kRed);
01147             arrow->SetFillColor(kRed);
01148             arrow->SetBit(kIsClassTree);
01149             arrow->Draw();
01150          }
01151       }
01152    }
01153 }
01154 
01155 
01156 //______________________________________________________________________________
01157 void TClassTree::Streamer(TBuffer &R__b)
01158 {
01159    // Stream an object of class TClassTree.
01160    // the status of the object is saved and can be replayed in a subsequent session
01161 
01162    Int_t i;
01163    if (R__b.IsReading()) {
01164       Version_t R__v = R__b.ReadVersion(); if (R__v) { }
01165       TNamed::Streamer(R__b);
01166       fClasses.Streamer(R__b);
01167       R__b >> fYoffset;
01168       R__b >> fLabelDx;
01169       R__b >> fNclasses;
01170       R__b >> fShowCod;
01171       R__b >> fShowMul;
01172       R__b >> fShowHas;
01173       R__b >> fShowRef;
01174       fCnames     = new TString*[fNclasses];
01175       fCtitles    = new TString*[fNclasses];
01176       fCstatus    = new Int_t[fNclasses];
01177       fParents    = new Int_t[fNclasses];
01178       fCparent    = new Int_t[fNclasses];
01179       fNdata      = new Int_t[fNclasses];
01180       fCpointer   = new TClass*[fNclasses];
01181       fOptions    = new TString*[fNclasses];
01182       fLinks      = new TList*[fNclasses];
01183       fDerived    = new char*[fNclasses];
01184       for (i=0;i<fNclasses;i++) {
01185          R__b >> fCstatus[i];
01186          R__b >> fParents[i];
01187          R__b >> fNdata[i];
01188          fCnames[i]  = new TString();
01189          fCtitles[i] = new TString();
01190          fOptions[i] = new TString();
01191          fCnames[i]->Streamer(R__b);
01192          fCtitles[i]->Streamer(R__b);
01193          fOptions[i]->Streamer(R__b);
01194          fLinks[i] = new TList();
01195          fLinks[i]->Streamer(R__b);
01196          fDerived[i] = new char[fNclasses];
01197          R__b.ReadFastArray(fDerived[i],fNclasses);
01198       }
01199       fSourceDir.Streamer(R__b);
01200    } else {
01201       R__b.WriteVersion(TClassTree::IsA());
01202       TNamed::Streamer(R__b);
01203       fClasses.Streamer(R__b);
01204       R__b << fYoffset;
01205       R__b << fLabelDx;
01206       R__b << fNclasses;
01207       R__b << fShowCod;
01208       R__b << fShowMul;
01209       R__b << fShowHas;
01210       R__b << fShowRef;
01211       for (i=0;i<fNclasses;i++) {
01212          R__b << fCstatus[i];
01213          R__b << fParents[i];
01214          R__b << fNdata[i];
01215          fCnames[i]->Streamer(R__b);
01216          fCtitles[i]->Streamer(R__b);
01217          fOptions[i]->Streamer(R__b);
01218          fLinks[i]->Streamer(R__b);
01219          R__b.WriteFastArray(fDerived[i],fNclasses);
01220       }
01221       fSourceDir.Streamer(R__b);
01222    }
01223 }

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