// @(#)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 %sn",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 writtenn",fname);
} else {
TFile local(filename,"recreate");
if (local.IsZombie()) return;
Write();
printf("TClassTree::SaveAs, file: %s has been writtenn",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);
}
}
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.