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

Last change on this file since 9565 was 9532, checked in by tbretz, 15 years ago
*** empty log message ***
File size: 15.6 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-2009
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
59#include <TGraph.h>
60
61using namespace std;
62
63// --------------------------------------------------------------------------
64//
65// Initialize the MStatusArray from an MStatusDisplay. Note, the contents
66// still owned by MStatusDisplay and will vanish if the display changes
67// or is deleted without further notice.
68//
69MStatusArray::MStatusArray(const MStatusDisplay &d) : TObjArray()
70{
71 d.FillArray(*this);
72}
73
74// --------------------------------------------------------------------------
75//
76// Remove objects matching the id (the first character of their class
77// name) recuresively
78//
79void MStatusArray::RecursiveDelete(TVirtualPad *p, const char id) const
80{
81 if (!p)
82 return;
83
84 TIter Next2(p->GetListOfPrimitives());
85 TObject *o=0;
86 while ((o=Next2()))
87 {
88 if (!dynamic_cast<TVirtualPad*>(o) && (o->ClassName()[0]==id || id==0))
89 {
90 while (p->GetListOfPrimitives()->Remove(o));
91 delete o;
92
93 continue;
94 }
95
96 RecursiveDelete(dynamic_cast<TVirtualPad*>(o), id);
97 }
98
99}
100
101// --------------------------------------------------------------------------
102//
103// Make sure to set the kMustCleanup for all object in our tree
104// which will later be deleted when the array is destructed.
105//
106void MStatusArray::SetCleanup(TObject *obj) const
107{
108 if (!obj)
109 return;
110
111 TVirtualPad *pad = dynamic_cast<TVirtualPad*>(obj);
112
113 // Do not set the bit for pads because it would end in
114 // endless recursions
115 if (pad && !dynamic_cast<TCanvas*>(obj))
116 obj->ResetBit(kMustCleanup);
117 else
118 obj->SetBit(kMustCleanup);
119
120 if (!pad)
121 return;
122
123 TIter Next(pad->GetListOfPrimitives());
124 TObject *o=0;
125 while ((o=Next()))
126 SetCleanup(o);
127}
128
129// --------------------------------------------------------------------------
130//
131// This is a workaround to make sure that TH1 which are part of two TGraphs
132// (TGraph::GetHistogram) are not finally deleted twice. Unfortunately,
133// TGraph doesn't have it in RecursiveRemove.
134//
135void MStatusArray::RecursiveRemove(TVirtualPad *p, TObject *obj)
136{
137 if (!p)
138 return;
139
140 TIter Next(p->GetListOfPrimitives());
141 TObject *o=0;
142 while ((o=Next()))
143 {
144 if (dynamic_cast<TGraph*>(o))
145 {
146 TGraph *g = static_cast<TGraph*>(o);
147 if (g->GetHistogram()==obj)
148 g->SetHistogram(0);
149
150 continue;
151 }
152
153 RecursiveRemove(dynamic_cast<TVirtualPad*>(o), obj);
154 }
155
156}
157
158// --------------------------------------------------------------------------
159//
160// This is a workaround to make sure that TH1 which are part of two TGraphs
161// (TGraph::GetHistogram) are not finally deleted twice. Unfortunately,
162// TGraph doesn't have it in RecursiveRemove.
163//
164void MStatusArray::RecursiveRemove(TObject *obj)
165{
166 TObjArray::RecursiveRemove(obj);
167
168 TObject *o = 0;
169
170 TIter Next(this);
171 while ((o=Next()))
172 RecursiveRemove(dynamic_cast<TVirtualPad*>(o), obj);
173}
174
175// --------------------------------------------------------------------------
176//
177// Try to do a delete of the whole list in a way which is less vulnarable
178// to double deletion due to wrongly set bits or other things
179//
180void MStatusArray::Delete(Option_t *)
181{
182 // Add this to the list of cleanups to ensure as many cleaning
183 // operations as possible are propagated
184 gROOT->GetListOfCleanups()->Add(this);
185
186 // First make sure that all kMustCleanup bits are se
187 TIter Next(this);
188 TObject *o=0;
189 while ((o=Next()))
190 SetCleanup(o);
191
192 // Now delete the MARS object first because we have full control
193 // of them
194 TIter Next2(this);
195 while ((o=Next2()))
196 RecursiveDelete(dynamic_cast<TVirtualPad*>(o), 'M');
197
198 // Now delete all root objects
199 TIter Next3(this);
200 while ((o=Next3()))
201 RecursiveDelete(dynamic_cast<TVirtualPad*>(o));
202
203 // And delete all the rest
204 TObjArray::Delete();
205
206 // Remove it from the list again
207 gROOT->GetListOfCleanups()->Remove(this);
208}
209
210// --------------------------------------------------------------------------
211//
212// If o==NULL a new status display is created, otherwise the one with name o
213// is searched in gROOT->GetListOfSpecials().
214// In this display the contents of the MStatusArray is displayed.
215//
216TObject *MStatusArray::DisplayIn(Option_t *o) const
217{
218 MStatusDisplay *d = 0;
219 if (TString(o).IsNull())
220 d = new MStatusDisplay;
221
222 if (!d)
223 d = (MStatusDisplay*)gROOT->GetListOfSpecials()->FindObject(o);
224
225 if (!d)
226 return 0;
227
228 if (d->Display(*this))
229 return d;
230
231 delete d;
232 return 0;
233}
234
235// --------------------------------------------------------------------------
236//
237// Display the contents of the given tab in the display given as argument.
238//
239void MStatusArray::DisplayIn(MStatusDisplay &d, const char *tab) const
240{
241 d.Display(*this, tab);
242}
243
244TObject *MStatusArray::FindObjectInPad(TVirtualPad *pad, const char *object, TClass *cls) const
245{
246 TObject *o = NULL;//pad->FindObject(object);
247// if (o && o->InheritsFrom(cls))
248// return o;
249
250 TIter Next(pad->GetListOfPrimitives());
251 while ((o=Next()))
252 {
253 if (o->GetName()==(TString)object && o->InheritsFrom(cls))
254 return o;
255
256 if (o==pad || !o->InheritsFrom(TVirtualPad::Class()))
257 continue;
258
259 if ((o = FindObjectInPad((TVirtualPad*)o, object, cls)))
260 return o;
261// if (o->InheritsFrom(cls))
262// return o;
263 }
264 return 0;
265}
266
267TCanvas *MStatusArray::FindCanvas(const char *name) const
268{
269 TObject *o = TObjArray::FindObject(name);
270 if (!o)
271 return 0;
272
273 return o->InheritsFrom(TCanvas::Class()) ? (TCanvas*)o : 0;
274}
275
276
277TObject *MStatusArray::FindObjectInCanvas(const char *object, const char *base, const char *canvas) const
278{
279 gLog << err;
280 TClass *cls = MParContainer::GetClass(base, &gLog);
281 if (!cls)
282 return 0;
283
284 TCanvas *c = canvas ? FindCanvas(canvas) : 0;
285 if (canvas)
286 {
287 if (!c)
288 {
289 gLog << warn << "Canvas '" << canvas << "' not found..." << endl;
290 return 0;
291 }
292
293 TObject *o = FindObjectInPad(c, object, cls);
294 if (!o)
295 {
296 gLog << warn << "Object '" << object << "' [" << base << "] not found in canvas '" << canvas << "'..." << endl;
297 return 0;
298 }
299
300 return o; //o->InheritsFrom(cls) ? o : 0;
301 }
302
303 TObject *o=0;
304 TIter Next(this);
305 while ((o=Next()))
306 {
307 if (!o->InheritsFrom(TVirtualPad::Class()))
308 continue;
309
310 if ((o=FindObjectInPad((TVirtualPad*)c, object, cls)))
311 return o;
312 }
313
314 gLog << warn << "Object '" << object << "' [" << base << "] not found in canvas '" << canvas << "'..." << endl;
315 return NULL;
316}
317
318TObject *MStatusArray::FindObjectInCanvas(const char *object, const char *canvas) const
319{
320 return FindObjectInCanvas(object, object, canvas);
321}
322
323TObject *MStatusArray::FindObject(const char *object, const char *base) const
324{
325 return FindObjectInCanvas(object, base, 0);
326}
327
328TObject *MStatusArray::FindObject(const char *object) const
329{
330 return FindObjectInCanvas(object, object, 0);
331}
332
333// --------------------------------------------------------------------------
334//
335// Print recursively all objects in this and sub-pads
336//
337void MStatusArray::PrintObjectsInPad(const TCollection *list, const TString &name, Int_t lvl) const
338{
339 TIter Next(list);
340 TObject *o=0;
341 while ((o=Next()))
342 {
343 const Bool_t print = name.IsNull() || name==(TString)o->GetName();
344 if (print)
345 {
346 if (lvl>0)
347 gLog << setw(lvl) << ' ';
348 gLog << " " << o->ClassName() << ": " << o->GetName() << " <" << Next.GetOption() << "> (" << o << ") " << (int)o->TestBit(kCanDelete) << endl;
349 }
350
351 if (o->InheritsFrom(TVirtualPad::Class()))
352 PrintObjectsInPad(((TVirtualPad*)o)->GetListOfPrimitives(), print?TString():name, lvl+1);
353 }
354}
355
356// --------------------------------------------------------------------------
357//
358// Print recursively all objects in this and sub-pads. If !option.IsNull()
359// only objects in the corresponding pad are printed.
360//
361void MStatusArray::Print(Option_t *option) const
362{
363 gLog << all;
364
365 PrintObjectsInPad(this, TString(option));
366}
367
368/*
369// --------------------------------------------------------------------------
370//
371// Make sure that kCanDelete is properly set for all directly contained
372// objects. Some kCanDelete bits might not be properly set or get lost when
373// the MParContainer is stored.
374//
375void MStatusArray::SetCanDelete(const TCollection *list) const
376{
377 TIter Next(list);
378 TObject *o=0;
379 while ((o=Next()))
380 {
381 if (o->InheritsFrom(TVirtualPad::Class()))
382 SetCanDelete(((TVirtualPad*)o)->GetListOfPrimitives());
383 else
384 o->SetBit(kCanDelete|kMustCleanup);
385 }
386}
387*/
388
389// --------------------------------------------------------------------------
390//
391// Set kCanDelete for all objects for which kMyCanDelete is set. This
392// is a STUPID workaruond for an ANNOYING root bug which is that
393// the streamer function of TH1 resets the KCanDelete bit after reading.
394//
395void MStatusArray::SetCanDelete(const TCollection *list) const
396{
397 TIter Next(list);
398 TObject *o=0;
399 while ((o=Next()))
400 {
401 if (o->InheritsFrom(TVirtualPad::Class()))
402 SetCanDelete(((TVirtualPad*)o)->GetListOfPrimitives());
403 else
404 {
405 if (o->TestBit(kMyCanDelete) && o->InheritsFrom("TH1"))
406 {
407 o->SetBit(kCanDelete);
408 o->ResetBit(kMyCanDelete);
409 }
410 }
411 }
412}
413
414void MStatusArray::EnableTH1Workaround(const TCollection *list) const
415{
416 TIter Next(list?list:this);
417 TObject *o=0;
418 while ((o=Next()))
419 {
420 if (o->InheritsFrom(TVirtualPad::Class()))
421 EnableTH1Workaround(((TVirtualPad*)o)->GetListOfPrimitives());
422 else
423 if (o->InheritsFrom("TH1"))
424 o->SetBit(kCanDelete);
425 }
426}
427
428// --------------------------------------------------------------------------
429//
430// Set kMyCanDelete for all objects for which kCanDelete is set. This
431// is a STUPID workaruond for an ANNOYING root bug which is that
432// the streamer function of TH1 resets the KCanDelete bit after reading.
433//
434void MStatusArray::SetMyCanDelete(const TCollection *list) const
435{
436 TIter Next(list);
437 TObject *o=0;
438 while ((o=Next()))
439 {
440 if (o->InheritsFrom(TVirtualPad::Class()))
441 SetMyCanDelete(((TVirtualPad*)o)->GetListOfPrimitives());
442 else
443 {
444 if (o->TestBit(kMyCanDelete) && o->InheritsFrom("TH1"))
445 gLog << warn << "WARNING - MStatusArray::Write - " << o->GetName() << " [" << o->ClassName() << "] has BIT(30) already set!" << endl;
446
447 if (o->TestBit(kCanDelete) && o->InheritsFrom("TH1"))
448 o->SetBit(kMyCanDelete);
449 }
450 }
451}
452
453// --------------------------------------------------------------------------
454//
455// Reset kMyCanDelete for all objects for which kMyCanDelete is set. This
456// is a STUPID workaruond for an ANNOYING root bug which is that
457// the streamer function of TH1 resets the KCanDelete bit after reading.
458//
459void MStatusArray::ResetMyCanDelete(const TCollection *list) const
460{
461 TIter Next(list);
462 TObject *o=0;
463 while ((o=Next()))
464 {
465 if (o->InheritsFrom(TVirtualPad::Class()))
466 ResetMyCanDelete(((TVirtualPad*)o)->GetListOfPrimitives());
467 else
468 {
469 if (o->TestBit(kMyCanDelete) && o->InheritsFrom("TH1"))
470 o->ResetBit(kMyCanDelete);
471 }
472 }
473}
474
475MStatusArray::~MStatusArray()
476{
477 // This is the destructor from TObjArray...
478 // It must be here, because for some reason I don't know it
479 // is otherwise not correctly executed from the Interpreter
480 // (root 5.12/00f)
481 if (IsOwner())
482 Delete();
483
484 TStorage::Dealloc(fCont);
485
486 fCont = 0;
487 fSize = 0;
488}
489
490// --------------------------------------------------------------------------
491//
492// Switch off adding histograms to current directory before reading.
493// Switch back
494//
495Int_t MStatusArray::Read(const char *name)
496{
497 // It seems that the contents are not properly deleted by TObjArray::Read
498 Delete();
499
500 SetOwner();
501
502 const TString keyname = name?name:"MStatusDisplay";
503
504 // Check if key exists (to suppress an error on the console
505 if (!gDirectory->GetListOfKeys()->FindObject(keyname))
506 {
507 gLog << inf << keyname << " [MStatusArray] not found." << endl;
508 return 0;
509 }
510
511 // Make sure newly read histograms are not added to the current directory
512 const Bool_t store = TH1::AddDirectoryStatus();
513 TH1::AddDirectory(kFALSE);
514 const Int_t rc = TObjArray::Read(keyname);
515 TH1::AddDirectory(store);
516
517 // All objects in the list (TNamed, TCanvas, etc) do not have
518 // the kCanDelete bit set. Make sure that it is set to make
519 // them deleted by the destructor of this list
520 TIter Next(this);
521 TObject *o=0;
522 while ((o=Next()))
523 {
524 if (o->InheritsFrom(TVirtualPad::Class()))
525 {
526 TIter Next2(((TVirtualPad*)o)->GetListOfPrimitives());
527 TObject *o2=0;
528 while ((o2=Next2()))
529 if (o2->InheritsFrom(MParContainer::Class()))
530 o2->SetBit(kCanDelete);
531 }
532 o->SetBit(kCanDelete);
533 }
534
535 // Make sure that all kCanDelete bits are properly set
536 SetCanDelete(this);
537 SetOwner();
538
539 return rc;
540}
541
542// --------------------------------------------------------------------------
543//
544// Switch off adding histograms to current directory before reading.
545// Switch back
546//
547Int_t MStatusArray::Write(const char *name, Int_t option, Int_t bufsize) const
548{
549 SetMyCanDelete(this);
550 const Int_t rc = TObjArray::Write(name, option, bufsize);
551 ResetMyCanDelete(this);
552
553 return rc;
554}
Note: See TracBrowser for help on using the repository browser.