    // @(#)root/gpad:$Name:  $:$Id: TClassTree.cxx,v 1.5 2002/01/24 11:39:28 rdm Exp $
    // Author: Rene Brun   01/12/98

    /*************************************************************************
     * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/

    #ifdef HAVE_CONFIG
    #include "config.h"
    #endif

    #include "TROOT.h"
    #include "TClassTree.h"
    #include "TClassTable.h"
    #include "TBaseClass.h"
    #include "TDataMember.h"
    #include "TDataType.h"
    #include "TRealData.h"
    #include "TMethod.h"
    #include "TMethodArg.h"
    #include "TPad.h"
    #include "TPaveClass.h"
    #include "TArrow.h"
    #include "TText.h"
    #include "TSystem.h"
    #include "TObjString.h"
    #include "TFile.h"
    #include "Riostream.h"

    const Int_t kIsClassTree = BIT(7);
    const Int_t kUsedByData  = BIT(11);
    const Int_t kUsedByFunc  = BIT(12);
    const Int_t kUsedByCode  = BIT(13);
    const Int_t kUsedByClass = BIT(14);
    const Int_t kUsingData   = BIT(15);
    const Int_t kUsingFunc   = BIT(16);
    const Int_t kUsingCode   = BIT(17);
    const Int_t kUsingClass  = BIT(18);
    const Int_t kUsedByCode1 = BIT(19);
    const Int_t kIsaPointer  = BIT(20);
    const Int_t kIsBasic     = BIT(21);

    static Float_t xsize, ysize, dx, dy, labdx, labdy, dxx, csize;
    static Int_t *ntsons, *nsons;

    ClassImp(TClassTree)

    //______________________________________________________________________________
    //
    // Draw inheritance tree and their relations for a list of classes
    // The following options are supported
    //   - Direct inheritance (default)
    //   - Multiple inheritance
    //   - Composition
    //   - References by data members and member functions
    //   - References from Code
    //
    // The list of classes is specified:
    //   - either in the TClassTree constructor as a second argument
    //   - or the parameter to TClassTRee::Draw
    //
    // Note that the ClassTree viewer can also be started from the canvas
    // pull down menu "Classes".
    //
    // In the list of classes, class names are separated by a ":"
    // wildcarding is supported.
    // The following formats are supported, eg in TClassTree::Draw
    //   1- Draw("ClassA")
    //         Draw inheritance tree for ClassA
    //         Show all classes referenced by ClassA
    //   2- Draw("*ClassB")
    //         Draw inheritance tree for ClassB
    //         and all the classes deriving from ClassB
    //   3- Draw(">ClassC")
    //         Draw inheritance tree for ClassC
    //         Show classes referencing ClassC
    //   4- Draw("ClassD<")
    //         Draw inheritance tree for ClassD
    //         Show classes referenced by ClassD
    //         Show all classes referencing ClassD
    //   5- Draw("Cla*")
    //         Draw inheritance tree for all classes with name starting with "Cla"
    //         Show classes referenced by these classes
    //   6- Draw("ClassA:ClassB<")
    //         Draw inheritance tree for ClassA
    //         Show all classes referenced by ClassA
    //         Draw inheritance tree for ClassB
    //         Show classes referenced by ClassB
    //         Show all classes referencing ClassB
    //
    //  example;  Draw("TTree<")
    //         Draw inheritance tree for the Root class TTree
    //         Show all classes referenced by TTree
    //         Show all classes using TTree
    //
    // By default, only direct inheritance is drawn.
    // Use TClassTree::ShowLinks(option) to show additional references
    //   option = "H" to show links to embedded classes
    //   option = "M" to show multiple inheritance
    //   option = "R" to show pointers to other classes from data members
    //   option = "C" to show classes used by the code(implementation) of a class
    //
    // The following picture is produced directly by:
    //       TClassTree ct("ct","*TH1")
    // It shows all the classes derived from the base class TH1.
    //

/* */ //

// // The ClassTree class uses the services of the class TPaveClass to // show the class names. By clicking with the right mouse button in // one TPaveClass object, one can invoke the following functions of TClassTree: // - ShowLinks(option) with by default option = "HMR" // - Draw(classes). By default the class drawn is the one being pointed // - ShowClassesUsedBy(classes) (by default the pointed class) // - ShowClassesUsing(classes) (by default the pointed class) // // The following picture has been generated with the following statements // TClassTree tc1("tc1","TObject"); // tc1.SetShowLinks("HMR"); // // /* */ //

// // Note that in case of embedded classes or pointers to classes, // the corresponding dashed lines or arrows respectively start // in the TPaveClass object at an X position reflecting the position // in the list of data members. // // - References by data members to other classes are show with a full red line // - Multiple inheritance is shown with a dashed blue line // - "Has a" relation is shown with a dotted cyan line // - References from code is shown by a full green line // // Use TClassTree::SetSourceDir to specify the search path for source files. // By default the search path includes the ROOTSYS/src directory, the current // directory and the subdirectory src. // // The first time TClassTree::Draw is invoked, all the classes in the // current application are processed, including the parsing of the code // to find all classes referenced by the include statements. // This process may take a few seconds. The following commands will be // much faster. // // A TClassTree object may be saved in a Root file. // This object can be processed later by a Root program that ignores // the original classes. This interesting possibility allows to send // the class structure of an application to a colleague who does not have // your classes. // Example: // TFile f("myClasses.root","recreate") // TClassTree *ct = new TClassTree("ct","ATLF*") // ct->Write(); // You can send at this point the file myClass.root to a colleague who can // run the following Root basic session // TFile f("myClass.root"); //connect the file // tt.ls(); //to list all classes and titles // tt.Draw("ATLFDisplay") //show class ATLFDisplay with all its dependencies // At this point, one has still access to all the classes present // in the original session and select any combination of these classes // to be displayed. //______________________________________________________________________________ TClassTree::TClassTree() { //*-*-*-*-*-*-*-*-*-*-*-*TClassTree default constructor*-*-*-*-*-*-*-*-*-*-* //*-* ============================== fShowCod = 0; fShowHas = 0; fShowMul = 0; fShowRef = 0; fNclasses = 0; fCstatus = 0; fParents = 0; fCparent = 0; fCpointer = 0; fCnames = 0; fCtitles = 0; fOptions = 0; fLinks = 0; fDerived = 0; fNdata = 0; SetLabelDx(); SetYoffset(0); #ifdef ROOTSRCDIR SetSourceDir(".:src:" ROOTSRCDIR "/src"); #else SetSourceDir(".:src:$ROOTSYS/src"); #endif } //_____________________________________________________________________________ TClassTree::TClassTree(const char *name, const char *classes) :TNamed(name,classes) { //*-*-*-*-*-*-*-*-*-*-*TClassTree constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-* //*-* ====================== fShowCod = 0; fShowHas = 0; fShowMul = 0; fShowRef = 0; fNclasses = 0; fCstatus = 0; fParents = 0; fCparent = 0; fCpointer = 0; fCnames = 0; fCtitles = 0; fOptions = 0; fLinks = 0; fDerived = 0; fNdata = 0; SetLabelDx(); SetYoffset(0); #ifdef ROOTSRCDIR SetSourceDir(".:src:" ROOTSRCDIR "/src"); #else SetSourceDir(".:src:$ROOTSYS/src"); #endif // draw list of classes (if specified) if (classes && strlen(classes)) { fClasses = classes; Draw(); } } //______________________________________________________________________________ TClassTree::~TClassTree() { //*-*-*-*-*-*-*-*-*-*TClassTree default destructor*-*-*-*-*-*-*-*-*-*-*-* //*-* ============================= for (Int_t i=0;i<fNclasses;i++) { //delete fOptions[i]; if (fLinks[i]) fLinks[i]->Delete(); //delete fLinks[i]; //if (fDerived[i]) {delete [] fDerived[i]; fDerived[i] = 0;} } delete [] fCnames; delete [] fCtitles; delete [] fCstatus; delete [] fParents; delete [] fCparent; delete [] fCpointer; delete [] fOptions; delete [] fLinks; delete [] fDerived; delete [] fNdata; } //______________________________________________________________________________ void TClassTree::Draw(const char *classes) { // Draw the inheritance tree and relations for the list of classes // see this class header for the syntax and examples if (!gPad) { if (gROOT->GetMakeDefCanvas()) (gROOT->GetMakeDefCanvas())(); } Init(); if (classes && strlen(classes)) fClasses = classes; for (Int_t i=0;i<fNclasses;i++) { fCstatus[i] = 0; fCparent[i] = -1; } Paint(); } //______________________________________________________________________________ Int_t TClassTree::FindClass(const char *classname) { // Find class number corresponding to classname in list of local classes for (Int_t i=0;i<fNclasses;i++) { if(!fCnames[i]->CompareTo(classname)) return i; } return -1; } //______________________________________________________________________________ void TClassTree::FindClassesUsedBy(Int_t iclass) { // Select all classes used/referenced by the class number iclass fCstatus[iclass] = 1; Int_t i; TObjString *os; TList *los = fLinks[iclass]; TIter next(los); while ((os = (TObjString*)next())) { i = FindClass(os->GetName()); if (i < 0) continue; if (fCstatus[i]) continue; Int_t udata = os->TestBit(kUsedByData); Int_t ufunc = os->TestBit(kUsedByFunc); Int_t ucode = os->TestBit(kUsedByCode); Int_t uclass = os->TestBit(kUsedByClass); if (udata || ufunc || ucode || uclass) { fCstatus[i] = 1; } } } //______________________________________________________________________________ void TClassTree::FindClassesUsing(Int_t iclass) { // Select all classes using/referencing the class number iclass // loop on all classes fCstatus[iclass] = 1; Int_t i; TObjString *os; TList *los = fLinks[iclass]; TIter next(los); while ((os = (TObjString*)next())) { i = FindClass(os->GetName()); if (i < 0) continue; if (fCstatus[i]) continue; Int_t udata = os->TestBit(kUsingData); Int_t ufunc = os->TestBit(kUsingFunc); Int_t ucode = os->TestBit(kUsingCode); Int_t uclass = os->TestBit(kUsingClass); if (udata || ufunc || ucode || uclass) { fCstatus[i] = 1; } } } //______________________________________________________________________________ void TClassTree::FindClassPosition(const char *classname, Float_t &x, Float_t &y) { // Search the TPaveClass object in the pad with label=classname // returns the x and y position of the center of the pave. TIter next(gPad->GetListOfPrimitives()); TObject *obj; TPaveClass *pave; while((obj=next())) { if (obj->InheritsFrom(TPaveClass::Class())) { pave = (TPaveClass*)obj; if (!strcmp(pave->GetLabel(),classname)) { x = 0.5*(pave->GetX1() + pave->GetX2()); y = 0.5*(pave->GetY1() + pave->GetY2()); return; } } } x = y = 0; } //_____________________________________________________________________________ void TClassTree::Init() { // Initialize the data structures if (fNclasses) return; // fill the classes structures gClassTable->Init(); fNclasses = gClassTable->Classes(); //number of classes in the application fCnames = new TString*[fNclasses]; //class names fCtitles = new TString*[fNclasses]; //class titles (given in ClassDef) fCstatus = new Int_t[fNclasses]; //=0 if not used in current expression fParents = new Int_t[fNclasses]; //parent number of classes (permanent) fCparent = new Int_t[fNclasses]; //parent number of classes (local to expression) fNdata = new Int_t[fNclasses]; //number of data members per class fCpointer = new TClass*[fNclasses]; //pointers to the TClass fOptions = new TString*[fNclasses]; //options per class fLinks = new TList*[fNclasses]; //list of classes referencing/referenced fDerived = new char*[fNclasses]; //derivation matrix Int_t i,j; for (i=0;i<fNclasses;i++) { fCnames[i] = new TString(gClassTable->Next()); fCpointer[i] = gROOT->GetClass(fCnames[i]->Data()); fCtitles[i] = new TString(fCpointer[i]->GetTitle()); fCstatus[i] = 0; fOptions[i] = new TString("ID"); fLinks[i] = new TList(); fDerived[i] = new char[fNclasses]; } TBaseClass *clbase; TClass *cl; for (i=0;i<fNclasses;i++) { TList *lm = fCpointer[i]->GetListOfDataMembers(); if (lm) fNdata[i] = lm->GetSize(); else fNdata[i] = 0; // build derivation matrix char *derived = fDerived[i]; for (j=0;j<fNclasses;j++) { derived[j] = 0; if (fCpointer[i]->InheritsFrom(fCpointer[j])) { derived[j] = 1; } } //build list of class parent fParents[i] = -1; TList *lb = fCpointer[i]->GetListOfBases(); if (!lb) continue; clbase = (TBaseClass*)lb->First(); if (clbase == 0) continue; cl = (TClass*)clbase->GetClassPointer(); for (j=0;j<fNclasses;j++) { if(cl == fCpointer[j]) { fParents[i] = j; break; } } } //now the real & hard stuff for (i=0;i<fNclasses;i++) { ScanClasses(i); } } //_____________________________________________________________________________ void TClassTree::ls(Option_t *) const { // list classes names and titles char line[500]; for (Int_t i=0;i<fNclasses;i++) { sprintf(line,"%s%s",fCnames[i]->Data(),"..........................."); sprintf(&line[30],"%s",fCtitles[i]->Data()); line[79] = 0; printf("%5d %s\n",i,line); } } //_____________________________________________________________________________ TObjString *TClassTree::Mark(const char *classname, TList *los, Int_t abit) { // set bit abit in class classname in list los if (!los) return 0; TObjString *os = (TObjString*)los->FindObject(classname); if (!os) { os = new TObjString(classname); los->Add(os); } os->SetBit(abit); return os; } //______________________________________________________________________________ void TClassTree::Paint(Option_t *) { // Draw the current class setting in fClasses and fStatus //delete primitives belonging to a previous paint if (gPad) { TIter next(gPad->GetListOfPrimitives()); TObject *obj; while((obj=next())) { if (obj->TestBit(kIsClassTree)) delete obj; } } Int_t nch = strlen(GetClasses()); if (nch == 0) return; char *classes = new char[nch+1]; nsons = new Int_t[fNclasses]; ntsons = new Int_t[fNclasses]; strcpy(classes,GetClasses()); Int_t i,j; char *derived; char *ptr = strtok(classes,":"); //mark referenced classes while (ptr) { nch = strlen(ptr); if (ptr[0] == '*') { j = FindClass(&ptr[1]); if (j >= 0) { for (i=0;i<fNclasses;i++) { derived = fDerived[i]; if(derived[j]) fCstatus[i] = 1; } } } else if (ptr[0] == '>') { for (i=0;i<fNclasses;i++) { if(fCnames[i]->Contains(&ptr[1])) { FindClassesUsing(i); fCstatus[i] = 2; break; } } } else if (ptr[nch-1] == '<') { ptr[nch-1] = 0; for (i=0;i<fNclasses;i++) { if(fCnames[i]->Contains(ptr)) { FindClassesUsedBy(i); FindClassesUsing(i); fCstatus[i] = 2; break; } } } else if (ptr[nch-1] == '*') { ptr[nch-1] = 0; for (i=0;i<fNclasses;i++) { if(fCnames[i]->Contains(ptr)) fCstatus[i] = 1; } } else { for (i=0;i<fNclasses;i++) { if(!fCnames[i]->CompareTo(ptr)) { FindClassesUsedBy(i); fCstatus[i] = 2; break; } } } ptr = strtok(0,":"); } //mark base classes of referenced classes for (i=0;i<fNclasses;i++) { nsons[i] = ntsons[i] = 0; } for (i=0;i<fNclasses;i++) { if (fCstatus[i] == 0) continue; derived = fDerived[i]; for (j=0;j<fNclasses;j++) { if (j == i) continue; if(derived[j]) { fCstatus[j] = 1; } } } //find parent class number for selected classes for (i=0;i<fNclasses;i++) { if (fCstatus[i] == 0) continue; j = fParents[i]; if (j >=0 ) { fCparent[i] = j; nsons[j]++; } } //compute total number of sons for each node Int_t maxlev = 1; Int_t icl,ip; for (i=0;i<fNclasses;i++) { if (fCstatus[i] == 0) continue; if (nsons[i] != 0) continue; icl = i; Int_t nlevel = 1; while (fCparent[icl] >= 0) { nlevel++; if (nlevel > maxlev) maxlev = nlevel; ip = fCparent[icl]; ntsons[ip]++; icl = ip; } } //compute levels, number and list of sons Int_t ndiv=0; Int_t nmore = 0; for (i=0;i<fNclasses;i++) { if (fCstatus[i] == 0) continue; if (fCparent[i] < 0) { ndiv += ntsons[i]+1; nmore++; } } ndiv++; // We are now ready to draw the active nodes Float_t xmin = gPad->GetX1(); Float_t xmax = gPad->GetX2(); Float_t ymin = gPad->GetY1(); Float_t ymax = gPad->GetY2(); Float_t ytop = ysize/20; xsize = xmax - xmin; ysize = ymax - ymin; dy = (ysize-ytop)/(ndiv); if (dy > ysize/10.) dy = ysize/10.; dx = 0.9*xsize/5; if (maxlev > 5) dx = 0.97*xsize/maxlev; Float_t y = ymax -ytop; labdx = fLabelDx*xsize; if (labdx > 0.95*dx) labdx = 0.95*dx; labdy = 0.3*dy; dxx = 0.5*xsize/26.; Float_t xleft = xmin +dxx; Float_t ymore = 0.5*nmore*dy+fYoffset*ysize; Int_t dxpixels = gPad->XtoAbsPixel(labdx) - gPad->XtoAbsPixel(0); Int_t dypixels = gPad->YtoAbsPixel(0) - gPad->YtoAbsPixel(labdy); csize = dxpixels/(10.*dypixels); csize = TMath::Max(csize,Float_t(0.75)); csize = TMath::Min(csize,Float_t(1.1)); // draw classes level 0 for (i=0;i<fNclasses;i++) { if (fCstatus[i] == 0) continue; if (fCparent[i] < 0) { y -= dy+0.5*ntsons[i]*dy; if (!fCnames[i]->CompareTo("TObject")) y += ymore; PaintClass(i,xleft,y); y -= 0.5*ntsons[i]*dy; } } // show all types of links corresponding to selected options if (fShowCod) ShowCod(); if (fShowHas) ShowHas(); if (fShowMul) ShowMul(); if (fShowRef) ShowRef(); nch = strlen(GetClasses()); xmax = 0.3; if (nch > 20) xmax = 0.5; if (nch > 50) xmax = 0.7; if (nch > 70) xmax = 0.9; TPaveClass *ptitle = new TPaveClass(xmin +0.1*xsize/26. ,ymin+ysize-0.9*ysize/20. ,xmin+xmax*xsize ,ymin+ysize-0.1*ysize/26. ,GetClasses(),this); ptitle->SetFillColor(42); ptitle->SetBit(kIsClassTree); ptitle->Draw(); //cleanup delete [] classes; delete [] nsons; delete [] ntsons; } //______________________________________________________________________________ void TClassTree::PaintClass(Int_t iclass, Float_t xleft, Float_t y) { // Paint one class level Float_t u[2],yu=0,yl=0; Int_t ns = nsons[iclass]; u[0] = xleft; u[1] = u[0]+dxx; if(ns != 0) u[1] = u[0]+dx; TLine *line = new TLine(u[0],y,u[1],y); line->SetBit(kIsClassTree); line->Draw(); Int_t icobject = FindClass("TObject"); TPaveClass *label = new TPaveClass(xleft+dxx,y-labdy,xleft+labdx,y+labdy,fCnames[iclass]->Data(),this); char *derived = fDerived[iclass]; if (icobject >= 0 && !derived[icobject]) label->SetFillColor(30); if (fCstatus[iclass] > 1) label->SetFillColor(kYellow); label->SetTextSize(csize); label->SetBit(kIsClassTree); label->SetToolTipText(fCtitles[iclass]->Data(),500); label->Draw(); if (ns == 0) return; // drawing sons y += 0.5*ntsons[iclass]*dy; Int_t first =0; for (Int_t i=0;i<fNclasses;i++) { if(fCparent[i] != iclass) continue; if (ntsons[i] > 1) y -= 0.5*ntsons[i]*dy; else y -= 0.5*dy; if (!first) {first=1; yu = y;} PaintClass(i,u[1],y); yl = y; if (ntsons[i] > 1) y -= 0.5*ntsons[i]*dy; else y -= 0.5*dy; } if (ns == 1) return; line = new TLine(u[1],yl,u[1],yu); line->SetBit(kIsClassTree); line->Draw(); } //______________________________________________________________________________ void TClassTree::SaveAs(const char *filename) { // save current configuration in a Root file // if filename is blank, the name of the file will be the current objectname.root // all the current settings are preserved // the Root file produced can be looked at by a another Root session // with no access to the original classes. if (!filename || strlen(filename) == 0) { char fname[100]; sprintf(fname,"%s.root",GetName()); TFile local(fname,"recreate"); if (local.IsZombie()) return; Write(); printf("TClassTree::SaveAs, file: %s has been written\n",fname); } else { TFile local(filename,"recreate"); if (local.IsZombie()) return; Write(); printf("TClassTree::SaveAs, file: %s has been written\n",filename); } } //______________________________________________________________________________ void TClassTree::ScanClasses(Int_t iclass) { // Select all classes used by/referenced/referencing the class number iclass // and build the list of these classes Int_t ic, icl; TList *los = fLinks[iclass]; TList *losref = 0; TObjString *os; // scan list of data members // ========================= TClass *cl = fCpointer[iclass]; TDataMember *dm; TList *lm = cl->GetListOfDataMembers(); if (lm) { TIter next(lm); Int_t imember = 0; while ((dm = (TDataMember *) next())) { imember++; ic = FindClass(dm->GetTypeName()); if (ic < 0 || ic == iclass) continue; losref = fLinks[ic]; os = Mark(fCnames[ic]->Data(),los,kUsedByData); os->SetBit(kIsaPointer,dm->IsaPointer()); os->SetBit(kIsBasic,dm->IsBasic()); os->SetUniqueID(imember); Mark(fCnames[iclass]->Data(),losref,kUsingData); } } // scan base classes // ================= char *derived = fDerived[iclass]; TBaseClass *clbase; Int_t numb = 0; TList *lb = fCpointer[iclass]->GetListOfBases(); if (lb) { TIter nextb(lb); while ((clbase = (TBaseClass*)nextb())) { numb++; if (numb == 1) continue; ic = FindClass(clbase->GetName()); derived[ic] = 2; } for (ic=0;ic<fNclasses;ic++) { if (ic == iclass) continue; if (derived[ic]) { losref = fLinks[ic]; Mark(fCnames[ic]->Data(),los,kUsedByClass); Mark(fCnames[iclass]->Data(),losref,kUsingClass); } } } // scan member functions // ===================== char *star, *cref; TMethod *method; TMethodArg *methodarg; TList *lf = cl->GetListOfMethods(); if (lf) { TIter nextm(lf); char name[100]; while ((method = (TMethod*) nextm())) { // check return type strcpy(name,method->GetReturnTypeName()); star = strstr(name,"*"); if (star) *star = 0; cref = strstr(name,"&"); if (cref) *cref = 0; ic = FindClass(name); if (ic < 0 || ic == iclass) continue; losref = fLinks[ic]; Mark(fCnames[ic]->Data(),los,kUsedByFunc); Mark(fCnames[iclass]->Data(),losref,kUsingFunc); // now loop on all method arguments // ================================ TIter nexta(method->GetListOfMethodArgs()); while ((methodarg = (TMethodArg*) nexta())) { strcpy(name,methodarg->GetTypeName()); star = strstr(name,"*"); if (star) *star = 0; cref = strstr(name,"&"); if (cref) *cref = 0; ic = FindClass(name); if (ic < 0 || ic == iclass) continue; losref = fLinks[ic]; Mark(fCnames[ic]->Data(),los,kUsedByFunc); Mark(fCnames[iclass]->Data(),losref,kUsingFunc); } } } // Look into the source code to search the list of includes // here we assume that include file names are classes file names // we stop reading the code when // - a class member function is found // - any class constructor is found const char *source = gSystem->BaseName( gSystem->UnixPathName(cl->GetImplFileName())); char *sourceName = gSystem->Which( fSourceDir.Data(), source , kReadPermission ); if (!sourceName) return; char cname[100]; sprintf(cname,"%s::",fCnames[iclass]->Data()); Int_t ncn = strlen(cname); // open source file ifstream sourceFile; sourceFile.open( sourceName, ios::in Int_t nlines = 0; if( sourceFile.good() ) { const Int_t MAXLEN=500; char line[MAXLEN]; while( !sourceFile.eof() ) { sourceFile.getline( line, MAXLEN-1 ); if( sourceFile.eof() ) break; Int_t nblank = strspn(line," "); if (!strncmp(&line[nblank],"//",2)) continue; char *cc = strstr(line,"::"); if (cc) { *cc = 0; if (!strncmp(&line[nblank],cname,ncn)) break; //reach class member function Int_t nl = strlen(&line[nblank]); if (!strncmp(&line[nblank],cc+2,nl)) break; //reach any class constructor } nlines++; if (nlines > 1000) break; char *inc = strstr(line,"#include"); if (inc) { char *ch = strstr(line,".h"); if (!ch) continue; *ch = 0; char *start = strstr(line,"<"); if (!start) start = strstr(line,"\""); if (!start) continue; start++; while ((start < ch) && (*start == ' ')) start++; icl = FindClass(start); if (icl < 0 || icl == iclass) continue; // mark this include being used by this class losref = fLinks[icl]; Mark(fCnames[icl]->Data(),los,kUsedByCode1); Mark(fCnames[icl]->Data(),los,kUsedByCode); Mark(fCnames[iclass]->Data(),losref,kUsingCode); // and also the base classes of the class in the include derived = fDerived[icl]; for (ic=0;ic<fNclasses;ic++) { if (ic == icl) continue; if (derived[ic]) { losref = fLinks[ic]; Mark(fCnames[ic]->Data(),los,kUsedByCode); Mark(fCnames[iclass]->Data(),losref,kUsingCode); } } } } } sourceFile.close(); } //______________________________________________________________________________ void TClassTree::SetClasses(const char *classes, Option_t *) { // Set the list of classes for which the hierarchy is to be drawn // See Paint for the syntax if (classes == 0) return; fClasses = classes; for (Int_t i=0;i<fNclasses;i++) { fCstatus[i] = 0; fCparent[i] = -1; } if (gPad) Paint(); } //______________________________________________________________________________ void TClassTree::SetLabelDx(Float_t labeldx) { // Set the size along x of the TPavellabel showing the class name fLabelDx = labeldx; if (gPad) Paint(); } //______________________________________________________________________________ void TClassTree::SetYoffset(Float_t offset) { // Set the offset at the top of the picture // The default offset is computed automatically taking into account // classes not inheriting from TObject. fYoffset = offset; if (gPad) Paint(); } //______________________________________________________________________________ void TClassTree::ShowClassesUsedBy(const char *classes) { // mark classes used by the list of classes in classes Int_t i,j; Int_t nch = strlen(classes); char *ptr = new char[nch+1]; strcpy(ptr,classes); if (ptr[0] == '*') { i = FindClass(&ptr[1]); if (i >= 0) { char *derived = fDerived[i]; for (j=0;j<fNclasses;j++) { if(derived[j]) FindClassesUsedBy(j); } } } else if (ptr[nch-1] == '*') { ptr[nch-1] = 0; for (j=0;j<fNclasses;j++) { if(fCnames[j]->Contains(ptr)) FindClassesUsedBy(j); } } else { for (j=0;j<fNclasses;j++) { if(!fCnames[j]->CompareTo(ptr)) FindClassesUsedBy(j); } } delete [] ptr; if (gPad) Paint(); } //______________________________________________________________________________ void TClassTree::ShowClassesUsing(const char *classes) { // mark classes using any class in the list of classes in classes Int_t i,j; Int_t nch = strlen(classes); char *ptr = new char[nch+1]; strcpy(ptr,classes); if (ptr[0] == '*') { i = FindClass(&ptr[1]); if (i >= 0) { char *derived = fDerived[i]; for (j=0;j<fNclasses;j++) { if(derived[j]) FindClassesUsing(j); } } } else if (ptr[nch-1] == '*') { ptr[nch-1] = 0; for (j=0;j<fNclasses;j++) { if(fCnames[j]->Contains(ptr)) FindClassesUsing(j); } } else { for (j=0;j<fNclasses;j++) { if(!fCnames[j]->CompareTo(ptr)) FindClassesUsing(j); } } delete [] ptr; if (gPad) Paint(); } //______________________________________________________________________________ void TClassTree::ShowCod() { // Draw the Code References relationships TIter next(gPad->GetListOfPrimitives()); TObject *obj; TObjString *os; TPaveClass *pave; Int_t ic,icl; Float_t x,y,x1,y1; //iterate on all TPaveClass objects in the pad while((obj=next())) { if (obj->InheritsFrom(TPaveClass::Class())) { pave = (TPaveClass*)obj; icl = FindClass(pave->GetLabel()); if (icl < 0) continue; char *derived = fDerived[icl]; x = 0.5*(pave->GetX1() + pave->GetX2()); y = 0.5*(pave->GetY1() + pave->GetY2()); TIter nextos(fLinks[icl]); //iterate on all classes in the list of classes of this class while((os=(TObjString*)nextos())) { if (!os->TestBit(kUsedByCode1)) continue; ic = FindClass(os->GetName()); if (derived[ic]) continue; FindClassPosition(os->GetName(),x1,y1); if (x1 == 0 || y1 == 0) continue; //may be pointed class was not drawn TArrow *arrow = new TArrow(x,y,x1,y1,0.008,"|>"); arrow->SetLineColor(kGreen); arrow->SetFillColor(kGreen); arrow->SetBit(kIsClassTree); arrow->Draw(); } } } } //______________________________________________________________________________ void TClassTree::ShowHas() { // Draw the "Has a" relationships TIter next(gPad->GetListOfPrimitives()); TObject *obj; TObjString *os; TPaveClass *pave; Int_t icl; Float_t y,x1,y1,dx; //iterate on all TPaveClass objects in the pad while((obj=next())) { if (obj->InheritsFrom(TPaveClass::Class())) { pave = (TPaveClass*)obj; icl = FindClass(pave->GetLabel()); if (icl < 0) continue; y = 0.5*(pave->GetY1() + pave->GetY2()); Int_t nmembers = fNdata[icl]; if (nmembers == 0) continue; dx = (pave->GetX2() - pave->GetX1())/nmembers; TIter nextos(fLinks[icl]); //iterate on all classes in the list of classes of this class while((os=(TObjString*)nextos())) { if (!os->TestBit(kUsedByData)) continue; if (os->TestBit(kIsaPointer)) continue; if (os->TestBit(kIsBasic)) continue; FindClassPosition(os->GetName(),x1,y1); if (x1 == 0 || y1 == 0) continue; //may be base class was not drawn Int_t imember = os->GetUniqueID(); TLine *line = new TLine(pave->GetX1()+(imember+0.5)*dx,y,x1,y1); line->SetLineStyle(3); line->SetLineColor(6); line->SetBit(kIsClassTree); line->Draw(); } } } } //______________________________________________________________________________ void TClassTree::ShowLinks(Option_t *option) { // Set link options in the ClassTree object // "C" show References from code // "H" show Has a relations // "M" show Multiple Inheritance // "R" show References from data members TString opt = option; opt.ToUpper(); fShowCod = fShowHas = fShowMul = fShowRef = 0; if (opt.Contains("C")) fShowCod = 1; if (opt.Contains("H")) fShowHas = 1; if (opt.Contains("M")) fShowMul = 1; if (opt.Contains("R")) fShowRef = 1; if (gPad) Paint(); } //______________________________________________________________________________ void TClassTree::ShowMul() { // Draw the Multiple inheritance relationships TIter next(gPad->GetListOfPrimitives()); TObject *obj; TObjString *os; TPaveClass *pave; Int_t ic,icl; Float_t x,y,x1,y1; //iterate on all TPaveClass objects in the pad while((obj=next())) { if (obj->InheritsFrom(TPaveClass::Class())) { pave = (TPaveClass*)obj; icl = FindClass(pave->GetLabel()); if (icl < 0) continue; char *derived = fDerived[icl]; x = 0.5*(pave->GetX1() + pave->GetX2()); y = 0.5*(pave->GetY1() + pave->GetY2()); TIter nextos(fLinks[icl]); //iterate on all classes in the list of classes of this class while((os=(TObjString*)nextos())) { if (!os->TestBit(kUsedByClass)) continue; ic = FindClass(os->GetName()); if (derived[ic] != 2) continue; //keep only multiple inheritance FindClassPosition(os->GetName(),x1,y1); if (x1 == 0 || y1 == 0) continue; //may be base class was not drawn TLine *line = new TLine(x,y,x1,y1); line->SetBit(kIsClassTree); line->SetLineStyle(2); line->SetLineColor(kBlue); line->Draw(); } } } } //______________________________________________________________________________ void TClassTree::ShowRef() { // Draw the References relationships (other than inheritance or composition) TIter next(gPad->GetListOfPrimitives()); TObject *obj; TObjString *os; TPaveClass *pave; Int_t ic,icl; Float_t y,x1,y1,dx; Int_t icc = FindClass("TClass"); //iterate on all TPaveClass objects in the pad while((obj=next())) { if (obj->InheritsFrom(TPaveClass::Class())) { pave = (TPaveClass*)obj; icl = FindClass(pave->GetLabel()); if (icl < 0) continue; y = 0.5*(pave->GetY1() + pave->GetY2()); Int_t nmembers = fNdata[icl]; if (nmembers == 0) continue; dx = (pave->GetX2() - pave->GetX1())/nmembers; TIter nextos(fLinks[icl]); //iterate on all classes in the list of classes of this class while((os=(TObjString*)nextos())) { if (!os->TestBit(kUsedByData)) continue; ic = FindClass(os->GetName()); if (!os->TestBit(kIsaPointer)) continue; if (os->TestBit(kIsBasic)) continue; if (ic == icc) continue; // do not show relations with TClass FindClassPosition(os->GetName(),x1,y1); if (x1 == 0 || y1 == 0) continue; //may be pointed class was not drawn Int_t imember = os->GetUniqueID(); TArrow *arrow = new TArrow(pave->GetX1()+(imember+0.5)*dx,y,x1,y1,0.008,"|>"); arrow->SetLineColor(kRed); arrow->SetFillColor(kRed); arrow->SetBit(kIsClassTree); arrow->Draw(); } } } } //______________________________________________________________________________ void TClassTree::Streamer(TBuffer &R__b) { // Stream an object of class TClassTree. // the status of the object is saved and can be replayed in a subsequent session Int_t i; if (R__b.IsReading()) { Version_t R__v = R__b.ReadVersion(); if (R__v) { } TNamed::Streamer(R__b); fClasses.Streamer(R__b); R__b >> fYoffset; R__b >> fLabelDx; R__b >> fNclasses; R__b >> fShowCod; R__b >> fShowMul; R__b >> fShowHas; R__b >> fShowRef; fCnames = new TString*[fNclasses]; fCtitles = new TString*[fNclasses]; fCstatus = new Int_t[fNclasses]; fParents = new Int_t[fNclasses]; fCparent = new Int_t[fNclasses]; fNdata = new Int_t[fNclasses]; fCpointer = new TClass*[fNclasses]; fOptions = new TString*[fNclasses]; fLinks = new TList*[fNclasses]; fDerived = new char*[fNclasses]; for (i=0;i<fNclasses;i++) { R__b >> fCstatus[i]; R__b >> fParents[i]; R__b >> fNdata[i]; fCnames[i] = new TString(); fCtitles[i] = new TString(); fOptions[i] = new TString(); fCnames[i]->Streamer(R__b); fCtitles[i]->Streamer(R__b); fOptions[i]->Streamer(R__b); fLinks[i] = new TList(); fLinks[i]->Streamer(R__b); fDerived[i] = new char[fNclasses]; R__b.ReadFastArray(fDerived[i],fNclasses); } fSourceDir.Streamer(R__b); } else { R__b.WriteVersion(TClassTree::IsA()); TNamed::Streamer(R__b); fClasses.Streamer(R__b); R__b << fYoffset; R__b << fLabelDx; R__b << fNclasses; R__b << fShowCod; R__b << fShowMul; R__b << fShowHas; R__b << fShowRef; for (i=0;i<fNclasses;i++) { R__b << fCstatus[i]; R__b << fParents[i]; R__b << fNdata[i]; fCnames[i]->Streamer(R__b); fCtitles[i]->Streamer(R__b); fOptions[i]->Streamer(R__b); fLinks[i]->Streamer(R__b); R__b.WriteFastArray(fDerived[i],fNclasses); } fSourceDir.Streamer(R__b); } }