//*CMZ : 2.22/07 05/07/99 19.26.51 by Rene Brun
//*CMZ : 2.20/05 15/12/98 12.31.48 by Rene Brun
//*CMZ : 2.20/02 03/12/98 08.59.32 by Rene Brun
//*CMZ : 2.20/01 02/12/98 17.06.57 by Rene Brun
//*-- Author : Rene Brun 01/12/98
//*KEEP,CopyRight,T=C.
/*************************************************************************
* Copyright(c) 1995-1999, The ROOT System, All rights reserved. *
* Authors: Rene Brun, Fons Rademakers. *
* For list of contributors see $ROOTSYS/AA_CREDITS. *
* *
* Permission to use, copy, modify and distribute this software and its *
* documentation for non-commercial purposes is hereby granted without *
* fee, provided that the above copyright notice appears in all copies *
* and that both the copyright notice and this permission notice appear *
* in the supporting documentation. The authors make no claims about the *
* suitability of this software for any purpose. It is provided "as is" *
* without express or implied warranty. *
*************************************************************************/
//*KEND.
//*KEEP,TROOT.
#include "TROOT.h"
//*KEEP,TClassTree,T=C++.
#include "TClassTree.h"
//*KEEP,TClassTable.
#include "TClassTable.h"
//*KEEP,TBaseClass.
#include "TBaseClass.h"
//*KEEP,TClass.
#include "TClass.h"
//*KEEP,TDataMember.
#include "TDataMember.h"
//*KEEP,TDataType.
#include "TDataType.h"
//*KEEP,TPaveLabel.
#include "TPaveLabel.h"
//*KEEP,TArrow.
#include "TArrow.h"
//*KEEP,TText.
#include "TText.h"
//*KEND.
ClassImp(TClassTree)
//______________________________________________________________________________
//
// Draw inheritance tree for a list of classes
// The following options are supported
// - Direct inheritance (default)
// - Multiple inheritance
// - Composition
// - References
//
// See TClassTree::DrawTree for examples and pictures
//______________________________________________________________________________
TClassTree::TClassTree() : TCanvas()
{
//*-*-*-*-*-*-*-*-*-*-*-*TClassTree default constructor*-*-*-*-*-*-*-*-*-*-*
//*-* ==============================
}
//_____________________________________________________________________________
TClassTree::TClassTree(const Text_t *name, const Text_t *title, UInt_t ww, UInt_t wh)
: TCanvas(name,title,ww,wh)
{
//*-*-*-*-*-*-*-*-*-*-*TClassTree constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ======================
fShowHas = 0;
fShowMul = 0;
fShowRef = 0;
fClasses = title;
// Set a default canvas range
Float_t xsize = 26;
Float_t ysize = 20;
Range(0,0,xsize,ysize);
SetLabelDx();
SetYoffset();
SetFillColor(33);
// if title is specified, use title as list of classes to be shown
if (title && strlen(title)) DrawTree();
}
//______________________________________________________________________________
TClassTree::~TClassTree()
{
//*-*-*-*-*-*-*-*-*-*TClassTree default destructor*-*-*-*-*-*-*-*-*-*-*-*
//*-* =============================
}
//______________________________________________________________________________
void TClassTree::DrawTree(const char *userClasses, Option_t *option)
{
// Draw inheritance tree for classes in userClasses
// userClasses is a list of classes to be used to draw the tree
// if userClasses is the null string, the last list entered
// via TClassTree::SetClasses is taken.
// class names are separated by a ":"
// wildcarding is supported
//
// the character "*" following a class name means include
// all class names starting with this string
// example TH1* selects all classes starting with "TH1"
//
// the character "*" preceeding a class name include
// all classes deriving from this class
// example *TH1 selects all classes deriving from TH1,
// this includes all TH1* classes + TH2* + TH3* +TProfile
//
// The following example draws the inheritance tree
// for all histogram + tree + all GUI classes deriving from TGFrame
// "*TH1:*TTree:*TGFrame"
//
// By default, only direct inheritance is drawn.
// Use:
// - TClassTree::SetShowHas to show links to embedded classes
// - TClassTree::SetShowMul to show multiple inheritance
// - TClassTree::SetShowRef to show pointers to other classes
//
// You can start the ClassTree viewer in two ways:
// 1- TClassTree ct("ct","*TH1:*TGraph:TAxis")
// 2- using the pull down menu "Classes" from a TCanvas menu bar
//
// Once a TClassTree canvas is created, you can click on the right button:
// - Select "SetClasses" to draw a new class list
// - Select "SetShowHas" to toggle the embedded classes option
// - Select "SetShowMul" to toggle the multiple inheritance option
// - Select "SetShowRef" to toggle the pointers to classes option
// - Select "Range" to change the canvas range
// - Select "SetCanvasSize" to make a big canvas (eg, 1000x4000) and scroll
//
// The following picture has been generated with the following statements
// TClassTree tc1("tc1","*TH1:*TCollection");
// tc1.SetShowHas();
// tc1.SetShowRef();
//
//
/*
*/
//
//
// The following picture has been generated with the following statements
// TClassTree tc2("tc2");
// tc2.SetClasses("*TGCompositeFrame");
// tc2.SetShowHas();
// tc2.SetShowMul();
// tc2.SetShowRef();
//
/*
*/
//
//
// Note that in case of embedded classes or pointers to classes,
// the corresponding dashed lines or arrows respectively start
// in the TPavelabel object at an X position reflecting the position
// in the list of data members.
//clear canvas unless option same is specified
TString opt = option;
if (!opt.Contains("same")) Clear();
if (userClasses == 0) return;
if (strlen(userClasses)) SetClasses(userClasses);
Int_t nch = strlen(GetClasses());
char *classes = new char[nch+1];
Int_t nclass = gClassTable->Classes();
char **cnames = new char*[nclass];
Int_t *cstatus = new Int_t[nclass];
Int_t *cparent = new Int_t[nclass];
Int_t *nsons = new Int_t[nclass];
Int_t *ntsons = new Int_t[nclass];
Int_t *levels = new Int_t[nclass];
Int_t *lsons = new Int_t[nclass*50];
Float_t *dyc = new Float_t[nclass];
Float_t *yg = new Float_t[nclass];
TClass **clp = new TClass*[nclass];
strcpy(classes,GetClasses());
Int_t i,j;
TClass *cl;
TBaseClass *clbase;
gClassTable->Init();
for (i=0;i<nclass;i++) {
cnames[i] = gClassTable->Next();
clp[i] = gROOT->GetClass(cnames[i]);
cstatus[i] = 0;
}
char *ptr = strtok(classes,":");
//mark referenced classes
while (ptr) {
nch = strlen(ptr);
if (ptr[0] == '*') {
cl = gROOT->GetClass(&ptr[1]);
if (cl) {
for (i=0;i<nclass;i++) {
if(clp[i]->InheritsFrom(cl)) cstatus[i] = 1;
}
}
} else if (ptr[nch-1] == '*') {
ptr[nch-1] = 0;
for (i=0;i<nclass;i++) {
if(strstr(cnames[i],ptr) != 0) cstatus[i] = 1;
}
} else {
for (i=0;i<nclass;i++) {
if(strcmp(cnames[i],ptr) == 0) cstatus[i] = 1;
}
}
ptr = strtok(0,":");
}
//mark base classes of referenced classes
for (i=0;i<nclass;i++) {
if (cstatus[i] == 0) continue;
for (j=0;j<nclass;j++) {
if(clp[i]->InheritsFrom(clp[j])) cstatus[j] = 1;
}
}
//find parent class number for selected classes
for (i=0;i<nclass;i++) {
nsons[i] = ntsons[i] = levels[i] = 0;
if (cstatus[i] == 0) continue;
for (j=0;j<50;j++) lsons[50*i+j] = 0;
cparent[i] = -1;
clbase = (TBaseClass*)clp[i]->GetListOfBases()->First();
if (clbase == 0) continue;
cl = (TClass*)clbase->GetClassPointer();
for (j=0;j<nclass;j++) {
if(cl == clp[j]) cparent[i] = j;
}
}
//compute levels, number and list of sons
Int_t maxlev = 1;
Int_t ndiv=0, ip1 =0;
Int_t ip,icl,ns,nts,nlevel,kl;
for (i=0;i<nclass;i++) {
if (cstatus[i] == 0) continue;
nlevel = 1;
icl = i;
while (cparent[icl] >= 0) {
ip = cparent[icl];
if (nlevel == 1) ip1 = ip;
if (ip >= 0) {
if (nsons[i] == 0) ntsons[ip]++;
nlevel++;
icl = ip;
}
}
if (nlevel > 1) {
ns = nsons[ip1];
lsons[50*ip1+ns] = i;
nsons[ip1]++;
}
levels[i] = nlevel;
if (nlevel > maxlev) maxlev = nlevel;
}
Int_t nmore = 0;
for (i=0;i<nclass;i++) {
if (cstatus[i] == 0) continue;
if (levels[i] == 1) {
if (ntsons[i] == 0) ntsons[i] = 1;
ndiv += ntsons[i];
nmore++;
}
}
if (ndiv == 0) ndiv = 1;
Float_t xsize = GetX2();
Float_t ysize = GetY2();
Float_t ymore = fYoffset;
if (nmore == 1) ymore = 0;
if (ndiv < 15) ymore = -2;
Float_t dy = (ysize)/ndiv;
if(dy > 0.85) dy = 0.85;
Float_t dx = 0.9*xsize/6;
if (maxlev > 6) dx = 0.97*xsize/maxlev;
Float_t y = ysize-1;
Float_t u[2];
Float_t labdx = fLabelDx;
if (labdx > 0.95*dx) labdx = 0.95*dx;
Float_t labdy = 0.3*dy;
Float_t xleft, ycurrent, yu=0, yl=0;
TPaveLabel *label;
TLine *line = new TLine();
TClass *clObject = gROOT->GetClass("TObject");
for (Int_t ilev=0;ilev<maxlev;ilev++) {
xleft = ilev*dx+0.5;
for (Int_t iclass=0;iclass<nclass;iclass++) {
if (cstatus[iclass] == 0) continue;
if (levels[iclass] != ilev+1) continue;
dyc[iclass] = ntsons[iclass]*dy;
if (ilev == 0) {
y -= dyc[iclass];
if (clp[iclass] == clObject && ntsons[iclass] > 1) y += ymore;
yg[iclass] = y+0.5*dyc[iclass];
}
ns = nsons[iclass];
if (ns > 1) ycurrent = yg[iclass]+0.5*dyc[iclass]-0.5*dy;
else ycurrent = yg[iclass];
for (Int_t is=0;is<ns;is++) {
kl = lsons[50*iclass+is];
nts = ntsons[kl];
if (ns > 1) yg[kl] = ycurrent-0.5*nts*dy;
else yg[kl] = ycurrent;
if(is == 0) yu = yg[kl];
if(is == ns-1) yl = yg[kl];
ycurrent -= dy*(nts+1);
}
u[0] = xleft;
u[1] = u[0]+0.5;
if(ns != 0) u[1] = u[0]+dx;
line->DrawLine(u[0],yg[iclass],u[1],yg[iclass]);
if(ns > 1) line->DrawLine(u[1],yl,u[1],yu);
label = new TPaveLabel(xleft+0.5,yg[iclass]-labdy,xleft+labdx,yg[iclass]+labdy,cnames[iclass]);
if (clp[iclass] == clObject) label->SetFillColor(kYellow);
if (!clp[iclass]->InheritsFrom("TObject")) label->SetFillColor(30);
label->SetTextSize(0.9);
label->Draw();
}
}
nch = strlen(GetClasses());
Float_t xmax = 0.3;
if (nch > 20) xmax = 0.5;
if (nch > 50) xmax = 0.7;
if (nch > 70) xmax = 0.9;
TPaveLabel *ptitle = new TPaveLabel(0.1,ysize-0.9,xmax*xsize,ysize-0.1,GetClasses());
ptitle->SetFillColor(42);
ptitle->Draw();
if (fShowHas) ShowHas();
if (fShowMul) ShowMul();
if (fShowRef) ShowRef();
if (nch == 0) Help();
Update();
//cleanup
delete line;
delete [] cnames;
delete [] clp;
delete [] cstatus;
delete [] classes;
delete [] cparent;
delete [] nsons;
delete [] ntsons;
delete [] levels;
delete [] lsons;
delete [] dyc;
delete [] yg;
}
//______________________________________________________________________________
void TClassTree::FindClassPosition(const char *classname, Float_t &x, Float_t &y)
{
// Search the TPavelabel object in the pad with label=classname
// returns the x and y position of the center of the pave.
TIter next(GetListOfPrimitives());
TObject *obj;
TPaveLabel *pave;
while((obj=next())) {
if (obj->InheritsFrom(TPaveLabel::Class())) {
pave = (TPaveLabel*)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::Help()
{
// Print help about interactive use of this class in the canvas
const char *HelpAbout[] = {
"Use canvas popup menu item "SetClasses" to give the list of classes.",
"Class names are separated by a ":", wildcarding is supported.",
" ",
"The character "*" following a class name means include",
"all class names starting with this string.",
" example TH1* selects all classes starting with "TH1"",
" ",
"The character "*" preceeding a class name include",
"all classes deriving from this class.",
" example *TH1 selects all classes deriving from TH1,",
" this includes all TH1* classes + TH2* + TH3* +TProfile",
" ",
"The following example draws the inheritance tree for",
"all histogram + tree + all GUI classes deriving from TGFrame.",
" "*TH1:*TTree:*TGFrame"",
" ",
"By default, only direct inheritance is drawn.",
"Using the canvas popup menu, you can select the options: ",
" - "SetClasses" to draw a new class list",
" - "SetShowHas" to toggle the embedded classes option",
" - "SetShowMul" to toggle the multiple inheritance option",
" - "SetShowRef" to toggle the pointers to classes option",
" - "Range" to change the canvas range",
" - "SetCanvasSize" to make a big canvas (eg, 1000x4000)",
"",
};
Clear();
Float_t y = 0.9*GetY2();
Float_t dy = y/26.;
TText text;
text.SetTextAlign(12);
text.SetTextFont(52);
text.SetTextSize(1./33.);
for (Int_t i=0;i<30;i++) {
if (strlen(HelpAbout[i]) == 0) break;
text.DrawText(0.1*GetX2(),y,HelpAbout[i]);
y -= dy;
}
}
//______________________________________________________________________________
void TClassTree::SetClasses(const char *classes)
{
// Set the list of classes for which the hierarchy is to be drawn
// See DrawTree for the syntax
if (classes == 0) return;
fClasses = classes;
DrawTree();
}
//______________________________________________________________________________
void TClassTree::SetLabelDx(Float_t labeldx)
{
// Set the size along x of the TPavellabel showing the class name
fLabelDx = labeldx;
DrawTree();
}
//______________________________________________________________________________
void TClassTree::SetShowHas(Int_t showhas)
{
// Enable/disable the "Has a" relationship drawing option
fShowHas = showhas;
DrawTree();
}
//______________________________________________________________________________
void TClassTree::SetShowMul(Int_t showmul)
{
// Enable/disable the Show Multiple inheritance relationship option
fShowMul = showmul;
DrawTree();
}
//______________________________________________________________________________
void TClassTree::SetShowRef(Int_t showref)
{
// Enable/disable the Show References relationship option
fShowRef = showref;
DrawTree();
}
//______________________________________________________________________________
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;
DrawTree();
}
//______________________________________________________________________________
void TClassTree::ShowHas()
{
// Draw the "Has a" relationships
TIter next(GetListOfPrimitives());
TObject *obj;
TPaveLabel *pave;
TDataMember *member;
TClass *cl;
Float_t y,x1,y1,dx;
while((obj=next())) {
if (obj->InheritsFrom(TPaveLabel::Class())) {
pave = (TPaveLabel*)obj;
cl = gROOT->GetClass(pave->GetLabel());
if (!cl) continue;
y = 0.5*(pave->GetY1() + pave->GetY2());
TList *lm = cl->GetListOfDataMembers();
Int_t nmembers = lm->GetSize();
if (nmembers == 0) continue;
dx = (pave->GetX2() - pave->GetX1())/nmembers;
TIter nextd(lm);
//Iterate on list of data members
Int_t imember = 0;
while((member=(TDataMember*)nextd())) {
imember++;
if (member->IsaPointer()) continue;
if (member->IsBasic()) continue;
FindClassPosition(member->GetTypeName(),x1,y1);
if (x1 == 0 || y1 == 0) continue; //may be base class was not drawn
TLine *line = new TLine(pave->GetX1()+(imember+0.5)*dx,y,x1,y1);
line->SetLineStyle(3);
line->SetLineColor(6);
line->Draw();
}
}
}
}
//______________________________________________________________________________
void TClassTree::ShowMul()
{
// Draw the Multiple inheritance relationships
TIter next(GetListOfPrimitives());
TObject *obj;
TBaseClass *base;
TPaveLabel *pave;
TClass *cl;
Float_t x,y,x1,y1;
while((obj=next())) {
if (obj->InheritsFrom(TPaveLabel::Class())) {
pave = (TPaveLabel*)obj;
cl = gROOT->GetClass(pave->GetLabel());
if (!cl) continue;
x = 0.5*(pave->GetX1() + pave->GetX2());
y = 0.5*(pave->GetY1() + pave->GetY2());
TIter nextb(cl->GetListOfBases());
Int_t ibase = 0;
//Iterate on list of base classes, skip first
while((base=(TBaseClass*)nextb())) {
ibase++;
if (ibase == 1) continue;
FindClassPosition(base->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->SetLineStyle(2);
line->SetLineColor(kBlue);
line->Draw();
}
}
}
}
//______________________________________________________________________________
void TClassTree::ShowRef()
{
// Draw the References relationships (other than inheritance or composition)
TIter next(GetListOfPrimitives());
TObject *obj;
TPaveLabel *pave;
TDataMember *member;
TClass *cl;
Float_t y,x1,y1,dx;
while((obj=next())) {
if (obj->InheritsFrom(TPaveLabel::Class())) {
pave = (TPaveLabel*)obj;
cl = gROOT->GetClass(pave->GetLabel());
if (!cl) continue;
y = 0.5*(pave->GetY1() + pave->GetY2());
TList *lm = cl->GetListOfDataMembers();
Int_t nmembers = lm->GetSize();
if (nmembers == 0) continue;
dx = (pave->GetX2() - pave->GetX1())/nmembers;
TIter nextd(lm);
//Iterate on list of data members
Int_t imember = 0;
while((member=(TDataMember*)nextd())) {
imember++;
if (!member->IsaPointer()) continue;
if (member->IsBasic()) continue;
if (!strcmp("fgIsA",member->GetName())) continue;
FindClassPosition(member->GetTypeName(),x1,y1);
if (x1 == 0 || y1 == 0) continue; //may be pointed class was not drawn
TArrow *arrow = new TArrow(pave->GetX1()+(imember+0.5)*dx,y,x1,y1,0.008,"|>");
arrow->SetLineColor(kRed);
arrow->SetFillColor(kRed);
arrow->Draw();
}
}
}
}
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.