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