1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
18 #include "AliMUONVPainter.h"
20 #include "AliMUONObjectPair.h"
21 #include "AliMUONPainterContour.h"
22 #include "AliMUONPainterGroup.h"
23 #include "AliMUONPainterHelper.h"
24 #include "AliMUONVTrackerData.h"
25 #include "AliCodeTimer.h"
27 #include <Riostream.h>
34 #include <TMethodCall.h>
35 #include <TObjArray.h>
36 #include <TObjString.h>
38 #include <TVirtualPad.h>
43 /// \class AliMUONVPainter
45 /// Base class for a graphical object representing some part of the
46 /// MUON tracking system.
48 /// A painter is a graphical representation of some part (e.g. detection element,
49 /// full chamber, one manu, etc...) of the MUON tracking system.
51 /// A painter is a double fold hierarchical structure.
53 /// First, a painter is part of a tree (mother->childrens), that describe
54 /// the natural organization of the spectrometer. For instance, a chamber
55 /// painter has children that are the detection element, the detection elements
56 /// themselves contain manus, which in turn contain channels.
58 /// Second, a painter contains a number of "painter groups" (see AliMUONPainterGroup).
59 /// A group gather all the painters of the same type,
60 /// where the type is a string identifying which part of system we're dealing
61 /// with (chamber, DE, manu, etc...)
63 /// The groups are there to ease the manipulation of similar painters, e.g. if
64 /// we want to hide all detection elements, we hide the "detection element group"
65 /// Some special groups are the responder and the plotter groups. The responder
66 /// group is the group which is currently responding to mouse events.
67 /// The plotter group is the group which is supposed to represent some data.
69 /// There are two ways to represent the painter on screen. In any case, we can
70 /// outline the painter (i.e. draw its borders) (see AliMUONVPainter::PaintOutline).
71 /// In the cases where the painter is attached to some data source (i.e. it is
72 /// used to represent some data about its type, e.g. the mean charge on some manu),
73 /// we can draw the full area of the contour, using some color (see
74 /// AliMUONVPainter::PaintArea).
76 /// Note that you can outline several types of painters (aka groups) at the same
77 /// time, but you cannot plot several groups at the same time.
79 /// Painters are TQObject so they can emit signals.
81 /// Currently emitted signal are :
83 /// void Clicked(AliMUONVPainter* painter, Double_t*);
84 /// DoubleClicked(AliMUONVPainter* painter, Double_t*);
86 /// to know which and where a painter was (double-) clicked.
88 /// \author Laurent Aphecetche, Subatech
91 ClassImp(AliMUONVPainter)
94 //_____________________________________________________________________________
95 AliMUONVPainter::AliMUONVPainter(const char* type)
105 fResponderGroup(0x0),
118 //_____________________________________________________________________________
119 AliMUONVPainter::AliMUONVPainter(const AliMUONVPainter& rhs)
129 fResponderGroup(0x0),
142 //_____________________________________________________________________________
144 AliMUONVPainter::operator=(const AliMUONVPainter& rhs)
146 /// assignment operator
154 //_____________________________________________________________________________
155 AliMUONVPainter::~AliMUONVPainter()
161 //_____________________________________________________________________________
163 AliMUONVPainter::Area() const
165 /// Return the area covered by this painter
168 return fContour->Area();
172 AliWarning("Returning an invalid area, as contour is not defined");
177 //_____________________________________________________________________________
179 AliMUONVPainter::Add(AliMUONVPainter* painter)
181 /// Add a child painter
182 if (!fChildren) fChildren = new TObjArray;
183 assert(painter->Mother()==0x0);
184 fChildren->Add(painter);
185 painter->SetMother(this);
188 //_____________________________________________________________________________
190 AliMUONVPainter::Children() const
192 /// Return the list of childrens
196 //_____________________________________________________________________________
198 AliMUONVPainter::Clicked(AliMUONVPainter* painter, Double_t* values)
200 /// Let our mother emit the signal as clients are probably connected to
201 /// our (grand)mother, not to us
205 Mother()->Clicked(painter,values);
209 Long_t param[] = { (Long_t)painter,(Long_t)values };
211 Emit("Clicked(AliMUONVPainter*,Double_t*)",param);
215 //_____________________________________________________________________________
217 AliMUONVPainter::ShiftClicked(AliMUONVPainter* painter, Double_t* values)
219 /// Let our mother emit the signal as clients are probably connected to
220 /// our (grand)mother, not to us
224 Mother()->ShiftClicked(painter,values);
228 Long_t param[] = { (Long_t)painter,(Long_t)values };
230 Emit("ShiftClicked(AliMUONVPainter*,Double_t*)",param);
234 //_____________________________________________________________________________
236 AliMUONVPainter::ComputeDataRange(const AliMUONVTrackerData&, Int_t,
237 Double_t&, Double_t&) const
239 /// Should compute the min and max of a given data source
240 AliError("Not implemented. Please fixe me");
243 //_____________________________________________________________________________
245 AliMUONVPainter::ContourName() const
247 /// Default implementation of the contour name.
249 TString name(PathName());
252 name += fAttributes.Name();
257 //_____________________________________________________________________________
259 AliMUONVPainter::Copy(TObject& object) const
261 /// Copy this to object.
263 TObject::Copy(object);
265 AliMUONVPainter& painter = static_cast<AliMUONVPainter&>(object);
267 painter.fType = fType;
268 painter.fName = fName;
269 painter.fPathName = fPathName;
271 painter.fMother = 0x0;
272 painter.fContour = fContour;
274 painter.fGroup = 0x0;
275 painter.fResponderGroup = 0x0;
276 painter.fPlotterGroup = 0x0;
278 painter.fBorderFactor = fBorderFactor;
280 painter.fAttributes = fAttributes;
282 painter.fAttributes.SetCathodeAndPlaneDisabled(kFALSE);
286 painter.fLineColor = fLineColor;
287 painter.fLineWidth = fLineWidth;
289 painter.fIsValid = fIsValid;
291 delete painter.fChildren;
292 painter.fChildren = 0x0;
294 painter.fID[0] = fID[0];
295 painter.fID[1] = fID[1];
297 TIter next(fChildren);
300 while ( ( p = static_cast<AliMUONVPainter*>(next()) ) )
302 painter.Add(static_cast<AliMUONVPainter*>(p->Clone()));
305 painter.UpdateGroupsFrom(*this);
307 object.ResetBit(kCanDelete);
310 //_____________________________________________________________________________
312 AliMUONVPainter::CreateGroup(const char* type, Int_t depth)
314 /// Create a painter group at a given depth
316 if (!fPainterGroups) fPainterGroups = new TMap;
317 TObject* o = fPainterGroups->GetValue(type);
320 AliError(Form("Group %s is already there ! Check this",type));
323 AliMUONPainterGroup* group = new AliMUONPainterGroup(type,depth);
324 fPainterGroups->Add(new TObjString(type),group);
328 //_____________________________________________________________________________
330 AliMUONVPainter::CreateGroups()
332 /// Groups our children into groups
336 AliFatal("Not supposed to create groups for a children");
343 AliMUONVPainter* painter;
345 while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
347 AliMUONPainterGroup* group = Group(painter->Type());
350 group = CreateGroup(painter->Type(),painter->Depth());
356 //_____________________________________________________________________________
358 AliMUONVPainter::Detach() const
360 /// Make this a new top painter (i.e. a master)
362 AliDebug(1,Form("Detaching %s",GetName()));
364 AliMUONVPainter* p = static_cast<AliMUONVPainter*>(Clone());
366 AliMUONVPainter* master = Master();
370 AliDebug(1,Form("UpdatingGroups of the detached painter %s from its master %s",
371 p->GetName(),master->GetName()));
372 p->UpdateGroupsFrom(*master);
378 //_____________________________________________________________________________
380 AliMUONVPainter::Depth() const
382 /// Return our depth in the hierarchy
386 return Mother()->Depth() + 1;
394 //_____________________________________________________________________________
396 AliMUONVPainter::DistancetoPrimitive(Int_t px, Int_t py)
398 /// See TObject::DistancetoPrimitive
400 static const Int_t kBigValue = 999999;
402 if (!gPad) return kBigValue;
406 AliMUONVPainter* painter = GetPainter(px,py,x,y);
408 x=y=0.0; // to avoid compiler warning
410 if ( painter == this) return 0;
415 //_____________________________________________________________________________
417 AliMUONVPainter::DoubleClicked(AliMUONVPainter*, Double_t*)
419 /// Should emit the DoubleClicked signal (if I knew how to detect those events...)
421 AliWarning("Please implement me !");
425 // // let our top mother emit the signal as clients are probably connected to
426 // // our mother, not to us
427 // Top()->DoubleClicked(painter,values);
431 // Long_t param[] = { (Long_t)painter,(Long_t)values };
433 // Emit("DoubleClicked(AliMUONVPainter*,Double_t*)",param);
437 //_____________________________________________________________________________
439 AliMUONVPainter::Draw(Option_t* opt)
441 /// Append ourselves to the current pad
445 gROOT->MakeDefCanvas();
448 Bool_t kMustSetRange(kFALSE);
453 if (sopt.Contains("R") ) kMustSetRange=kTRUE;
457 Double_t x1,y1,x2,y2;
458 GetBoundingBox(x1,y1,x2,y2);
459 if ( gPad) gPad->Range(x1,y1,x2,y2);
462 if ( !fMother && !fPainterGroups )
467 TIter next(fChildren);
468 AliMUONVPainter* painter;
469 while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
479 //_____________________________________________________________________________
481 AliMUONVPainter::ExecuteEvent(Int_t event, Int_t px, Int_t py)
483 /// Handle graphics events
487 AliMUONVPainter* painter = GetPainter(px,py,x,y);
489 if ( painter == this )
491 Double_t values[] = { x,y };
496 ShiftClicked(this,values);
499 Clicked(this,values);
502 //the following statement is required against other loop executions before returning (depending on the time between the clicks)
503 gPad->GetCanvas()->HandleInput((EEventType)-1,0,0);
504 DoubleClicked(this,values);
510 //_____________________________________________________________________________
512 AliMUONVPainter::FlatList(TList& list)
514 /// Make a flat list of our children
516 TIter next(fChildren);
517 AliMUONVPainter* painter;
518 while ( ( painter = static_cast<AliMUONVPainter*>(next())))
520 painter->FlatList(list);
526 //_____________________________________________________________________________
528 AliMUONVPainter::GetBoundingBox(Double_t& x1, Double_t& y1,
529 Double_t& x2, Double_t& y2) const
531 /// Get the bounding box = our area
532 AliMpArea area(Area().Position(),Area().Dimensions()*fBorderFactor);
534 x1 = area.LeftBorder();
535 y1 = area.DownBorder();
536 x2 = area.RightBorder();
537 y2 = area.UpBorder();
540 //_____________________________________________________________________________
542 AliMUONVPainter::GetObjectInfo(Int_t, Int_t) const
544 /// See TObject::GetObjectInfo
545 return const_cast<char*>(GetName());
548 //_____________________________________________________________________________
550 AliMUONVPainter::GetPainter(Int_t px, Int_t py, Double_t& x, Double_t& y) const
552 /// Get the responder painter at integer position (px,py), and get back its
553 /// absolute position (x,y)
555 PixelToPad(px,py,x,y);
557 if ( !IsInside(x,y) ) return 0x0;
559 if ( fGroup->IsResponder() ) return const_cast<AliMUONVPainter*>(this);
563 TIter next(fChildren);
564 AliMUONVPainter* painter;
566 while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
568 AliMUONVPainter* p = painter->GetPainter(px,py,x,y);
576 //_____________________________________________________________________________
578 AliMUONVPainter::GetTypes(TObjArray& types) const
580 /// Get the list of types (as a TObjArray of TObjString)
581 /// of our hierarchy, sorted alphabetically
583 types.SetOwner(kTRUE);
587 tmp.SetOwner(kFALSE);
589 TIter next(fPainterGroups);
592 while ( ( str = static_cast<TObjString*>(next()) ) )
594 AliMUONPainterGroup* group = Group(str->String().Data());
600 Int_t n = tmp.GetLast()+1;
602 Int_t* index = new Int_t[n];
604 Int_t* a = new Int_t[n];
606 for ( Int_t i = 0; i < n; ++i )
608 AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(tmp.At(i));
609 a[i] = group->Depth();
612 TMath::Sort(n,a,index,kFALSE);
614 for ( Int_t i = 0; i < n; ++i )
616 AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(tmp.At(index[i]));
617 types.AddLast(new TObjString(group->Type()));
624 //_____________________________________________________________________________
626 AliMUONVPainter::Group(const char* type) const
628 /// Returns a group of a given type
629 if (!fPainterGroups) return 0x0;
630 return static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(type));
633 //_____________________________________________________________________________
635 AliMUONVPainter::Group(Int_t depth) const
637 /// Returns a group of a given depth
638 if (!fPainterGroups) return 0x0;
639 TIter next(fPainterGroups);
640 TObjString* groupName;
641 while ( ( groupName = static_cast<TObjString*>(next()) ) )
643 AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>
644 (fPainterGroups->GetValue(groupName->String().Data()));
645 if ( group->Depth() == depth )
653 //_____________________________________________________________________________
655 AliMUONVPainter::IsInside(Double_t x, Double_t y) const
657 /// Whether point (x,y) is inside our contour
658 if (!fContour) return kFALSE;
659 return fContour->IsInside(x,y);
662 //_____________________________________________________________________________
664 AliMUONVPainter::IsResponder() const
666 /// Whether we're responding to mouse events
667 return MotherGroup()->IsResponder();
670 //_____________________________________________________________________________
672 AliMUONVPainter::Master() const
674 /// Return the top of the hierarchy
676 /// if we get no mother, we are the master
678 if ( Mother() == 0x0 ) return const_cast<AliMUONVPainter*>(this);
680 AliMUONVPainter* p = Mother();
682 while ( p->Mother() )
690 //_____________________________________________________________________________
692 AliMUONVPainter::Paint(Option_t*)
694 /// Paint ourselves of screen
695 /// If we have some data (i.e. we're belonging to the plotter group)
696 /// we use PaintArea.
697 /// And if must be outlined, then we do that too.
699 if ( !MotherGroup()->IsVisible() ) return;
701 if ( MotherGroup()->IsPlotter() )
703 PaintArea(*(MotherGroup()->Data()),
704 MotherGroup()->DataIndex(),
705 MotherGroup()->DataMin(),
706 MotherGroup()->DataMax());
709 if ( MotherGroup()->IsOutlined() )
715 //_____________________________________________________________________________
717 AliMUONVPainter::Describe(const AliMUONVTrackerData&, Int_t, Double_t, Double_t)
719 /// Default implementation (must be overriden)
720 AliError(Form("%s : implement me",GetName()));
724 //_____________________________________________________________________________
726 AliMUONVPainter::PaintArea(const AliMUONVTrackerData&, Int_t, Double_t, Double_t)
728 /// Default implementation (must be overriden)
729 AliError(Form("%s : implement me",GetName()));
732 //_____________________________________________________________________________
734 AliMUONVPainter::PaintOutline(Int_t color, Int_t width, Double_t /*x*/, Double_t /*y*/)
736 /// Default implementation is simply a drawing of the contour lines,
737 /// not using the optional (x,y)
738 Int_t c = color >= 0 ? color : GetLineColor();
739 Int_t w = width >= 0 ? width : GetLineWidth();
741 fContour->PaintOutline(c,w);
744 //_____________________________________________________________________________
746 AliMUONVPainter::PixelToPad(Int_t px, Int_t py, Double_t& x, Double_t& y)
748 /// convert (px,py) into pad position (x,y)
750 x = gPad->PadtoX(gPad->AbsPixeltoX(px));
751 y = gPad->PadtoY(gPad->AbsPixeltoY(py));
754 //_____________________________________________________________________________
756 AliMUONVPainter::Print(Option_t* opt) const
759 for ( Int_t i = 0; i < Depth()*4; ++i )
764 if ( !IsValid() ) cout << "!!!INVALID!!!" << endl;
766 cout << Form("%p Name %s Depth %d ContourName %s ID=(%d,%d)",
767 this,GetName(),Depth(),ContourName().Data(),ID0(),ID1());
769 if ( fResponderGroup )
771 cout << Form(" Responder group %p %s",fResponderGroup,fResponderGroup->Type());
775 cout << Form(" Plotter group %p %s",fPlotterGroup,fPlotterGroup->Type());
779 cout << Form(" Mother %p %s",Mother(),Mother()->GetName());
783 cout << Form(" Group %p %s ",MotherGroup(),MotherGroup()->Type());
788 cout << Form(" %d children",fChildren->GetLast()+1);
796 if ( fChildren && ( sopt == "FULL" || sopt == "CHILD" ) )
798 TIter next(fChildren);
799 AliMUONVPainter* painter;
800 while ( ( painter = static_cast<AliMUONVPainter*>(next()) ) )
806 if ( fPainterGroups && ( sopt == "FULL" || sopt == "GROUP" ) )
808 TIter next(fPainterGroups);
809 TObjString* groupName;
810 while ( ( groupName = static_cast<TObjString*>(next()) ) )
812 AliMUONPainterGroup* group = Group(groupName->String().Data());
818 //_____________________________________________________________________________
820 AliMUONVPainter::SetAttributes(const AliMUONAttPainter& attributes)
822 /// Set our attributes
823 fAttributes = attributes;
826 //_____________________________________________________________________________
828 AliMUONVPainter::SetContour(AliMUONPainterContour* contour)
833 AliError(Form("Setting a null contour for painter %s : bad idea !",PathName().Data()));
838 //_____________________________________________________________________________
840 AliMUONVPainter::SetData(const char* pattern, AliMUONVTrackerData* data,
843 /// Tell all painters which type matches pattern that they should
844 /// monitor a given data source
846 if ( !fPainterGroups )
851 TIter next(fPainterGroups);
856 while ( ( str = static_cast<TObjString*>(next()) ) )
858 AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
859 if ( group->Matches(pattern) )
861 group->SetData(data,dataIndex);
864 fPlotterGroup = group;
869 group->SetData(0x0,-1);
874 //_____________________________________________________________________________
876 AliMUONVPainter::SetLine(Int_t depth, Int_t lineColor, Int_t lineWidth)
878 /// Set the line attributes of painters at a given depth
879 AliMUONPainterGroup* group = Group(depth);
882 group->SetLine(lineColor,lineWidth);
886 //_____________________________________________________________________________
888 AliMUONVPainter::SetMother(AliMUONVPainter* painter)
894 //_____________________________________________________________________________
896 AliMUONVPainter::SetOutlined(const char* pattern, Bool_t flag)
898 /// Decide whether or not painters which type matches pattern
899 /// should be outlined
901 AliDebug(1,Form("pattern=%s flag=%d",pattern,flag));
908 TIter next(fPainterGroups);
911 while ( ( str = static_cast<TObjString*>(next()) ) )
913 AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
914 if ( group->Matches(pattern) )
916 group->SetOutlined(flag);
921 //_____________________________________________________________________________
923 AliMUONVPainter::SetResponder(const char* pattern)
925 /// Set the painters matching pattern to be the responder
927 AliDebug(1,Form("pattern=%s",pattern));
934 TIter next(fPainterGroups);
937 fResponderGroup = 0x0;
939 while ( ( str = static_cast<TObjString*>(next()) ) )
941 AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
942 if ( group->Matches(pattern) )
944 AliDebug(1,Form("group %s is matching pattern %s : setting to responder",
945 group->Type(),pattern));
946 group->SetResponder(kTRUE);
947 fResponderGroup = group;
951 group->SetResponder(kFALSE);
956 //_____________________________________________________________________________
958 AliMUONVPainter::SetResponder(Int_t depth)
960 /// Select as responder the *first* group that has a given depth
962 AliDebug(1,Form("depth=%d",depth));
969 TIter next(fPainterGroups);
972 fResponderGroup = 0x0;
974 while ( ( str = static_cast<TObjString*>(next()) ) )
976 AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
977 if ( group->Depth() == depth )
979 AliDebug(1,Form("group %s has correct depth = %d, using as responder",
980 group->Type(),depth));
981 group->SetResponder(kTRUE);
982 fResponderGroup = group;
987 group->SetResponder(kFALSE);
992 //_____________________________________________________________________________
994 AliMUONVPainter::SetVisible(const char* pattern, Bool_t flag)
996 /// Decide whether the painters matching pattern should be visible or not
997 AliDebug(1,Form("pattern=%s flag=%d",pattern,flag));
1004 TIter next(fPainterGroups);
1007 while ( ( str = static_cast<TObjString*>(next()) ) )
1009 AliMUONPainterGroup* group = static_cast<AliMUONPainterGroup*>(fPainterGroups->GetValue(str));
1010 if ( group->Matches(pattern) )
1012 group->SetVisible(flag);
1017 //_____________________________________________________________________________
1019 AliMUONVPainter::UpdateGroupsFrom(const AliMUONVPainter& painter)
1021 /// (re)Create groups
1022 delete fPainterGroups;
1023 fPainterGroups = 0x0;
1027 // and copy the status of responder, plotter and visible
1028 if ( painter.ResponderGroup() )
1030 SetResponder(painter.ResponderGroup()->Type());
1033 if ( painter.PlotterGroup() )
1035 SetData(painter.PlotterGroup()->Type(),
1036 painter.PlotterGroup()->Data(),
1037 painter.PlotterGroup()->DataIndex());
1038 PlotterGroup()->SetDataRange(painter.PlotterGroup()->DataMin(),
1039 painter.PlotterGroup()->DataMax());
1043 painter.GetTypes(types);
1045 TObjString* groupName;
1047 while ( ( groupName = static_cast<TObjString*>(next()) ) )
1049 AliMUONPainterGroup* group = painter.Group(groupName->String().Data());
1050 if ( group->IsVisible() )
1052 SetVisible(group->Type(),kTRUE);
1056 SetVisible(group->Type(),kFALSE);
1059 if ( group->IsOutlined() )
1061 SetOutlined(group->Type(),kTRUE);
1065 SetOutlined(group->Type(),kFALSE);
1068 SetLine(group->Depth(),group->GetLineColor(),group->GetLineWidth());
1072 //_____________________________________________________________________________
1074 AliMUONVPainter::CreatePainter(const char* className,
1075 const AliMUONAttPainter& att,
1076 Int_t id1, Int_t id2)
1078 /// Create a painter (factory method)
1080 TClass* c = TClass::GetClass(className);
1084 AliErrorClass(Form("Cannot get class %s",className));
1092 call.InitWithPrototype(c,className,"AliMUONAttPainter&,Int_t");
1094 if (call.IsValid()) n = 1;
1097 call.InitWithPrototype(c,className,"AliMUONAttPainter&,Int_t,Int_t");
1099 if ( call.IsValid() ) n = 2;
1102 Long_t returnLong(0x0);
1106 Long_t params[] = { (Long_t)(&att), (Long_t)(id1) };
1107 call.SetParamPtrs((void*)(params));
1108 call.Execute((void*)(0x0),returnLong);
1112 Long_t params[] = { (Long_t)(&att), (Long_t)(id1), (Long_t)(id2) };
1113 call.SetParamPtrs((void*)(params));
1114 call.Execute((void*)(0x0),returnLong);
1119 AliErrorClass(Form("Cannot create a painter of class %s",className));
1122 AliMUONVPainter* rv = reinterpret_cast<AliMUONVPainter*> (returnLong);
1126 AliErrorClass(Form("Painter of class %s is not valid",className));