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