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

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