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