source: trunk/MagicSoft/Mars/mbase/MStatusArray.cc@ 9531

Last change on this file since 9531 was 9519, checked in by tbretz, 15 years ago
*** empty log message ***
File size: 14.3 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 03/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2004
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MStatusArray
28//
29// Helper class for MStatusDisplay
30//
31// If you want to read a MStatusArray (normally with name MStatusDisplay)
32// it is recommended to do it like this:
33// TFile f("myfile.root", "read");
34// MStatusArray arr;
35// arr.Read();
36//
37// If you want to use TFile::Get or TFile::GetObject you should switch off
38// addding Histograms automatically to the current directory first:
39// TFile f("myfile.root", "read");
40// TH1::AddDirectory(kFALSE);
41// f.Get("MStatusDisplay");
42//
43//////////////////////////////////////////////////////////////////////////////
44#include "MStatusArray.h"
45
46#include <TH1.h> // TH1::AddDirectoryStatus();
47#include <TFile.h> // gFile
48#include <TClass.h>
49#include <TCanvas.h>
50
51#include "MLog.h"
52#include "MLogManip.h"
53
54#include "MParContainer.h" // MParContainer::GetClass
55#include "MStatusDisplay.h"
56
57ClassImp(MStatusArray);
58
59using namespace std;
60
61// --------------------------------------------------------------------------
62//
63// Initialize the MStatusArray from an MStatusDisplay. Note, the contents
64// still owned by MStatusDisplay and will vanish if the display changes
65// or is deleted without further notice.
66//
67MStatusArray::MStatusArray(const MStatusDisplay &d) : TObjArray()
68{
69 d.FillArray(*this);
70}
71
72// --------------------------------------------------------------------------
73//
74// Remove objects matching the id (the first character of their class
75// name) recuresively
76//
77void MStatusArray::RecursiveDelete(TVirtualPad *p, const char id) const
78{
79 if (!p)
80 return;
81
82 TIter Next2(p->GetListOfPrimitives());
83 TObject *o=0;
84 while ((o=Next2()))
85 {
86 if (!dynamic_cast<TVirtualPad*>(o) && (o->ClassName()[0]==id || id==0))
87 delete p->GetListOfPrimitives()->Remove(o);
88 else
89 RecursiveDelete(dynamic_cast<TVirtualPad*>(o), id);
90 }
91
92}
93
94// --------------------------------------------------------------------------
95//
96// Make sure to set the kMustCleanup for all object in our tree
97// which will later be deleted when the array is destructed.
98//
99void MStatusArray::SetCleanup(TObject *obj) const
100{
101 if (!obj)
102 return;
103
104 TVirtualPad *pad = dynamic_cast<TVirtualPad*>(obj);
105
106 // Do not set the bit for pads because it would end in
107 // endless recursions
108 if (pad && !dynamic_cast<TCanvas*>(obj))
109 obj->ResetBit(kMustCleanup);
110 else
111 obj->SetBit(kMustCleanup);
112
113 if (!pad)
114 return;
115
116 TIter Next(pad->GetListOfPrimitives());
117 TObject *o=0;
118 while ((o=Next()))
119 SetCleanup(o);
120}
121
122// --------------------------------------------------------------------------
123//
124// Try to do a delete of the whole list in a way which is less vulnarable
125// to double deletion due to wrongly set bits or other things
126//
127void MStatusArray::Delete(Option_t *)
128{
129 // Add this to the list of cleanups to ensure as many cleaning
130 // operations as possible are propagated
131 gROOT->GetListOfCleanups()->Add(this);
132
133 // First make sure that all kMustCleanup bits are se
134 TIter Next(this);
135 TObject *o=0;
136 while ((o=Next()))
137 SetCleanup(o);
138
139 // Now delete the MARS object first because we have full control
140 // of them
141 TIter Next2(this);
142 while ((o=Next2()))
143 RecursiveDelete(dynamic_cast<TVirtualPad*>(o), 'M');
144
145 // Now delete all root objects
146 TIter Next3(this);
147 while ((o=Next3()))
148 RecursiveDelete(dynamic_cast<TVirtualPad*>(o));
149
150 // And delete all the rest
151 TObjArray::Delete();
152
153 // Remove it from the list again
154 gROOT->GetListOfCleanups()->Remove(this);
155}
156
157// --------------------------------------------------------------------------
158//
159// If o==NULL a new status display is created, otherwise the one with name o
160// is searched in gROOT->GetListOfSpecials().
161// In this display the contents of the MStatusArray is displayed.
162//
163TObject *MStatusArray::DisplayIn(Option_t *o) const
164{
165 MStatusDisplay *d = 0;
166 if (TString(o).IsNull())
167 d = new MStatusDisplay;
168
169 if (!d)
170 d = (MStatusDisplay*)gROOT->GetListOfSpecials()->FindObject(o);
171
172 if (!d)
173 return 0;
174
175 if (d->Display(*this))
176 return d;
177
178 delete d;
179 return 0;
180}
181
182// --------------------------------------------------------------------------
183//
184// Display the contents of the given tab in the display given as argument.
185//
186void MStatusArray::DisplayIn(MStatusDisplay &d, const char *tab) const
187{
188 d.Display(*this, tab);
189}
190
191TObject *MStatusArray::FindObjectInPad(TVirtualPad *pad, const char *object, TClass *cls) const
192{
193 TObject *o = NULL;//pad->FindObject(object);
194// if (o && o->InheritsFrom(cls))
195// return o;
196
197 TIter Next(pad->GetListOfPrimitives());
198 while ((o=Next()))
199 {
200 if (o->GetName()==(TString)object && o->InheritsFrom(cls))
201 return o;
202
203 if (o==pad || !o->InheritsFrom(TVirtualPad::Class()))
204 continue;
205
206 if ((o = FindObjectInPad((TVirtualPad*)o, object, cls)))
207 return o;
208// if (o->InheritsFrom(cls))
209// return o;
210 }
211 return 0;
212}
213
214TCanvas *MStatusArray::FindCanvas(const char *name) const
215{
216 TObject *o = TObjArray::FindObject(name);
217 if (!o)
218 return 0;
219
220 return o->InheritsFrom(TCanvas::Class()) ? (TCanvas*)o : 0;
221}
222
223
224TObject *MStatusArray::FindObjectInCanvas(const char *object, const char *base, const char *canvas) const
225{
226 gLog << err;
227 TClass *cls = MParContainer::GetClass(base, &gLog);
228 if (!cls)
229 return 0;
230
231 TCanvas *c = canvas ? FindCanvas(canvas) : 0;
232 if (canvas)
233 {
234 if (!c)
235 {
236 gLog << warn << "Canvas '" << canvas << "' not found..." << endl;
237 return 0;
238 }
239
240 TObject *o = FindObjectInPad(c, object, cls);
241 if (!o)
242 {
243 gLog << warn << "Object '" << object << "' [" << base << "] not found in canvas '" << canvas << "'..." << endl;
244 return 0;
245 }
246
247 return o; //o->InheritsFrom(cls) ? o : 0;
248 }
249
250 TObject *o=0;
251 TIter Next(this);
252 while ((o=Next()))
253 {
254 if (!o->InheritsFrom(TVirtualPad::Class()))
255 continue;
256
257 if ((o=FindObjectInPad((TVirtualPad*)c, object, cls)))
258 return o;
259 }
260
261 gLog << warn << "Object '" << object << "' [" << base << "] not found in canvas '" << canvas << "'..." << endl;
262 return NULL;
263}
264
265TObject *MStatusArray::FindObjectInCanvas(const char *object, const char *canvas) const
266{
267 return FindObjectInCanvas(object, object, canvas);
268}
269
270TObject *MStatusArray::FindObject(const char *object, const char *base) const
271{
272 return FindObjectInCanvas(object, base, 0);
273}
274
275TObject *MStatusArray::FindObject(const char *object) const
276{
277 return FindObjectInCanvas(object, object, 0);
278}
279
280// --------------------------------------------------------------------------
281//
282// Print recursively all objects in this and sub-pads
283//
284void MStatusArray::PrintObjectsInPad(const TCollection *list, const TString &name, Int_t lvl) const
285{
286 TIter Next(list);
287 TObject *o=0;
288 while ((o=Next()))
289 {
290 const Bool_t print = name.IsNull() || name==(TString)o->GetName();
291 if (print)
292 {
293 if (lvl>0)
294 gLog << setw(lvl) << ' ';
295 gLog << " " << o->ClassName() << ": " << o->GetName() << " <" << Next.GetOption() << "> (" << o << ") " << (int)o->TestBit(kCanDelete) << endl;
296 }
297
298 if (o->InheritsFrom(TVirtualPad::Class()))
299 PrintObjectsInPad(((TVirtualPad*)o)->GetListOfPrimitives(), print?TString():name, lvl+1);
300 }
301}
302
303// --------------------------------------------------------------------------
304//
305// Print recursively all objects in this and sub-pads. If !option.IsNull()
306// only objects in the corresponding pad are printed.
307//
308void MStatusArray::Print(Option_t *option) const
309{
310 gLog << all;
311
312 PrintObjectsInPad(this, TString(option));
313}
314
315/*
316// --------------------------------------------------------------------------
317//
318// Make sure that kCanDelete is properly set for all directly contained
319// objects. Some kCanDelete bits might not be properly set or get lost when
320// the MParContainer is stored.
321//
322void MStatusArray::SetCanDelete(const TCollection *list) const
323{
324 TIter Next(list);
325 TObject *o=0;
326 while ((o=Next()))
327 {
328 if (o->InheritsFrom(TVirtualPad::Class()))
329 SetCanDelete(((TVirtualPad*)o)->GetListOfPrimitives());
330 else
331 o->SetBit(kCanDelete|kMustCleanup);
332 }
333}
334*/
335
336// --------------------------------------------------------------------------
337//
338// Set kCanDelete for all objects for which kMyCanDelete is set. This
339// is a STUPID workaruond for an ANNOYING root bug which is that
340// the streamer function of TH1 resets the KCanDelete bit after reading.
341//
342void MStatusArray::SetCanDelete(const TCollection *list) const
343{
344 TIter Next(list);
345 TObject *o=0;
346 while ((o=Next()))
347 {
348 if (o->InheritsFrom(TVirtualPad::Class()))
349 SetCanDelete(((TVirtualPad*)o)->GetListOfPrimitives());
350 else
351 {
352 if (o->TestBit(kMyCanDelete) && o->InheritsFrom("TH1"))
353 {
354 o->SetBit(kCanDelete);
355 o->ResetBit(kMyCanDelete);
356 }
357 }
358 }
359}
360
361void MStatusArray::EnableTH1Workaround(const TCollection *list) const
362{
363 TIter Next(list?list:this);
364 TObject *o=0;
365 while ((o=Next()))
366 {
367 if (o->InheritsFrom(TVirtualPad::Class()))
368 EnableTH1Workaround(((TVirtualPad*)o)->GetListOfPrimitives());
369 else
370 if (o->InheritsFrom("TH1"))
371 o->SetBit(kCanDelete);
372 }
373}
374
375// --------------------------------------------------------------------------
376//
377// Set kMyCanDelete for all objects for which kCanDelete is set. This
378// is a STUPID workaruond for an ANNOYING root bug which is that
379// the streamer function of TH1 resets the KCanDelete bit after reading.
380//
381void MStatusArray::SetMyCanDelete(const TCollection *list) const
382{
383 TIter Next(list);
384 TObject *o=0;
385 while ((o=Next()))
386 {
387 if (o->InheritsFrom(TVirtualPad::Class()))
388 SetMyCanDelete(((TVirtualPad*)o)->GetListOfPrimitives());
389 else
390 {
391 if (o->TestBit(kMyCanDelete) && o->InheritsFrom("TH1"))
392 gLog << warn << "WARNING - MStatusArray::Write - " << o->GetName() << " [" << o->ClassName() << "] has BIT(30) already set!" << endl;
393
394 if (o->TestBit(kCanDelete) && o->InheritsFrom("TH1"))
395 o->SetBit(kMyCanDelete);
396 }
397 }
398}
399
400// --------------------------------------------------------------------------
401//
402// Reset kMyCanDelete for all objects for which kMyCanDelete is set. This
403// is a STUPID workaruond for an ANNOYING root bug which is that
404// the streamer function of TH1 resets the KCanDelete bit after reading.
405//
406void MStatusArray::ResetMyCanDelete(const TCollection *list) const
407{
408 TIter Next(list);
409 TObject *o=0;
410 while ((o=Next()))
411 {
412 if (o->InheritsFrom(TVirtualPad::Class()))
413 ResetMyCanDelete(((TVirtualPad*)o)->GetListOfPrimitives());
414 else
415 {
416 if (o->TestBit(kMyCanDelete) && o->InheritsFrom("TH1"))
417 o->ResetBit(kMyCanDelete);
418 }
419 }
420}
421
422MStatusArray::~MStatusArray()
423{
424 // This is the destructor from TObjArray...
425 // It must be here, because for some reason I don't know it
426 // is otherwise not correctly executed from the Interpreter
427 // (root 5.12/00f)
428 if (IsOwner())
429 Delete();
430
431 TStorage::Dealloc(fCont);
432
433 fCont = 0;
434 fSize = 0;
435}
436
437// --------------------------------------------------------------------------
438//
439// Switch off adding histograms to current directory before reading.
440// Switch back
441//
442Int_t MStatusArray::Read(const char *name)
443{
444 // It seems that the contents are not properly deleted by TObjArray::Read
445 Delete();
446
447 SetOwner();
448
449 const TString keyname = name?name:"MStatusDisplay";
450
451 // Check if key exists (to suppress an error on the console
452 if (!gDirectory->GetListOfKeys()->FindObject(keyname))
453 {
454 gLog << inf << keyname << " [MStatusArray] not found." << endl;
455 return 0;
456 }
457
458 // Make sure newly read histograms are not added to the current directory
459 const Bool_t store = TH1::AddDirectoryStatus();
460 TH1::AddDirectory(kFALSE);
461 const Int_t rc = TObjArray::Read(keyname);
462 TH1::AddDirectory(store);
463
464 // All objects in the list (TNamed, TCanvas, etc) do not have
465 // the kCanDelete bit set. Make sure that it is set to make
466 // them deleted by the destructor of this list
467 TIter Next(this);
468 TObject *o=0;
469 while ((o=Next()))
470 {
471 if (o->InheritsFrom(TVirtualPad::Class()))
472 {
473 TIter Next2(((TVirtualPad*)o)->GetListOfPrimitives());
474 TObject *o2=0;
475 while ((o2=Next2()))
476 if (o2->InheritsFrom(MParContainer::Class()))
477 o2->SetBit(kCanDelete);
478 }
479 o->SetBit(kCanDelete);
480 }
481
482 // Make sure that all kCanDelete bits are properly set
483 SetCanDelete(this);
484 SetOwner();
485
486 return rc;
487}
488
489// --------------------------------------------------------------------------
490//
491// Switch off adding histograms to current directory before reading.
492// Switch back
493//
494Int_t MStatusArray::Write(const char *name, Int_t option, Int_t bufsize) const
495{
496 SetMyCanDelete(this);
497 const Int_t rc = TObjArray::Write(name, option, bufsize);
498 ResetMyCanDelete(this);
499
500 return rc;
501}
Note: See TracBrowser for help on using the repository browser.