]> git.uio.no Git - u/mrichter/AliRoot.git/blob - EVE/EveDet/AliEveListAnalyser.cxx
Updates of the list anlyser (Ben)
[u/mrichter/AliRoot.git] / EVE / EveDet / AliEveListAnalyser.cxx
1 // Author: Benjamin Hess   06/11/2009
2
3 /*************************************************************************
4  * Copyright (C) 2009, Alexandru Bercuci, Benjamin Hess.                 *
5  * All rights reserved.                                                  *
6  *************************************************************************/
7
8 // TODO: Documentation
9 //////////////////////////////////////////////////////////////////////////
10 //                                                                      //
11 // AliEveListAnalyser                                           //
12 //                                                                      //
13 // An AliEveListAnalyser is, in principal, a TEveElementList    //
14 // with some sophisticated features. You can add macros to this list,   //
15 // which then can be applied to the list of tracks (these tracks can be //
16 // added to the list in the same way as for the TEveElementList).       //
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 // be removed. 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 // With ApplySTSelectionMacros(...) or ApplyProcessMacros(...)          //
28 // respectively you can apply the macros to the track list via          //
29 // iterators (same style like for RemoveSelectedMacros(...)(cf. above)).//
30 // Selection macros (de-)select macros according to a selection rule    //
31 // by setting the rnr-state of the tracks.                              //
32 // If multiple selection macros are applied, a track is selected, if    //
33 // all selection macros select the track.                               //
34 // Process macros create data or histograms, which will be stored in    //
35 // a temporary file. The editor of this class will access this file     //
36 // and draw all the stuff within it's DrawHistos() function. The file   //
37 // will be deleted by the destructor.                                   //
38 //                                                                      //
39 // Currently, the following macro types are supported:                  //
40 // Selection macros:                                                    //
41 // Bool_t YourMacro(const YourObjectType*);                              //
42 // Bool_t YourMacro(const YourObjectType*, const YourObjectType*);        //
43 //                                                                      //
44 // Process macros:                                                      //
45 // void YourMacro(const YourObjectType*, Double_t*&, Int_t&);            //
46 // void YourMacro(const YourObjectType*, const YourObjectType*,           //
47 //                Double_t*&, Int_t&);                                  //
48 // TH1* YourMacro(const YourObjectType*);                                //
49 // TH1* YourMacro(const YourObjectType*, const YourObjectType*);          //
50 //                                                                      //
51 // The macros which take 2 tracks are applied to all track pairs        //
52 // (whereby BOTH tracks of the pair have to be selected by the single   //
53 // track selection macros and have to be unequal, otherwise they will   //
54 // be skipped) that have been selected by ALL correlated tracks         //
55 // selection macros. The selection macros with 2 tracks do NOT affect   //
56 // process macros that process only a single track!                     //
57 //////////////////////////////////////////////////////////////////////////
58
59
60 // Uncomment to display debugging infos
61 //#define AliEveListAnalyser_DEBUG
62
63 #include <TFile.h>
64 #include <TFunction.h>
65 #include <TMethodArg.h>
66 #include <TH1.h>
67 #include <TList.h>
68 #include <TMap.h>
69 #include <TObjString.h>
70 #include <TROOT.h>
71 #include <TSystem.h>
72 #include <TTree.h>
73 #include <TTreeStream.h>
74 #include <TMethodCall.h>
75
76 //TODO - NEW -> Ordering! resp. remove the non-needed files 
77 #include <TQObject.h>
78 #include <TEveManager.h>
79 #include <TGLSelectRecord.h>
80 #include <TGLViewer.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 //TODO - NEW - To be implemented, tested, documented
278 //______________________________________________________
279 void AliEveListAnalyser::AddObjectToList(Int_t pointId)
280 {
281   TEvePointSet* ps = dynamic_cast<TEvePointSet*>((TQObject*) gTQSender);
282   
283   if (!ps)
284   {
285     Error("AliEveListAnalyser::AddObjectToList", "Zero pointer!\n");
286     return;
287   }
288
289   // Check, if object is already there. If so, remove it!
290   
291   // 1st possibility: Object of the list clicked
292   if (this->HasChild(ps))
293   {
294     this->RemoveElement(ps);
295     return;
296   }
297     
298   TObject* obj = ps->GetPointId(pointId);
299   if (obj)
300   {
301     // 2nd possibility: Same object clicked again
302     TEveElement* listObj = 0x0;
303     listObj = this->FindChild(Form("[viewer:%d] %s%d", obj->GetUniqueID(), obj->GetName(), pointId));
304     if (listObj)
305     {
306       this->RemoveElement(listObj);  
307       return;
308     }
309
310     // Object clicked that is not in the list -> Add this object to list
311     TEvePointSet* newPS = new TEvePointSet(Form("[viewer:%d] %s%d", obj->GetUniqueID(), obj->GetName(), pointId));
312     Double_t x = 0, y = 0, z = 0;
313     ps->GetPoint(pointId, x, y, z);
314     newPS->SetPoint(0, x, y, z);
315     newPS->SetUserData(obj);
316     newPS->SetMarkerColor(5);
317     newPS->SetMarkerStyle(2);
318     newPS->SetMarkerSize(2.0);
319
320     AddElement(newPS);
321     gEve->Redraw3D();
322   }
323   else
324   {
325     Error("AliEveListAnalyser::AddObjectToList", "Selected object is NULL and therefore ignored!");
326   }
327
328 /*
329   TGLSelectRecord rec = gEve->GetDefaultGLViewer()->GetSelRec();
330
331   printf("Objects (%d):\n", rec.GetN());
332   for (int i = 0; i < rec.GetN(); i++)
333   {
334     //printf("%s\n", ((TObject*)rec.GetItem(i))->IsA()->GetName());
335   }
336 */
337   
338   //printf("Type: %s\npointID: %s\n\n", ps->IsA()->GetName(), pointId);
339   //printf("Type objectsender: %s\nType sender: %s\n", ((TQObject*)gTQSender)->IsA()->GetName(), ((TQObjSender*)gTQSender)->IsA()->GetName());
340 }
341
342 //______________________________________________________
343 void AliEveListAnalyser::AddStandardContent()
344 {
345   // Adds standard macros to the macro list.
346
347   // Add your standard macros here, e.g.: 
348   // To add a macro use:
349   // AddMacro("$(ALICE_ROOT)/myFolder", "myMacroName.C");
350   // -> If the file does not exist, nothing happens. So if you want to handle this,
351   // use the return value of AddMacro (NOT_EXIST_ERROR is returned, if file does not exist)
352   // (-> You can also check for other return values (see AddMacro(...)))
353
354 }
355
356 //______________________________________________________
357 Bool_t AliEveListAnalyser::ApplyProcessMacros(const TList* selIterator, const TList* procIterator)
358 {
359   // Uses the procIterator (for the selected process macros) to apply the selected macros to the data.
360   // Returns kTRUE on success, otherwise kFALSE. If there no process macros selected, kTRUE is returned 
361   // (this is no error!).
362   // The single object process macros are applied to all selected objects.
363   // The selIterator (for the selected selection macros) will be used to apply the correlated objects selection
364   // macros to all object pairs (whereby BOTH objects have to be selected, otherwise they will be skipped).
365   // All object pairs that have been selected by ALL correlated objects selection macros will be processed by
366   // the correlated objects process macros.
367
368   // No process macros need to be processed
369   if (procIterator->GetEntries() <= 0)  return kTRUE;
370
371   // Clear root
372   // A.B. gROOT->Reset();
373   
374   // Clear old data and re-allocate
375   if (fDataTree == 0x0){ 
376     TDirectory *cwd = gDirectory;
377     fDataTree = new TTreeSRedirector(Form("/tmp/ListAnalyserMacroData_%s.root", gSystem->Getenv("USER")));
378     cwd->cd();
379   }
380   if (!fDataTree){
381     Error("Apply process macros", Form("File \"/tmp/ListAnalyserMacroData_%s.root\" could not be accessed properly!", 
382           gSystem->Getenv("USER")));
383     return kFALSE;
384   }
385   
386   if (fDataFromMacroList != 0) {
387     fDataFromMacroList->Delete();
388     delete fDataFromMacroList;
389   }
390   fDataFromMacroList = new TList();
391   fDataFromMacroList->TCollection::SetOwner(kTRUE);
392
393   fHistoDataSelected = 0;
394
395
396   TGeneralMacroData* macro = 0;
397
398   Char_t** procCmds = 0;
399   AliEveListAnalyserMacroType* mProcType = 0;
400   if (procIterator->GetEntries() > 0) {
401     procCmds = new Char_t*[procIterator->GetEntries()];
402     mProcType = new AliEveListAnalyserMacroType[procIterator->GetEntries()];
403   }
404   
405   TClass** mProcObjectType = 0;
406   if (procIterator->GetEntries() > 0) {
407     mProcObjectType = new TClass*[procIterator->GetEntries()];
408   }
409
410   Char_t** selCmds  = 0;
411   AliEveListAnalyserMacroType* mSelType = 0;
412   if (selIterator->GetEntries() > 0) {
413     selCmds = new Char_t*[selIterator->GetEntries()];
414     mSelType = new AliEveListAnalyserMacroType[selIterator->GetEntries()];
415   }
416
417   TClass** mSelObjectType = 0;
418   if (selIterator->GetEntries() > 0) {
419     mSelObjectType = new TClass*[selIterator->GetEntries()];
420   }
421   
422   Bool_t selectedByCorrSelMacro = kFALSE;
423
424   AliEveListAnalyserMacroType macroType = kUnknown;
425   Int_t numHistoMacros = 0;
426   TH1** histos = 0;
427
428   TEveElement* object1 = 0;
429   TEveElement* object2 = 0;
430
431   // Collect the commands for each process macro and add them to "data-from-list"
432   for (Int_t i = 0; i < procIterator->GetEntries(); i++){
433     procCmds[i] = new Char_t[(fkMaxMacroPathNameLength + fkMaxApplyCommandLength)];
434     memset(procCmds[i], '\0', sizeof(Char_t) * (fkMaxMacroNameLength + fkMaxApplyCommandLength));
435
436     macro = (TGeneralMacroData*)fMacroList->GetValue(procIterator->At(i)->GetTitle());
437
438     if (!macro){
439       Error("Apply process macros", 
440         Form("Macro list is corrupted: Macro \"%s\" is not registered!", 
441         procIterator->At(i)->GetTitle()));
442       continue;
443     }
444
445 #ifdef AliEveListAnalyser_DEBUG
446     printf("AliEveListAnalyser: Checking process macro: %s\n", macro->GetName());
447 #endif 
448            
449     // Find the object type of the macro
450     mProcObjectType[i] = macro->GetObjectType();
451
452     // Find the type of the process macro
453     macroType = macro->GetType();
454     if (macroType == kSingleObjectHisto || macroType == kCorrelObjectHisto){
455       mProcType[i] = macroType;
456       numHistoMacros++;
457       // Create the command 
458       sprintf(procCmds[i], macro->GetCmd());
459
460       // Add to "data-from-list" -> Mark as a histo macro with the substring "(histo macro)"
461       fDataFromMacroList->Add(new TObjString(Form("%s (histo macro)", macro->GetName())));
462     } else if (macroType == kSingleObjectAnalyse || macroType == kCorrelObjectAnalyse) {
463       mProcType[i] = macroType;
464       // Create the command 
465       sprintf(procCmds[i], macro->GetCmd());
466
467       // Add to "data-from-list"
468       fDataFromMacroList->Add(new TObjString(macro->GetName()));
469     } else {
470       Error("Apply process macros", 
471         Form("Macro list corrupted: Macro \"%s/%s.C\" is not registered as a process macro!", 
472         macro->GetPath(), macro->GetName()));
473       mProcType[i] = kUnknown;
474     } 
475   }  
476
477   // Collect the commands for each selection macro and add them to "data-from-list"
478   for (Int_t i = 0; i < selIterator->GetEntries(); i++){
479     selCmds[i] = new Char_t[(fkMaxMacroPathNameLength + fkMaxApplyCommandLength)];
480     memset(selCmds[i], '\0', sizeof(Char_t) * (fkMaxMacroNameLength + fkMaxApplyCommandLength));
481
482     macro = (TGeneralMacroData*)fMacroList->GetValue(selIterator->At(i)->GetTitle());
483
484     if (!macro){
485       Error("Apply process macros", 
486         Form("Macro list is corrupted: Macro \"%s\" is not registered!", 
487         selIterator->At(i)->GetTitle()));
488       continue;
489     }
490
491 #ifdef AliEveListAnalyser_DEBUG
492     printf("AliEveListAnalyser: Checking selection macro: %s\n", macro->GetName());
493 #endif
494
495     // Find the object type of the macro
496     mSelObjectType[i] = macro->GetObjectType();
497        
498     // Find the type of the process macro
499     macroType = macro->GetType();
500
501     // Single Object select macro
502     if (macroType == kSingleObjectSelect) {
503       // Has already been processed by ApplySTSelectionMacros(...)
504       mSelType[i] = macroType;         
505     }
506     // Correlated Objects select macro
507     else if (macroType == kCorrelObjectSelect) {
508       mSelType[i] = macroType;  
509  
510       // Create the command
511       sprintf(selCmds[i], macro->GetCmd());
512     } else {
513       Error("Apply process macros", 
514         Form("Macro list corrupted: Macro \"%s/%s.C\" is not registered as a selection macro!", 
515         macro->GetPath(), macro->GetName()));
516       mSelType[i] = kUnknown;
517     } 
518   }  
519
520   // Allocate memory for the histograms
521   if (numHistoMacros > 0)  histos = new TH1*[numHistoMacros];
522   for (Int_t i = 0; i < numHistoMacros; i++)  histos[i] = 0x0;
523
524
525   //////////////////////////////////
526   // WALK THROUGH THE LIST OF OBJECTS
527   //////////////////////////////////     
528   for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter){
529     if(!(object1 = dynamic_cast<TEveElement*>(*iter))) continue;
530
531     // Skip objects that have not been selected
532     if (!object1->GetRnrState())  continue;
533     
534     // Cast to the "real" object behind
535     gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object1));
536     gROOT->ProcessLineSync("TObject* automaticObject_1 = (TObject*)automaticEveElement->GetUserData();");
537
538     // Collect data for each macro
539     for (Int_t i = 0, histoIndex = 0; i < procIterator->GetEntries(); i++){
540       // Find the type of the object and relate it to the macro object type
541       // Only apply macro to this object, if...
542       // ... the macro takes objects of exactly this type.
543       // ... the macro object type is a child of this object's type.
544       // Otherwise: Continue
545
546       // Finally, via procCmds[i], the automatic objects are casted to the correct type and analysed by each macro!
547       if (((TObject*)object1->GetUserData())->IsA() != mProcObjectType[i] && 
548           !((TObject*)object1->GetUserData())->InheritsFrom(mProcObjectType[i]))  continue;
549
550         
551       // Single object histo
552       if (mProcType[i] == kSingleObjectHisto){
553         histos[histoIndex++] = (TH1*)gROOT->ProcessLineSync(procCmds[i]);
554        // Correlated Objects histo
555       } else if (mProcType[i] == kCorrelObjectHisto) {
556         // Loop over all pairs behind the current one - together with the other loop this will be a loop
557         // over all pairs. We have a pair of objects, if and only if both objects of the pair are selected (Rnr-state)
558         // and are not equal.
559         // The correlated objects process macro will be applied to all pairs that will be additionally selected by
560         // all correlated objects selection macros.
561         TEveElement::List_i iter2 = iter;
562         iter2++;
563         for ( ; iter2 != this->EndChildren(); ++iter2)
564         {
565           if(!(object2 = dynamic_cast<TEveElement*>(*iter2))) continue;
566
567           // Skip objects that have not been selected
568           if (!object2->GetRnrState())  continue;
569
570           // Same check of the macro object type as before
571           if (((TObject*)object2->GetUserData())->IsA() != mProcObjectType[i] && 
572               !((TObject*)object2->GetUserData())->InheritsFrom(mProcObjectType[i]))  continue;
573       
574           // Cast to the "real" object behind
575           gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object2));
576           gROOT->ProcessLineSync("TObject* automaticObject_2 = (TObject*)automaticEveElement->GetUserData();");
577
578           // Select object by default (so it will be processed, if there are no correlated objects selection macros!)
579           selectedByCorrSelMacro = kTRUE;
580           for (Int_t j = 0; j < selIterator->GetEntries(); j++){
581             if (mSelType[j] == kCorrelObjectSelect){
582           // Check, whether the macro can deal with both objects. If not, skip it.
583           // Note: Again, via selCmds[i], the automatic objects are casted to the correct type!
584           if (((TObject*)object1->GetUserData())->IsA() != mSelObjectType[j] && 
585               !((TObject*)object1->GetUserData())->InheritsFrom(mSelObjectType[j]))  continue;
586           if (((TObject*)object2->GetUserData())->IsA() != mSelObjectType[j] && 
587               !((TObject*)object2->GetUserData())->InheritsFrom(mSelObjectType[j]))  continue;
588
589               selectedByCorrSelMacro = (Bool_t)gROOT->ProcessLineSync(selCmds[j]);
590               if (!selectedByCorrSelMacro)  break;
591             }
592           }       
593
594           // If the pair has not been selected by the correlated objects selection macros, skip it!
595           if (!selectedByCorrSelMacro) continue;
596           
597           histos[histoIndex] = (TH1*)gROOT->ProcessLineSync(procCmds[i]);
598         }
599         histoIndex++;
600       }
601       // Single object analyse
602       else if (mProcType[i] == kSingleObjectAnalyse) {
603         // Create data pointers in CINT, execute the macro and get the data
604         gROOT->ProcessLineSync("Double_t* results = 0;");
605         gROOT->ProcessLineSync("Int_t n = 0;");
606         gROOT->ProcessLineSync(procCmds[i]);
607         Double_t* results = (Double_t*)gROOT->ProcessLineSync("results;");
608         Int_t nResults = (Int_t)gROOT->ProcessLineSync("n;");
609         
610         if (results == 0) {
611           Error("Apply macros", Form("Error reading data from macro \"%s\"", procIterator->At(i)->GetTitle()));
612           continue;
613         }
614         for (Int_t resInd = 0; resInd < nResults; resInd++){
615           (*fDataTree) << Form("ObjectData%d", i) << Form("Macro%d=", i) << results[resInd] << (Char_t*)"\n";   
616         }
617
618         delete results;
619         results = 0;
620       }
621       // Correlated objects analyse
622       else if (mProcType[i] == kCorrelObjectAnalyse){
623         // Loop over all pairs behind the current one - together with the other loop this will be a loop
624         // over all pairs. We have a pair of objects, if and only if both objects of the pair are selected (Rnr-state)
625         // and are not equal.
626         // The correlated objects process macro will be applied to all pairs that will be additionally selected by
627         // all correlated objects selection macros.
628         TEveElement::List_i iter2 = iter;
629         iter2++;
630
631         for ( ; iter2 != this->EndChildren(); ++iter2) {
632           if(!(object2 = dynamic_cast<TEveElement*>(*iter2))) continue;
633  
634           // Skip objects that have not been selected
635           if (!object2->GetRnrState())  continue;
636
637           // Same check of the macro object type as before
638           if (((TObject*)object2->GetUserData())->IsA() != mProcObjectType[i] && 
639               !((TObject*)object2->GetUserData())->InheritsFrom(mProcObjectType[i]))  continue;
640     
641           // Cast to the "real" object behind
642           gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object2));
643           gROOT->ProcessLineSync("TObject* automaticObject_2 = (TObject*)automaticEveElement->GetUserData();");
644
645           // Select object by default (so it will be processed, if there are no correlated objects selection macros!)
646           selectedByCorrSelMacro = kTRUE;
647           for (Int_t j = 0; j < selIterator->GetEntries(); j++) {
648             if (mSelType[j] == kCorrelObjectSelect) {
649               // Check, whether the macro can deal with both objects. If not, skip it.
650               // Note: Again, via selCmds[i], the automatic objects are casted to the correct type!
651               if (((TObject*)object1->GetUserData())->IsA() != mSelObjectType[j] && 
652                   !((TObject*)object1->GetUserData())->InheritsFrom(mSelObjectType[j]))  continue;
653               if (((TObject*)object2->GetUserData())->IsA() != mSelObjectType[j] && 
654                   !((TObject*)object2->GetUserData())->InheritsFrom(mSelObjectType[j]))  continue;
655
656               selectedByCorrSelMacro = (Bool_t)gROOT->ProcessLineSync(selCmds[j]);
657               if (!selectedByCorrSelMacro)  break;
658             }
659           }       
660
661           // If the pair has not been selected by the correlated objects selection macros, skip it!
662           if (!selectedByCorrSelMacro) continue;
663           
664           // Create data pointers in CINT, execute the macro and get the data
665           gROOT->ProcessLineSync("Double_t* results = 0;");
666           gROOT->ProcessLineSync("Int_t n = 0;");
667           gROOT->ProcessLineSync(procCmds[i]);
668           Double_t* results = (Double_t*)gROOT->ProcessLineSync("results;");
669           Int_t nResults = (Int_t)gROOT->ProcessLineSync("n;");
670      
671           if (results == 0) {
672             Error("Apply macros", Form("Error reading data from macro \"%s\"", procIterator->At(i)->GetTitle()));
673             continue;
674           }
675           for (Int_t resInd = 0; resInd < nResults; resInd++) {
676             (*fDataTree) << Form("ObjectData%d", i) << Form("Macro%d=", i) << results[resInd] << (Char_t*)"\n";   
677           }
678
679           delete results;
680           results = 0;
681         }
682       }
683     }
684   }    
685
686   for (Int_t i = 0, histoIndex = 0; i < procIterator->GetEntries() && histoIndex < numHistoMacros; i++) {
687     if (mProcType[i] == kSingleObjectHisto || mProcType[i] == kCorrelObjectHisto) {
688       // Might be empty (e.g. no objects have been selected)!
689       if (histos[histoIndex]) {
690         (*fDataTree) << Form("ObjectData%d", i) << Form("Macro%d=", i) << histos[histoIndex] << (Char_t*)"\n";
691       }
692       histoIndex++;
693     }
694   }
695
696   if (fDataTree != 0) delete fDataTree;
697   fDataTree = 0;
698
699   if (procCmds != 0)  delete [] procCmds;
700   procCmds = 0;
701   if (mProcObjectType != 0) delete mProcObjectType;
702   mProcObjectType = 0;
703   if (mProcType != 0)  delete mProcType;
704   mProcType = 0;
705
706   if (selCmds != 0)  delete [] selCmds;
707   selCmds = 0;
708   if (mSelObjectType != 0)  delete mSelObjectType;
709   mSelObjectType = 0;
710   if (mSelType != 0)  delete mSelType;
711   mSelType = 0;
712
713   if (histos != 0)  delete [] histos;
714   histos = 0;
715
716   // Clear root
717   // A.B. gROOT->Reset();
718   
719   // If there is data, select the first data set
720   if (procIterator->GetEntries() > 0) SETBIT(fHistoDataSelected, 0);
721
722   // Now the data is stored in "/tmp/ListAnalyserMacroData_$USER.root"
723   // The editor will access this file to display the data
724   return kTRUE;
725 }
726
727 //______________________________________________________
728 void AliEveListAnalyser::ApplySTSelectionMacros(const TList* iterator)
729 {
730   // Uses the iterator (for the selected selection macros) to apply the selected macros to the data.
731   // The rnr-states of the objects are set according to the result of the macro calls (kTRUE, if all
732   // macros return kTRUE for this object, otherwise: kFALSE).
733   // "ST" stands for "single object". This means that only single object selection macros are applied.
734   // Correlated objects selection macros will be used inside the call of ApplyProcessMacros(...)!
735
736   TGeneralMacroData* macro = 0;
737   AliEveListAnalyserMacroType macroType = kUnknown;
738   TEveElement* object1 = 0;
739   Bool_t selectedByMacro = kFALSE;
740
741   // Clear root
742   // A.B. gROOT->Reset();
743
744   // Select all objecs at first. A object is then deselected, if at least one selection macro
745   // returns kFALSE for this object.
746   // Enable all objects (Note: EnableListElements(..) will call "ElementChanged", which will cause unforeseen behaviour!)
747   for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter) ((TEveElement*)(*iter))->SetRnrState(kTRUE);
748   SetRnrState(kTRUE);
749   
750   for (Int_t i = 0; i < iterator->GetEntries(); i++){
751     macro = (TGeneralMacroData*)fMacroList->GetValue(iterator->At(i)->GetTitle());
752
753     if (!macro){
754       Error("Apply selection macros", 
755             Form("Macro list is corrupted: Macro \"%s\" is not registered!", iterator->At(i)->GetTitle()));
756       continue;
757     }
758
759 #ifdef AliEveListAnalyser_DEBUG
760     printf("AliEveListAnalyser: Applying selection macro: %s\n", macro->GetName());
761 #endif
762     
763     // Determine macro type
764     macroType = macro->GetType();
765
766     // Single object select macro
767     if (macroType == kSingleObjectSelect){
768       // Walk through the list of objects
769       for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter)
770       {
771         object1 = dynamic_cast<TEveElement*>(*iter);
772
773         if (!object1) continue;
774
775         // If the object has already been deselected, nothing is to do here
776         if (!object1->GetRnrState()) continue;
777
778         // Find the type of the object and relate it to the macro object type
779         // Only apply macro to this object, if...
780         // ... the macro takes objects of exactly this type.
781         // ... the macro object type is a child of this object's type.
782         // Otherwise: Continue
783         if (((TObject*)object1->GetUserData())->IsA() != macro->GetObjectType() && 
784             !((TObject*)object1->GetUserData())->InheritsFrom(macro->GetObjectType()))  continue;
785
786         // Cast to the "real" object behind
787         gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object1));
788         gROOT->ProcessLineSync("TObject* automaticObject_1 = (TObject*)automaticEveElement->GetUserData();");
789
790         // GetCmd() will cast the automatic objects to the correct type for each macro!
791         selectedByMacro = (Bool_t)gROOT->ProcessLineSync(macro->GetCmd());
792         object1->SetRnrState(selectedByMacro && object1->GetRnrState());               
793       }
794     }
795     // Correlated objects select macro
796     else if (macroType == kCorrelObjectSelect){
797       // Will be processed in ApplyProcessMacros(...)
798       continue;
799     } else {
800       Error("Apply selection macros", 
801         Form("Macro list corrupted: Macro \"%s/%s.C\" is not registered as a selection macro!", 
802         macro->GetPath(), macro->GetName()));
803     } 
804   }
805
806   // Clear root
807   // A.B. gROOT->Reset();  
808 }
809
810 //______________________________________________________
811 AliEveListAnalyser::AliEveListAnalyserMacroType AliEveListAnalyser::GetMacroType(const Char_t* name, const Char_t* objectType, Bool_t UseList) const
812 {
813   // Returns the type of the corresponding macro, that accepts pointers of the class "objectType" as a parametre. 
814   // If "UseList" is kTRUE, the type will be looked up in the internal list (very fast). But if this list
815   // does not exist, you have to use kFALSE for this parameter. Then the type will be determined by the
816   // prototype! NOTE: It is assumed that the macro has been compiled! If not, the return value is not
817   // predictable, but normally will be kUnknown.
818   // Note: AddMacro(Fast) will update the internal list and RemoveMacros respectively.
819
820   AliEveListAnalyserMacroType type = kUnknown;
821
822   TString* typeStr = 0;
823   
824   if (objectType != 0) 
825   {
826     typeStr = new TString(objectType);
827     // Remove white-spaces
828     typeStr->ReplaceAll(" ", "");
829   }
830   else
831   {
832     typeStr = new TString("TObject");
833   }
834
835   TString* mangled1Str = new TString();
836   TString* mangled2Str = new TString();
837   TString* mangled3Str = new TString();
838   TString* mangled4Str = new TString();
839   TString* mangledArg1Str = new TString();
840   TString* mangledArg2Str = new TString();
841
842   // We want "const 'OBJECTTYPE'*"
843   mangled1Str->Append("const ").Append(*typeStr).Append("*");
844
845   // We want "const 'OBJECTTYPE'*, Double_t*&, Int_t&"
846   mangled2Str->Append("const ").Append(*typeStr).Append("*, Double_t*&, Int_t&");
847
848   // We want "const 'OBJECTTYPE'*, const 'OBJECTTYPE'*"
849   mangled3Str->Append("const ").Append(*typeStr).Append("*, const ").Append(*typeStr).Append("*");
850
851   // We want "const 'OBJECTTYPE'*, const 'OBJECTTYPE'*, Double_t*&, Int_t&"
852   mangled4Str->Append("const ").Append(*typeStr).Append("*, const ").Append(*typeStr).Append("*, Double_t*&, Int_t&");
853
854   // We want "oPconstsP'OBJECTTYPE'mUsP"
855   mangledArg1Str->Append("oPconstsP").Append(*typeStr).Append("mUsP");
856
857   // We want "cOconstsP'OBJECTTYPE'mUsP"
858   mangledArg2Str->Append("cOconstsP").Append(*typeStr).Append("mUsP");  
859   
860   // Re-do the check of the macro type
861   if (!UseList){
862     // Single object select macro or single object histo macro?
863     TFunction* f = gROOT->GetGlobalFunctionWithPrototype(name, mangled1Str->Data(), kTRUE);
864
865     if (f != 0x0)
866     {
867       // Some additional check (is the parameter EXACTLY of the desired type?)
868       if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0)
869       {
870         // Single object select macro?
871         if (!strcmp(f->GetReturnTypeName(), "Bool_t")) 
872         { 
873           type = kSingleObjectSelect;     
874         }
875         // single object histo macro?
876         else if (!strcmp(f->GetReturnTypeName(), "TH1*"))
877         {
878           type = kSingleObjectHisto;
879         }
880       }
881     }
882     // Single object analyse macro?
883     else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, mangled2Str->Data(), kTRUE)) 
884              != 0x0)
885     {
886       if (!strcmp(f->GetReturnTypeName(), "void"))
887       {
888         // Some additional check (are the parameters EXACTLY of the desired type?)
889         if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0 &&
890             strstr(f->GetMangledName(), "cODouble_tmUaNsP") != 0x0 &&
891             strstr(f->GetMangledName(), "cOInt_taNsP") != 0x0)
892         {
893           type = kSingleObjectAnalyse;
894         }
895       }
896     }    
897     // Correlated objects select macro or correlated objects histo macro?
898     else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, mangled3Str->Data(), kTRUE)) 
899              != 0x0)
900     {
901       // Some additional check (is the parameter EXACTLY of the desired type?)
902       if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0 &&
903           strstr(f->GetMangledName(), mangledArg2Str->Data()) != 0x0)
904       {
905         // Correlated objects select macro?
906         if (!strcmp(f->GetReturnTypeName(), "Bool_t")) 
907         { 
908           type = kCorrelObjectSelect;     
909         }
910         // Correlated objects histo macro?
911         else if (!strcmp(f->GetReturnTypeName(), "TH1*"))
912         {
913           type = kCorrelObjectHisto;
914         }
915       }
916     }    
917     // Correlated objects analyse macro?
918     else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, mangled4Str->Data(), kTRUE)) 
919              != 0x0)
920     {
921       if (!strcmp(f->GetReturnTypeName(), "void"))
922       {
923         // Some additional check (is the parameter EXACTLY of the desired type?)
924         if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0 &&
925             strstr(f->GetMangledName(), mangledArg2Str->Data()) != 0x0 &&
926             strstr(f->GetMangledName(), "cODouble_tmUaNsP") != 0x0 &&
927             strstr(f->GetMangledName(), "cOInt_taNsP") != 0x0)
928         {
929           type = kCorrelObjectAnalyse;
930         }
931       }
932     }    
933   }
934   // Use list to look up the macro type
935   else
936   {
937     TGeneralMacroData* macro = 0;
938     macro = (TGeneralMacroData*)fMacroList->GetValue(name);
939     if (macro == 0)  return kUnknown; 
940     
941     type = macro->GetType();
942     switch (type)
943     {
944       case kSingleObjectSelect:
945       case kSingleObjectAnalyse:
946       case kSingleObjectHisto:
947       case kCorrelObjectSelect:
948       case kCorrelObjectAnalyse:
949       case kCorrelObjectHisto:      
950         break;
951     default:
952       type = kUnknown;
953       break;
954     }
955   }
956
957   // Clean up
958   if (mangled1Str != 0)
959   {
960     mangled1Str->Clear();
961     delete mangled1Str;
962     mangled1Str = 0;
963   }
964   if (mangled2Str != 0)
965   {
966     mangled2Str->Clear();
967     delete mangled2Str;
968     mangled2Str = 0;
969   }
970   if (mangled3Str != 0)
971   {
972     mangled3Str->Clear();
973     delete mangled3Str;
974     mangled3Str = 0;
975   }
976   if (mangled4Str != 0)
977   {
978     mangled4Str->Clear();
979     delete mangled4Str;
980     mangled4Str = 0;
981   }
982   if (mangledArg1Str != 0)
983   {
984     mangledArg1Str->Clear();
985     delete mangledArg1Str;
986     mangledArg1Str = 0;
987   }
988   if (mangledArg2Str != 0)
989   {
990     mangledArg2Str->Clear();
991     delete mangledArg2Str;
992     mangledArg2Str = 0;
993   }
994   if (typeStr != 0)
995   {
996     typeStr->Clear();
997     delete typeStr;
998     typeStr = 0;
999   }
1000
1001
1002   return type;
1003 }
1004
1005 // TODO: DOCUMENTATION
1006 //______________________________________________________
1007 TClass* AliEveListAnalyser::GetMacroObjectType(const Char_t* name) const
1008 {
1009   TFunction* f = gROOT->GetGlobalFunction(name, 0 , kTRUE);
1010   TMethodArg* m = 0;
1011   TList* list = 0;
1012
1013   if (f)
1014   {
1015     list = f->GetListOfMethodArgs();
1016     
1017     if (!list->IsEmpty())
1018     {
1019       m = (TMethodArg*)list->At(0);
1020
1021       if (m)  return TClass::GetClass(m->GetTypeName());
1022     }
1023   }  
1024
1025   // Error
1026   return 0x0;
1027 }
1028
1029 //______________________________________________________
1030 void AliEveListAnalyser::RemoveSelectedMacros(const TList* iterator) 
1031 {
1032   // Uses the iterator (for the selected macros) to remove the selected macros from 
1033   // the corresponding list.
1034    
1035   TObject* key = 0;
1036   TPair*   entry = 0;
1037   for (Int_t i = 0; i < iterator->GetEntries(); i++)
1038   {
1039     entry = (TPair*)fMacroList->FindObject(iterator->At(i)->GetTitle());
1040
1041     if (entry == 0)
1042     {
1043       Error("AliEveListAnalyser::RemoveSelectedMacros", Form("Macro \"%s\" not found in list!", 
1044                                                                      iterator->At(i)->GetTitle()));
1045       continue;
1046     }
1047     key = entry->Key();
1048
1049     if (key == 0)   
1050     {
1051       Error("AliEveListAnalyser::RemoveSelectedMacros", Form("Key for macro \"%s\" not found in list!", 
1052                                                                      iterator->At(i)->GetTitle()));
1053       continue;
1054     }
1055
1056     // Key and value will be deleted, too, since fMacroList is the owner of them
1057     Bool_t rem = fMacroList->DeleteEntry(key);
1058
1059     if (rem)
1060     {
1061 #ifdef AliEveListAnalyser_DEBUG
1062     printf("AliEveListAnalyser::RemoveSelectedMacros(): Removed macro: %s\n", iterator->At(i)->GetTitle());
1063 #endif
1064     }
1065     else
1066     {
1067       Error("AliEveListAnalyser::RemoveSelectedMacros", Form("Macro \"%s\" could not be removed from the list!", 
1068                                                                      iterator->At(i)->GetTitle()));
1069     }
1070   }
1071 }
1072
1073 //______________________________________________________
1074 void AliEveListAnalyser::ResetObjectList()
1075 {
1076   // Remove all objects from the list.
1077
1078   RemoveElements();
1079 }
1080
1081 //______________________________________________________
1082 Bool_t AliEveListAnalyser::StartAddingObjects()
1083
1084   // Start adding objects for the analysis. Returns kTRUE on success.
1085
1086   if (fConnected == kFALSE)
1087   {
1088     fConnected = TQObject::Connect("TEvePointSet", "PointSelected(Int_t)", "AliEveListAnalyser", this, "AddObjectToList(Int_t)");
1089     //fConnected = TQObject::Connect("TEvePointSet", "Message(char*)", "AliEveListAnalyser", this, "AddObjectToList(char*)");
1090     if (fConnected) return kTRUE;
1091     
1092     Error("AliEveListAnalyser::StartAddingObjects", "Connection failed!");
1093   }
1094
1095   return kFALSE;
1096 }
1097
1098 //______________________________________________________
1099 Bool_t AliEveListAnalyser::StopAddingObjects()
1100 {
1101   // Stop adding objects for the analysis. Returns kTRUE on success.
1102
1103   if (fConnected)
1104   {
1105     //if (TQObject::Disconnect("TEvePointSet", "AddObjectToList(Char_t*)"))  fConnected = kFALSE;
1106     if (TQObject::Disconnect("TEvePointSet", "PointSelected(Int_t)", this, "AddObjectToList(Int_t)"))
1107     { 
1108       fConnected = kFALSE;
1109       return kTRUE;
1110     }
1111     else
1112     {
1113       Error("AliEveListAnalyser::StopAddingObjects", "Disconnection failed!");
1114       return kFALSE;
1115     }
1116   }
1117
1118   return kTRUE;
1119 }