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