// @(#)root/gpad:$Id$ // 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. * *************************************************************************/ #include "RConfigure.h" #include "TROOT.h" #include "TClassTree.h" #include "TClassTable.h" #include "TClass.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 "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 gXsize, gYsize, gDx, gDy, gLabdx, gLabdy, gDxx, gCsize; static Int_t *gNtsons, *gNsons; 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. //Begin_Html /* */ //End_Html // // 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"); // //Begin_Html /* */ //End_Html // // 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); #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); #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;iDelete(); //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) { gROOT->MakeDefCanvas(); } Init(); if (classes && strlen(classes)) fClasses = classes; for (Int_t i=0;iCompareTo(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;iNext()); fCpointer[i] = TClass::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;iGetListOfDataMembers(); if (lm) fNdata[i] = lm->GetSize(); else fNdata[i] = 0; // build derivation matrix char *derived = fDerived[i]; for (j=0;jInheritsFrom(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;jData(),"..........................."); snprintf(&line[30],460,"%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]; gNsons = new Int_t[fNclasses]; gNtsons = new Int_t[fNclasses]; strlcpy(classes,GetClasses(),nch+1); 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') { for (i=0;iContains(&ptr[1])) { FindClassesUsing(i); fCstatus[i] = 2; break; } } } else if (ptr[nch-1] == '<') { ptr[nch-1] = 0; for (i=0;iContains(ptr)) { FindClassesUsedBy(i); FindClassesUsing(i); fCstatus[i] = 2; break; } } } else if (ptr[nch-1] == '*') { ptr[nch-1] = 0; for (i=0;iContains(ptr)) fCstatus[i] = 1; } } else { for (i=0;iCompareTo(ptr)) { FindClassesUsedBy(i); fCstatus[i] = 2; break; } } } ptr = strtok(0,":"); } //mark base classes of referenced classes for (i=0;i=0 ) { fCparent[i] = j; gNsons[j]++; } } //compute total number of sons for each node Int_t maxlev = 1; Int_t icl,ip; for (i=0;i= 0) { nlevel++; if (nlevel > maxlev) maxlev = nlevel; ip = fCparent[icl]; gNtsons[ip]++; icl = ip; } } //compute levels, number and list of sons Int_t ndiv=0; Int_t nmore = 0; for (i=0;iGetX1(); Float_t xmax = gPad->GetX2(); Float_t ymin = gPad->GetY1(); Float_t ymax = gPad->GetY2(); Float_t ytop = gYsize/20; gXsize = xmax - xmin; gYsize = ymax - ymin; gDy = (gYsize-ytop)/(ndiv); if (gDy > gYsize/10.) gDy = gYsize/10.; gDx = 0.9*gXsize/5; if (maxlev > 5) gDx = 0.97*gXsize/maxlev; Float_t y = ymax -ytop; gLabdx = fLabelDx*gXsize; if (gLabdx > 0.95*gDx) gLabdx = 0.95*gDx; gLabdy = 0.3*gDy; gDxx = 0.5*gXsize/26.; Float_t xleft = xmin +gDxx; Float_t ymore = 0.5*nmore*gDy+fYoffset*gYsize; Int_t dxpixels = gPad->XtoAbsPixel(gLabdx) - gPad->XtoAbsPixel(0); Int_t dypixels = gPad->YtoAbsPixel(0) - gPad->YtoAbsPixel(gLabdy); gCsize = dxpixels/(10.*dypixels); gCsize = std::max(gCsize,Float_t(0.75)); gCsize = std::min(gCsize,Float_t(1.1)); // draw classes level 0 for (i=0;iCompareTo("TObject")) y += ymore; PaintClass(i,xleft,y); y -= 0.5*gNtsons[i]*gDy; } } // 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*gXsize/26. ,ymin+gYsize-0.9*gYsize/20. ,xmin+xmax*gXsize ,ymin+gYsize-0.1*gYsize/26. ,GetClasses(),this); ptitle->SetFillColor(42); ptitle->SetBit(kIsClassTree); ptitle->Draw(); //cleanup delete [] classes; delete [] gNsons; delete [] gNtsons; } //______________________________________________________________________________ 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 = gNsons[iclass]; u[0] = xleft; u[1] = u[0]+gDxx; if(ns != 0) u[1] = u[0]+gDx; 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+gDxx,y-gLabdy,xleft+gLabdx,y+gLabdy,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(gCsize); label->SetBit(kIsClassTree); label->SetToolTipText(fCtitles[iclass]->Data(),500); label->Draw(); if (ns == 0) return; // drawing sons y += 0.5*gNtsons[iclass]*gDy; Int_t first =0; for (Int_t i=0;i 1) y -= 0.5*gNtsons[i]*gDy; else y -= 0.5*gDy; if (!first) {first=1; yu = y;} PaintClass(i,u[1],y); yl = y; if (gNtsons[i] > 1) y -= 0.5*gNtsons[i]*gDy; else y -= 0.5*gDy; } if (ns == 1) return; line = new TLine(u[1],yl,u[1],yu); line->SetBit(kIsClassTree); line->Draw(); } //______________________________________________________________________________ void TClassTree::SaveAs(const char *filename, Option_t *option) const { // 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. // By default a message is printed. Specify option "Q" to remove the message if (gDirectory) gDirectory->SaveObjectAs(this,filename,option); } //______________________________________________________________________________ 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); if (os) { 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;icData(),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); TString name; while ((method = (TMethod*) nextm())) { // check return type name = method->GetReturnTypeName(); star = strstr((char*)name.Data(),"*"); if (star) *star = 0; cref = strstr((char*)name.Data(),"&"); 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())) { name = methodarg->GetTypeName(); star = strstr((char*)name.Data(),"*"); if (star) *star = 0; cref = strstr((char*)name.Data(),"&"); 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 if (!cl->GetImplFileName() || !cl->GetImplFileName()[0]) return; const char *source = gSystem->BaseName( gSystem->UnixPathName(cl->GetImplFileName())); char *sourceName = gSystem->Which( fSourceDir.Data(), source , kReadPermission ); if (!sourceName) return; Int_t ncn = strlen(fCnames[iclass]->Data())+2; char *cname = new char[ncn+1]; snprintf(cname,ncn,"%s::",fCnames[iclass]->Data()); // open source file ifstream sourceFile; sourceFile.open( sourceName, ios::in ); Int_t nlines = 0; if( sourceFile.good() ) { const Int_t kMAXLEN=1500; char line[kMAXLEN]; while( !sourceFile.eof() ) { sourceFile.getline( line, kMAXLEN-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;icData(),los,kUsedByCode); Mark(fCnames[iclass]->Data(),losref,kUsingCode); } } } } } delete [] cname; 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= 0) { char *derived = fDerived[i]; for (j=0;jContains(ptr)) FindClassesUsedBy(j); } } else { for (j=0;jCompareTo(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]; strlcpy(ptr,classes,nch+1); if (ptr[0] == '*') { i = FindClass(&ptr[1]); if (i >= 0) { char *derived = fDerived[i]; for (j=0;jContains(ptr)) FindClassesUsing(j); } } else { for (j=0;jCompareTo(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> 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;iStreamer(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); } }