Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TClassTree.cxx
Go to the documentation of this file.
1 // @(#)root/gpad:$Id$
2 // Author: Rene Brun 01/12/98
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "RConfigure.h"
13 
14 #include "TROOT.h"
15 #include "TClassTree.h"
16 #include "TClassTable.h"
17 #include "TClass.h"
18 #include "TBaseClass.h"
19 #include "TDataMember.h"
20 #include "TDataType.h"
21 #include "TMethod.h"
22 #include "TMethodArg.h"
23 #include "TPad.h"
24 #include "TPaveClass.h"
25 #include "TArrow.h"
26 #include "TText.h"
27 #include "TSystem.h"
28 #include "TObjString.h"
29 #include "Riostream.h"
30 #include <algorithm>
31 
32 const Int_t kIsClassTree = BIT(7);
33 const Int_t kUsedByData = BIT(11);
34 const Int_t kUsedByFunc = BIT(12);
35 const Int_t kUsedByCode = BIT(13);
36 const Int_t kUsedByClass = BIT(14);
37 const Int_t kUsingData = BIT(15);
38 const Int_t kUsingFunc = BIT(16);
39 const Int_t kUsingCode = BIT(17);
40 const Int_t kUsingClass = BIT(18);
41 const Int_t kUsedByCode1 = BIT(19);
42 const Int_t kIsaPointer = BIT(20);
43 const Int_t kIsBasic = BIT(21);
44 
45 static Float_t gXsize, gYsize, gDx, gDy, gLabdx, gLabdy, gDxx, gCsize;
46 static Int_t *gNtsons, *gNsons;
47 
48 ClassImp(TClassTree);
49 
50 /** \class TClassTree
51 \ingroup gpad
52 
53 Draw inheritance tree and their relations for a list of classes.
54 
55 The following options are supported
56  - Direct inheritance (default)
57  - Multiple inheritance
58  - Composition
59  - References by data members and member functions
60  - References from Code
61 
62 The list of classes is specified:
63  - either in the TClassTree constructor as a second argument
64  - or the parameter to TClassTree::Draw
65 
66 Note that the ClassTree viewer can also be started from the canvas
67 pull down menu "Classes".
68 
69 In the list of classes, class names are separated by a ":"
70 wildcarding is supported.
71 The following formats are supported, eg in TClassTree::Draw
72  1. `Draw("ClassA")`
73  - Draw inheritance tree for ClassA
74  - Show all classes referenced by ClassA
75  2. `Draw("*ClassB")`
76  - Draw inheritance tree for ClassB
77  and all the classes deriving from ClassB
78  3. `Draw(">ClassC")`
79  - Draw inheritance tree for ClassC
80  - Show classes referencing ClassC
81  4. `Draw("ClassD<")`
82  - Draw inheritance tree for ClassD
83  - Show classes referenced by ClassD
84  - Show all classes referencing ClassD
85  5. `Draw("Cla*")`
86  - Draw inheritance tree for all classes with name starting with "Cla"
87  - Show classes referenced by these classes
88  6. `Draw("ClassA:ClassB<")`
89  - Draw inheritance tree for ClassA
90  - Show all classes referenced by ClassA
91  - Draw inheritance tree for ClassB
92  - Show classes referenced by ClassB
93  - Show all classes referencing ClassB
94 
95 Example: `Draw("TTree<")`
96  - Draw inheritance tree for the Root class TTree
97  - Show all classes referenced by TTree
98  - Show all classes using TTree
99 
100 By default, only direct inheritance is drawn.
101 Use TClassTree::ShowLinks(option) to show additional references
102  - option = "H" to show links to embedded classes
103  - option = "M" to show multiple inheritance
104  - option = "R" to show pointers to other classes from data members
105  - option = "C" to show classes used by the code(implementation) of a class
106 
107 The following picture is produced directly by:
108 ~~~ {.cpp}
109  TClassTree ct("ct","*TH1")
110 ~~~
111 It shows all the classes derived from the base class TH1.
112 
113 \image html gpad_classtree1.png
114 
115 The TClassTree class uses the services of the class TPaveClass to
116 show the class names. By clicking with the right mouse button in
117 one TPaveClass object, one can invoke the following functions of TClassTree:
118  - ShowLinks(option) with by default option = "HMR"
119  - Draw(classes). By default the class drawn is the one being pointed
120  - ShowClassesUsedBy(classes) (by default the pointed class)
121  - ShowClassesUsing(classes) (by default the pointed class)
122 
123 The following picture has been generated with the following statements
124 ~~~ {.cpp}
125  TClassTree tc1("tc1","TH1");
126  tc1.ShowLinks("HMR");
127 ~~~
128 
129 \image html gpad_classtree2.png
130 
131 Note that in case of embedded classes or pointers to classes,
132 the corresponding dashed lines or arrows respectively start
133 in the TPaveClass object at an X position reflecting the position
134 in the list of data members.
135 
136  - References by data members to other classes are show with a full red line
137  - Multiple inheritance is shown with a dashed blue line
138  - "Has a" relation is shown with a dotted cyan line
139  - References from code is shown by a full green line
140 
141 Use TClassTree::SetSourceDir to specify the search path for source files.
142 By default the search path includes the `$ROOTSYS` directory, the current
143 directory and the subdirectory `src`.
144 
145 The first time TClassTree::Draw is invoked, all the classes in the
146 current application are processed, including the parsing of the code
147 to find all classes referenced by the include statements.
148 This process may take a few seconds. The following commands will be
149 much faster.
150 
151 A TClassTree object may be saved in a Root file.
152 This object can be processed later by a Root program that ignores
153 the original classes. This interesting possibility allows to send
154 the class structure of an application to a colleague who does not have
155 your classes.
156 
157 Example:
158 ~~~ {.cpp}
159  TFile f("myClasses.root","recreate")
160  TClassTree *ct = new TClassTree("ct","ATLF*")
161  ct->Write();
162 ~~~
163 You can send at this point the file myClass.root to a colleague who can
164 run the following Root basic session
165 ~~~ {.cpp}
166  TFile f("myClass.root"); //connect the file
167  tt.ls(); //to list all classes and titles
168  tt.Draw("ATLFDisplay") //show class ATLFDisplay with all its dependencies
169 ~~~
170 At this point, one has still access to all the classes present
171 in the original session and select any combination of these classes
172 to be displayed.
173 */
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 /// TClassTree default constructor.
177 
178 TClassTree::TClassTree()
179 {
180  fShowCod = 0;
181  fShowHas = 0;
182  fShowMul = 0;
183  fShowRef = 0;
184  fNclasses = 0;
185  fCstatus = 0;
186  fParents = 0;
187  fCparent = 0;
188  fCpointer = 0;
189  fCnames = 0;
190  fCtitles = 0;
191  fOptions = 0;
192  fLinks = 0;
193  fDerived = 0;
194  fNdata = 0;
195  SetLabelDx();
196  SetYoffset(0);
197  SetSourceDir(".:src:" + TROOT::GetSourceDir());
198 }
199 
200 ////////////////////////////////////////////////////////////////////////////////
201 /// TClassTree constructor.
202 
203 TClassTree::TClassTree(const char *name, const char *classes)
204  :TNamed(name,classes)
205 {
206  fShowCod = 0;
207  fShowHas = 0;
208  fShowMul = 0;
209  fShowRef = 0;
210  fNclasses = 0;
211  fCstatus = 0;
212  fParents = 0;
213  fCparent = 0;
214  fCpointer = 0;
215  fCnames = 0;
216  fCtitles = 0;
217  fOptions = 0;
218  fLinks = 0;
219  fDerived = 0;
220  fNdata = 0;
221  SetLabelDx();
222  SetYoffset(0);
223  SetSourceDir(".:src:" + TROOT::GetSourceDir());
224 
225  // draw list of classes (if specified)
226  if (classes && strlen(classes)) {
227  fClasses = classes;
228  Draw();
229  }
230 }
231 
232 ////////////////////////////////////////////////////////////////////////////////
233 /// TClassTree default destructor.
234 
235 TClassTree::~TClassTree()
236 {
237  for (Int_t i=0;i<fNclasses;i++) {
238  //delete fOptions[i];
239  if (fLinks[i]) fLinks[i]->Delete();
240  //delete fLinks[i];
241  //if (fDerived[i]) {delete [] fDerived[i]; fDerived[i] = 0;}
242  }
243  delete [] fCnames;
244  delete [] fCtitles;
245  delete [] fCstatus;
246  delete [] fParents;
247  delete [] fCparent;
248  delete [] fCpointer;
249  delete [] fOptions;
250  delete [] fLinks;
251  delete [] fDerived;
252  delete [] fNdata;
253 }
254 
255 ////////////////////////////////////////////////////////////////////////////////
256 /// Draw the inheritance tree and relations for the list of classes
257 /// see this class header for the syntax and examples
258 
259 void TClassTree::Draw(const char *classes)
260 {
261  if (!gPad) {
262  gROOT->MakeDefCanvas();
263  }
264  Init();
265  if (classes && strlen(classes)) fClasses = classes;
266  for (Int_t i=0;i<fNclasses;i++) {
267  fCstatus[i] = 0;
268  fCparent[i] = -1;
269  }
270  Paint();
271 }
272 
273 ////////////////////////////////////////////////////////////////////////////////
274 /// Find class number corresponding to classname in list of local classes
275 
276 Int_t TClassTree::FindClass(const char *classname)
277 {
278  for (Int_t i=0;i<fNclasses;i++) {
279  if(!fCnames[i]->CompareTo(classname)) return i;
280  }
281  return -1;
282 }
283 
284 ////////////////////////////////////////////////////////////////////////////////
285 /// Select all classes used/referenced by the class number iclass
286 
287 void TClassTree::FindClassesUsedBy(Int_t iclass)
288 {
289  fCstatus[iclass] = 1;
290  Int_t i;
291  TObjString *os;
292  TList *los = fLinks[iclass];
293  TIter next(los);
294  while ((os = (TObjString*)next())) {
295  i = FindClass(os->GetName());
296  if (i < 0) continue;
297  if (fCstatus[i]) continue;
298  Int_t udata = os->TestBit(kUsedByData);
299  Int_t ufunc = os->TestBit(kUsedByFunc);
300  Int_t ucode = os->TestBit(kUsedByCode);
301  Int_t uclass = os->TestBit(kUsedByClass);
302  if (udata || ufunc || ucode || uclass) {
303  fCstatus[i] = 1;
304  }
305  }
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Select all classes using/referencing the class number iclass
310 
311 void TClassTree::FindClassesUsing(Int_t iclass)
312 {
313  // loop on all classes
314  fCstatus[iclass] = 1;
315  Int_t i;
316  TObjString *os;
317  TList *los = fLinks[iclass];
318  TIter next(los);
319  while ((os = (TObjString*)next())) {
320  i = FindClass(os->GetName());
321  if (i < 0) continue;
322  if (fCstatus[i]) continue;
323  Int_t udata = os->TestBit(kUsingData);
324  Int_t ufunc = os->TestBit(kUsingFunc);
325  Int_t ucode = os->TestBit(kUsingCode);
326  Int_t uclass = os->TestBit(kUsingClass);
327  if (udata || ufunc || ucode || uclass) {
328  fCstatus[i] = 1;
329  }
330  }
331 }
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 /// Search the TPaveClass object in the pad with label=classname
335 /// returns the x and y position of the center of the pave.
336 
337 void TClassTree::FindClassPosition(const char *classname, Float_t &x, Float_t &y)
338 {
339  TIter next(gPad->GetListOfPrimitives());
340  TObject *obj;
341  TPaveClass *pave;
342  while((obj=next())) {
343  if (obj->InheritsFrom(TPaveClass::Class())) {
344  pave = (TPaveClass*)obj;
345  if (!strcmp(pave->GetLabel(),classname)) {
346  x = 0.5*(pave->GetX1() + pave->GetX2());
347  y = 0.5*(pave->GetY1() + pave->GetY2());
348  return;
349  }
350  }
351  }
352  x = y = 0;
353 }
354 
355 ////////////////////////////////////////////////////////////////////////////////
356 /// Initialize the data structures
357 
358 void TClassTree::Init()
359 {
360  if (fNclasses) return;
361 
362  // fill the classes structures
363  gClassTable->Init();
364  fNclasses = gClassTable->Classes(); //number of classes in the application
365  fCnames = new TString*[fNclasses]; //class names
366  fCtitles = new TString*[fNclasses]; //class titles (given in ClassDef)
367  fCstatus = new Int_t[fNclasses]; //=0 if not used in current expression
368  fParents = new Int_t[fNclasses]; //parent number of classes (permanent)
369  fCparent = new Int_t[fNclasses]; //parent number of classes (local to expression)
370  fNdata = new Int_t[fNclasses]; //number of data members per class
371  fCpointer = new TClass*[fNclasses]; //pointers to the TClass
372  fOptions = new TString*[fNclasses]; //options per class
373  fLinks = new TList*[fNclasses]; //list of classes referencing/referenced
374  fDerived = new char*[fNclasses]; //derivation matrix
375 
376  Int_t i,j;
377  for (i=0;i<fNclasses;i++) {
378  fCnames[i] = new TString(gClassTable->Next());
379  fCpointer[i] = TClass::GetClass(fCnames[i]->Data());
380  fCtitles[i] = new TString(fCpointer[i]->GetTitle());
381  fCstatus[i] = 0;
382  fOptions[i] = new TString("ID");
383  fLinks[i] = new TList();
384  fDerived[i] = new char[fNclasses];
385  }
386  TBaseClass *clbase;
387  TClass *cl;
388  for (i=0;i<fNclasses;i++) {
389  TList *lm = fCpointer[i]->GetListOfDataMembers();
390  if (lm) fNdata[i] = lm->GetSize();
391  else fNdata[i] = 0;
392  // build derivation matrix
393  char *derived = fDerived[i];
394  for (j=0;j<fNclasses;j++) {
395  derived[j] = 0;
396  if (fCpointer[i]->InheritsFrom(fCpointer[j])) {
397  derived[j] = 1;
398  }
399  }
400  //build list of class parent
401  fParents[i] = -1;
402  TList *lb = fCpointer[i]->GetListOfBases();
403  if (!lb) continue;
404  clbase = (TBaseClass*)lb->First();
405  if (clbase == 0) continue;
406  cl = (TClass*)clbase->GetClassPointer();
407  for (j=0;j<fNclasses;j++) {
408  if(cl == fCpointer[j]) {
409  fParents[i] = j;
410  break;
411  }
412  }
413  }
414  //now the real & hard stuff
415  for (i=0;i<fNclasses;i++) {
416  ScanClasses(i);
417  }
418 }
419 
420 ////////////////////////////////////////////////////////////////////////////////
421 /// list classes names and titles
422 
423 void TClassTree::ls(Option_t *) const
424 {
425  char line[500];
426  for (Int_t i=0;i<fNclasses;i++) {
427  snprintf(line,500,"%s%s",fCnames[i]->Data(),"...........................");
428  snprintf(&line[30],460,"%s",fCtitles[i]->Data());
429  line[79] = 0;
430  printf("%5d %s\n",i,line);
431  }
432 }
433 
434 ////////////////////////////////////////////////////////////////////////////////
435 /// set bit abit in class classname in list los
436 
437 TObjString *TClassTree::Mark(const char *classname, TList *los, Int_t abit)
438 {
439  if (!los) return 0;
440  TObjString *os = (TObjString*)los->FindObject(classname);
441  if (!os) {
442  os = new TObjString(classname);
443  los->Add(os);
444  }
445  os->SetBit(abit);
446  return os;
447 }
448 
449 ////////////////////////////////////////////////////////////////////////////////
450 /// Draw the current class setting in fClasses and fStatus
451 
452 void TClassTree::Paint(Option_t *)
453 {
454  //delete primitives belonging to a previous paint
455  if (gPad) {
456  TIter next(gPad->GetListOfPrimitives());
457  TObject *obj;
458  while((obj=next())) {
459  if (obj->TestBit(kIsClassTree)) delete obj;
460  }
461  }
462 
463  Int_t nch = strlen(GetClasses());
464  if (nch == 0) return;
465  char *classes = new char[nch+1];
466  gNsons = new Int_t[fNclasses];
467  gNtsons = new Int_t[fNclasses];
468  strlcpy(classes,GetClasses(),nch+1);
469  Int_t i,j;
470  char *derived;
471  char *ptr = strtok(classes,":");
472  //mark referenced classes
473  while (ptr) {
474  nch = strlen(ptr);
475  if (ptr[0] == '*') {
476  j = FindClass(&ptr[1]);
477  if (j >= 0) {
478  for (i=0;i<fNclasses;i++) {
479  derived = fDerived[i];
480  if(derived[j]) fCstatus[i] = 1;
481  }
482  }
483  } else if (ptr[0] == '>') {
484  for (i=0;i<fNclasses;i++) {
485  if(fCnames[i]->Contains(&ptr[1])) {
486  FindClassesUsing(i);
487  fCstatus[i] = 2;
488  break;
489  }
490  }
491  } else if (ptr[nch-1] == '<') {
492  ptr[nch-1] = 0;
493  for (i=0;i<fNclasses;i++) {
494  if(fCnames[i]->Contains(ptr)) {
495  FindClassesUsedBy(i);
496  FindClassesUsing(i);
497  fCstatus[i] = 2;
498  break;
499  }
500  }
501  } else if (ptr[nch-1] == '*') {
502  ptr[nch-1] = 0;
503  for (i=0;i<fNclasses;i++) {
504  if(fCnames[i]->Contains(ptr)) fCstatus[i] = 1;
505  }
506  } else {
507  for (i=0;i<fNclasses;i++) {
508  if(!fCnames[i]->CompareTo(ptr)) {
509  FindClassesUsedBy(i);
510  fCstatus[i] = 2;
511  break;
512  }
513  }
514  }
515  ptr = strtok(0,":");
516  }
517  //mark base classes of referenced classes
518  for (i=0;i<fNclasses;i++) {
519  gNsons[i] = gNtsons[i] = 0;
520  }
521  for (i=0;i<fNclasses;i++) {
522  if (fCstatus[i] == 0) continue;
523  derived = fDerived[i];
524  for (j=0;j<fNclasses;j++) {
525  if (j == i) continue;
526  if(derived[j]) {
527  fCstatus[j] = 1;
528  }
529  }
530  }
531  //find parent class number for selected classes
532  for (i=0;i<fNclasses;i++) {
533  if (fCstatus[i] == 0) continue;
534  j = fParents[i];
535  if (j >=0 ) {
536  fCparent[i] = j;
537  gNsons[j]++;
538  }
539  }
540  //compute total number of sons for each node
541  Int_t maxlev = 1;
542  Int_t icl,ip;
543  for (i=0;i<fNclasses;i++) {
544  if (fCstatus[i] == 0) continue;
545  if (gNsons[i] != 0) continue;
546  icl = i;
547  Int_t nlevel = 1;
548  while (fCparent[icl] >= 0) {
549  nlevel++;
550  if (nlevel > maxlev) maxlev = nlevel;
551  ip = fCparent[icl];
552  gNtsons[ip]++;
553  icl = ip;
554  }
555  }
556 
557  //compute levels, number and list of sons
558  Int_t ndiv=0;
559  Int_t nmore = 0;
560  for (i=0;i<fNclasses;i++) {
561  if (fCstatus[i] == 0) continue;
562  if (fCparent[i] < 0) {
563  ndiv += gNtsons[i]+1;
564  nmore++;
565  }
566  }
567  ndiv++;
568 
569  // We are now ready to draw the active nodes
570  Float_t xmin = gPad->GetX1();
571  Float_t xmax = gPad->GetX2();
572  Float_t ymin = gPad->GetY1();
573  Float_t ymax = gPad->GetY2();
574  Float_t ytop = gYsize/20;
575  gXsize = xmax - xmin;
576  gYsize = ymax - ymin;
577  gDy = (gYsize-ytop)/(ndiv);
578  if (gDy > gYsize/10.) gDy = gYsize/10.;
579  gDx = 0.9*gXsize/5;
580  if (maxlev > 5) gDx = 0.97*gXsize/maxlev;
581  Float_t y = ymax -ytop;
582  gLabdx = fLabelDx*gXsize;
583  if (gLabdx > 0.95*gDx) gLabdx = 0.95*gDx;
584  gLabdy = 0.3*gDy;
585  gDxx = 0.5*gXsize/26.;
586  Float_t xleft = xmin +gDxx;
587  Float_t ymore = 0.5*nmore*gDy+fYoffset*gYsize;
588  Int_t dxpixels = gPad->XtoAbsPixel(gLabdx) - gPad->XtoAbsPixel(0);
589  Int_t dypixels = gPad->YtoAbsPixel(0) - gPad->YtoAbsPixel(gLabdy);
590  gCsize = dxpixels/(10.*dypixels);
591  gCsize = std::max(gCsize,Float_t(0.75));
592  gCsize = std::min(gCsize,Float_t(1.1));
593  // draw classes level 0
594  for (i=0;i<fNclasses;i++) {
595  if (fCstatus[i] == 0) continue;
596  if (fCparent[i] < 0) {
597  y -= gDy+0.5*gNtsons[i]*gDy;
598  if (!fCnames[i]->CompareTo("TObject")) y += ymore;
599  PaintClass(i,xleft,y);
600  y -= 0.5*gNtsons[i]*gDy;
601  }
602  }
603 
604  // show all types of links corresponding to selected options
605  if (fShowCod) ShowCod();
606  if (fShowHas) ShowHas();
607  if (fShowMul) ShowMul();
608  if (fShowRef) ShowRef();
609 
610  nch = strlen(GetClasses());
611  xmax = 0.3;
612  if (nch > 20) xmax = 0.5;
613  if (nch > 50) xmax = 0.7;
614  if (nch > 70) xmax = 0.9;
615  TPaveClass *ptitle = new TPaveClass(xmin +0.1*gXsize/26.
616  ,ymin+gYsize-0.9*gYsize/20.
617  ,xmin+xmax*gXsize
618  ,ymin+gYsize-0.1*gYsize/26.
619  ,GetClasses(),this);
620  ptitle->SetFillColor(42);
621  ptitle->SetBit(kIsClassTree);
622  ptitle->Draw();
623 
624  //cleanup
625  delete [] classes;
626  delete [] gNsons;
627  delete [] gNtsons;
628 }
629 
630 ////////////////////////////////////////////////////////////////////////////////
631 /// Paint one class level
632 
633 void TClassTree::PaintClass(Int_t iclass, Float_t xleft, Float_t y)
634 {
635  Float_t u[2],yu=0,yl=0;
636  Int_t ns = gNsons[iclass];
637  u[0] = xleft;
638  u[1] = u[0]+gDxx;
639  if(ns != 0) u[1] = u[0]+gDx;
640  TLine *line = new TLine(u[0],y,u[1],y);
641  line->SetBit(kIsClassTree);
642  line->Draw();
643  Int_t icobject = FindClass("TObject");
644  TPaveClass *label = new TPaveClass(xleft+gDxx,y-gLabdy,xleft+gLabdx,y+gLabdy,fCnames[iclass]->Data(),this);
645  char *derived = fDerived[iclass];
646  if (icobject >= 0 && !derived[icobject]) label->SetFillColor(30);
647  if (fCstatus[iclass] > 1) label->SetFillColor(kYellow);
648  label->SetTextSize(gCsize);
649  label->SetBit(kIsClassTree);
650  label->SetToolTipText(fCtitles[iclass]->Data(),500);
651  label->Draw();
652  if (ns == 0) return;
653 
654  // drawing sons
655  y += 0.5*gNtsons[iclass]*gDy;
656  Int_t first =0;
657  for (Int_t i=0;i<fNclasses;i++) {
658  if(fCparent[i] != iclass) continue;
659  if (gNtsons[i] > 1) y -= 0.5*gNtsons[i]*gDy;
660  else y -= 0.5*gDy;
661  if (!first) {first=1; yu = y;}
662  PaintClass(i,u[1],y);
663  yl = y;
664  if (gNtsons[i] > 1) y -= 0.5*gNtsons[i]*gDy;
665  else y -= 0.5*gDy;
666  }
667  if (ns == 1) return;
668  line = new TLine(u[1],yl,u[1],yu);
669  line->SetBit(kIsClassTree);
670  line->Draw();
671 }
672 
673 ////////////////////////////////////////////////////////////////////////////////
674 /// save current configuration in a Root file
675 /// if filename is blank, the name of the file will be the current objectname.root
676 /// all the current settings are preserved
677 /// the Root file produced can be looked at by a another Root session
678 /// with no access to the original classes.
679 /// By default a message is printed. Specify option "Q" to remove the message
680 
681 void TClassTree::SaveAs(const char *filename, Option_t *option) const
682 {
683  if (gDirectory) gDirectory->SaveObjectAs(this,filename,option);
684 }
685 
686 ////////////////////////////////////////////////////////////////////////////////
687 /// Select all classes used by/referenced/referencing the class number iclass
688 /// and build the list of these classes
689 
690 void TClassTree::ScanClasses(Int_t iclass)
691 {
692  Int_t ic, icl;
693  TList *los = fLinks[iclass];
694  TList *losref = 0;
695  TObjString *os;
696 
697  // scan list of data members
698  // =========================
699  TClass *cl = fCpointer[iclass];
700  TDataMember *dm;
701  TList *lm = cl->GetListOfDataMembers();
702  if (lm) {
703  TIter next(lm);
704  Int_t imember = 0;
705  while ((dm = (TDataMember *) next())) {
706  imember++;
707  ic = FindClass(dm->GetTypeName());
708  if (ic < 0 || ic == iclass) continue;
709  losref = fLinks[ic];
710  os = Mark(fCnames[ic]->Data(),los,kUsedByData);
711  if (os) {
712  os->SetBit(kIsaPointer,dm->IsaPointer());
713  os->SetBit(kIsBasic,dm->IsBasic());
714  os->SetUniqueID(imember);
715  }
716  Mark(fCnames[iclass]->Data(),losref,kUsingData);
717  }
718  }
719 
720  // scan base classes
721  // =================
722  char *derived = fDerived[iclass];
723  TBaseClass *clbase;
724  Int_t numb = 0;
725  TList *lb = fCpointer[iclass]->GetListOfBases();
726  if (lb) {
727  TIter nextb(lb);
728  while ((clbase = (TBaseClass*)nextb())) {
729  numb++;
730  if (numb == 1) continue;
731  ic = FindClass(clbase->GetName());
732  derived[ic] = 2;
733  }
734  for (ic=0;ic<fNclasses;ic++) {
735  if (ic == iclass) continue;
736  if (derived[ic]) {
737  losref = fLinks[ic];
738  Mark(fCnames[ic]->Data(),los,kUsedByClass);
739  Mark(fCnames[iclass]->Data(),losref,kUsingClass);
740  }
741  }
742  }
743 
744  // scan member functions
745  // =====================
746  char *star, *cref;
747  TMethod *method;
748  TMethodArg *methodarg;
749  TList *lf = cl->GetListOfMethods();
750  if (lf) {
751  TIter nextm(lf);
752  TString name;
753  while ((method = (TMethod*) nextm())) {
754  // check return type
755  name = method->GetReturnTypeName();
756  star = strstr((char*)name.Data(),"*");
757  if (star) *star = 0;
758  cref = strstr((char*)name.Data(),"&");
759  if (cref) *cref = 0;
760  ic = FindClass(name);
761  if (ic < 0 || ic == iclass) continue;
762  losref = fLinks[ic];
763  Mark(fCnames[ic]->Data(),los,kUsedByFunc);
764  Mark(fCnames[iclass]->Data(),losref,kUsingFunc);
765 
766  // now loop on all method arguments
767  // ================================
768  TIter nexta(method->GetListOfMethodArgs());
769  while ((methodarg = (TMethodArg*) nexta())) {
770  name = methodarg->GetTypeName();
771  star = strstr((char*)name.Data(),"*");
772  if (star) *star = 0;
773  cref = strstr((char*)name.Data(),"&");
774  if (cref) *cref = 0;
775  ic = FindClass(name);
776  if (ic < 0 || ic == iclass) continue;
777  losref = fLinks[ic];
778  Mark(fCnames[ic]->Data(),los,kUsedByFunc);
779  Mark(fCnames[iclass]->Data(),losref,kUsingFunc);
780  }
781  }
782  }
783 
784  // Look into the source code to search the list of includes
785  // here we assume that include file names are classes file names
786  // we stop reading the code when
787  // - a class member function is found
788  // - any class constructor is found
789  if (!cl->GetImplFileName() || !cl->GetImplFileName()[0])
790  return;
791 
792  const char *source = gSystem->BaseName( gSystem->UnixPathName(cl->GetImplFileName()));
793  char *sourceName = gSystem->Which( fSourceDir.Data(), source , kReadPermission );
794  if (!sourceName) return;
795  Int_t ncn = strlen(fCnames[iclass]->Data())+2;
796  char *cname = new char[ncn+1];
797  snprintf(cname,ncn,"%s::",fCnames[iclass]->Data());
798  // open source file
799  std::ifstream sourceFile;
800  sourceFile.open( sourceName, std::ios::in );
801  Int_t nlines = 0;
802  if( sourceFile.good() ) {
803  const Int_t kMAXLEN=1500;
804  char line[kMAXLEN];
805  while( !sourceFile.eof() ) {
806  sourceFile.getline( line, kMAXLEN-1 );
807  if( sourceFile.eof() ) break;
808  Int_t nblank = strspn(line," ");
809  if (!strncmp(&line[nblank],"//",2)) continue;
810  char *cc = strstr(line,"::");
811  if (cc) {
812  *cc = 0;
813  if (!strncmp(&line[nblank],cname,ncn)) break; //reach class member function
814  Int_t nl = strlen(&line[nblank]);
815  if (!strncmp(&line[nblank],cc+2,nl)) break; //reach any class constructor
816  }
817  nlines++; if (nlines > 1000) break;
818  char *inc = strstr(line,"#include");
819  if (inc) {
820  char *ch = strstr(line,".h");
821  if (!ch) continue;
822  *ch = 0;
823  char *start = strstr(line,"<");
824  if (!start) start = strstr(line,"\"");
825  if (!start) continue;
826  start++;
827  while ((start < ch) && (*start == ' ')) start++;
828  icl = FindClass(start);
829  if (icl < 0 || icl == iclass) continue;
830  // mark this include being used by this class
831  losref = fLinks[icl];
832  Mark(fCnames[icl]->Data(),los,kUsedByCode1);
833  Mark(fCnames[icl]->Data(),los,kUsedByCode);
834  Mark(fCnames[iclass]->Data(),losref,kUsingCode);
835  // and also the base classes of the class in the include
836  derived = fDerived[icl];
837  for (ic=0;ic<fNclasses;ic++) {
838  if (ic == icl) continue;
839  if (derived[ic]) {
840  losref = fLinks[ic];
841  Mark(fCnames[ic]->Data(),los,kUsedByCode);
842  Mark(fCnames[iclass]->Data(),losref,kUsingCode);
843  }
844  }
845  }
846  }
847  }
848  delete [] cname;
849  sourceFile.close();
850 }
851 
852 ////////////////////////////////////////////////////////////////////////////////
853 /// Set the list of classes for which the hierarchy is to be drawn
854 /// See Paint for the syntax
855 
856 void TClassTree::SetClasses(const char *classes, Option_t *)
857 {
858  if (classes == 0) return;
859  fClasses = classes;
860  for (Int_t i=0;i<fNclasses;i++) {
861  fCstatus[i] = 0;
862  fCparent[i] = -1;
863  }
864  if (gPad) Paint();
865 }
866 
867 ////////////////////////////////////////////////////////////////////////////////
868 /// Set the size along x of the TPaveLabel showing the class name
869 
870 void TClassTree::SetLabelDx(Float_t labeldx)
871 {
872  fLabelDx = labeldx;
873  if (gPad) Paint();
874 }
875 
876 ////////////////////////////////////////////////////////////////////////////////
877 /// Set the offset at the top of the picture
878 /// The default offset is computed automatically taking into account
879 /// classes not inheriting from TObject.
880 
881 void TClassTree::SetYoffset(Float_t offset)
882 {
883  fYoffset = offset;
884  if (gPad) Paint();
885 }
886 
887 ////////////////////////////////////////////////////////////////////////////////
888 /// mark classes used by the list of classes in classes
889 
890 void TClassTree::ShowClassesUsedBy(const char *classes)
891 {
892  Int_t i,j;
893  Int_t nch = strlen(classes);
894  char *ptr = new char[nch+1];
895  strlcpy(ptr,classes,nch+1);
896  if (ptr[0] == '*') {
897  i = FindClass(&ptr[1]);
898  if (i >= 0) {
899  char *derived = fDerived[i];
900  for (j=0;j<fNclasses;j++) {
901  if(derived[j]) FindClassesUsedBy(j);
902  }
903  }
904  } else if (ptr[nch-1] == '*') {
905  ptr[nch-1] = 0;
906  for (j=0;j<fNclasses;j++) {
907  if(fCnames[j]->Contains(ptr)) FindClassesUsedBy(j);
908  }
909  } else {
910  for (j=0;j<fNclasses;j++) {
911  if(!fCnames[j]->CompareTo(ptr)) FindClassesUsedBy(j);
912  }
913  }
914  delete [] ptr;
915  if (gPad) Paint();
916 }
917 
918 ////////////////////////////////////////////////////////////////////////////////
919 /// mark classes using any class in the list of classes in classes
920 
921 void TClassTree::ShowClassesUsing(const char *classes)
922 {
923  Int_t i,j;
924  Int_t nch = strlen(classes);
925  char *ptr = new char[nch+1];
926  strlcpy(ptr,classes,nch+1);
927  if (ptr[0] == '*') {
928  i = FindClass(&ptr[1]);
929  if (i >= 0) {
930  char *derived = fDerived[i];
931  for (j=0;j<fNclasses;j++) {
932  if(derived[j]) FindClassesUsing(j);
933  }
934  }
935  } else if (ptr[nch-1] == '*') {
936  ptr[nch-1] = 0;
937  for (j=0;j<fNclasses;j++) {
938  if(fCnames[j]->Contains(ptr)) FindClassesUsing(j);
939  }
940  } else {
941  for (j=0;j<fNclasses;j++) {
942  if(!fCnames[j]->CompareTo(ptr)) FindClassesUsing(j);
943  }
944  }
945  delete [] ptr;
946  if (gPad) Paint();
947 }
948 
949 ////////////////////////////////////////////////////////////////////////////////
950 /// Draw the Code References relationships
951 
952 void TClassTree::ShowCod()
953 {
954  TIter next(gPad->GetListOfPrimitives());
955  TObject *obj;
956  TObjString *os;
957  TPaveClass *pave;
958  Int_t ic,icl;
959  Float_t x,y,x1,y1;
960  //iterate on all TPaveClass objects in the pad
961  while((obj=next())) {
962  if (obj->InheritsFrom(TPaveClass::Class())) {
963  pave = (TPaveClass*)obj;
964  icl = FindClass(pave->GetLabel());
965  if (icl < 0) continue;
966  char *derived = fDerived[icl];
967  x = 0.5*(pave->GetX1() + pave->GetX2());
968  y = 0.5*(pave->GetY1() + pave->GetY2());
969  TIter nextos(fLinks[icl]);
970  //iterate on all classes in the list of classes of this class
971  while((os=(TObjString*)nextos())) {
972  if (!os->TestBit(kUsedByCode1)) continue;
973  ic = FindClass(os->GetName());
974  if (derived[ic]) continue;
975  FindClassPosition(os->GetName(),x1,y1);
976  if (x1 == 0 || y1 == 0) continue; //may be pointed class was not drawn
977  TArrow *arrow = new TArrow(x,y,x1,y1,0.008,"|>");
978  arrow->SetLineColor(kGreen);
979  arrow->SetFillColor(kGreen);
980  arrow->SetBit(kIsClassTree);
981  arrow->Draw();
982  }
983  }
984  }
985 }
986 
987 ////////////////////////////////////////////////////////////////////////////////
988 /// Draw the "Has a" relationships
989 
990 void TClassTree::ShowHas()
991 {
992  TIter next(gPad->GetListOfPrimitives());
993  TObject *obj;
994  TObjString *os;
995  TPaveClass *pave;
996  Int_t icl;
997  Float_t y,x1,y1,dx;
998  //iterate on all TPaveClass objects in the pad
999  while((obj=next())) {
1000  if (obj->InheritsFrom(TPaveClass::Class())) {
1001  pave = (TPaveClass*)obj;
1002  icl = FindClass(pave->GetLabel());
1003  if (icl < 0) continue;
1004  y = 0.5*(pave->GetY1() + pave->GetY2());
1005  Int_t nmembers = fNdata[icl];
1006  if (nmembers == 0) continue;
1007  dx = (pave->GetX2() - pave->GetX1())/nmembers;
1008  TIter nextos(fLinks[icl]);
1009  //iterate on all classes in the list of classes of this class
1010  while((os=(TObjString*)nextos())) {
1011  if (!os->TestBit(kUsedByData)) continue;
1012  if (os->TestBit(kIsaPointer)) continue;
1013  if (os->TestBit(kIsBasic)) continue;
1014  FindClassPosition(os->GetName(),x1,y1);
1015  if (x1 == 0 || y1 == 0) continue; //may be base class was not drawn
1016  Int_t imember = os->GetUniqueID();
1017  TLine *line = new TLine(pave->GetX1()+(imember+0.5)*dx,y,x1,y1);
1018  line->SetLineStyle(3);
1019  line->SetLineColor(6);
1020  line->SetBit(kIsClassTree);
1021  line->Draw();
1022  }
1023  }
1024  }
1025 }
1026 
1027 ////////////////////////////////////////////////////////////////////////////////
1028 /// Set link options in the ClassTree object
1029 ///
1030 /// - "C" show References from code
1031 /// - "H" show Has a relations
1032 /// - "M" show Multiple Inheritance
1033 /// - "R" show References from data members
1034 
1035 void TClassTree::ShowLinks(Option_t *option)
1036 {
1037  TString opt = option;
1038  opt.ToUpper();
1039  fShowCod = fShowHas = fShowMul = fShowRef = 0;
1040  if (opt.Contains("C")) fShowCod = 1;
1041  if (opt.Contains("H")) fShowHas = 1;
1042  if (opt.Contains("M")) fShowMul = 1;
1043  if (opt.Contains("R")) fShowRef = 1;
1044  if (gPad) Paint();
1045 }
1046 
1047 ////////////////////////////////////////////////////////////////////////////////
1048 /// Draw the Multiple inheritance relationships
1049 
1050 void TClassTree::ShowMul()
1051 {
1052  TIter next(gPad->GetListOfPrimitives());
1053  TObject *obj;
1054  TObjString *os;
1055  TPaveClass *pave;
1056  Int_t ic,icl;
1057  Float_t x,y,x1,y1;
1058  //iterate on all TPaveClass objects in the pad
1059  while((obj=next())) {
1060  if (obj->InheritsFrom(TPaveClass::Class())) {
1061  pave = (TPaveClass*)obj;
1062  icl = FindClass(pave->GetLabel());
1063  if (icl < 0) continue;
1064  char *derived = fDerived[icl];
1065  x = 0.5*(pave->GetX1() + pave->GetX2());
1066  y = 0.5*(pave->GetY1() + pave->GetY2());
1067  TIter nextos(fLinks[icl]);
1068  //iterate on all classes in the list of classes of this class
1069  while((os=(TObjString*)nextos())) {
1070  if (!os->TestBit(kUsedByClass)) continue;
1071  ic = FindClass(os->GetName());
1072  if (derived[ic] != 2) continue; //keep only multiple inheritance
1073  FindClassPosition(os->GetName(),x1,y1);
1074  if (x1 == 0 || y1 == 0) continue; //may be base class was not drawn
1075  TLine *line = new TLine(x,y,x1,y1);
1076  line->SetBit(kIsClassTree);
1077  line->SetLineStyle(2);
1078  line->SetLineColor(kBlue);
1079  line->Draw();
1080  }
1081  }
1082  }
1083 }
1084 
1085 ////////////////////////////////////////////////////////////////////////////////
1086 /// Draw the References relationships (other than inheritance or composition)
1087 
1088 void TClassTree::ShowRef()
1089 {
1090  TIter next(gPad->GetListOfPrimitives());
1091  TObject *obj;
1092  TObjString *os;
1093  TPaveClass *pave;
1094  Int_t ic,icl;
1095  Float_t y,x1,y1,dx;
1096  Int_t icc = FindClass("TClass");
1097  //iterate on all TPaveClass objects in the pad
1098  while((obj=next())) {
1099  if (obj->InheritsFrom(TPaveClass::Class())) {
1100  pave = (TPaveClass*)obj;
1101  icl = FindClass(pave->GetLabel());
1102  if (icl < 0) continue;
1103  y = 0.5*(pave->GetY1() + pave->GetY2());
1104  Int_t nmembers = fNdata[icl];
1105  if (nmembers == 0) continue;
1106  dx = (pave->GetX2() - pave->GetX1())/nmembers;
1107  TIter nextos(fLinks[icl]);
1108  //iterate on all classes in the list of classes of this class
1109  while((os=(TObjString*)nextos())) {
1110  if (!os->TestBit(kUsedByData)) continue;
1111  ic = FindClass(os->GetName());
1112  if (!os->TestBit(kIsaPointer)) continue;
1113  if (os->TestBit(kIsBasic)) continue;
1114  if (ic == icc) continue; // do not show relations with TClass
1115  FindClassPosition(os->GetName(),x1,y1);
1116  if (x1 == 0 || y1 == 0) continue; //may be pointed class was not drawn
1117  Int_t imember = os->GetUniqueID();
1118  TArrow *arrow = new TArrow(pave->GetX1()+(imember+0.5)*dx,y,x1,y1,0.008,"|>");
1119  arrow->SetLineColor(kRed);
1120  arrow->SetFillColor(kRed);
1121  arrow->SetBit(kIsClassTree);
1122  arrow->Draw();
1123  }
1124  }
1125  }
1126 }
1127 
1128 ////////////////////////////////////////////////////////////////////////////////
1129 /// Stream an object of class TClassTree.
1130 /// the status of the object is saved and can be replayed in a subsequent session
1131 
1132 void TClassTree::Streamer(TBuffer &R__b)
1133 {
1134  Int_t i;
1135  if (R__b.IsReading()) {
1136  Version_t R__v = R__b.ReadVersion(); if (R__v) { }
1137  TNamed::Streamer(R__b);
1138  fClasses.Streamer(R__b);
1139  R__b >> fYoffset;
1140  R__b >> fLabelDx;
1141  R__b >> fNclasses;
1142  R__b >> fShowCod;
1143  R__b >> fShowMul;
1144  R__b >> fShowHas;
1145  R__b >> fShowRef;
1146  fCnames = new TString*[fNclasses];
1147  fCtitles = new TString*[fNclasses];
1148  fCstatus = new Int_t[fNclasses];
1149  fParents = new Int_t[fNclasses];
1150  fCparent = new Int_t[fNclasses];
1151  fNdata = new Int_t[fNclasses];
1152  fCpointer = new TClass*[fNclasses];
1153  fOptions = new TString*[fNclasses];
1154  fLinks = new TList*[fNclasses];
1155  fDerived = new char*[fNclasses];
1156  for (i=0;i<fNclasses;i++) {
1157  R__b >> fCstatus[i];
1158  R__b >> fParents[i];
1159  R__b >> fNdata[i];
1160  fCnames[i] = new TString();
1161  fCtitles[i] = new TString();
1162  fOptions[i] = new TString();
1163  fCnames[i]->Streamer(R__b);
1164  fCtitles[i]->Streamer(R__b);
1165  fOptions[i]->Streamer(R__b);
1166  fLinks[i] = new TList();
1167  fLinks[i]->Streamer(R__b);
1168  fDerived[i] = new char[fNclasses];
1169  R__b.ReadFastArray(fDerived[i],fNclasses);
1170  }
1171  fSourceDir.Streamer(R__b);
1172  } else {
1173  R__b.WriteVersion(TClassTree::IsA());
1174  TNamed::Streamer(R__b);
1175  fClasses.Streamer(R__b);
1176  R__b << fYoffset;
1177  R__b << fLabelDx;
1178  R__b << fNclasses;
1179  R__b << fShowCod;
1180  R__b << fShowMul;
1181  R__b << fShowHas;
1182  R__b << fShowRef;
1183  for (i=0;i<fNclasses;i++) {
1184  R__b << fCstatus[i];
1185  R__b << fParents[i];
1186  R__b << fNdata[i];
1187  fCnames[i]->Streamer(R__b);
1188  fCtitles[i]->Streamer(R__b);
1189  fOptions[i]->Streamer(R__b);
1190  fLinks[i]->Streamer(R__b);
1191  R__b.WriteFastArray(fDerived[i],fNclasses);
1192  }
1193  fSourceDir.Streamer(R__b);
1194  }
1195 }