Fix coverity defect
[u/mrichter/AliRoot.git] / MUON / AliMUONVPainter.cxx
1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 *                                                                        *
4 * Author: The ALICE Off-line Project.                                    *
5 * Contributors are mentioned in the code where appropriate.              *
6 *                                                                        *
7 * Permission to use, copy, modify and distribute this software and its   *
8 * documentation strictly for non-commercial purposes is hereby granted   *
9 * without fee, provided that the above copyright notice appears in all   *
10 * copies and that both the copyright notice and this permission notice   *
11 * appear in the supporting documentation. The authors make no claims     *
12 * about the suitability of this software for any purpose. It is          *
13 * provided "as is" without express or implied warranty.                  *
14 **************************************************************************/
15
16 // $Id$
17
18 #include "AliMUONVPainter.h"
19
20 #include "AliLog.h"
21 #include "AliMUON2DMap.h"
22 #include "AliMUONCalibParamND.h"
23 #include "AliMUONContour.h"
24 #include "AliMUONContourPainter.h"
25 #include "AliMUONObjectPair.h"
26 #include "AliMUONPainterGroup.h"
27 #include "AliMUONPainterHelper.h"
28 #include "AliMUONPainterDataRegistry.h"
29 #include "AliMUONTrackerDataHistogrammer.h"
30 #include "AliMUONVTrackerData.h"
31 #include "AliMpManuUID.h"
32 #include <Riostream.h>
33 #include <TCanvas.h>
34 #include <TClass.h>
35 #include <TClassMenuItem.h>
36 #include <TH1.h>
37 #include <TList.h>
38 #include <TMap.h>
39 #include <TMath.h>
40 #include <TMethodCall.h>
41 #include <TObjArray.h>
42 #include <TObjString.h>
43 #include <TROOT.h>
44 #include <TVirtualPad.h>
45 #include <cassert>
46 #include <float.h>
47
48 /// \class AliMUONVPainter
49 ///
50 /// Base class for a graphical object representing some part of the
51 /// MUON tracking system.
52 /// 
53 /// A painter is a graphical representation of some part (e.g. detection element,
54 /// full chamber, one manu, etc...) of the MUON tracking system.
55 ///
56 /// A painter is a double fold hierarchical structure. 
57 ///
58 /// First, a painter is part of a tree (mother->childrens), that describe
59 /// the natural organization of the spectrometer. For instance, a chamber
60 /// painter has children that are the detection element, the detection elements
61 /// themselves contain manus, which in turn contain channels.
62 ///
63 /// Second, a painter contains a number of "painter groups" (see AliMUONPainterGroup). 
64 /// A group gather all the painters of the same type, 
65 /// where the type is a string identifying which part of system we're dealing
66 /// with (chamber, DE, manu, etc...)
67 ///
68 /// The groups are there to ease the manipulation of similar painters, e.g. if
69 /// we want to hide all detection elements, we hide the "detection element group"
70 /// Some special groups are the responder and the plotter groups. The responder
71 /// group is the group which is currently responding to mouse events. 
72 /// The plotter group is the group which is supposed to represent some data.
73 /// 
74 /// There are two ways to represent the painter on screen. In any case, we can
75 /// outline the painter (i.e. draw its borders) (see AliMUONVPainter::PaintOutline).
76 /// In the cases where the painter is attached to some data source (i.e. it is
77 /// used to represent some data about its type, e.g. the mean charge on some manu),
78 /// we can draw the full area of the contour, using some color (see
79 /// AliMUONVPainter::PaintArea).
80 ///
81 /// Note that you can outline several types of painters (aka groups) at the same
82 /// time, but you cannot plot several groups at the same time.
83 ///
84 /// Painters are TQObject so they can emit signals.
85 ///
86 /// Currently emitted signal are : 
87 ///
88 /// void Clicked(AliMUONVPainter* painter, Double_t*);
89 /// DoubleClicked(AliMUONVPainter* painter, Double_t*);
90 ///
91 /// to know which and where a painter was (double-) clicked.
92 ///
93 /// \author Laurent Aphecetche, Subatech
94
95 ///\cond CLASSIMP
96 ClassImp(AliMUONVPainter)
97 ///\endcond
98
99 //_____________________________________________________________________________
100 AliMUONVPainter::AliMUONVPainter(TRootIOCtor*) : TObject(), 
101 TQObject(),
102 fHistogram(0x0),
103 fPainterGroups(0x0),
104 fResponderGroup(0x0),
105 fName(""),
106 fPathName(""),
107 fType(""),
108 fMother(0x0),
109 fGroup(0x0),
110 fContour(0x0),
111 fChildren(0x0),
112 fPlotterGroup(0x0),
113 fBorderFactor(1.1),
114 fPad(0x0),
115 fAttributes(),
116 fLineColor(1),
117 fLineWidth(1),
118 fIsValid(kTRUE)
119 {
120   /// streamer ctor
121   SetID(-1,-1);
122 }
123
124 //_____________________________________________________________________________
125 AliMUONVPainter::AliMUONVPainter(const char* type)
126 : TObject(), 
127   TQObject(),
128   fHistogram(0x0),
129   fPainterGroups(0x0),
130   fResponderGroup(0x0),
131   fName(""),
132   fPathName(""),
133   fType(type),
134   fMother(0x0),
135   fGroup(0x0),
136   fContour(0x0),
137   fChildren(0x0),
138   fPlotterGroup(0x0),
139   fBorderFactor(1.1),
140   fPad(0x0),
141   fAttributes(),
142   fLineColor(1),
143   fLineWidth(1),
144   fIsValid(kTRUE)
145 {
146     /// ctor
147     SetID(-1,-1);
148 }
149
150 //_____________________________________________________________________________
151 AliMUONVPainter::AliMUONVPainter(const AliMUONVPainter& rhs)
152 : TObject(rhs),
153 TQObject(),
154 fHistogram(0x0),
155 fPainterGroups(0x0),
156 fResponderGroup(0x0),
157 fName(""),
158 fPathName(""),
159 fType(""),
160 fMother(0x0),
161 fGroup(0x0),
162 fContour(0x0),
163 fChildren(0x0),
164 fPlotterGroup(0x0),
165 fBorderFactor(1.0),
166 fPad(0x0),
167 fAttributes(),
168 fLineColor(-1),
169 fLineWidth(-1),
170 fIsValid(kTRUE)
171 {
172   /// copy ctor
173   rhs.Copy(*this);
174 }
175
176 //_____________________________________________________________________________
177 AliMUONVPainter& 
178 AliMUONVPainter::operator=(const AliMUONVPainter& rhs)
179 {
180   /// assignment operator
181   if ( this != &rhs ) 
182   {
183     rhs.Copy(*this);
184   }
185   return *this;
186 }
187
188 //_____________________________________________________________________________
189 AliMUONVPainter::~AliMUONVPainter()
190 {
191   /// dtor
192   delete fChildren;
193   delete fHistogram;
194 }
195
196 //_____________________________________________________________________________
197 AliMpArea
198 AliMUONVPainter::Area() const
199 {
200   /// Return the area covered by this painter
201   if ( fContour ) 
202   {
203     return fContour->Area();
204   }
205   else
206   {
207     AliWarning("Returning an invalid area, as contour is not defined");
208     return AliMpArea();
209   }
210 }
211
212 //_____________________________________________________________________________
213 void
214 AliMUONVPainter::Add(AliMUONVPainter* painter)
215 {
216   /// Add a child painter
217   if (!fChildren) fChildren = new TObjArray;
218   assert(painter->Mother()==0x0);
219   fChildren->Add(painter);
220   painter->SetMother(this);
221 }
222
223 //_____________________________________________________________________________
224 TCollection*
225 AliMUONVPainter::Children() const
226 {
227   /// Return the list of childrens
228   return fChildren;
229 }
230
231 //_____________________________________________________________________________
232 void
233 AliMUONVPainter::Clicked(AliMUONVPainter* painter, Double_t* values)
234 {
235   /// Let our mother emit the signal as clients are probably connected to
236   /// our (grand)mother, not to us
237
238   if ( Mother() ) 
239   {
240     Mother()->Clicked(painter,values);
241   }
242   else
243   {
244     Long_t param[] = { (Long_t)painter,(Long_t)values };
245   
246     Emit("Clicked(AliMUONVPainter*,Double_t*)",param);
247   }
248 }
249
250 //_____________________________________________________________________________
251 void
252 AliMUONVPainter::ShiftClicked(AliMUONVPainter* painter, Double_t* values)
253 {
254   /// Let our mother emit the signal as clients are probably connected to
255   /// our (grand)mother, not to us
256   
257   if ( Mother() ) 
258   {
259     Mother()->ShiftClicked(painter,values);
260   }
261   else
262   {
263     Long_t param[] = { (Long_t)painter,(Long_t)values };
264     
265     Emit("ShiftClicked(AliMUONVPainter*,Double_t*)",param);
266   }
267 }
268
269 //_____________________________________________________________________________
270 void
271 AliMUONVPainter::ComputeDataRange(const AliMUONVTrackerData&, Int_t,
272                                   Double_t&, Double_t&) const
273 {
274   /// Should compute the min and max of a given data source
275   AliError("Not implemented. Please fixe me");
276 }
277
278 //_____________________________________________________________________________
279 TString
280 AliMUONVPainter::ContourName() const
281 {
282   /// Default implementation of the contour name.
283   
284   TString name(PathName());
285
286   name += "-";
287   name += fAttributes.Name();
288   
289   return name;
290 }
291
292 //_____________________________________________________________________________
293 void
294 AliMUONVPainter::Copy(TObject& object) const
295 {
296   /// Copy this to object.
297   
298   TObject::Copy(object);
299
300   AliMUONVPainter& painter = static_cast<AliMUONVPainter&>(object);
301
302   painter.fType = fType;
303   painter.fName = fName;
304   painter.fPathName = fPathName;
305   
306   painter.fMother = 0x0;
307   painter.fContour = fContour;
308   
309   painter.fGroup = 0x0;
310   painter.fResponderGroup = 0x0;
311   painter.fPlotterGroup = 0x0;
312   
313   painter.fBorderFactor = fBorderFactor;
314
315   painter.fAttributes = fAttributes;
316   
317   painter.fAttributes.SetCathodeAndPlaneDisabled(kFALSE);
318   
319   painter.fPad = fPad;
320   
321   painter.fLineColor = fLineColor;
322   painter.fLineWidth = fLineWidth;
323   
324   painter.fIsValid = fIsValid;
325   
326   delete painter.fChildren;
327   painter.fChildren = 0x0;
328   
329   painter.fID[0] = fID[0];
330   painter.fID[1] = fID[1];
331   
332   delete painter.fHistogram;
333   painter.fHistogram = 0x0;
334   
335   TIter next(fChildren);
336   AliMUONVPainter* p;
337   
338   while ( ( p = static_cast<AliMUONVPainter*>(next()) ) )
339   {
340     painter.Add(static_cast<AliMUONVPainter*>(p->Clone()));
341   }
342     
343   painter.UpdateGroupsFrom(*this);
344   
345   object.ResetBit(kCanDelete);
346 }
347
348 //_____________________________________________________________________________
349 AliMUONPainterGroup*
350 AliMUONVPainter::CreateGroup(const char* type, Int_t depth)
351 {
352   /// Create a painter group at a given depth
353   
354   if (!fPainterGroups) fPainterGroups = new TMap;
355   TObject* o = fPainterGroups->GetValue(type);
356   if (o)
357   {
358     AliError(Form("Group %s is already there ! Check this",type));
359     return 0x0;
360   }
361   AliMUONPainterGroup* group = new AliMUONPainterGroup(type,depth);
362   fPainterGroups->Add(new TObjString(type),group);
363   return group;
364 }
365
366 //_____________________________________________________________________________
367 void
368 AliMUONVPainter::CreateGroups()
369 {
370   /// Groups our children into groups
371   
372   if ( Mother() ) 
373   {
374     AliFatal("Not supposed to create groups for a children");
375   }
376   
377   TList list;
378   FlatList(list);
379   
380   TIter next(&list);
381   AliMUONVPainter* painter;
382   
383   while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
384   {
385     AliMUONPainterGroup* group = Group(painter->Type());
386     if (!group) 
387     {
388       group = CreateGroup(painter->Type(),painter->Depth());
389     }
390     group->Add(painter);
391   }
392 }
393
394 //_____________________________________________________________________________
395 AliMUONVPainter*
396 AliMUONVPainter::Detach() const
397 {
398   /// Make this a new top painter (i.e. a master)
399   
400   AliDebug(1,Form("Detaching %s",GetName()));
401            
402   AliMUONVPainter* p = static_cast<AliMUONVPainter*>(Clone());
403   
404   AliMUONVPainter* master = Master();
405   
406   if ( master )
407   {
408     AliDebug(1,Form("UpdatingGroups of the detached painter %s from its master %s",
409                     p->GetName(),master->GetName()));
410     p->UpdateGroupsFrom(*master);
411   }
412   
413   return p;
414 }
415
416 //_____________________________________________________________________________
417 Int_t
418 AliMUONVPainter::Depth() const
419 {
420   /// Return our depth in the hierarchy
421   
422   if ( Mother() ) 
423   {
424     return Mother()->Depth() + 1;
425   }
426   else
427   {
428     return 0;
429   }
430 }
431
432 //_____________________________________________________________________________
433 Int_t   
434 AliMUONVPainter::DistancetoPrimitive(Int_t px, Int_t py)
435 {
436   /// See TObject::DistancetoPrimitive
437   
438   static const Int_t kBigValue = 999999;
439
440   if (!gPad) return kBigValue;
441   
442   Double_t x,y;
443   
444   AliMUONVPainter* painter = GetPainter(px,py,x,y);
445   
446   x=y=0.0; // to avoid compiler warning
447   
448   if ( painter == this) return 0;
449   
450   return kBigValue;
451 }
452
453 //_____________________________________________________________________________
454 void
455 AliMUONVPainter::DoubleClicked(AliMUONVPainter*, Double_t*)
456 {
457   /// Should emit the DoubleClicked signal (if I knew how to detect those events...)
458   
459   AliWarning("Please implement me !");
460
461   //  if ( fMother )
462 //  {
463 //    // let our top mother emit the signal as clients are probably connected to
464 //    // our mother, not to us
465 //    Top()->DoubleClicked(painter,values);
466 //  }
467 //  else
468 //  {
469 //    Long_t param[] = { (Long_t)painter,(Long_t)values };
470 //    
471 //    Emit("DoubleClicked(AliMUONVPainter*,Double_t*)",param);
472 //  }
473 }
474
475 //_____________________________________________________________________________
476 void
477 AliMUONVPainter::Draw(Option_t* opt)
478 {
479   /// Append ourselves to the current pad
480   
481   if (!gPad) 
482   {
483     gROOT->MakeDefCanvas();
484   }
485   
486   Bool_t kMustSetRange(kFALSE);
487  
488   TString sopt(opt);
489   sopt.ToUpper();
490  
491   if (sopt.Contains("R") ) kMustSetRange=kTRUE;
492   
493   if (kMustSetRange)
494   {
495     Double_t x1,y1,x2,y2;
496     GetBoundingBox(x1,y1,x2,y2);
497     if ( gPad) gPad->Range(x1,y1,x2,y2);
498   }
499  
500   if ( !fMother && !fPainterGroups ) 
501   {
502     CreateGroups();
503   }
504   
505   TIter next(fChildren);
506   AliMUONVPainter* painter;
507   while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
508   {
509     painter->Draw();
510   }  
511   
512   AppendPad(opt);
513   
514   fPad = gPad;
515 }
516
517 //_____________________________________________________________________________
518 void 
519 AliMUONVPainter::ExecuteEvent(Int_t event, Int_t px, Int_t py)
520 {
521   /// Handle graphics events
522   
523   Double_t x,y;
524     
525   AliMUONVPainter* painter = GetPainter(px,py,x,y);
526
527   if ( painter == this ) 
528   {
529     Double_t values[] = { x,y };
530   
531     switch (event)
532     {
533       case kButton2Up:
534         ShiftClicked(this,values);
535         break;
536       case kButton1Up:
537         Clicked(this,values);      
538         break;
539       case kButton1Double:
540         //the following statement is required against other loop executions before returning (depending on the time between the clicks) 
541         gPad->GetCanvas()->HandleInput((EEventType)-1,0,0); 
542         DoubleClicked(this,values);
543         break;
544     }
545   }
546 }
547
548 //_____________________________________________________________________________
549 void
550 AliMUONVPainter::FlatList(TList& list)
551 {
552   /// Make a flat list of our children (and ourselves)
553   
554   TIter next(fChildren);
555   AliMUONVPainter* painter;
556   while ( ( painter = static_cast<AliMUONVPainter*>(next())))
557   {
558     painter->FlatList(list);
559   }
560   
561   list.Add(this);
562 }
563
564 //_____________________________________________________________________________
565 void 
566 AliMUONVPainter::GetBoundingBox(Double_t& x1, Double_t& y1, 
567                                 Double_t& x2, Double_t& y2) const
568 {
569   /// Get the bounding box = our area
570   AliMpArea area(Area().GetPositionX(),
571                  Area().GetPositionY(),
572                  Area().GetDimensionX()*fBorderFactor,
573                  Area().GetDimensionY()*fBorderFactor);
574
575   x1 = area.LeftBorder();
576   y1 = area.DownBorder();
577   x2 = area.RightBorder();
578   y2 = area.UpBorder();
579 }
580
581 //_____________________________________________________________________________
582 char*   
583 AliMUONVPainter::GetObjectInfo(Int_t, Int_t) const
584 {
585   /// See TObject::GetObjectInfo
586   return const_cast<char*>(GetName());
587 }
588
589 //_____________________________________________________________________________
590 AliMUONVPainter* 
591 AliMUONVPainter::GetPainter(Int_t px, Int_t py, Double_t& x, Double_t& y) const
592 {
593   /// Get the responder painter at integer position (px,py), and get back its
594   /// absolute position (x,y)
595   
596   PixelToPad(px,py,x,y);
597   
598   if ( !IsInside(x,y) ) return 0x0;
599   
600   if ( fGroup->IsResponder() ) return const_cast<AliMUONVPainter*>(this);
601   
602   if (fChildren)
603   {
604     TIter next(fChildren);
605     AliMUONVPainter* painter;
606     
607     while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
608     {
609       AliMUONVPainter* p = painter->GetPainter(px,py,x,y);
610       if (p) return p;
611     }
612   }  
613   
614   return 0x0;
615 }
616
617 //_____________________________________________________________________________
618 void
619 AliMUONVPainter::GetTypes(TObjArray& types) const
620 {
621   /// Get the list of types (as a TObjArray of TObjString) 
622   /// of our hierarchy, sorted alphabetically
623   
624   types.SetOwner(kTRUE);
625   types.Clear();
626
627   TObjArray tmp;
628   tmp.SetOwner(kFALSE);
629   
630   TIter next(fPainterGroups);
631   
632   TObjString* str;
633   while ( ( str = static_cast<TObjString*>(next()) ) )
634   {
635     AliMUONPainterGroup* group = Group(str->String().Data());
636     tmp.AddLast(group);
637   }
638   
639   tmp.Sort();
640   
641   Int_t n = tmp.GetLast()+1;
642   
643   Int_t* index = new Int_t[n];
644   
645   Int_t* a = new Int_t[n];
646   
647   for ( Int_t i = 0; i < n; ++i )
648   {
649     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(tmp.At(i));
650     a[i] = group->Depth();
651   }
652   
653   TMath::Sort(n,a,index,kFALSE);
654   
655   for ( Int_t i = 0; i < n; ++i ) 
656   {
657     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(tmp.At(index[i]));
658     types.AddLast(new TObjString(group->Type()));
659   }
660   
661   delete[] index;
662   delete[] a;
663 }
664
665 //_____________________________________________________________________________
666 AliMUONPainterGroup*
667 AliMUONVPainter::Group(const char* type) const
668 {
669   /// Returns a group of a given type
670   if (!fPainterGroups) return 0x0;
671   return static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(type));
672 }
673
674 //_____________________________________________________________________________
675 AliMUONPainterGroup*
676 AliMUONVPainter::Group(Int_t depth) const
677 {
678   /// Returns a group of a given depth
679   if (!fPainterGroups) return 0x0;
680   TIter next(fPainterGroups);
681   TObjString* groupName;
682   while ( ( groupName = static_cast<TObjString*>(next()) ) )
683   {
684     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>
685     (fPainterGroups->GetValue(groupName->String().Data()));
686     if ( group->Depth() == depth ) 
687     {
688       return group;
689     }
690   }
691   return 0x0;
692 }
693
694 //_____________________________________________________________________________
695 Bool_t 
696 AliMUONVPainter::IsInside(Double_t x, Double_t y) const
697 {
698   /// Whether point (x,y) is inside our contour
699   if (!fContour) return kFALSE;
700   return fContour->IsInside(x,y);
701 }
702
703 //_____________________________________________________________________________
704 Bool_t 
705 AliMUONVPainter::IsResponder() const
706 {
707   /// Whether we're responding to mouse events
708   return MotherGroup()->IsResponder();
709 }
710
711 //_____________________________________________________________________________
712 AliMUONVPainter*
713 AliMUONVPainter::Master() const
714 {
715   /// Return the top of the hierarchy
716   
717   /// if we get no mother, we are the master
718   
719   if ( Mother() == 0x0 ) return const_cast<AliMUONVPainter*>(this);
720   
721   AliMUONVPainter* p = Mother();
722   
723   while ( p->Mother() )
724   {
725     p = p->Mother();
726   }
727   
728   return p;
729 }
730
731 //_____________________________________________________________________________
732 void
733 AliMUONVPainter::Paint(Option_t*)
734 {
735   /// Paint ourselves of screen
736   /// If we have some data (i.e. we're belonging to the plotter group)
737   /// we use PaintArea.
738   /// And if must be outlined, then we do that too.
739   
740   if ( !MotherGroup()->IsVisible() ) return;
741
742   if ( MotherGroup()->IsPlotter() ) 
743   {
744     PaintArea(*(MotherGroup()->Data()),
745               MotherGroup()->DataIndex(),
746               MotherGroup()->DataMin(),
747               MotherGroup()->DataMax());
748   }
749   
750   if ( MotherGroup()->IsOutlined() )
751   {
752     PaintOutline();
753   }
754   
755   if ( IsExcluded() )
756   {
757     AliMUONContourPainter::Paint(*fContour,1,1,2); // red fill with black thin outline
758   }
759 }
760
761 //_____________________________________________________________________________
762 TString
763 AliMUONVPainter::Describe(const AliMUONVTrackerData&, Int_t, Double_t, Double_t)
764 {
765   /// Default implementation (must be overriden)
766   AliError(Form("%s : implement me",GetName()));
767   return "";
768 }
769
770 //_____________________________________________________________________________
771 void
772 AliMUONVPainter::PaintArea(const AliMUONVTrackerData&, Int_t, Double_t, Double_t)
773 {
774   /// Default implementation (must be overriden)
775   AliError(Form("%s : implement me",GetName()));
776   return;
777 }
778
779 //_____________________________________________________________________________
780 void
781 AliMUONVPainter::PaintOutline(Int_t color, Int_t width, Double_t /*x*/, Double_t /*y*/)
782 {
783   /// Default implementation is simply a drawing of the contour lines,
784   /// not using the optional (x,y)
785   Int_t c = color >= 0 ? color : GetLineColor();
786   Int_t w = width >= 0 ? width : GetLineWidth();
787   
788   AliMUONContourPainter::Paint(*fContour,c,w);
789 }
790
791 //_____________________________________________________________________________
792 void 
793 AliMUONVPainter::PixelToPad(Int_t px, Int_t py, Double_t& x, Double_t& y)
794 {
795   /// convert (px,py) into pad position (x,y)
796   
797   x = gPad->PadtoX(gPad->AbsPixeltoX(px));
798   y = gPad->PadtoY(gPad->AbsPixeltoY(py));
799 }
800
801 //_____________________________________________________________________________
802 void
803 AliMUONVPainter::Print(Option_t* opt) const
804 {
805   /// Printout
806   for ( Int_t i = 0; i < Depth()*4; ++i ) 
807   {
808     cout << " ";
809   }
810   
811   if ( !IsValid() ) cout << "!!!INVALID!!!" << endl;
812   
813   cout << Form("%p Name %s Depth %d ContourName %s ID=(%d,%d)",
814                this,GetName(),Depth(),ContourName().Data(),ID0(),ID1());
815   
816   if ( fResponderGroup )
817   {
818     cout << Form(" Responder group %p %s",fResponderGroup,fResponderGroup->Type());
819   }
820   if ( fPlotterGroup )
821   {
822     cout << Form(" Plotter group %p %s",fPlotterGroup,fPlotterGroup->Type());
823   }
824   if ( Mother() )
825   {
826     cout << Form(" Mother %p %s",Mother(),Mother()->GetName());
827   }
828   if ( MotherGroup() )
829   {
830     cout << Form(" Group %p %s ",MotherGroup(),MotherGroup()->Type());
831   }
832   
833   if ( fChildren ) 
834   {
835     cout << Form(" %d children",fChildren->GetLast()+1);
836   }
837   
838   cout << endl;
839   
840   TString sopt(opt);
841   sopt.ToUpper();
842   
843   if ( fChildren && ( sopt == "FULL" || sopt == "CHILD" ) ) 
844   {
845     TIter next(fChildren);
846     AliMUONVPainter* painter;
847     while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
848     {
849       painter->Print(opt);
850     }
851   }
852   
853   if ( fPainterGroups && ( sopt == "FULL" || sopt == "GROUP" ) )
854   {
855     TIter next(fPainterGroups);
856     TObjString* groupName;
857     while ( ( groupName = static_cast<TObjString*>(next()) ) )
858     {
859       AliMUONPainterGroup* group = Group(groupName->String().Data());
860       group->Print(opt);
861     }
862   }
863 }
864
865 //_____________________________________________________________________________
866 void 
867 AliMUONVPainter::SetAttributes(const AliMUONAttPainter& attributes)
868 {
869   /// Set our attributes  
870   fAttributes = attributes;
871 }
872
873 //_____________________________________________________________________________
874 void 
875 AliMUONVPainter::SetContour(AliMUONContour* contour)
876 {
877   /// Set out contour
878   if (!contour)
879   {
880     AliError(Form("Setting a null contour for painter %s : bad idea !",PathName().Data()));
881   }
882   fContour = contour;
883 }
884
885 //_____________________________________________________________________________
886 void
887 AliMUONVPainter::SetData(const char* pattern, AliMUONVTrackerData* data,
888                          Int_t dataIndex)
889 {
890   /// Tell all painters which type matches pattern that they should
891   /// monitor a given data source
892   
893   if ( !fPainterGroups ) 
894   {
895     CreateGroups();
896   }
897   
898   if ( data ) 
899   {
900     data->Connect("Destroyed()",ClassName(),this,Form("SetData(=\"%s\",0x0,-1)",pattern));
901   }
902   
903   TIter next(fPainterGroups);
904   TObjString* str;
905   
906   fPlotterGroup = 0x0;
907   
908   while ( ( str = static_cast<TObjString*>(next()) ) )
909   {
910     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
911         
912     if ( group->Matches(pattern) )
913     {
914       group->SetData(data,dataIndex);
915       if ( data ) 
916       {        
917         fPlotterGroup = group;
918       }
919     }
920     else
921     {
922       group->SetData(0x0,-1);
923     }
924   }
925   
926   // Update context menus
927   TList list;
928   FlatList(list);
929   
930   TIter pnext(&list);
931   AliMUONVPainter* p;
932   
933   AliMUONPainterGroup* group = Master()->PlotterGroup();
934   
935   while ( ( p = static_cast<AliMUONVPainter*>(pnext()) ) )
936   {
937     TList* l = p->IsA()->GetMenuList();
938   
939     l->Delete();
940   
941     TClassMenuItem* n(0x0);
942     
943     l->Add(new TClassMenuItem(TClassMenuItem::kPopupUserFunction,p->IsA(),
944                               "Include","Include",p,"",-1,kTRUE));
945     l->Add(new TClassMenuItem(TClassMenuItem::kPopupUserFunction,p->IsA(),
946                               "Exclude","Exclude",p,"",-1,kTRUE));    
947     
948     if ( group )  
949     {
950       if ( data && data->IsHistogrammed(0) ) 
951       {
952         // Add histo drawing to the popup menu
953         TString name("Draw histogram of ");
954         
955         name += data->ExternalDimensionName(0);
956         
957         n = new TClassMenuItem(TClassMenuItem::kPopupUserFunction,p->IsA(),
958                                name.Data(),"DrawHistogram0",p,"",-1,kTRUE);
959         l->Add(n);
960         
961         name += " clone";
962         
963         n = new TClassMenuItem(TClassMenuItem::kPopupUserFunction,p->IsA(),
964                                name.Data(),"DrawHistogramClone0",p,"",-1,kTRUE);
965         l->Add(n);
966       }
967       
968       Int_t nd = data->IsSingleEvent() ? data->ExternalDimension() : data->ExternalDimension()*2;
969       
970       for ( Int_t i = 0; i < nd; ++i ) 
971       {
972         n = new TClassMenuItem(TClassMenuItem::kPopupUserFunction,p->IsA(),
973                                Form("Draw %s clone",data->DimensionName(i).Data()),
974                                Form("DrawInternalHistogramClone%d",i),p,"",-1,kTRUE);
975         l->Add(n);
976       } 
977     }
978   }
979 }
980
981 //_____________________________________________________________________________
982 void
983 AliMUONVPainter::DrawInternalHistogram(Int_t dim) const
984 {
985   /// Draw histogram (and delete the previous one)
986   
987   delete fHistogram;
988   fHistogram = 0x0;
989   
990   DrawInternalHistogramClone(dim);
991 }
992
993 //_____________________________________________________________________________
994 void
995 AliMUONVPainter::DrawInternalHistogramClone(Int_t dim) const
996 {
997   /// Draw histogram 
998   
999   fHistogram = AliMUONTrackerDataHistogrammer::CreateHisto(*this,-1,dim);
1000   
1001   if (fHistogram) 
1002   {
1003     new TCanvas();
1004     fHistogram->Draw();
1005   }
1006 }
1007
1008 //_____________________________________________________________________________
1009 void
1010 AliMUONVPainter::DrawHistogram(Double_t* values) const
1011 {
1012   /// Draw histogram (and delete the previous one)
1013
1014   delete fHistogram;
1015   fHistogram = 0x0;
1016   
1017   DrawHistogramClone(values);
1018 }
1019
1020 //_____________________________________________________________________________
1021 void
1022 AliMUONVPainter::DrawHistogramClone(Double_t*) const
1023 {
1024   /// Draw histogram 
1025   
1026   fHistogram = AliMUONTrackerDataHistogrammer::CreateHisto(*this,0,-1);
1027   
1028   if (fHistogram) 
1029   {
1030     new TCanvas();
1031     fHistogram->Draw();
1032   }
1033 }
1034
1035 //_____________________________________________________________________________
1036 void
1037 AliMUONVPainter::FillManuList(TObjArray& manuList) const
1038 {
1039   /// Append to manulist
1040   /// This is the default implementation, which just calls the FillManuList
1041   /// of all our children.
1042   /// Some derived class might need to override this in order to exclude
1043   /// some children from the fill.
1044   
1045   TIter next(Children());
1046   
1047   AliMUONVPainter* p;
1048   
1049   while ( ( p = static_cast<AliMUONVPainter*>(next()) ) )
1050   {
1051     p->FillManuList(manuList);
1052   }
1053 }
1054
1055 //_____________________________________________________________________________
1056 void
1057 AliMUONVPainter::SetLine(Int_t depth, Int_t lineColor, Int_t lineWidth)
1058 {
1059   /// Set the line attributes of painters at a given depth
1060   AliMUONPainterGroup* group = Group(depth);
1061   if ( group )
1062   {
1063     group->SetLine(lineColor,lineWidth);
1064   }
1065 }
1066
1067 //_____________________________________________________________________________
1068 void
1069 AliMUONVPainter::SetMother(AliMUONVPainter* painter)
1070 {
1071   /// Set our mother
1072   fMother = painter;
1073 }
1074
1075 //_____________________________________________________________________________
1076 void
1077 AliMUONVPainter::SetOutlined(const char* pattern, Bool_t flag)
1078 {
1079   /// Decide whether or not painters which type matches pattern 
1080   /// should be outlined
1081   
1082   AliDebug(1,Form("pattern=%s flag=%d",pattern,flag));
1083   
1084   if (!fPainterGroups)
1085   {
1086     CreateGroups();
1087   }
1088   
1089   TIter next(fPainterGroups);
1090   TObjString* str;
1091   
1092   while ( ( str = static_cast<TObjString*>(next()) ) )
1093   {
1094     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
1095     if ( group->Matches(pattern) )
1096     {
1097       group->SetOutlined(flag);
1098     }
1099   }
1100 }
1101
1102 //_____________________________________________________________________________
1103 void
1104 AliMUONVPainter::SetResponder(const char* pattern)
1105 {
1106   /// Set the painters matching pattern to be the responder
1107   
1108   AliDebug(1,Form("pattern=%s",pattern));
1109   
1110   if (!fPainterGroups)
1111   {
1112     CreateGroups();
1113   }
1114   
1115   TIter next(fPainterGroups);
1116   TObjString* str;
1117   
1118   fResponderGroup = 0x0;
1119   
1120   while ( ( str = static_cast<TObjString*>(next()) ) )
1121   {
1122     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
1123     if ( group->Matches(pattern) )
1124     {
1125       AliDebug(1,Form("group %s is matching pattern %s : setting to responder",
1126                       group->Type(),pattern));
1127       group->SetResponder(kTRUE);
1128       fResponderGroup = group;
1129     }
1130     else
1131     {
1132       group->SetResponder(kFALSE);
1133     }
1134   }
1135 }
1136
1137 //_____________________________________________________________________________
1138 void
1139 AliMUONVPainter::SetResponder(Int_t depth)
1140 {
1141   /// Select as responder the *first* group that has a given depth
1142   
1143   AliDebug(1,Form("depth=%d",depth));
1144   
1145   if (!fPainterGroups)
1146   {
1147     CreateGroups();
1148   }
1149   
1150   TIter next(fPainterGroups);
1151   TObjString* str;
1152   
1153   fResponderGroup = 0x0;
1154   
1155   while ( ( str = static_cast<TObjString*>(next()) ) )
1156   {
1157     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
1158     if ( group->Depth() == depth ) 
1159     {
1160       AliDebug(1,Form("group %s has correct depth = %d, using as responder",
1161                       group->Type(),depth));
1162       group->SetResponder(kTRUE);
1163       fResponderGroup = group;
1164       break;
1165     }
1166     else
1167     {
1168       group->SetResponder(kFALSE);
1169     }
1170   }
1171 }
1172
1173 //_____________________________________________________________________________
1174 void
1175 AliMUONVPainter::SetVisible(const char* pattern, Bool_t flag)
1176 {
1177   /// Decide whether the painters matching pattern should be visible or not
1178   AliDebug(1,Form("pattern=%s flag=%d",pattern,flag));
1179   
1180   if (!fPainterGroups)
1181   {
1182     CreateGroups();
1183   }
1184   
1185   TIter next(fPainterGroups);
1186   TObjString* str;
1187   
1188   while ( ( str = static_cast<TObjString*>(next()) ) )
1189   {
1190     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
1191     if ( group->Matches(pattern) )
1192     {
1193       group->SetVisible(flag);
1194     }
1195   }
1196 }
1197
1198 //_____________________________________________________________________________
1199 void
1200 AliMUONVPainter::UpdateGroupsFrom(const AliMUONVPainter& painter)
1201 {
1202   /// (re)Create groups
1203   delete fPainterGroups;
1204   fPainterGroups = 0x0;
1205   
1206   CreateGroups();
1207   
1208   // and copy the status of responder, plotter and visible
1209   if ( painter.ResponderGroup() ) 
1210   {
1211     SetResponder(painter.ResponderGroup()->Type());
1212   }
1213   
1214   if ( painter.PlotterGroup() ) 
1215   {
1216     SetData(painter.PlotterGroup()->Type(),
1217             painter.PlotterGroup()->Data(),
1218             painter.PlotterGroup()->DataIndex());
1219     PlotterGroup()->SetDataRange(painter.PlotterGroup()->DataMin(),
1220                                  painter.PlotterGroup()->DataMax());
1221   }
1222   
1223   TObjArray types;
1224   painter.GetTypes(types);
1225   TIter next(&types);
1226   TObjString* groupName;
1227   
1228   while ( ( groupName = static_cast<TObjString*>(next()) ) )
1229   {
1230     AliMUONPainterGroup* group = painter.Group(groupName->String().Data());      
1231     if ( group->IsVisible() ) 
1232     {
1233       SetVisible(group->Type(),kTRUE);
1234     }
1235     else
1236     {
1237       SetVisible(group->Type(),kFALSE);
1238     }
1239
1240     if ( group->IsOutlined() ) 
1241     {
1242       SetOutlined(group->Type(),kTRUE);
1243     }
1244     else
1245     {
1246       SetOutlined(group->Type(),kFALSE);
1247     }
1248     
1249     SetLine(group->Depth(),group->GetLineColor(),group->GetLineWidth());
1250   }
1251   
1252 }
1253
1254 //_____________________________________________________________________________
1255 void
1256 AliMUONVPainter::Include()
1257 {
1258   /// Include this painter
1259   AliInfo(GetName());
1260   
1261   /// Update the global interactive read out configuration  
1262   WriteIROC(1);
1263 }
1264
1265 //_____________________________________________________________________________
1266 void
1267 AliMUONVPainter::GetIROCManuList(TObjArray& manuList)
1268 {
1269   /// Get the list of manus spanned by this painter AND by its dual
1270
1271   FillManuList(manuList);
1272   
1273   // get our dual
1274   AliMUONAttPainter att(Attributes());
1275   
1276   att.Invert();
1277   
1278   att.SetCathodeAndPlaneDisabled(kTRUE);
1279   
1280   AliMUONVPainter* p = AliMUONVPainter::CreatePainter(ClassName(),att,ID0(),ID1());
1281   
1282   if (p)
1283   {
1284     p->FillManuList(manuList);
1285   }
1286   
1287   delete p;
1288 }
1289
1290 //_____________________________________________________________________________
1291 void
1292 AliMUONVPainter::WriteIROC(Double_t value)
1293 {
1294   /// Update the interactive readout configuration
1295   
1296   TObjArray manuList;
1297   GetIROCManuList(manuList);
1298   
1299   AliMpManuUID* muid;
1300   TIter nextm(&manuList);
1301   AliMUON2DMap store(true);
1302   
1303   while ((muid=static_cast<AliMpManuUID*>(nextm())))
1304   {
1305     AliMUONVCalibParam* param = new AliMUONCalibParamND(1,64,
1306                                                         muid->DetElemId(),
1307                                                         muid->ManuId(),value);
1308     store.Add(param);
1309   }
1310   
1311   InteractiveReadOutConfig()->Replace(store);
1312 }
1313
1314 //_____________________________________________________________________________
1315 void
1316 AliMUONVPainter::Exclude()
1317 {
1318   /// Exclude this painter
1319   AliInfo(GetName());
1320   
1321   /// Update the global interactive read out configuration
1322   WriteIROC(0.0);
1323 }
1324
1325 //_____________________________________________________________________________
1326 AliMUONVTrackerData*
1327 AliMUONVPainter::InteractiveReadOutConfig() const
1328 {
1329   /// get the interactive readout config object
1330   return AliMUONPainterDataRegistry::Instance()->InteractiveReadOutConfig();
1331 }
1332
1333 //_____________________________________________________________________________
1334 AliMUONVPainter* 
1335 AliMUONVPainter::CreatePainter(const char* className, 
1336                                const AliMUONAttPainter& att, 
1337                                Int_t id1, Int_t id2)
1338 {
1339   /// Create a painter (factory method)
1340   
1341   TClass* c = TClass::GetClass(className);
1342   
1343   if (!c)
1344   {
1345     AliErrorClass(Form("Cannot get class %s",className));
1346     return 0x0;
1347   }
1348   
1349   Int_t n(0);
1350   
1351   TMethodCall call;
1352   
1353   call.InitWithPrototype(c,className,"AliMUONAttPainter&,Int_t");
1354   
1355   if (call.IsValid()) n = 1;
1356   else
1357   {
1358     call.InitWithPrototype(c,className,"AliMUONAttPainter&,Int_t,Int_t");
1359     
1360     if ( call.IsValid() ) n = 2;
1361   }
1362   
1363   Long_t returnLong(0x0);
1364   
1365   if ( n ==1 ) 
1366   {
1367     Long_t params[] = { (Long_t)(&att), (Long_t)(id1) };
1368     call.SetParamPtrs((void*)(params));
1369     call.Execute((void*)(0x0),returnLong);
1370   }
1371   else if ( n == 2 ) 
1372   {
1373     Long_t params[] = { (Long_t)(&att), (Long_t)(id1), (Long_t)(id2) };
1374     call.SetParamPtrs((void*)(params));
1375     call.Execute((void*)(0x0),returnLong);
1376   }
1377   
1378   if (!returnLong)
1379   {
1380     AliErrorClass(Form("Cannot create a painter of class %s",className));
1381   }
1382   
1383   AliMUONVPainter* rv = reinterpret_cast<AliMUONVPainter*> (returnLong);
1384   
1385   if (!rv->IsValid()) 
1386   {
1387     AliErrorClass(Form("Painter of class %s is not valid",className));
1388     delete rv;
1389     rv = 0x0;
1390   }
1391   return rv;
1392 }
1393
1394 //_____________________________________________________________________________
1395 void
1396 AliMUONVPainter::PaintArea(Int_t fillColor)
1397 {
1398   /// Draw a filled area
1399   AliMUONContourPainter::Paint(*(Contour()),-1,-1,fillColor);
1400 }