First big commit of the mchview program and its accompanying library,
[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 "AliMUONObjectPair.h"
21 #include "AliMUONPainterContour.h"
22 #include "AliMUONPainterGroup.h"
23 #include "AliMUONPainterHelper.h"
24 #include "AliMUONVTrackerData.h"
25 #include "AliCodeTimer.h"
26 #include "AliLog.h"
27 #include <Riostream.h>
28 #include <TCanvas.h>
29 #include <TClass.h>
30 #include <TClass.h>
31 #include <TList.h>
32 #include <TMap.h>
33 #include <TMath.h>
34 #include <TMethodCall.h>
35 #include <TObjArray.h>
36 #include <TObjString.h>
37 #include <TROOT.h>
38 #include <TVirtualPad.h>
39 #include <cassert>
40 #include <float.h>
41
42
43 /// \class AliMUONVPainter
44 ///
45 /// Base class for a graphical object representing some part of the
46 /// MUON tracking system.
47 /// 
48 /// A painter is a graphical representation of some part (e.g. detection element,
49 /// full chamber, one manu, etc...) of the MUON tracking system.
50 ///
51 /// A painter is a double fold hierarchical structure. 
52 ///
53 /// First, a painter is part of a tree (mother->childrens), that describe
54 /// the natural organization of the spectrometer. For instance, a chamber
55 /// painter has children that are the detection element, the detection elements
56 /// themselves contain manus, which in turn contain channels.
57 ///
58 /// Second, a painter contains a number of "painter groups" (see AliMUONPainterGroup). 
59 /// A group gather all the painters of the same type, 
60 /// where the type is a string identifying which part of system we're dealing
61 /// with (chamber, DE, manu, etc...)
62 ///
63 /// The groups are there to ease the manipulation of similar painters, e.g. if
64 /// we want to hide all detection elements, we hide the "detection element group"
65 /// Some special groups are the responder and the plotter groups. The responder
66 /// group is the group which is currently responding to mouse events. 
67 /// The plotter group is the group which is supposed to represent some data.
68 /// 
69 /// There are two ways to represent the painter on screen. In any case, we can
70 /// outline the painter (i.e. draw its borders) (see AliMUONVPainter::PaintOutline).
71 /// In the cases where the painter is attached to some data source (i.e. it is
72 /// used to represent some data about its type, e.g. the mean charge on some manu),
73 /// we can draw the full area of the contour, using some color (see
74 /// AliMUONVPainter::PaintArea).
75 ///
76 /// Note that you can outline several types of painters (aka groups) at the same
77 /// time, but you cannot plot several groups at the same time.
78 ///
79 /// Painters are TQObject so they can emit signals.
80 ///
81 /// Currently emitted signal are : 
82 ///
83 /// void Clicked(AliMUONVPainter* painter, Double_t*);
84 /// DoubleClicked(AliMUONVPainter* painter, Double_t*);
85 ///
86 /// to know which and where a painter was (double-) clicked.
87 ///
88 /// \author Laurent Aphecetche, Subatech
89
90 ///\cond CLASSIMP
91 ClassImp(AliMUONVPainter)
92 ///\endcond
93
94 //_____________________________________________________________________________
95 AliMUONVPainter::AliMUONVPainter(const char* type)
96 : TObject(), 
97   fName(""),
98   fPathName(""),
99   fType(type),
100   fMother(0x0),
101   fGroup(0x0),
102   fContour(0x0),
103   fPainterGroups(0x0),
104   fChildren(0x0),
105   fResponderGroup(0x0),
106   fPlotterGroup(0x0),
107   fBorderFactor(1.1),
108   fPad(0x0),
109   fAttributes(),
110   fLineColor(1),
111   fLineWidth(1),
112   fIsValid(kTRUE)
113 {
114     /// ctor
115     SetID(-1,-1);
116 }
117
118 //_____________________________________________________________________________
119 AliMUONVPainter::AliMUONVPainter(const AliMUONVPainter& rhs)
120 : TObject(rhs),
121 fName(""),
122 fPathName(""),
123 fType(""),
124 fMother(0x0),
125 fGroup(0x0),
126 fContour(0x0),
127 fPainterGroups(0x0),
128 fChildren(0x0),
129 fResponderGroup(0x0),
130 fPlotterGroup(0x0),
131 fBorderFactor(1.0),
132 fPad(0x0),
133 fAttributes(),
134 fLineColor(-1),
135 fLineWidth(-1),
136 fIsValid(kTRUE)
137 {
138   /// copy ctor
139   rhs.Copy(*this);
140 }
141
142 //_____________________________________________________________________________
143 AliMUONVPainter& 
144 AliMUONVPainter::operator=(const AliMUONVPainter& rhs)
145 {
146   /// assignment operator
147   if ( this != &rhs ) 
148   {
149     rhs.Copy(*this);
150   }
151   return *this;
152 }
153
154 //_____________________________________________________________________________
155 AliMUONVPainter::~AliMUONVPainter()
156 {
157   /// dtor
158   delete fChildren;
159 }
160
161 //_____________________________________________________________________________
162 AliMpArea
163 AliMUONVPainter::Area() const
164 {
165   /// Return the area covered by this painter
166   if ( fContour ) 
167   {
168     return fContour->Area();
169   }
170   else
171   {
172     AliWarning("Returning an invalid area, as contour is not defined");
173     return AliMpArea();
174   }
175 }
176
177 //_____________________________________________________________________________
178 void
179 AliMUONVPainter::Add(AliMUONVPainter* painter)
180 {
181   /// Add a child painter
182   if (!fChildren) fChildren = new TObjArray;
183   assert(painter->Mother()==0x0);
184   fChildren->Add(painter);
185   painter->SetMother(this);
186 }
187
188 //_____________________________________________________________________________
189 TCollection*
190 AliMUONVPainter::Children() const
191 {
192   /// Return the list of childrens
193   return fChildren;
194 }
195
196 //_____________________________________________________________________________
197 void
198 AliMUONVPainter::Clicked(AliMUONVPainter* painter, Double_t* values)
199 {
200   // let our mother emit the signal as clients are probably connected to
201   // our (grand)mother, not to us
202
203   if ( Mother() ) 
204   {
205     Mother()->Clicked(painter,values);
206   }
207   else
208   {
209     Long_t param[] = { (Long_t)painter,(Long_t)values };
210   
211     Emit("Clicked(AliMUONVPainter*,Double_t*)",param);
212   }
213 }
214
215 //_____________________________________________________________________________
216 void
217 AliMUONVPainter::ShiftClicked(AliMUONVPainter* painter, Double_t* values)
218 {
219   // let our mother emit the signal as clients are probably connected to
220   // our (grand)mother, not to us
221   
222   if ( Mother() ) 
223   {
224     Mother()->ShiftClicked(painter,values);
225   }
226   else
227   {
228     Long_t param[] = { (Long_t)painter,(Long_t)values };
229     
230     Emit("ShiftClicked(AliMUONVPainter*,Double_t*)",param);
231   }
232 }
233
234 //_____________________________________________________________________________
235 void
236 AliMUONVPainter::ComputeDataRange(const AliMUONVTrackerData&, Int_t,
237                                   Double_t&, Double_t&) const
238 {
239   /// Should compute the min and max of a given data source
240   AliError("Not implemented. Please fixe me");
241 }
242
243 //_____________________________________________________________________________
244 TString
245 AliMUONVPainter::ContourName() const
246 {
247   /// Default implementation of the contour name.
248   
249   TString name(PathName());
250
251   name += "-";
252   name += fAttributes.Name();
253   
254   return name;
255 }
256
257 //_____________________________________________________________________________
258 void
259 AliMUONVPainter::Copy(TObject& object) const
260 {
261   /// Copy this to object.
262   
263   TObject::Copy(object);
264
265   AliMUONVPainter& painter = static_cast<AliMUONVPainter&>(object);
266
267   painter.fType = fType;
268   painter.fName = fName;
269   painter.fPathName = fPathName;
270   
271   painter.fMother = 0x0;
272   painter.fContour = fContour;
273   
274   painter.fGroup = 0x0;
275   painter.fResponderGroup = 0x0;
276   painter.fPlotterGroup = 0x0;
277   
278   painter.fBorderFactor = fBorderFactor;
279
280   painter.fAttributes = fAttributes;
281   
282   painter.fAttributes.SetCathodeAndPlaneDisabled(kFALSE);
283   
284   painter.fPad = fPad;
285   
286   painter.fLineColor = fLineColor;
287   painter.fLineWidth = fLineWidth;
288   
289   painter.fIsValid = fIsValid;
290   
291   delete painter.fChildren;
292   painter.fChildren = 0x0;
293   
294   painter.fID[0] = fID[0];
295   painter.fID[1] = fID[1];
296   
297   TIter next(fChildren);
298   AliMUONVPainter* p;
299   
300   while ( ( p = static_cast<AliMUONVPainter*>(next()) ) )
301   {
302     painter.Add(static_cast<AliMUONVPainter*>(p->Clone()));
303   }
304     
305   painter.UpdateGroupsFrom(*this);
306   
307   object.ResetBit(kCanDelete);
308 }
309
310 //_____________________________________________________________________________
311 AliMUONPainterGroup*
312 AliMUONVPainter::CreateGroup(const char* type, Int_t depth)
313 {
314   /// Create a painter group at a given depth
315   
316   if (!fPainterGroups) fPainterGroups = new TMap;
317   TObject* o = fPainterGroups->GetValue(type);
318   if (o)
319   {
320     AliError(Form("Group %s is already there ! Check this",type));
321     return 0x0;
322   }
323   AliMUONPainterGroup* group = new AliMUONPainterGroup(type,depth);
324   fPainterGroups->Add(new TObjString(type),group);
325   return group;
326 }
327
328 //_____________________________________________________________________________
329 void
330 AliMUONVPainter::CreateGroups()
331 {
332   /// Groups our children into groups
333   
334   if ( Mother() ) 
335   {
336     AliFatal("Not supposed to create groups for a children");
337   }
338   
339   TList list;
340   FlatList(list);
341   
342   TIter next(&list);
343   AliMUONVPainter* painter;
344   
345   while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
346   {
347     AliMUONPainterGroup* group = Group(painter->Type());
348     if (!group) 
349     {
350       group = CreateGroup(painter->Type(),painter->Depth());
351     }
352     group->Add(painter);
353   }
354 }
355
356 //_____________________________________________________________________________
357 AliMUONVPainter*
358 AliMUONVPainter::Detach() const
359 {
360   /// Make this a new top painter (i.e. a master)
361   
362   AliDebug(1,Form("Detaching %s",GetName()));
363            
364   AliMUONVPainter* p = static_cast<AliMUONVPainter*>(Clone());
365   
366   AliMUONVPainter* master = Master();
367   
368   if ( master )
369   {
370     AliDebug(1,Form("UpdatingGroups of the detached painter %s from its master %s",
371                     p->GetName(),master->GetName()));
372     p->UpdateGroupsFrom(*master);
373   }
374   
375   return p;
376 }
377
378 //_____________________________________________________________________________
379 Int_t
380 AliMUONVPainter::Depth() const
381 {
382   /// Return our depth in the hierarchy
383   
384   if ( Mother() ) 
385   {
386     return Mother()->Depth() + 1;
387   }
388   else
389   {
390     return 0;
391   }
392 }
393
394 //_____________________________________________________________________________
395 Int_t   
396 AliMUONVPainter::DistancetoPrimitive(Int_t px, Int_t py)
397 {
398   /// See TObject::DistancetoPrimitive
399   
400   static const Int_t kBigValue = 999999;
401
402   if (!gPad) return kBigValue;
403   
404   Double_t x,y;
405   
406   AliMUONVPainter* painter = GetPainter(px,py,x,y);
407   
408   x=y=0.0; // to avoid compiler warning
409   
410   if ( painter == this) return 0;
411   
412   return kBigValue;
413 }
414
415 //_____________________________________________________________________________
416 void
417 AliMUONVPainter::DoubleClicked(AliMUONVPainter*, Double_t*)
418 {
419   /// Should emit the DoubleClicked signal (if I knew how to detect those events...)
420   
421   AliWarning("Please implement me !");
422
423   //  if ( fMother )
424 //  {
425 //    // let our top mother emit the signal as clients are probably connected to
426 //    // our mother, not to us
427 //    Top()->DoubleClicked(painter,values);
428 //  }
429 //  else
430 //  {
431 //    Long_t param[] = { (Long_t)painter,(Long_t)values };
432 //    
433 //    Emit("DoubleClicked(AliMUONVPainter*,Double_t*)",param);
434 //  }
435 }
436
437 //_____________________________________________________________________________
438 void
439 AliMUONVPainter::Draw(Option_t* opt)
440 {
441   /// Append ourselves to the current pad
442   
443   if (!gPad) 
444   {
445     gROOT->MakeDefCanvas();
446   }
447   
448   Bool_t kMustSetRange(kFALSE);
449  
450   TString sopt(opt);
451   sopt.ToUpper();
452  
453   if (sopt.Contains("R") ) kMustSetRange=kTRUE;
454   
455   if (kMustSetRange)
456   {
457     Double_t x1,y1,x2,y2;
458     GetBoundingBox(x1,y1,x2,y2);
459     if ( gPad) gPad->Range(x1,y1,x2,y2);
460   }
461  
462   if ( !fMother && !fPainterGroups ) 
463   {
464     CreateGroups();
465   }
466   
467   TIter next(fChildren);
468   AliMUONVPainter* painter;
469   while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
470   {
471     painter->Draw();
472   }  
473   
474   AppendPad(opt);
475   
476   fPad = gPad;
477 }
478
479 //_____________________________________________________________________________
480 void 
481 AliMUONVPainter::ExecuteEvent(Int_t event, Int_t px, Int_t py)
482 {
483   /// Handle graphics events
484   
485   Double_t x,y;
486     
487   AliMUONVPainter* painter = GetPainter(px,py,x,y);
488
489   if ( painter == this ) 
490   {
491     Double_t values[] = { x,y };
492   
493     switch (event)
494     {
495       case kButton2Up:
496         ShiftClicked(this,values);
497         break;
498       case kButton1Up:
499         Clicked(this,values);      
500         break;
501       case kButton1Double:
502         //the following statement is required against other loop executions before returning (depending on the time between the clicks) 
503         gPad->GetCanvas()->HandleInput((EEventType)-1,0,0); 
504         DoubleClicked(this,values);
505         break;
506     }
507   }
508 }
509
510 //_____________________________________________________________________________
511 void
512 AliMUONVPainter::FlatList(TList& list)
513 {
514   /// Make a flat list of our children
515   
516   TIter next(fChildren);
517   AliMUONVPainter* painter;
518   while ( ( painter = static_cast<AliMUONVPainter*>(next())))
519   {
520     painter->FlatList(list);
521   }
522   
523   list.Add(this);
524 }
525
526 //_____________________________________________________________________________
527 void 
528 AliMUONVPainter::GetBoundingBox(Double_t& x1, Double_t& y1, 
529                                 Double_t& x2, Double_t& y2) const
530 {
531   /// Get the bounding box = our area
532   AliMpArea area(Area().Position(),Area().Dimensions()*fBorderFactor);
533
534   x1 = area.LeftBorder();
535   y1 = area.DownBorder();
536   x2 = area.RightBorder();
537   y2 = area.UpBorder();
538 }
539
540 //_____________________________________________________________________________
541 char*   
542 AliMUONVPainter::GetObjectInfo(Int_t, Int_t) const
543 {
544   /// See TObject::GetObjectInfo
545   return const_cast<char*>(GetName());
546 }
547
548 //_____________________________________________________________________________
549 AliMUONVPainter* 
550 AliMUONVPainter::GetPainter(Int_t px, Int_t py, Double_t& x, Double_t& y) const
551 {
552   /// Get the responder painter at integer position (px,py), and get back its
553   /// absolute position (x,y)
554   
555   PixelToPad(px,py,x,y);
556   
557   if ( !IsInside(x,y) ) return 0x0;
558   
559   if ( fGroup->IsResponder() ) return const_cast<AliMUONVPainter*>(this);
560   
561   if (fChildren)
562   {
563     TIter next(fChildren);
564     AliMUONVPainter* painter;
565     
566     while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
567     {
568       AliMUONVPainter* p = painter->GetPainter(px,py,x,y);
569       if (p) return p;
570     }
571   }  
572   
573   return 0x0;
574 }
575
576 //_____________________________________________________________________________
577 void
578 AliMUONVPainter::GetTypes(TObjArray& types) const
579 {
580   /// Get the list of types (as a TObjArray of TObjString) 
581   /// of our hierarchy, sorted alphabetically
582   
583   types.SetOwner(kTRUE);
584   types.Clear();
585
586   TObjArray tmp;
587   tmp.SetOwner(kFALSE);
588   
589   TIter next(fPainterGroups);
590   
591   TObjString* str;
592   while ( ( str = static_cast<TObjString*>(next()) ) )
593   {
594     AliMUONPainterGroup* group = Group(str->String().Data());
595     tmp.AddLast(group);
596   }
597   
598   tmp.Sort();
599   
600   Int_t n = tmp.GetLast()+1;
601   
602   Int_t* index = new Int_t[n];
603   
604   Int_t* a = new Int_t[n];
605   
606   for ( Int_t i = 0; i < n; ++i )
607   {
608     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(tmp.At(i));
609     a[i] = group->Depth();
610   }
611   
612   TMath::Sort(n,a,index,kFALSE);
613   
614   for ( Int_t i = 0; i < n; ++i ) 
615   {
616     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(tmp.At(index[i]));
617     types.AddLast(new TObjString(group->Type()));
618   }
619   
620   delete[] index;
621   delete[] a;
622 }
623
624 //_____________________________________________________________________________
625 AliMUONPainterGroup*
626 AliMUONVPainter::Group(const char* type) const
627 {
628   /// Returns a group of a given type
629   if (!fPainterGroups) return 0x0;
630   return static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(type));
631 }
632
633 //_____________________________________________________________________________
634 AliMUONPainterGroup*
635 AliMUONVPainter::Group(Int_t depth) const
636 {
637   /// Returns a group of a given depth
638   if (!fPainterGroups) return 0x0;
639   TIter next(fPainterGroups);
640   TObjString* groupName;
641   while ( ( groupName = static_cast<TObjString*>(next()) ) )
642   {
643     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>
644     (fPainterGroups->GetValue(groupName->String().Data()));
645     if ( group->Depth() == depth ) 
646     {
647       return group;
648     }
649   }
650   return 0x0;
651 }
652
653 //_____________________________________________________________________________
654 Bool_t 
655 AliMUONVPainter::IsInside(Double_t x, Double_t y) const
656 {
657   /// Whether point (x,y) is inside our contour
658   if (!fContour) return kFALSE;
659   return fContour->IsInside(x,y);
660 }
661
662 //_____________________________________________________________________________
663 Bool_t 
664 AliMUONVPainter::IsResponder() const
665 {
666   /// Whether we're responding to mouse events
667   return MotherGroup()->IsResponder();
668 }
669
670 //_____________________________________________________________________________
671 AliMUONVPainter*
672 AliMUONVPainter::Master() const
673 {
674   /// Return the top of the hierarchy
675   
676   /// if we get no mother, we are the master
677   
678   if ( Mother() == 0x0 ) return const_cast<AliMUONVPainter*>(this);
679   
680   AliMUONVPainter* p = Mother();
681   
682   while ( p->Mother() )
683   {
684     p = p->Mother();
685   }
686   
687   return p;
688 }
689
690 //_____________________________________________________________________________
691 void
692 AliMUONVPainter::Paint(Option_t*)
693 {
694   /// Paint ourselves of screen
695   /// If we have some data (i.e. we're belonging to the plotter group)
696   /// we use PaintArea.
697   /// And if must be outlined, then we do that too.
698   
699   if ( !MotherGroup()->IsVisible() ) return;
700
701   if ( MotherGroup()->IsPlotter() ) 
702   {
703     PaintArea(*(MotherGroup()->Data()),
704               MotherGroup()->DataIndex(),
705               MotherGroup()->DataMin(),
706               MotherGroup()->DataMax());
707   }
708   
709   if ( MotherGroup()->IsOutlined() )
710   {
711     PaintOutline();
712   }
713 }
714
715 //_____________________________________________________________________________
716 TString
717 AliMUONVPainter::Describe(const AliMUONVTrackerData&, Int_t, Double_t, Double_t)
718 {
719   /// Default implementation (must be overriden)
720   AliError(Form("%s : implement me",GetName()));
721   return "";
722 }
723
724 //_____________________________________________________________________________
725 void
726 AliMUONVPainter::PaintArea(const AliMUONVTrackerData&, Int_t, Double_t, Double_t)
727 {
728   /// Default implementation (must be overriden)
729   AliError(Form("%s : implement me",GetName()));
730 }
731
732 //_____________________________________________________________________________
733 void
734 AliMUONVPainter::PaintOutline(Int_t color, Int_t width, Double_t /*x*/, Double_t /*y*/)
735 {
736   /// Default implementation is simply a drawing of the contour lines,
737   /// not using the optional (x,y)
738   Int_t c = color >= 0 ? color : GetLineColor();
739   Int_t w = width >= 0 ? width : GetLineWidth();
740   
741   fContour->PaintOutline(c,w);
742 }
743
744 //_____________________________________________________________________________
745 void 
746 AliMUONVPainter::PixelToPad(Int_t px, Int_t py, Double_t& x, Double_t& y)
747 {
748   /// convert (px,py) into pad position (x,y)
749   
750   x = gPad->PadtoX(gPad->AbsPixeltoX(px));
751   y = gPad->PadtoY(gPad->AbsPixeltoY(py));
752 }
753
754 //_____________________________________________________________________________
755 void
756 AliMUONVPainter::Print(Option_t* opt) const
757 {
758   /// Printout
759   for ( Int_t i = 0; i < Depth()*4; ++i ) 
760   {
761     cout << " ";
762   }
763   
764   if ( !IsValid() ) cout << "!!!INVALID!!!" << endl;
765   
766   cout << Form("%p Name %s Depth %d ContourName %s ID=(%d,%d)",
767                this,GetName(),Depth(),ContourName().Data(),ID0(),ID1());
768   
769   if ( fResponderGroup )
770   {
771     cout << Form(" Responder group %p %s",fResponderGroup,fResponderGroup->Type());
772   }
773   if ( fPlotterGroup )
774   {
775     cout << Form(" Plotter group %p %s",fPlotterGroup,fPlotterGroup->Type());
776   }
777   if ( Mother() )
778   {
779     cout << Form(" Mother %p %s",Mother(),Mother()->GetName());
780   }
781   if ( MotherGroup() )
782   {
783     cout << Form(" Group %p %s ",MotherGroup(),MotherGroup()->Type());
784   }
785   
786   if ( fChildren ) 
787   {
788     cout << Form(" %d children",fChildren->GetLast()+1);
789   }
790   
791   cout << endl;
792   
793   TString sopt(opt);
794   sopt.ToUpper();
795   
796   if ( fChildren && ( sopt == "FULL" || sopt == "CHILD" ) ) 
797   {
798     TIter next(fChildren);
799     AliMUONVPainter* painter;
800     while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
801     {
802       painter->Print(opt);
803     }
804   }
805   
806   if ( fPainterGroups && ( sopt == "FULL" || sopt == "GROUP" ) )
807   {
808     TIter next(fPainterGroups);
809     TObjString* groupName;
810     while ( ( groupName = static_cast<TObjString*>(next()) ) )
811     {
812       AliMUONPainterGroup* group = Group(groupName->String().Data());
813       group->Print(opt);
814     }
815   }
816 }
817
818 //_____________________________________________________________________________
819 void 
820 AliMUONVPainter::SetAttributes(const AliMUONAttPainter& attributes)
821 {
822   /// Set our attributes  
823   fAttributes = attributes;
824 }
825
826 //_____________________________________________________________________________
827 void 
828 AliMUONVPainter::SetContour(AliMUONPainterContour* contour)
829 {
830   /// Set out contour
831   if (!contour)
832   {
833     AliError(Form("Setting a null contour for painter %s : bad idea !",PathName().Data()));
834   }
835   fContour = contour;
836 }
837
838 //_____________________________________________________________________________
839 void
840 AliMUONVPainter::SetData(const char* pattern, AliMUONVTrackerData* data,
841                          Int_t dataIndex)
842 {
843   /// Tell all painters which type matches pattern that they should
844   /// monitor a given data source
845   
846   if ( !fPainterGroups ) 
847   {
848     CreateGroups();
849   }
850   
851   TIter next(fPainterGroups);
852   TObjString* str;
853   
854   fPlotterGroup = 0x0;
855   
856   while ( ( str = static_cast<TObjString*>(next()) ) )
857   {
858     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
859     if ( group->Matches(pattern) )
860     {
861       group->SetData(data,dataIndex);
862       if ( data ) 
863       {        
864         fPlotterGroup = group;
865       }
866     }
867     else
868     {
869       group->SetData(0x0,-1);
870     }
871   }
872 }
873
874 //_____________________________________________________________________________
875 void
876 AliMUONVPainter::SetLine(Int_t depth, Int_t lineColor, Int_t lineWidth)
877 {
878   /// Set the line attributes of painters at a given depth
879   AliMUONPainterGroup* group = Group(depth);
880   if ( group )
881   {
882     group->SetLine(lineColor,lineWidth);
883   }
884 }
885
886 //_____________________________________________________________________________
887 void
888 AliMUONVPainter::SetMother(AliMUONVPainter* painter)
889 {
890   /// Set our mother
891   fMother = painter;
892 }
893
894 //_____________________________________________________________________________
895 void
896 AliMUONVPainter::SetOutlined(const char* pattern, Bool_t flag)
897 {
898   /// Decide whether or not painters which type matches pattern 
899   /// should be outlined
900   
901   AliDebug(1,Form("pattern=%s flag=%d",pattern,flag));
902   
903   if (!fPainterGroups)
904   {
905     CreateGroups();
906   }
907   
908   TIter next(fPainterGroups);
909   TObjString* str;
910   
911   while ( ( str = static_cast<TObjString*>(next()) ) )
912   {
913     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
914     if ( group->Matches(pattern) )
915     {
916       group->SetOutlined(flag);
917     }
918   }
919 }
920
921 //_____________________________________________________________________________
922 void
923 AliMUONVPainter::SetResponder(const char* pattern)
924 {
925   /// Set the painters matching pattern to be the responder
926   
927   AliDebug(1,Form("pattern=%s",pattern));
928   
929   if (!fPainterGroups)
930   {
931     CreateGroups();
932   }
933   
934   TIter next(fPainterGroups);
935   TObjString* str;
936   
937   fResponderGroup = 0x0;
938   
939   while ( ( str = static_cast<TObjString*>(next()) ) )
940   {
941     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
942     if ( group->Matches(pattern) )
943     {
944       AliDebug(1,Form("group %s is matching pattern %s : setting to responder",
945                       group->Type(),pattern));
946       group->SetResponder(kTRUE);
947       fResponderGroup = group;
948     }
949     else
950     {
951       group->SetResponder(kFALSE);
952     }
953   }
954 }
955
956 //_____________________________________________________________________________
957 void
958 AliMUONVPainter::SetResponder(Int_t depth)
959 {
960   /// Select as responder the *first* group that has a given depth
961   
962   AliDebug(1,Form("depth=%d",depth));
963   
964   if (!fPainterGroups)
965   {
966     CreateGroups();
967   }
968   
969   TIter next(fPainterGroups);
970   TObjString* str;
971   
972   fResponderGroup = 0x0;
973   
974   while ( ( str = static_cast<TObjString*>(next()) ) )
975   {
976     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
977     if ( group->Depth() == depth ) 
978     {
979       AliDebug(1,Form("group %s has correct depth = %d, using as responder",
980                       group->Type(),depth));
981       group->SetResponder(kTRUE);
982       fResponderGroup = group;
983       break;
984     }
985     else
986     {
987       group->SetResponder(kFALSE);
988     }
989   }
990 }
991
992 //_____________________________________________________________________________
993 void
994 AliMUONVPainter::SetVisible(const char* pattern, Bool_t flag)
995 {
996   /// Decide whether the painters matching pattern should be visible or not
997   AliDebug(1,Form("pattern=%s flag=%d",pattern,flag));
998   
999   if (!fPainterGroups)
1000   {
1001     CreateGroups();
1002   }
1003   
1004   TIter next(fPainterGroups);
1005   TObjString* str;
1006   
1007   while ( ( str = static_cast<TObjString*>(next()) ) )
1008   {
1009     AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
1010     if ( group->Matches(pattern) )
1011     {
1012       group->SetVisible(flag);
1013     }
1014   }
1015 }
1016
1017 //_____________________________________________________________________________
1018 void
1019 AliMUONVPainter::UpdateGroupsFrom(const AliMUONVPainter& painter)
1020 {
1021   /// (re)Create groups
1022   delete fPainterGroups;
1023   fPainterGroups = 0x0;
1024   
1025   CreateGroups();
1026   
1027   // and copy the status of responder, plotter and visible
1028   if ( painter.ResponderGroup() ) 
1029   {
1030     SetResponder(painter.ResponderGroup()->Type());
1031   }
1032   
1033   if ( painter.PlotterGroup() ) 
1034   {
1035     SetData(painter.PlotterGroup()->Type(),
1036             painter.PlotterGroup()->Data(),
1037             painter.PlotterGroup()->DataIndex());
1038     PlotterGroup()->SetDataRange(painter.PlotterGroup()->DataMin(),
1039                                  painter.PlotterGroup()->DataMax());
1040   }
1041   
1042   TObjArray types;
1043   painter.GetTypes(types);
1044   TIter next(&types);
1045   TObjString* groupName;
1046   
1047   while ( ( groupName = static_cast<TObjString*>(next()) ) )
1048   {
1049     AliMUONPainterGroup* group = painter.Group(groupName->String().Data());      
1050     if ( group->IsVisible() ) 
1051     {
1052       SetVisible(group->Type(),kTRUE);
1053     }
1054     else
1055     {
1056       SetVisible(group->Type(),kFALSE);
1057     }
1058
1059     if ( group->IsOutlined() ) 
1060     {
1061       SetOutlined(group->Type(),kTRUE);
1062     }
1063     else
1064     {
1065       SetOutlined(group->Type(),kFALSE);
1066     }
1067     
1068     SetLine(group->Depth(),group->GetLineColor(),group->GetLineWidth());
1069   }
1070 }
1071
1072 //_____________________________________________________________________________
1073 AliMUONVPainter* 
1074 AliMUONVPainter::CreatePainter(const char* className, 
1075                                const AliMUONAttPainter& att, 
1076                                Int_t id1, Int_t id2)
1077 {
1078   /// Create a painter (factory method)
1079   
1080   TClass* c = TClass::GetClass(className);
1081   
1082   if (!c)
1083   {
1084     AliErrorClass(Form("Cannot get class %s",className));
1085     return 0x0;
1086   }
1087   
1088   Int_t n(0);
1089   
1090   TMethodCall call;
1091   
1092   call.InitWithPrototype(c,className,"AliMUONAttPainter&,Int_t");
1093   
1094   if (call.IsValid()) n = 1;
1095   else
1096   {
1097     call.InitWithPrototype(c,className,"AliMUONAttPainter&,Int_t,Int_t");
1098     
1099     if ( call.IsValid() ) n = 2;
1100   }
1101   
1102   Long_t returnLong(0x0);
1103   
1104   if ( n ==1 ) 
1105   {
1106     Long_t params[] = { (Long_t)(&att), (Long_t)(id1) };
1107     call.SetParamPtrs((void*)(params));
1108     call.Execute((void*)(0x0),returnLong);
1109   }
1110   else if ( n == 2 ) 
1111   {
1112     Long_t params[] = { (Long_t)(&att), (Long_t)(id1), (Long_t)(id2) };
1113     call.SetParamPtrs((void*)(params));
1114     call.Execute((void*)(0x0),returnLong);
1115   }
1116   
1117   if (!returnLong)
1118   {
1119     AliErrorClass(Form("Cannot create a painter of class %s",className));
1120   }
1121   
1122   AliMUONVPainter* rv = reinterpret_cast<AliMUONVPainter*> (returnLong);
1123   
1124   if (!rv->IsValid()) 
1125   {
1126     AliErrorClass(Form("Painter of class %s is not valid",className));
1127     delete rv;
1128     rv = 0x0;
1129   }
1130   return rv;
1131 }
1132