Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TInspectCanvas.cxx
Go to the documentation of this file.
1 // @(#)root/gpad:$Id$
2 // Author: Rene Brun 08/01/2000
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 "TROOT.h"
13 #include "TGuiFactory.h"
14 #include "TInspectCanvas.h"
15 #include "TButton.h"
16 #include "TClass.h"
17 #include "TLine.h"
18 #include "TLink.h"
19 #include "TDataMember.h"
20 #include "TDataType.h"
21 #include "TRealData.h"
22 #include "TLatex.h"
23 
24 ClassImp(TInspectCanvas);
25 
26 
27 /** \class TInspectorObject
28 \ingroup gpad
29 
30 This class is designed to wrap a Foreign object in order to
31 inject it into the Browse sub-system.
32 */
33 
34 class TInspectorObject : public TObject
35 {
36 public:
37 
38  TInspectorObject(void *obj, TClass *cl) : fObj(obj),fClass(cl) {};
39  ~TInspectorObject(){;}
40 
41  void *GetObject() const { return fObj; };
42  void Inspect() const {
43  gGuiFactory->CreateInspectorImp(this, 400, 200);
44  };
45  TClass *IsA() const { return fClass; }
46 
47 private:
48  void *fObj; //! pointer to the foreign object
49  TClass *fClass; //! pointer to class of the foreign object
50 
51 };
52 
53 
54 /** \class TInspectCanvas
55 \ingroup gpad
56 
57 A TInspectCanvas is a canvas specialized to inspect Root objects.
58 */
59 
60 ////////////////////////////////////////////////////////////////////////////////
61 /// InspectCanvas default constructor.
62 
63 TInspectCanvas::TInspectCanvas() : TCanvas()
64 {
65  fBackward = 0;
66  fForward = 0;
67  fCurObject = 0;
68  fObjects = 0;
69  fLogx = kFALSE;
70  fLogy = kFALSE;
71  SetFillColor(0);
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 /// InspectCanvas constructor.
76 
77 TInspectCanvas::TInspectCanvas(UInt_t ww, UInt_t wh)
78  : TCanvas("inspect","ROOT Object Inspector",ww,wh)
79 {
80  fBackward = 0;
81  fForward = 0;
82  fCurObject = 0;
83  fObjects = new TList;
84  fLogx = kFALSE;
85  fLogy = kFALSE;
86  SetFillColor(0);
87 }
88 
89 ////////////////////////////////////////////////////////////////////////////////
90 /// InspectCanvas default destructor.
91 
92 TInspectCanvas::~TInspectCanvas()
93 {
94  if (fObjects) {
95  fObjects->Clear("nodelete");
96  delete fObjects;
97  }
98 }
99 
100 ////////////////////////////////////////////////////////////////////////////////
101 /// Dump contents of obj in a graphics canvas.
102 /// Same action as TObject::Dump but in a graphical form.
103 /// In addition pointers to other objects can be followed.
104 ///
105 /// The following picture is the Inspect of a histogram object:
106 /// \image html gpad_inspect.png
107 
108 void TInspectCanvas::InspectObject(TObject *obj)
109 {
110  Int_t cdate = 0;
111  Int_t ctime = 0;
112  UInt_t *cdatime = 0;
113  Bool_t isdate = kFALSE;
114  Bool_t isbits = kFALSE;
115  const Int_t kname = 1;
116  const Int_t kvalue = 25;
117  const Int_t ktitle = 37;
118  const Int_t kline = 1024;
119  char line[kline];
120  char *pname;
121 
122  TClass *cl = obj->IsA();
123  if (cl == 0) return;
124  TInspectorObject *proxy=0;
125  if (!cl->IsTObject()) {
126  // This is possible only if obj is actually a TInspectorObject
127  // wrapping a non-TObject.
128  proxy = (TInspectorObject*)obj;
129  obj = (TObject*)proxy->GetObject();
130  }
131 
132  if (!cl->GetListOfRealData()) cl->BuildRealData(obj);
133 
134  // Count number of data members in order to resize the canvas
135  TRealData *rd;
136  TIter next(cl->GetListOfRealData());
137  Int_t nreal = cl->GetListOfRealData()->GetSize();
138  if (nreal == 0) return;
139 
140  Int_t nrows = 33;
141  if (nreal+7 > nrows) nrows = nreal+7;
142  Int_t nh = nrows*15;
143  Int_t nw = 700;
144  TVirtualPad *canvas = GetVirtCanvas();
145  if (canvas) {
146  canvas->Clear(); // remove primitives from canvas
147  canvas->SetCanvasSize(nw, nh); // set new size of drawing area
148  canvas->Range(0,-3,20,nreal+4);
149  }
150 
151  Float_t xvalue = 5;
152  Float_t xtitle = 8;
153  Float_t dy = 1;
154  Float_t ytext = Float_t(nreal) - 1.5;
155  Float_t tsize = 0.99/ytext;
156  if (tsize < 0.02) tsize = 0.02;
157  if (tsize > 0.03) tsize = 0.03;
158 
159  // Create text objects
160  TText tname, tvalue, ttitle;
161  TText *tval;
162  tname.SetTextFont(61);
163  tname.SetTextAngle(0);
164  tname.SetTextAlign(12);
165  tname.SetTextColor(1);
166  tname.SetTextSize(tsize);
167  tvalue.SetTextFont(61);
168  tvalue.SetTextAngle(0);
169  tvalue.SetTextAlign(12);
170  tvalue.SetTextColor(1);
171  tvalue.SetTextSize(tsize);
172  ttitle.SetTextFont(62);
173  ttitle.SetTextAngle(0);
174  ttitle.SetTextAlign(12);
175  ttitle.SetTextColor(1);
176  ttitle.SetTextSize(tsize);
177 
178  Float_t x1 = 0.2;
179  Float_t x2 = 19.8;
180  Float_t y1 = -0.5;
181  Float_t y2 = Float_t(nreal) - 0.5;
182  Float_t y3 = y2 + 1;
183  Float_t y4 = y3 + 1.5;
184  Float_t db = 25./GetWh();
185  Float_t btop = 0.999;
186 
187  // Draw buttons
188  fBackward = new TButton("backward","TInspectCanvas::GoBackward();",.01,btop-db,.15,btop);
189  fBackward->Draw();
190  fBackward->SetToolTipText("Inspect previous object");
191  fForward = new TButton("forward", "TInspectCanvas::GoForward();", .21,btop-db,.35,btop);
192  fForward->Draw();
193  fForward->SetToolTipText("Inspect next object");
194 
195  // Draw surrounding box and title areas
196  TLine frame;
197  frame.SetLineColor(1);
198  frame.SetLineStyle(1);
199  frame.SetLineWidth(1);
200  frame.DrawLine(x1, y1, x2, y1);
201  frame.DrawLine(x2, y1, x2, y4);
202  frame.DrawLine(x2, y4, x1, y4);
203  frame.DrawLine(x1, y4, x1, y1);
204  frame.DrawLine(x1, y2, x2, y2);
205  frame.DrawLine(x1, y3, x2, y3);
206  frame.DrawLine(xvalue, y1, xvalue, y3);
207  frame.DrawLine(xtitle, y1, xtitle, y3);
208  ttitle.SetTextSize(0.8*tsize);
209  ttitle.SetTextAlign(21);
210  ttitle.DrawText(0.5*(x1+xvalue), y2+0.1, "Member Name");
211  ttitle.DrawText(0.5*(xvalue+xtitle), y2+0.1, "Value");
212  ttitle.DrawText(0.5*(xtitle+x2), y2+0.1, "Title");
213  ttitle.SetTextSize(1.2*tsize);
214  ttitle.SetTextColor(2);
215  ttitle.SetTextAlign(11);
216  ttitle.DrawText(x1+0.2, y3+0.1, cl->GetName());
217  if (proxy==0) {
218  ttitle.SetTextColor(4);
219  strlcpy(line,obj->GetName(),kline);
220  ttitle.DrawText(xvalue+0.2, y3+0.1, line);
221  ttitle.SetTextColor(6);
222  ttitle.DrawText(xtitle+2, y3+0.1, obj->GetTitle());
223  } else {
224  ttitle.SetTextColor(4);
225  snprintf(line,1023,"%s:%d","Foreign object",0);
226  ttitle.DrawText(xvalue+0.2, y3+0.1, line);
227  ttitle.SetTextColor(6);
228  ttitle.DrawText(xtitle+2, y3+0.1, "no title given");
229  }
230  ttitle.SetTextSize(tsize);
231  ttitle.SetTextColor(1);
232  ttitle.SetTextFont(11);
233  ttitle.SetTextAlign(12);
234 
235  //---Now loop on data members-----------------------
236  // We make 3 passes. Faster than one single pass because changing
237  // font parameters is time consuming
238  for (Int_t pass = 0; pass < 3; pass++) {
239  ytext = y2 - 0.5;
240  next.Reset();
241  while ((rd = (TRealData*) next())) {
242  TDataMember *member = rd->GetDataMember();
243  if (!member) continue;
244  TDataType *membertype = member->GetDataType();
245  isdate = kFALSE;
246  if (strcmp(member->GetName(),"fDatime") == 0 && membertype && membertype->GetType() == kUInt_t) {
247  isdate = kTRUE;
248  }
249  isbits = kFALSE;
250  if (strcmp(member->GetName(),"fBits") == 0 && membertype && membertype->GetType() == kUInt_t) {
251  isbits = kTRUE;
252  }
253 
254  // Encode data member name
255  pname = &line[kname];
256  for (Int_t i=0;i<kline;i++) line[i] = ' ';
257  line[kline-1] = 0;
258  strlcpy(pname,rd->GetName(),kline-kname);
259  if (strstr(member->GetFullTypeName(),"**")) strlcat(pname,"**",kline-kname);
260 
261  // Encode data value or pointer value
262  tval = &tvalue;
263  Int_t offset = rd->GetThisOffset();
264  char *pointer = (char*)obj + offset;
265  char **ppointer = (char**)(pointer);
266  TLink *tlink = 0;
267 
268  TClass *clm=0;
269  if (!membertype) {
270  clm = member->GetClass();
271  }
272 
273  if (member->IsaPointer()) {
274  char **p3pointer = (char**)(*ppointer);
275  if (clm && !clm->IsStartingWithTObject() ) {
276  //NOTE: memory leak!
277  p3pointer = (char**)new TInspectorObject(p3pointer,clm);
278  }
279 
280  if (!p3pointer) {
281  snprintf(&line[kvalue],kline-kvalue,"->0");
282  } else if (!member->IsBasic()) {
283  if (pass == 1) {
284  tlink = new TLink(xvalue+0.1, ytext, p3pointer);
285  }
286  } else if (membertype) {
287  if (!strcmp(membertype->GetTypeName(), "char"))
288  strlcpy(&line[kvalue], *ppointer,kline-kvalue);
289  else
290  strlcpy(&line[kvalue], membertype->AsString(p3pointer),kline-kvalue);
291  } else if (!strcmp(member->GetFullTypeName(), "char*") ||
292  !strcmp(member->GetFullTypeName(), "const char*")) {
293  strlcpy(&line[kvalue], *ppointer,kline-kvalue);
294  } else {
295  if (pass == 1) tlink = new TLink(xvalue+0.1, ytext, p3pointer);
296  }
297  } else if (membertype)
298  if (isdate) {
299  cdatime = (UInt_t*)pointer;
300  TDatime::GetDateTime(cdatime[0],cdate,ctime);
301  snprintf(&line[kvalue],kline-kvalue,"%d/%d",cdate,ctime);
302  } else if (isbits) {
303  snprintf(&line[kvalue],kline-kvalue,"0x%08x", *(UInt_t*)pointer);
304  } else {
305  strlcpy(&line[kvalue], membertype->AsString(pointer),kline-kvalue);
306  }
307  else
308  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)pointer);
309 
310  // Encode data member title
311  Int_t ltit = 0;
312  if (isdate == kFALSE && strcmp(member->GetFullTypeName(), "char*") &&
313  strcmp(member->GetFullTypeName(), "const char*")) {
314  Int_t lentit = strlen(member->GetTitle());
315  if (lentit >= kline-ktitle) lentit = kline-ktitle-1;
316  strlcpy(&line[ktitle],member->GetTitle(),kline-ktitle);
317  line[ktitle+lentit] = 0;
318  ltit = ktitle;
319  }
320 
321  // Ready to draw the name, value and title columns
322  if (pass == 0)tname.DrawText( x1+0.1, ytext, &line[kname]);
323  if (pass == 1) {
324  if (tlink) {
325  tlink->SetTextFont(61);
326  tlink->SetTextAngle(0);
327  tlink->SetTextAlign(12);
328  tlink->SetTextColor(2);
329  tlink->SetTextSize(tsize);
330  tlink->SetBit(kCanDelete);
331  tlink->Draw();
332  if (strstr(member->GetFullTypeName(),"**")) tlink->SetBit(TLink::kIsStarStar);
333  tlink->SetName(member->GetTypeName());
334  } else {
335  tval->DrawText(xvalue+0.1, ytext, &line[kvalue]);
336  }
337  }
338  if (pass == 2 && ltit) ttitle.DrawText(xtitle+0.3, ytext, &line[ltit]);
339  ytext -= dy;
340  }
341  }
342  Update();
343  fCurObject = obj;
344 }
345 
346 ////////////////////////////////////////////////////////////////////////////////
347 /// static function , inspect previous object
348 
349 void TInspectCanvas::GoBackward()
350 {
351  TInspectCanvas *inspect = (TInspectCanvas*)(gROOT->GetListOfCanvases())->FindObject("inspect");
352  if (!inspect) return;
353  TObject *cur = inspect->GetCurObject();
354  TObject *obj = inspect->GetObjects()->Before(cur);
355  if (obj) inspect->InspectObject(obj);
356 }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// static function , inspect next object
360 
361 void TInspectCanvas::GoForward()
362 {
363  TInspectCanvas *inspect = (TInspectCanvas*)(gROOT->GetListOfCanvases())->FindObject("inspect");
364  if (!inspect) return;
365  TObject *cur = inspect->GetCurObject();
366  TObject *obj = inspect->GetObjects()->After(cur);
367  if (obj) inspect->InspectObject(obj);
368 }
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 /// static function , interface to InspectObject.
372 /// Create the InspectCanvas if it does not exist yet.
373 
374 void TInspectCanvas::Inspector(TObject *obj)
375 {
376  TVirtualPad *padsav = gPad;
377  TInspectCanvas *inspect = (TInspectCanvas*)(gROOT->GetListOfCanvases())->FindObject("inspect");
378  if (!inspect) inspect = new TInspectCanvas(700,600);
379  else inspect->cd();
380 
381  inspect->InspectObject(obj);
382  inspect->GetObjects()->Add(obj);
383  //obj->SetBit(kMustCleanup);
384 
385  if (padsav) padsav->cd();
386 }
387 
388 ////////////////////////////////////////////////////////////////////////////////
389 /// Recursively remove object from the list of objects.
390 
391 void TInspectCanvas::RecursiveRemove(TObject *obj)
392 {
393  fObjects->Remove(obj);
394  TPad::RecursiveRemove(obj);
395 }