]> git.uio.no Git - u/mrichter/AliRoot.git/blob - EVE/EveDet/AliEveListAnalyser.cxx
updates for the list analyser (Ben)
[u/mrichter/AliRoot.git] / EVE / EveDet / AliEveListAnalyser.cxx
1 // Author: Benjamin Hess   15/01/2010
2
3 /*************************************************************************
4  * Copyright (C) 2009-2010, Alexandru Bercuci, Benjamin Hess.            *
5  * All rights reserved.                                                  *
6  *************************************************************************/
7
8 //////////////////////////////////////////////////////////////////////////
9 //                                                                      //
10 // AliEveListAnalyser                                                   //
11 //                                                                      //
12 // An AliEveListAnalyser is, in principal, a TEveElementList with some  //
13 // sophisticated features. You can add macros to this list, which then  //
14 // can be applied to the list of analysis objects (these objects can be //
15 // added to the list in the same way as for the TEveElementList, but    //
16 // also "by clicking" (cf. AliEveListAnaLyserEditor)).                  //
17 // In general, please use AddMacro(...) for this purpose.               //
18 // Macros that are no longer needed can be removed from the list via    //
19 // RemoveSelectedMacros(...). This function takes an iterator of the    //
20 // list of macros that are to be removed.                               //
21 // An entry looks like:                                                 //
22 // The data for each macro consists of path, name, type and the command //
23 // that will be used to apply the macro. This stuff is stored in a map  //
24 // which takes the macro name for the key and the above mentioned data  //
25 // in a TGeneralMacroData-object for the value.                         //
26 // You can get the macro type via GetMacroType(...).                    //
27 // To find the type of objects the macro will deal with (corresponds to //
28 // "YourObjectType" in the examples below) please use                   //
29 // GetMacroObjectType(...).                                             //
30 // With ApplySTSelectionMacros(...) or ApplyProcessMacros(...)          //
31 // respectively you can apply the macros to the track list via          //
32 // iterators (same style like for RemoveSelectedMacros(...)(cf. above)).//
33 // Selection macros (de-)select macros according to a selection rule    //
34 // by setting the rnr-state of the tracks.                              //
35 // If multiple selection macros are applied, a track is selected, if    //
36 // all selection macros select the track.                               //
37 // Process macros create data or histograms, which will be stored in    //
38 // a temporary file. The editor of this class will access this file     //
39 // and draw all the stuff within it's DrawHistos() function. The file   //
40 // will be deleted by the destructor.                                   //
41 //                                                                      //
42 // Currently, the following macro types are supported:                  //
43 // Selection macros:                                                    //
44 // Bool_t YourMacro(const YourObjectType*);                             //
45 // Bool_t YourMacro(const YourObjectType*, const YourObjectType*);      //
46 //                                                                      //
47 // Process macros:                                                      //
48 // void YourMacro(const YourObjectType*, Double_t*&, Int_t&);           //
49 // void YourMacro(const YourObjectType*, const YourObjectType*,         //
50 //                Double_t*&, Int_t&);                                  //
51 // TH1* YourMacro(const YourObjectType*);                               //
52 // TH1* YourMacro(const YourObjectType*, const YourObjectType*);        //
53 //                                                                      //
54 // The macros which take 2 tracks are applied to all track pairs        //
55 // (whereby BOTH tracks of the pair have to be selected by the single   //
56 // track selection macros and have to be unequal, otherwise they will   //
57 // be skipped) that have been selected by ALL correlated tracks         //
58 // selection macros. The selection macros with 2 tracks do NOT affect   //
59 // process macros that process only a single track!                     //
60 //////////////////////////////////////////////////////////////////////////
61
62
63 // Uncomment to display debugging infos
64 //#define AliEveListAnalyser_DEBUG
65
66 #include <TEveManager.h>
67 #include <TEveSelection.h>
68 #include <TFile.h>
69 #include <TFunction.h>
70 #include <TH1.h>
71 #include <TList.h>
72 #include <TMap.h>
73 #include <TMethodArg.h>
74 #include <TMethodCall.h>
75 #include <TObjString.h>
76 #include <TQObject.h>
77 #include <TROOT.h>
78 #include <TSystem.h>
79 #include <TTree.h>
80 #include <TTreeStream.h>
81
82 #include <AliTRDReconstructor.h>
83
84 #include <EveDet/AliEveListAnalyser.h>
85 #include <EveDet/AliEveListAnalyserEditor.h>
86
87 ClassImp(AliEveListAnalyser)
88
89 ///////////////////////////////////////////////////////////
90 /////////////   AliEveListAnalyser ////////////////////////
91 ///////////////////////////////////////////////////////////
92 AliEveListAnalyser::AliEveListAnalyser(const Text_t* n, const Text_t* t, Bool_t doColor):
93   TEveElementList(n, t, doColor),
94   fConnected(kFALSE),
95   fDataFromMacroList(0x0),
96   fEditor(0x0),
97   fMacroList(0x0),
98   fDataTree(0x0),
99   fHistoDataSelected(0),
100   fMacroListSelected(0),
101   fSelectedTab(2)                               // Standard tab: "Apply macros" (index 2)
102 {
103   // Creates the AliEveListAnalyser.
104
105   // Only accept childs of type TEveElement
106   SetChildClass(TEveElement::Class());
107
108   // Allocate memory for the lists and declare them as owners of their contents
109   fDataFromMacroList = new TList();
110   fDataFromMacroList->TCollection::SetOwner(kTRUE);
111
112   fMacroList = new TMap();
113   // Set map to owner of it's objects to delete them, if they are removed from the map
114   fMacroList->SetOwnerKeyValue(kTRUE, kTRUE);
115
116   // Set the build directory for AClic
117   if(gSystem->AccessPathName(Form("%s/.QArec" , gSystem->Getenv("HOME")))) gSystem->Exec("mkdir $HOME/.QArec");
118   gSystem->SetBuildDir(Form("%s/.QArec", gSystem->Getenv("HOME")));
119
120   AddStandardContent();
121 }
122
123 //______________________________________________________
124 AliEveListAnalyser::~AliEveListAnalyser()
125 {
126   // Frees allocated memory (lists etc.).
127
128   // Stop adding objects
129   StopAddingObjects();
130
131   // Let the editor know that the list will be destroyed -> The editor will save the data
132   if (fEditor != 0)
133   {
134     fEditor->SaveMacroList(fMacroList);
135     fEditor = 0;
136   }
137
138   if (fDataFromMacroList != 0)
139   {
140     fDataFromMacroList->Delete();
141     delete fDataFromMacroList;
142     fDataFromMacroList = 0;
143   } 
144   if (fDataTree != 0)
145   {
146     delete fDataTree;
147     fDataTree = 0;
148   } 
149   if (fMacroList != 0)
150   {
151     fMacroList->DeleteAll();
152     delete fMacroList;
153     fMacroList = 0;
154   }
155   // Note: gSystem->AccessPathName(...) returns kTRUE, if the access FAILED!
156   if(!gSystem->AccessPathName(Form("/tmp/ListAnalyserMacroData_%s.root", gSystem->Getenv("USER")))) 
157     gSystem->Exec(Form("rm /tmp/ListAnalyserMacroData_%s.root", gSystem->Getenv("USER")));
158 }
159
160 //______________________________________________________
161 Int_t AliEveListAnalyser::AddMacro(const Char_t* path, const Char_t* nameC, Bool_t forceReload)
162 {
163   // Checks, if the file exists and if the signature is correct.
164   // If these criteria are fullfilled, the library for this macro is built
165   // and the macro is added to the corresponding list.
166   // Supported macro types:
167   // Selection macros:                                                    
168   // Bool_t YourMacro(const YourObjectType*)
169   // Bool_t YourMacro(const YourObjectType*, const YourObjectType*)
170   //
171   // Process macros:                                                      
172   // void YourMacro(const YourObjectType*, Double_t*&, Int_t&)             
173   // void YourMacro(const YourObjectType*, const TObject*, Double_t*&, Int_t&)                                   
174   // TH1* YourMacro(const YourObjectType*)                                 
175   // TH1* YourMacro(const YourObjectType*, const YourObjectType*)                              
176
177   Char_t pathname[fkMaxMacroPathNameLength];
178   memset(pathname, '\0', sizeof(Char_t) * fkMaxMacroPathNameLength);
179
180   // Expand the path and create the pathname
181   Char_t* systemPath = gSystem->ExpandPathName(path);
182   sprintf(pathname, "%s/%s", systemPath, nameC);
183   delete systemPath;
184   systemPath = 0;
185
186   // Delete ".C" from filename
187   Char_t name[fkMaxMacroNameLength];
188   memset(name, '\0', sizeof(Char_t) * fkMaxMacroNameLength);
189   
190   for (UInt_t ind = 0; ind < fkMaxMacroNameLength && ind < strlen(nameC) - 2; ind++)  name[ind] = nameC[ind];
191
192   // Check, if files exists
193   FILE* fp = 0x0;
194   if((fp = fopen(pathname, "rb"))){
195     fclose(fp);
196     fp = 0x0;
197   } else  return NOT_EXIST_ERROR;
198   
199   // Clean up root, load the desired macro and then check the type of the macro
200   // A.B. gROOT->Reset();
201  
202   gROOT->ProcessLineSync(Form(".L %s+%c", pathname, forceReload ? '+' : ' '));
203
204   TClass* objectType;
205
206   objectType = GetMacroObjectType(name);
207
208   // We need this line... otherwise, in some cases, there will be problems concerning ACLIC
209   gROOT->ProcessLineSync(Form(".L %s", pathname));
210
211   if (!objectType)  return UNKNOWN_OBJECT_TYPE_ERROR;
212
213   AliEveListAnalyserMacroType type = GetMacroType(name, objectType->GetName(), kFALSE);
214
215   // Clean up again
216   // A.B. gROOT->Reset();
217  
218   // Has not the correct signature!
219   if (type == kUnknown) return SIGNATURE_ERROR;
220
221   // Only add macro, if it is not already in the list
222   Int_t returnValue = WARNING;
223   if(fMacroList->GetValue(name) == 0) 
224   {
225     returnValue = AddMacroFast(path, name, type, objectType) ? SUCCESS : ERROR;
226   }
227
228   return returnValue;
229 }
230
231 //______________________________________________________
232 Bool_t AliEveListAnalyser::AddMacroFast(const Char_t* path, const Char_t* name, AliEveListAnalyserMacroType type, TClass* objectType)
233 {
234   // Adds a macro (path/name) to the corresponding list. No checks are performed (file exists, 
235   // macro already in list/map, signature correct),  no libraries are created!
236   // You can use this function only, if the macro has been added successfully before 
237   // (and then maybe was removed). The function is very fast. On success kTRUE is returned, otherwise: kFALSE;
238
239   Bool_t success = kFALSE;
240
241   switch (type)
242   {
243     case kSingleObjectSelect:
244     case kCorrelObjectSelect:
245     case kSingleObjectAnalyse:
246     case kSingleObjectHisto:
247     case kCorrelObjectAnalyse:
248     case kCorrelObjectHisto:
249       fMacroList->Add(new TObjString(name), new TGeneralMacroData(name, path, type, objectType));
250
251       // We do not know, where the element has been inserted - deselect this list
252       fMacroListSelected = 0;
253     
254       success = kTRUE;
255
256 #ifdef AliEveListAnalyser_DEBUG
257       // Successfull add will only be displayed in debug mode
258       printf("AliEveListAnalyser::AddMacroFast: Added macro \"%s/%s\" with object type \"%s\" to the corresponding list\n", path, name,
259              objectType->GetName());
260 #endif
261
262       break;
263
264     default:
265       // Error will always be displayed
266       printf("AliEveListAnalyser::AddMacroFast: ERROR: Could not add macro \"%s/%s\" with object type \"%s\" to the corresponding list\n", 
267              path, name, objectType->GetName());
268
269       success = kFALSE;
270
271       break;
272   }
273
274   return success;
275 }
276
277
278 //______________________________________________________
279 Int_t AliEveListAnalyser::AddPrimSelectedObject(TEveElement* el)
280 {
281   // Adds the TEveElement el to the list. If it is already in the list, it is removed.
282   // This function is designed to be used together with a signal:
283   // It adds the (primarily) selected objects in the viewer to the list (objects that are already in the list are removed!).
284   // Returns "ERROR" (cf. defines) on error, "WARNING" if the element does not contain any user data and else "SUCCESS" (i.e.
285   // the element has been added successfully or the element is the list itself and therefore ignored, or the element is ignored 
286   // because it has been added via secondary selection).
287  
288   if (!el)
289   {
290     Error("AliEveListAnalyser::AddPrimSelectedObject", "Zero pointer!\n");
291
292     return ERROR;
293   }
294
295   // If the clicked element is the list itself, just do nothing.
296   if (el == this)  return SUCCESS;
297   
298   if (!this->HasChild(el))
299   {
300
301     // Ignore objects that do not have any user data, since these cannot be used in the analysis!
302     if (el->GetUserData() == 0x0)
303     {
304       Warning("AddPrimSelectedObject", "Selected object does not contain any \"user data\" and therefore is ignored!");
305
306       return WARNING;
307     }
308
309     // Element clicked that is not in the list (and is not the list itself!) -> Add this element to list
310     this->AddElement(el);
311   }
312   else
313   {
314     // Element clicked that is already in the list. Remove it. But: Only take care of objects that have been added
315     // via primary selection (name does not start with "[sec")
316     if (TString(el->GetElementName()).BeginsWith("[sec:"))  return SUCCESS;
317     this->RemoveElement(el);
318   } 
319
320   this->SetTitle(Form("Objects %d", this->NumChildren()));
321   gEve->Redraw3D();
322
323   return SUCCESS;
324 }
325
326
327 /*
328 //______________________________________________________
329 void AliEveListAnalyser::AddPrimSelectedObjects()
330 {
331   // Adds the (primarily) selected objects in the viewer to the list (objects that are already in the list are ignored).
332   // Hold the CTRL-key for multiple selection.
333
334   TEveSelection* eveSel = gEve->GetSelection();
335   if (!eveSel)
336   {
337     Error("AliEveListAnalyser::AddPrimSelectedObjects", "Failed to get the selection!\n");
338     return;
339   }
340   
341   TEveElement* elem = 0x0;
342   Bool_t changedSomething = kFALSE;
343
344   for (TEveElement::List_i iter = eveSel->BeginChildren(); iter != eveSel->EndChildren(); ++iter)
345   {
346     if(!(elem = dynamic_cast<TEveElement*>(*iter))) continue;
347
348     if (!this->HasChild(elem) && elem != this)
349     {
350       // Element clicked that is not in the list (and is not the list itself!) -> Add this element to list
351       this->AddElement(elem);
352       this->SetTitle(Form("Objects %d", this->NumChildren()));
353       changedSomething = kTRUE;
354     }
355   }
356
357   if (changedSomething) gEve->Redraw3D();
358 }
359 */
360
361 //______________________________________________________
362 void AliEveListAnalyser::AddSecSelectedSingleObjectToList(Int_t pointId)
363 {
364   // This function adds the selected object (secondary selection in the viewer) to the list
365   // of analysis objects. If the object is already in the list, it will be removed from it.
366   // This function is used to add single objects of a TEvePointset, e.g. single clusters.
367
368   TEvePointSet* ps = dynamic_cast<TEvePointSet*>((TQObject*) gTQSender);
369   if (!ps)
370   {
371     Error("AliEveListAnalyser::AddSecSelectedSingleObjectToList", "Zero pointer!\n");
372     return;
373   }
374
375   // Check, if object is already there. If so, remove it!
376   
377   // 1st possibility: Object of the list clicked. But: Only take care of objects that have been added
378   // via secondary selection (name starts with "[sec"). Note: HasChild will also return kTRUE, if e.g.
379   // the whole TEvePointSet of clusters is in the last (but maybe another point of it has been clicked!)
380
381   if (this->HasChild(ps))
382   {
383     if (TString(ps->GetName()).BeginsWith("[sec:"))
384     {
385       // I don't know why, but you get a crash, if you try this->RemoveElement(ps) (in some cases).
386       // So, use this way instead.
387       //this->RemoveElement((TEveElement*)ps);
388       TEveElement* listObj = this->FindChild(ps->GetName());
389       if (listObj)
390       {
391         this->RemoveElement(listObj);
392         this->SetTitle(Form("Objects %d", this->NumChildren()));
393         gEve->Redraw3D();
394       }
395
396       return;
397     }
398   }
399   
400   TObject* obj = ps->GetPointId(pointId);
401   if (obj)
402   {
403     // 2nd possibility: Same object clicked again
404     TEveElement* listObj = 0x0;
405     listObj = this->FindChild(Form("[sec:%d] %s%d", obj->GetUniqueID(), obj->GetName(), pointId));
406     if (listObj)
407     {
408       this->RemoveElement(listObj);  
409       this->SetTitle(Form("Objects %d", this->NumChildren()));
410
411       gEve->Redraw3D();
412       return;
413     }
414
415     // Object clicked that is not in the list -> Add this object to list
416     TEvePointSet* newPS = new TEvePointSet(Form("[sec:%d] %s%d", obj->GetUniqueID(), obj->GetName(), pointId));
417     Double_t x = 0, y = 0, z = 0;
418     ps->GetPoint(pointId, x, y, z);
419     newPS->SetPoint(0, x, y, z);
420     newPS->SetUserData(obj);
421     // Choose yellow for the added points and inherit style and size for the marker
422     newPS->SetMarkerColor(5);
423     newPS->SetMarkerStyle(ps->GetMarkerStyle());
424     newPS->SetMarkerSize(ps->GetMarkerSize());
425
426     this->AddElement(newPS);
427     this->SetTitle(Form("Objects %d", this->NumChildren()));
428     gEve->Redraw3D();
429   }
430   else
431   {
432     Error("AliEveListAnalyser::AddSecSelectedSingleObjectToList", "Selected object is NULL and therefore ignored!");
433   }
434 }
435
436 //______________________________________________________
437 void AliEveListAnalyser::AddStandardContent()
438 {
439   // Adds standard macros to the macro list.
440
441   // Add your standard macros here, e.g.: 
442   // To add a macro use:
443   // AddMacro("$(ALICE_ROOT)/myFolder", "myMacroName.C");
444   // -> If the file does not exist, nothing happens. So if you want to handle this,
445   // use the return value of AddMacro (NOT_EXIST_ERROR is returned, if file does not exist)
446   // (-> You can also check for other return values (see AddMacro(...)))
447
448 }
449
450 //______________________________________________________
451 Bool_t AliEveListAnalyser::ApplyProcessMacros(const TList* selIterator, const TList* procIterator)
452 {
453   // Uses the procIterator (for the selected process macros) to apply the selected macros to the data.
454   // Returns kTRUE on success, otherwise kFALSE. If there no process macros selected, kTRUE is returned 
455   // (this is no error!).
456   // The single object process macros are applied to all selected objects.
457   // The selIterator (for the selected selection macros) will be used to apply the correlated objects selection
458   // macros to all object pairs (whereby BOTH objects have to be selected, otherwise they will be skipped).
459   // All object pairs that have been selected by ALL correlated objects selection macros will be processed by
460   // the correlated objects process macros.
461
462   // No process macros need to be processed
463   if (procIterator->GetEntries() <= 0)  return kTRUE;
464
465   // Clear root
466   // A.B. gROOT->Reset();
467   
468   // Clear old data and re-allocate
469   if (fDataTree == 0x0){ 
470     TDirectory *cwd = gDirectory;
471     fDataTree = new TTreeSRedirector(Form("/tmp/ListAnalyserMacroData_%s.root", gSystem->Getenv("USER")));
472     cwd->cd();
473   }
474   if (!fDataTree){
475     Error("Apply process macros", Form("File \"/tmp/ListAnalyserMacroData_%s.root\" could not be accessed properly!", 
476           gSystem->Getenv("USER")));
477     return kFALSE;
478   }
479   
480   if (fDataFromMacroList != 0) {
481     fDataFromMacroList->Delete();
482     delete fDataFromMacroList;
483   }
484   fDataFromMacroList = new TList();
485   fDataFromMacroList->TCollection::SetOwner(kTRUE);
486
487   fHistoDataSelected = 0;
488
489
490   TGeneralMacroData* macro = 0;
491
492   Char_t** procCmds = 0;
493   AliEveListAnalyserMacroType* mProcType = 0;
494   if (procIterator->GetEntries() > 0) {
495     procCmds = new Char_t*[procIterator->GetEntries()];
496     mProcType = new AliEveListAnalyserMacroType[procIterator->GetEntries()];
497   }
498   
499   TClass** mProcObjectType = 0;
500   if (procIterator->GetEntries() > 0) {
501     mProcObjectType = new TClass*[procIterator->GetEntries()];
502   }
503
504   Char_t** selCmds  = 0;
505   AliEveListAnalyserMacroType* mSelType = 0;
506   if (selIterator->GetEntries() > 0) {
507     selCmds = new Char_t*[selIterator->GetEntries()];
508     mSelType = new AliEveListAnalyserMacroType[selIterator->GetEntries()];
509   }
510
511   TClass** mSelObjectType = 0;
512   if (selIterator->GetEntries() > 0) {
513     mSelObjectType = new TClass*[selIterator->GetEntries()];
514   }
515   
516   Bool_t selectedByCorrSelMacro = kFALSE;
517
518   AliEveListAnalyserMacroType macroType = kUnknown;
519   Int_t numHistoMacros = 0;
520   TH1** histos = 0;
521
522   TEveElement* object1 = 0;
523   TEveElement* object2 = 0;
524
525   // Collect the commands for each process macro and add them to "data-from-list"
526   for (Int_t i = 0; i < procIterator->GetEntries(); i++){
527     procCmds[i] = new Char_t[(fkMaxMacroPathNameLength + fkMaxApplyCommandLength)];
528     memset(procCmds[i], '\0', sizeof(Char_t) * (fkMaxMacroNameLength + fkMaxApplyCommandLength));
529
530     macro = (TGeneralMacroData*)fMacroList->GetValue(procIterator->At(i)->GetTitle());
531
532     if (!macro){
533       Error("Apply process macros", 
534         Form("Macro list is corrupted: Macro \"%s\" is not registered!", 
535         procIterator->At(i)->GetTitle()));
536       continue;
537     }
538
539 #ifdef AliEveListAnalyser_DEBUG
540     printf("AliEveListAnalyser: Checking process macro: %s\n", macro->GetName());
541 #endif 
542            
543     // Find the object type of the macro
544     mProcObjectType[i] = macro->GetObjectType();
545
546     // Find the type of the process macro
547     macroType = macro->GetType();
548     if (macroType == kSingleObjectHisto || macroType == kCorrelObjectHisto){
549       mProcType[i] = macroType;
550       numHistoMacros++;
551       // Create the command 
552       sprintf(procCmds[i], macro->GetCmd());
553
554       // Add to "data-from-list" -> Mark as a histo macro with the substring "(histo macro)"
555       fDataFromMacroList->Add(new TObjString(Form("%s (histo macro)", macro->GetName())));
556     } else if (macroType == kSingleObjectAnalyse || macroType == kCorrelObjectAnalyse) {
557       mProcType[i] = macroType;
558       // Create the command 
559       sprintf(procCmds[i], macro->GetCmd());
560
561       // Add to "data-from-list"
562       fDataFromMacroList->Add(new TObjString(macro->GetName()));
563     } else {
564       Error("Apply process macros", 
565         Form("Macro list corrupted: Macro \"%s/%s.C\" is not registered as a process macro!", 
566         macro->GetPath(), macro->GetName()));
567       mProcType[i] = kUnknown;
568     } 
569   }  
570
571   // Collect the commands for each selection macro and add them to "data-from-list"
572   for (Int_t i = 0; i < selIterator->GetEntries(); i++){
573     selCmds[i] = new Char_t[(fkMaxMacroPathNameLength + fkMaxApplyCommandLength)];
574     memset(selCmds[i], '\0', sizeof(Char_t) * (fkMaxMacroNameLength + fkMaxApplyCommandLength));
575
576     macro = (TGeneralMacroData*)fMacroList->GetValue(selIterator->At(i)->GetTitle());
577
578     if (!macro){
579       Error("Apply process macros", 
580         Form("Macro list is corrupted: Macro \"%s\" is not registered!", 
581         selIterator->At(i)->GetTitle()));
582       continue;
583     }
584
585 #ifdef AliEveListAnalyser_DEBUG
586     printf("AliEveListAnalyser: Checking selection macro: %s\n", macro->GetName());
587 #endif
588
589     // Find the object type of the macro
590     mSelObjectType[i] = macro->GetObjectType();
591        
592     // Find the type of the process macro
593     macroType = macro->GetType();
594
595     // Single Object select macro
596     if (macroType == kSingleObjectSelect) {
597       // Has already been processed by ApplySTSelectionMacros(...)
598       mSelType[i] = macroType;         
599     }
600     // Correlated Objects select macro
601     else if (macroType == kCorrelObjectSelect) {
602       mSelType[i] = macroType;  
603  
604       // Create the command
605       sprintf(selCmds[i], macro->GetCmd());
606     } else {
607       Error("Apply process macros", 
608         Form("Macro list corrupted: Macro \"%s/%s.C\" is not registered as a selection macro!", 
609         macro->GetPath(), macro->GetName()));
610       mSelType[i] = kUnknown;
611     } 
612   }  
613
614   // Allocate memory for the histograms
615   if (numHistoMacros > 0)  histos = new TH1*[numHistoMacros];
616   for (Int_t i = 0; i < numHistoMacros; i++)  histos[i] = 0x0;
617
618
619   //////////////////////////////////////
620   // WALK THROUGH THE LIST OF OBJECTS //
621   //////////////////////////////////////     
622   for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter){
623     if(!(object1 = dynamic_cast<TEveElement*>(*iter))) continue;
624
625     // Skip objects that have not been selected
626     if (!object1->GetRnrState())  continue;
627     
628     // Cast to the "real" object behind
629     gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object1));
630     gROOT->ProcessLineSync("TObject* automaticObject_1 = (TObject*)automaticEveElement->GetUserData();");
631
632     // Collect data for each macro
633     for (Int_t i = 0, histoIndex = 0; i < procIterator->GetEntries(); i++){
634       // Find the type of the object and relate it to the macro object type
635       // Only apply macro to this object, if...
636       // ... the macro takes objects of exactly this type.
637       // ... the macro object type is a child of this object's type.
638       // Otherwise: Continue
639
640       // Finally, via procCmds[i], the automatic objects are casted to the correct type and analysed by each macro!
641       if (((TObject*)object1->GetUserData())->IsA() != mProcObjectType[i] && 
642           !((TObject*)object1->GetUserData())->InheritsFrom(mProcObjectType[i]))  continue;
643
644         
645       // Single object histo
646       if (mProcType[i] == kSingleObjectHisto){
647         histos[histoIndex++] = (TH1*)gROOT->ProcessLineSync(procCmds[i]);
648        // Correlated Objects histo
649       } else if (mProcType[i] == kCorrelObjectHisto) {
650         // Loop over all pairs behind the current one - together with the other loop this will be a loop
651         // over all pairs. We have a pair of objects, if and only if both objects of the pair are selected (Rnr-state)
652         // and are not equal.
653         // The correlated objects process macro will be applied to all pairs that will be additionally selected by
654         // all correlated objects selection macros.
655         TEveElement::List_i iter2 = iter;
656         iter2++;
657         for ( ; iter2 != this->EndChildren(); ++iter2)
658         {
659           if(!(object2 = dynamic_cast<TEveElement*>(*iter2))) continue;
660
661           // Skip objects that have not been selected
662           if (!object2->GetRnrState())  continue;
663
664           // Same check of the macro object type as before
665           if (((TObject*)object2->GetUserData())->IsA() != mProcObjectType[i] && 
666               !((TObject*)object2->GetUserData())->InheritsFrom(mProcObjectType[i]))  continue;
667       
668           // Cast to the "real" object behind
669           gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object2));
670           gROOT->ProcessLineSync("TObject* automaticObject_2 = (TObject*)automaticEveElement->GetUserData();");
671
672           // Select object by default (so it will be processed, if there are no correlated objects selection macros!)
673           selectedByCorrSelMacro = kTRUE;
674           for (Int_t j = 0; j < selIterator->GetEntries(); j++){
675             if (mSelType[j] == kCorrelObjectSelect){
676           // Check, whether the macro can deal with both objects. If not, skip it.
677           // Note: Again, via selCmds[i], the automatic objects are casted to the correct type!
678           if (((TObject*)object1->GetUserData())->IsA() != mSelObjectType[j] && 
679               !((TObject*)object1->GetUserData())->InheritsFrom(mSelObjectType[j]))  continue;
680           if (((TObject*)object2->GetUserData())->IsA() != mSelObjectType[j] && 
681               !((TObject*)object2->GetUserData())->InheritsFrom(mSelObjectType[j]))  continue;
682
683               selectedByCorrSelMacro = (Bool_t)gROOT->ProcessLineSync(selCmds[j]);
684               if (!selectedByCorrSelMacro)  break;
685             }
686           }       
687
688           // If the pair has not been selected by the correlated objects selection macros, skip it!
689           if (!selectedByCorrSelMacro) continue;
690           
691           histos[histoIndex] = (TH1*)gROOT->ProcessLineSync(procCmds[i]);
692         }
693         histoIndex++;
694       }
695       // Single object analyse
696       else if (mProcType[i] == kSingleObjectAnalyse) {
697         // Create data pointers in CINT, execute the macro and get the data
698         gROOT->ProcessLineSync("Double_t* results = 0;");
699         gROOT->ProcessLineSync("Int_t n = 0;");
700         gROOT->ProcessLineSync(procCmds[i]);
701         Double_t* results = (Double_t*)gROOT->ProcessLineSync("results;");
702         Int_t nResults = (Int_t)gROOT->ProcessLineSync("n;");
703         
704         if (results == 0) {
705           Error("Apply macros", Form("Error reading data from macro \"%s\"", procIterator->At(i)->GetTitle()));
706           continue;
707         }
708         for (Int_t resInd = 0; resInd < nResults; resInd++){
709           (*fDataTree) << Form("ObjectData%d", i) << Form("Macro%d=", i) << results[resInd] << (Char_t*)"\n";   
710         }
711
712         delete results;
713         results = 0;
714       }
715       // Correlated objects analyse
716       else if (mProcType[i] == kCorrelObjectAnalyse){
717         // Loop over all pairs behind the current one - together with the other loop this will be a loop
718         // over all pairs. We have a pair of objects, if and only if both objects of the pair are selected (Rnr-state)
719         // and are not equal.
720         // The correlated objects process macro will be applied to all pairs that will be additionally selected by
721         // all correlated objects selection macros.
722         TEveElement::List_i iter2 = iter;
723         iter2++;
724
725         for ( ; iter2 != this->EndChildren(); ++iter2) {
726           if(!(object2 = dynamic_cast<TEveElement*>(*iter2))) continue;
727  
728           // Skip objects that have not been selected
729           if (!object2->GetRnrState())  continue;
730
731           // Same check of the macro object type as before
732           if (((TObject*)object2->GetUserData())->IsA() != mProcObjectType[i] && 
733               !((TObject*)object2->GetUserData())->InheritsFrom(mProcObjectType[i]))  continue;
734     
735           // Cast to the "real" object behind
736           gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object2));
737           gROOT->ProcessLineSync("TObject* automaticObject_2 = (TObject*)automaticEveElement->GetUserData();");
738
739           // Select object by default (so it will be processed, if there are no correlated objects selection macros!)
740           selectedByCorrSelMacro = kTRUE;
741           for (Int_t j = 0; j < selIterator->GetEntries(); j++) {
742             if (mSelType[j] == kCorrelObjectSelect) {
743               // Check, whether the macro can deal with both objects. If not, skip it.
744               // Note: Again, via selCmds[i], the automatic objects are casted to the correct type!
745               if (((TObject*)object1->GetUserData())->IsA() != mSelObjectType[j] && 
746                   !((TObject*)object1->GetUserData())->InheritsFrom(mSelObjectType[j]))  continue;
747               if (((TObject*)object2->GetUserData())->IsA() != mSelObjectType[j] && 
748                   !((TObject*)object2->GetUserData())->InheritsFrom(mSelObjectType[j]))  continue;
749
750               selectedByCorrSelMacro = (Bool_t)gROOT->ProcessLineSync(selCmds[j]);
751               if (!selectedByCorrSelMacro)  break;
752             }
753           }       
754
755           // If the pair has not been selected by the correlated objects selection macros, skip it!
756           if (!selectedByCorrSelMacro) continue;
757           
758           // Create data pointers in CINT, execute the macro and get the data
759           gROOT->ProcessLineSync("Double_t* results = 0;");
760           gROOT->ProcessLineSync("Int_t n = 0;");
761           gROOT->ProcessLineSync(procCmds[i]);
762           Double_t* results = (Double_t*)gROOT->ProcessLineSync("results;");
763           Int_t nResults = (Int_t)gROOT->ProcessLineSync("n;");
764      
765           if (results == 0) {
766             Error("Apply macros", Form("Error reading data from macro \"%s\"", procIterator->At(i)->GetTitle()));
767             continue;
768           }
769           for (Int_t resInd = 0; resInd < nResults; resInd++) {
770             (*fDataTree) << Form("ObjectData%d", i) << Form("Macro%d=", i) << results[resInd] << (Char_t*)"\n";   
771           }
772
773           delete results;
774           results = 0;
775         }
776       }
777     }
778   }    
779
780   for (Int_t i = 0, histoIndex = 0; i < procIterator->GetEntries() && histoIndex < numHistoMacros; i++) {
781     if (mProcType[i] == kSingleObjectHisto || mProcType[i] == kCorrelObjectHisto) {
782       // Might be empty (e.g. no objects have been selected)!
783       if (histos[histoIndex]) {
784         (*fDataTree) << Form("ObjectData%d", i) << Form("Macro%d=", i) << histos[histoIndex] << (Char_t*)"\n";
785       }
786       histoIndex++;
787     }
788   }
789
790   if (fDataTree != 0) delete fDataTree;
791   fDataTree = 0;
792
793   if (procCmds != 0)  delete [] procCmds;
794   procCmds = 0;
795   if (mProcObjectType != 0) delete mProcObjectType;
796   mProcObjectType = 0;
797   if (mProcType != 0)  delete mProcType;
798   mProcType = 0;
799
800   if (selCmds != 0)  delete [] selCmds;
801   selCmds = 0;
802   if (mSelObjectType != 0)  delete mSelObjectType;
803   mSelObjectType = 0;
804   if (mSelType != 0)  delete mSelType;
805   mSelType = 0;
806
807   if (histos != 0)  delete [] histos;
808   histos = 0;
809
810   // Clear root
811   // A.B. gROOT->Reset();
812   
813   // If there is data, select the first data set
814   if (procIterator->GetEntries() > 0) SETBIT(fHistoDataSelected, 0);
815
816   // Now the data is stored in "/tmp/ListAnalyserMacroData_$USER.root"
817   // The editor will access this file to display the data
818   return kTRUE;
819 }
820
821 //______________________________________________________
822 void AliEveListAnalyser::ApplySTSelectionMacros(const TList* iterator)
823 {
824   // Uses the iterator (for the selected selection macros) to apply the selected macros to the data.
825   // The rnr-states of the objects are set according to the result of the macro calls (kTRUE, if all
826   // macros return kTRUE for this object, otherwise: kFALSE).
827   // "ST" stands for "single object". This means that only single object selection macros are applied.
828   // Correlated objects selection macros will be used inside the call of ApplyProcessMacros(...)!
829
830   TGeneralMacroData* macro = 0;
831   AliEveListAnalyserMacroType macroType = kUnknown;
832   TEveElement* object1 = 0;
833   Bool_t selectedByMacro = kFALSE;
834
835   // Clear root
836   // A.B. gROOT->Reset();
837
838   // Select all objecs at first. A object is then deselected, if at least one selection macro
839   // returns kFALSE for this object.
840   // Enable all objects (Note: EnableListElements(..) will call "ElementChanged", which will cause unforeseen behaviour!)
841   for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter) ((TEveElement*)(*iter))->SetRnrState(kTRUE);
842   SetRnrState(kTRUE);
843   
844   for (Int_t i = 0; i < iterator->GetEntries(); i++){
845     macro = (TGeneralMacroData*)fMacroList->GetValue(iterator->At(i)->GetTitle());
846
847     if (!macro){
848       Error("Apply selection macros", 
849             Form("Macro list is corrupted: Macro \"%s\" is not registered!", iterator->At(i)->GetTitle()));
850       continue;
851     }
852
853 #ifdef AliEveListAnalyser_DEBUG
854     printf("AliEveListAnalyser: Applying selection macro: %s\n", macro->GetName());
855 #endif
856     
857     // Determine macro type
858     macroType = macro->GetType();
859
860     // Single object select macro
861     if (macroType == kSingleObjectSelect){
862       // Walk through the list of objects
863       for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter)
864       {
865         object1 = dynamic_cast<TEveElement*>(*iter);
866
867         if (!object1) continue;
868
869         // If the object has already been deselected, nothing is to do here
870         if (!object1->GetRnrState()) continue;
871
872         // Find the type of the object and relate it to the macro object type
873         // Only apply macro to this object, if...
874         // ... the macro takes objects of exactly this type.
875         // ... the macro object type is a child of this object's type.
876         // Otherwise: Continue
877         if (((TObject*)object1->GetUserData())->IsA() != macro->GetObjectType() && 
878             !((TObject*)object1->GetUserData())->InheritsFrom(macro->GetObjectType()))  continue;
879
880         // Cast to the "real" object behind
881         gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object1));
882         gROOT->ProcessLineSync("TObject* automaticObject_1 = (TObject*)automaticEveElement->GetUserData();");
883
884         // GetCmd() will cast the automatic objects to the correct type for each macro!
885         selectedByMacro = (Bool_t)gROOT->ProcessLineSync(macro->GetCmd());
886         object1->SetRnrState(selectedByMacro && object1->GetRnrState());               
887       }
888     }
889     // Correlated objects select macro
890     else if (macroType == kCorrelObjectSelect){
891       // Will be processed in ApplyProcessMacros(...)
892       continue;
893     } else {
894       Error("Apply selection macros", 
895         Form("Macro list corrupted: Macro \"%s/%s.C\" is not registered as a selection macro!", 
896         macro->GetPath(), macro->GetName()));
897     } 
898   }
899
900   // Clear root
901   // A.B. gROOT->Reset();  
902 }
903
904 //______________________________________________________
905 TClass* AliEveListAnalyser::GetMacroObjectType(const Char_t* name) const
906 {
907   // Returns the type of object the macro with name "name" is dealing with; 
908   // e.g. if you have the signature:
909   // void MyMacro(const AliTRDtrackV1* track, Double_t* &results, Int_t& nResults)
910   // the call 'GetMacroObjectType("MyMacro")' yields the AliTRDtrackV1-class.
911   // If the macro is not found (or there is an error), 0x0 is returned.
912
913   TFunction* f = gROOT->GetGlobalFunction(name, 0 , kTRUE);
914   TMethodArg* m = 0;
915   TList* list = 0;
916
917   if (f)
918   {
919     list = f->GetListOfMethodArgs();
920     
921     if (!list->IsEmpty())
922     {
923       m = (TMethodArg*)list->At(0);
924
925       if (m)  return TClass::GetClass(m->GetTypeName());
926     }
927   }  
928
929   // Error
930   return 0x0;
931 }
932
933 //______________________________________________________
934 AliEveListAnalyser::AliEveListAnalyserMacroType AliEveListAnalyser::GetMacroType(const Char_t* name, const Char_t* objectType, Bool_t UseList) const
935 {
936   // Returns the type of the corresponding macro, that accepts pointers of the class "objectType" as a parametre. 
937   // If "UseList" is kTRUE, the type will be looked up in the internal list (very fast). But if this list
938   // does not exist, you have to use kFALSE for this parameter. Then the type will be determined by the
939   // prototype! NOTE: It is assumed that the macro has been compiled! If not, the return value is not
940   // predictable, but normally will be kUnknown.
941   // Note: AddMacro(Fast) will update the internal list and RemoveMacros respectively.
942
943   AliEveListAnalyserMacroType type = kUnknown;
944
945   TString* typeStr = 0;
946   
947   if (objectType != 0) 
948   {
949     typeStr = new TString(objectType);
950     // Remove white-spaces
951     typeStr->ReplaceAll(" ", "");
952   }
953   else
954   {
955     typeStr = new TString("TObject");
956   }
957
958   TString* mangled1Str = new TString();
959   TString* mangled2Str = new TString();
960   TString* mangled3Str = new TString();
961   TString* mangled4Str = new TString();
962   TString* mangledArg1Str = new TString();
963   TString* mangledArg2Str = new TString();
964
965   // We want "const 'OBJECTTYPE'*"
966   mangled1Str->Append("const ").Append(*typeStr).Append("*");
967
968   // We want "const 'OBJECTTYPE'*, Double_t*&, Int_t&"
969   mangled2Str->Append("const ").Append(*typeStr).Append("*, Double_t*&, Int_t&");
970
971   // We want "const 'OBJECTTYPE'*, const 'OBJECTTYPE'*"
972   mangled3Str->Append("const ").Append(*typeStr).Append("*, const ").Append(*typeStr).Append("*");
973
974   // We want "const 'OBJECTTYPE'*, const 'OBJECTTYPE'*, Double_t*&, Int_t&"
975   mangled4Str->Append("const ").Append(*typeStr).Append("*, const ").Append(*typeStr).Append("*, Double_t*&, Int_t&");
976
977   // We want "oPconstsP'OBJECTTYPE'mUsP"
978   mangledArg1Str->Append("oPconstsP").Append(*typeStr).Append("mUsP");
979
980   // We want "cOconstsP'OBJECTTYPE'mUsP"
981   mangledArg2Str->Append("cOconstsP").Append(*typeStr).Append("mUsP");  
982   
983   // Re-do the check of the macro type
984   if (!UseList){
985     // Single object select macro or single object histo macro?
986     TFunction* f = gROOT->GetGlobalFunctionWithPrototype(name, mangled1Str->Data(), kTRUE);
987
988     if (f != 0x0)
989     {
990       // Some additional check (is the parameter EXACTLY of the desired type?)
991       if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0)
992       {
993         // Single object select macro?
994         if (!strcmp(f->GetReturnTypeName(), "Bool_t")) 
995         { 
996           type = kSingleObjectSelect;     
997         }
998         // single object histo macro?
999         else if (!strcmp(f->GetReturnTypeName(), "TH1*"))
1000         {
1001           type = kSingleObjectHisto;
1002         }
1003       }
1004     }
1005     // Single object analyse macro?
1006     else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, mangled2Str->Data(), kTRUE)) 
1007              != 0x0)
1008     {
1009       if (!strcmp(f->GetReturnTypeName(), "void"))
1010       {
1011         // Some additional check (are the parameters EXACTLY of the desired type?)
1012         if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0 &&
1013             strstr(f->GetMangledName(), "cODouble_tmUaNsP") != 0x0 &&
1014             strstr(f->GetMangledName(), "cOInt_taNsP") != 0x0)
1015         {
1016           type = kSingleObjectAnalyse;
1017         }
1018       }
1019     }    
1020     // Correlated objects select macro or correlated objects histo macro?
1021     else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, mangled3Str->Data(), kTRUE)) 
1022              != 0x0)
1023     {
1024       // Some additional check (is the parameter EXACTLY of the desired type?)
1025       if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0 &&
1026           strstr(f->GetMangledName(), mangledArg2Str->Data()) != 0x0)
1027       {
1028         // Correlated objects select macro?
1029         if (!strcmp(f->GetReturnTypeName(), "Bool_t")) 
1030         { 
1031           type = kCorrelObjectSelect;     
1032         }
1033         // Correlated objects histo macro?
1034         else if (!strcmp(f->GetReturnTypeName(), "TH1*"))
1035         {
1036           type = kCorrelObjectHisto;
1037         }
1038       }
1039     }    
1040     // Correlated objects analyse macro?
1041     else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, mangled4Str->Data(), kTRUE)) 
1042              != 0x0)
1043     {
1044       if (!strcmp(f->GetReturnTypeName(), "void"))
1045       {
1046         // Some additional check (is the parameter EXACTLY of the desired type?)
1047         if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0 &&
1048             strstr(f->GetMangledName(), mangledArg2Str->Data()) != 0x0 &&
1049             strstr(f->GetMangledName(), "cODouble_tmUaNsP") != 0x0 &&
1050             strstr(f->GetMangledName(), "cOInt_taNsP") != 0x0)
1051         {
1052           type = kCorrelObjectAnalyse;
1053         }
1054       }
1055     }    
1056   }
1057   // Use list to look up the macro type
1058   else
1059   {
1060     TGeneralMacroData* macro = 0;
1061     macro = (TGeneralMacroData*)fMacroList->GetValue(name);
1062     if (macro == 0)  return kUnknown; 
1063     
1064     type = macro->GetType();
1065     switch (type)
1066     {
1067       case kSingleObjectSelect:
1068       case kSingleObjectAnalyse:
1069       case kSingleObjectHisto:
1070       case kCorrelObjectSelect:
1071       case kCorrelObjectAnalyse:
1072       case kCorrelObjectHisto:      
1073         break;
1074     default:
1075       type = kUnknown;
1076       break;
1077     }
1078   }
1079
1080   // Clean up
1081   if (mangled1Str != 0)
1082   {
1083     mangled1Str->Clear();
1084     delete mangled1Str;
1085     mangled1Str = 0;
1086   }
1087   if (mangled2Str != 0)
1088   {
1089     mangled2Str->Clear();
1090     delete mangled2Str;
1091     mangled2Str = 0;
1092   }
1093   if (mangled3Str != 0)
1094   {
1095     mangled3Str->Clear();
1096     delete mangled3Str;
1097     mangled3Str = 0;
1098   }
1099   if (mangled4Str != 0)
1100   {
1101     mangled4Str->Clear();
1102     delete mangled4Str;
1103     mangled4Str = 0;
1104   }
1105   if (mangledArg1Str != 0)
1106   {
1107     mangledArg1Str->Clear();
1108     delete mangledArg1Str;
1109     mangledArg1Str = 0;
1110   }
1111   if (mangledArg2Str != 0)
1112   {
1113     mangledArg2Str->Clear();
1114     delete mangledArg2Str;
1115     mangledArg2Str = 0;
1116   }
1117   if (typeStr != 0)
1118   {
1119     typeStr->Clear();
1120     delete typeStr;
1121     typeStr = 0;
1122   }
1123
1124
1125   return type;
1126 }
1127
1128
1129 /*
1130 //______________________________________________________
1131 void AliEveListAnalyser::RemovePrimSelectedObjects()
1132 {
1133   // Removes the (primarily) selected objects in the viewer from the list (objects that are already in the list are ignored).
1134   // Hold the CTRL-key for multiple selection.
1135
1136   TEveSelection* eveSel = gEve->GetSelection();
1137
1138   if (!eveSel)
1139   {
1140     Error("AliEveListAnalyser::RemovePrimSelectedObjects", "Failed to get the selection!\n");
1141     return;
1142   }
1143   
1144   TEveElement* elem = 0x0;
1145   Bool_t changedSomething = kFALSE;
1146
1147   for (TEveElement::List_i iter = eveSel->BeginChildren(); iter != eveSel->EndChildren(); ++iter)
1148   {
1149     if(!(elem = dynamic_cast<TEveElement*>(*iter))) continue;
1150
1151     // Check, if element is already there. If so, remove it!
1152     if (this->HasChild(elem) && elem != this)
1153     {
1154       this->RemoveElement(elem);
1155       this->SetTitle(Form("Objects %d", this->NumChildren()));
1156       changedSomething = kTRUE;
1157     }
1158   }
1159
1160   if (changedSomething) gEve->Redraw3D();
1161 }
1162 */
1163
1164 //______________________________________________________
1165 void AliEveListAnalyser::RemoveSelectedMacros(const TList* iterator) 
1166 {
1167   // Uses the iterator (for the selected macros) to remove the selected macros from 
1168   // the corresponding list.
1169    
1170   TObject* key = 0;
1171   TPair*   entry = 0;
1172   for (Int_t i = 0; i < iterator->GetEntries(); i++)
1173   {
1174     entry = (TPair*)fMacroList->FindObject(iterator->At(i)->GetTitle());
1175
1176     if (entry == 0)
1177     {
1178       Error("AliEveListAnalyser::RemoveSelectedMacros", Form("Macro \"%s\" not found in list!", 
1179                                                                      iterator->At(i)->GetTitle()));
1180       continue;
1181     }
1182     key = entry->Key();
1183
1184     if (key == 0)   
1185     {
1186       Error("AliEveListAnalyser::RemoveSelectedMacros", Form("Key for macro \"%s\" not found in list!", 
1187                                                                      iterator->At(i)->GetTitle()));
1188       continue;
1189     }
1190
1191     // Key and value will be deleted, too, since fMacroList is the owner of them
1192     Bool_t rem = fMacroList->DeleteEntry(key);
1193
1194     if (rem)
1195     {
1196 #ifdef AliEveListAnalyser_DEBUG
1197     printf("AliEveListAnalyser::RemoveSelectedMacros(): Removed macro: %s\n", iterator->At(i)->GetTitle());
1198 #endif
1199     }
1200     else
1201     {
1202       Error("AliEveListAnalyser::RemoveSelectedMacros", Form("Macro \"%s\" could not be removed from the list!", 
1203                                                                      iterator->At(i)->GetTitle()));
1204     }
1205   }
1206 }
1207
1208 //______________________________________________________
1209 void AliEveListAnalyser::ResetObjectList()
1210 {
1211   // Removes all objects from the list.
1212
1213   RemoveElements();
1214   this->SetTitle(Form("Objects %d", this->NumChildren()));
1215 }
1216
1217 //______________________________________________________
1218 Bool_t AliEveListAnalyser::StartAddingObjects()
1219
1220   // Starts adding objects for the analysis. Returns kTRUE on success.
1221
1222   if (fConnected == kFALSE)
1223   {
1224     fConnected = TQObject::Connect("TEvePointSet", "PointSelected(Int_t)", "AliEveListAnalyser", this, "AddSecSelectedSingleObjectToList(Int_t)");
1225     if (fConnected)  fConnected = TQObject::Connect(gEve->GetSelection(), "SelectionAdded(TEveElement*)", "AliEveListAnalyser", this, "AddPrimSelectedObject(TEveElement*)");
1226
1227     if (fConnected) return kTRUE;
1228     
1229     Error("AliEveListAnalyser::StartAddingObjects", "Connection failed!");
1230     
1231     // Connection of 2nd signal failed, but first connection succeeded -> Disconnect 1st signal.
1232     TQObject::Disconnect("TEvePointSet", "PointSelected(Int_t)", this, "AddObjectToList(Int_t)");
1233   }
1234
1235   return kFALSE;
1236 }
1237
1238 //______________________________________________________
1239 Bool_t AliEveListAnalyser::StopAddingObjects()
1240 {
1241   // Stops adding objects for the analysis. Returns kTRUE on success.
1242
1243   if (fConnected)
1244   {
1245     Bool_t dis1 = kFALSE, dis2 = kFALSE;
1246     dis1 = TQObject::Disconnect("TEvePointSet", "PointSelected(Int_t)", this, "AddSecSelectedSingleObjectToList(Int_t)");
1247     dis2 = TQObject::Disconnect(gEve->GetSelection(), "SelectionAdded(TEveElement*)", this, "AddPrimSelectedObject(TEveElement*)");
1248
1249     if (dis1 || dis2) fConnected = kFALSE;
1250     if (dis1 && dis2) return kTRUE;
1251     else
1252     {
1253       Error("AliEveListAnalyser::StopAddingObjects", "Disconnection failed!");
1254
1255       return kFALSE;
1256     }
1257   }
1258
1259   return kTRUE;
1260 }