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

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