1 // Author: Benjamin Hess 29/01/2010
3 /*************************************************************************
4 * Copyright (C) 2009-2010, Alexandru Bercuci, Benjamin Hess. *
5 * All rights reserved. *
6 *************************************************************************/
8 //////////////////////////////////////////////////////////////////////////
10 // AliEveListAnalyser //
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 ApplySOSelectionMacros(...) 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. //
42 // Currently, the following macro types are supported: //
43 // Selection macros: //
44 // Bool_t YourMacro(const YourObjectType*); //
45 // Bool_t YourMacro(const YourObjectType*, const YourObjectType2*); //
48 // void YourMacro(const YourObjectType*, Double_t*&, Int_t&); //
49 // void YourMacro(const YourObjectType*, const YourObjectType2*, //
50 // Double_t*&, Int_t&); //
51 // TH1* YourMacro(const YourObjectType*); //
52 // TH1* YourMacro(const YourObjectType*, const YourObjectType2*); //
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 //////////////////////////////////////////////////////////////////////////
63 // Uncomment to display debugging infos
64 //#define AliEveListAnalyser_DEBUG
66 #include <TEveManager.h>
67 #include <TEveSelection.h>
69 #include <TFunction.h>
73 #include <TMethodArg.h>
74 #include <TMethodCall.h>
75 #include <TObjString.h>
80 #include <TTreeStream.h>
82 #include <AliTRDReconstructor.h>
84 #include <EveDet/AliEveListAnalyser.h>
85 #include <EveDet/AliEveListAnalyserEditor.h>
87 ClassImp(AliEveListAnalyser)
89 ///////////////////////////////////////////////////////////
90 ///////////// AliEveListAnalyser ////////////////////////
91 ///////////////////////////////////////////////////////////
92 AliEveListAnalyser::AliEveListAnalyser(const Text_t* n, const Text_t* t, Bool_t doColor):
93 TEveElementList(n, t, doColor),
95 fDataFromMacroList(0x0),
99 fHistoDataSelected(0),
100 fMacroListSelected(0),
101 fSelectedTab(2) // Standard tab: "Apply macros" (index 2)
103 // Creates the AliEveListAnalyser.
105 // Only accept childs of type TEveElement
106 SetChildClass(TEveElement::Class());
108 // Allocate memory for the lists and declare them as owners of their contents
109 fDataFromMacroList = new TList();
110 fDataFromMacroList->TCollection::SetOwner(kTRUE);
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);
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")));
120 AddStandardContent();
123 //______________________________________________________
124 AliEveListAnalyser::~AliEveListAnalyser()
126 // Frees allocated memory (lists etc.).
128 // Stop adding objects
131 // Let the editor know that the list will be destroyed -> The editor will save the data
134 fEditor->SaveMacroList(fMacroList);
138 if (fDataFromMacroList != 0)
140 fDataFromMacroList->Delete();
141 delete fDataFromMacroList;
142 fDataFromMacroList = 0;
151 fMacroList->DeleteAll();
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")));
160 //______________________________________________________
161 Int_t AliEveListAnalyser::AddMacro(const Char_t* path, const Char_t* nameC, Bool_t forceReload)
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:
168 // Bool_t YourMacro(const YourObjectType*)
169 // Bool_t YourMacro(const YourObjectType*, const YourObjectType2*)
172 // void YourMacro(const YourObjectType*, Double_t*&, Int_t&)
173 // void YourMacro(const YourObjectType*, const YourObjectType2*, Double_t*&, Int_t&)
174 // TH1* YourMacro(const YourObjectType*)
175 // TH1* YourMacro(const YourObjectType*, const YourObjectType2*)
177 Char_t pathname[fkMaxMacroPathNameLength];
178 memset(pathname, '\0', sizeof(Char_t) * fkMaxMacroPathNameLength);
180 // Expand the path and create the pathname
181 Char_t* systemPath = gSystem->ExpandPathName(path);
182 sprintf(pathname, "%s/%s", systemPath, nameC);
186 // Delete ".C" from filename
187 Char_t name[fkMaxMacroNameLength];
188 memset(name, '\0', sizeof(Char_t) * fkMaxMacroNameLength);
190 for (UInt_t ind = 0; ind < fkMaxMacroNameLength && ind < strlen(nameC) - 2; ind++) name[ind] = nameC[ind];
192 // Check, if files exists
194 if((fp = fopen(pathname, "rb"))){
197 } else return NOT_EXIST_ERROR;
199 // Clean up root, load the desired macro and then check the type of the macro
200 // A.B. gROOT->Reset();
202 gROOT->ProcessLineSync(Form(".L %s+%c", pathname, forceReload ? '+' : ' '));
207 objectType = GetMacroObjectType(name, 1);
208 objectType2 = GetMacroObjectType(name, 2);
210 // We need this line... otherwise, in some cases, there will be problems concerning ACLIC
211 gROOT->ProcessLineSync(Form(".L %s", pathname));
213 if (!objectType) return UNKNOWN_OBJECT_TYPE_ERROR;
215 // This might be a macro dealing with only 1 object... test this afterwards!
216 Bool_t testSecondObj = kFALSE;
219 objectType2 = TObject::Class();
220 testSecondObj = kTRUE;
222 AliEveListAnalyserMacroType type = GetMacroType(name, objectType->GetName(), objectType2->GetName(), kFALSE);
228 case AliEveListAnalyser::kCorrelObjectSelect:
229 case AliEveListAnalyser::kCorrelObjectAnalyse:
230 case AliEveListAnalyser::kCorrelObjectHisto:
231 // There must be a second type -> Error!
232 return UNKNOWN_OBJECT_TYPE_ERROR;
235 // Ok, single object macro!
242 // A.B. gROOT->Reset();
244 // Has not the correct signature!
245 if (type == kUnknown) return SIGNATURE_ERROR;
247 // Only add macro, if it is not already in the list
248 Int_t returnValue = WARNING;
249 if(fMacroList->GetValue(name) == 0)
251 returnValue = AddMacroFast(path, name, type, objectType, objectType2) ? SUCCESS : ERROR;
257 //______________________________________________________
258 Bool_t AliEveListAnalyser::AddMacroFast(const Char_t* path, const Char_t* name, AliEveListAnalyserMacroType type,
259 TClass* objectType, TClass* objectType2)
261 // Adds a macro (path/name) to the corresponding list. No checks are performed (file exists,
262 // macro already in list/map, signature correct), no libraries are created!
263 // You can use this function only, if the macro has been added successfully before
264 // (and then maybe was removed). The function is very fast. On success kTRUE is returned, otherwise: kFALSE;
265 // Note: If your macro takes only 1 pointer as a parameter, just use "0x0" for objectType2!
267 Bool_t success = kFALSE;
271 case kSingleObjectSelect:
272 case kCorrelObjectSelect:
273 case kSingleObjectAnalyse:
274 case kSingleObjectHisto:
275 case kCorrelObjectAnalyse:
276 case kCorrelObjectHisto:
277 fMacroList->Add(new TObjString(name), new TGeneralMacroData(name, path, type, objectType, objectType2));
279 // We do not know, where the element has been inserted - deselect this list
280 fMacroListSelected = 0;
284 #ifdef AliEveListAnalyser_DEBUG
285 // Successfull add will only be displayed in debug mode
286 printf("AliEveListAnalyser::AddMacroFast: Added macro \"%s/%s\" with object types \"%s\" and \"%s\" to the corresponding list\n",
287 path, name, objectType->GetName(), objectType2->GetName());
293 // Error will always be displayed
294 printf("AliEveListAnalyser::AddMacroFast: ERROR: Could not add macro \"%s/%s\" with object types \"%s\" and \"%s\" to the corresponding list\n", path, name, objectType->GetName(), objectType2->GetName());
305 //______________________________________________________
306 Int_t AliEveListAnalyser::AddPrimSelectedObject(TEveElement* el)
308 // Adds the TEveElement el to the list. If it is already in the list, it is removed.
309 // If the list is the only parent of the clicked object, the object is moved outside the list in the browser (not deleted!).
310 // If you want to delete the object, just select it there and choose "Destroy" in the menu.
311 // This function is designed to be used together with a signal:
312 // It adds the (primarily) selected objects in the viewer to the list (objects that are already in the list are removed!).
313 // Returns "ERROR" (cf. defines) on error, "WARNING" if the element does not contain any user data and else "SUCCESS" (i.e.
314 // the element has been added successfully or the element is the list itself and therefore ignored, or the element is ignored
315 // because it has been added via secondary selection).
319 Error("AliEveListAnalyser::AddPrimSelectedObject", "Zero pointer!\n");
324 // If the clicked element is the list itself, just do nothing.
325 if (el == this) return SUCCESS;
327 if (!this->HasChild(el))
330 // Ignore objects that do not have any user data, since these cannot be used in the analysis!
331 if (el->GetUserData() == 0x0)
333 Warning("AddPrimSelectedObject", "Selected object does not contain any \"user data\" and therefore is ignored!");
338 // Element clicked that is not in the list (and is not the list itself!) -> Add this element to the list
339 this->AddElement(el);
340 this->SetTitle(Form("Objects %d", this->NumChildren()));
345 // Element clicked that is already in the list. Remove it. But: Only take care of objects that have been added
346 // via primary selection (name does not start with "[sec")
347 if (TString(el->GetElementName()).BeginsWith("[sec:")) return SUCCESS;
350 // Element is a child of this list. So, if there are only 2 parents, we know them: list + eve selection. In this case,
351 // the element needs to be destroyed. If there are more parents, just remove the element from the list.
352 // Since the elements editor will be opened, the element is not deleted, but "moved" outside the list (in the browser).
353 if (el->NumParents() > 2)
355 this->RemoveElement(el);
359 // There must be at least 2 parents!
360 if (el->NumParents() <= 1) return ERROR;
362 TEveElement* listObj = 0x0;
363 listObj = this->FindChild(el->GetElementName());
364 if (!listObj) return ERROR;
366 gEve->AddElement(listObj, 0);
367 // Alternatively: Switch on that the element is NOT destroyed, instead of adding it outside the list. Warning: Memory leaks possible.
368 //listObj->SetDestroyOnZeroRefCnt(kFALSE);
369 this->RemoveElement(listObj);
370 //gEve->RemoveElement(listObj, 0);
374 this->SetTitle(Form("Objects %d", this->NumChildren()));
382 //______________________________________________________
383 void AliEveListAnalyser::AddPrimSelectedObjects()
385 // Adds the (primarily) selected objects in the viewer to the list (objects that are already in the list are ignored).
386 // Hold the CTRL-key for multiple selection.
388 TEveSelection* eveSel = gEve->GetSelection();
391 Error("AliEveListAnalyser::AddPrimSelectedObjects", "Failed to get the selection!\n");
395 TEveElement* elem = 0x0;
396 Bool_t changedSomething = kFALSE;
398 for (TEveElement::List_i iter = eveSel->BeginChildren(); iter != eveSel->EndChildren(); ++iter)
400 if(!(elem = dynamic_cast<TEveElement*>(*iter))) continue;
402 if (!this->HasChild(elem) && elem != this)
404 // Element clicked that is not in the list (and is not the list itself!) -> Add this element to list
405 this->AddElement(elem);
406 this->SetTitle(Form("Objects %d", this->NumChildren()));
407 changedSomething = kTRUE;
411 if (changedSomething) gEve->Redraw3D();
415 //______________________________________________________
416 void AliEveListAnalyser::AddSecSelectedSingleObjectToList(Int_t pointId)
418 // This function adds the selected object (secondary selection in the viewer) to the list
419 // of analysis objects. If the object is already in the list, it will be removed from it.
420 // This function is used to add single objects of a TEvePointset, e.g. single clusters.
422 TEvePointSet* ps = dynamic_cast<TEvePointSet*>((TQObject*) gTQSender);
425 Error("AliEveListAnalyser::AddSecSelectedSingleObjectToList", "Zero pointer!\n");
429 // Check, if object is already there. If so, remove it!
431 // 1st possibility: Object of the list clicked. But: Only take care of objects that have been added
432 // via secondary selection (name starts with "[sec"). Note: HasChild will also return kTRUE, if e.g.
433 // the whole TEvePointSet of clusters is in the last (but maybe another point of it has been clicked!)
435 if (this->HasChild(ps))
437 if (TString(ps->GetName()).BeginsWith("[sec:"))
439 // I don't know why, but you get a crash, if you try this->RemoveElement(ps) (in some cases).
440 // So, use this way instead.
441 TEveElement* listObj = this->FindChild(ps->GetName());
444 listObj->SetUserData(0x0);
445 this->RemoveElement(listObj);
446 this->SetTitle(Form("Objects %d", this->NumChildren()));
453 TObject* obj = ps->GetPointId(pointId);
456 // 2nd possibility: Same object clicked again
457 TEveElement* listObj = 0x0;
458 listObj = this->FindChild(Form("[sec:%d] %s%d", obj->GetUniqueID(), obj->GetName(), pointId));
461 listObj->SetUserData(0x0);
462 this->RemoveElement(listObj);
463 this->SetTitle(Form("Objects %d", this->NumChildren()));
467 // Object clicked that is not in the list -> Add this object to list
468 TEvePointSet* newPS = new TEvePointSet(Form("[sec:%d] %s%d", obj->GetUniqueID(), obj->GetName(), pointId));
469 Double_t x = 0, y = 0, z = 0;
470 ps->GetPoint(pointId, x, y, z);
471 newPS->SetPoint(0, x, y, z);
472 newPS->SetUserData(obj);
473 // Choose yellow for the added points and inherit style and size for the marker
474 newPS->SetMarkerColor(5);
475 newPS->SetMarkerStyle(ps->GetMarkerStyle());
476 newPS->SetMarkerSize(ps->GetMarkerSize());
477 // Own points -> Will be cleared, if this object is removed
478 newPS->SetOwnIds(kTRUE);
480 this->AddElement(newPS);
481 this->SetTitle(Form("Objects %d", this->NumChildren()));
486 Error("AliEveListAnalyser::AddSecSelectedSingleObjectToList", "Selected object is NULL and therefore ignored!");
490 //______________________________________________________
491 void AliEveListAnalyser::AddStandardContent()
493 // Adds standard macros to the macro list.
495 // Add your standard macros here, e.g.:
496 // To add a macro use:
497 // AddMacro("$(ALICE_ROOT)/myFolder", "myMacroName.C");
498 // -> If the file does not exist, nothing happens. So if you want to handle this,
499 // use the return value of AddMacro (NOT_EXIST_ERROR is returned, if file does not exist)
500 // (-> You can also check for other return values (see AddMacro(...)))
504 //______________________________________________________
505 Bool_t AliEveListAnalyser::ApplyProcessMacros(const TList* selIterator, const TList* procIterator)
507 // Uses the procIterator (for the selected process macros) to apply the selected macros to the data.
508 // Returns kTRUE on success, otherwise kFALSE. If there no process macros selected, kTRUE is returned
509 // (this is no error!).
510 // The single object process macros are applied to all selected objects.
511 // The selIterator (for the selected selection macros) will be used to apply the correlated objects selection
512 // macros to all object pairs (whereby BOTH objects have to be selected, otherwise they will be skipped).
513 // All object pairs that have been selected by ALL correlated objects selection macros will be processed by
514 // the correlated objects process macros.
516 // No process macros need to be processed
517 if (procIterator->GetEntries() <= 0) return kTRUE;
520 // A.B. gROOT->Reset();
522 // Clear old data and re-allocate
523 if (fDataTree == 0x0){
524 TDirectory *cwd = gDirectory;
525 fDataTree = new TTreeSRedirector(Form("/tmp/ListAnalyserMacroData_%s.root", gSystem->Getenv("USER")));
529 Error("Apply process macros", Form("File \"/tmp/ListAnalyserMacroData_%s.root\" could not be accessed properly!",
530 gSystem->Getenv("USER")));
534 if (fDataFromMacroList != 0) {
535 fDataFromMacroList->Delete();
536 delete fDataFromMacroList;
538 fDataFromMacroList = new TList();
539 fDataFromMacroList->TCollection::SetOwner(kTRUE);
541 fHistoDataSelected = 0;
544 TGeneralMacroData* macro = 0;
546 Char_t** procCmds = 0;
547 AliEveListAnalyserMacroType* mProcType = 0;
548 if (procIterator->GetEntries() > 0) {
549 procCmds = new Char_t*[procIterator->GetEntries()];
550 mProcType = new AliEveListAnalyserMacroType[procIterator->GetEntries()];
553 TClass** mProcObjectType = 0;
554 TClass** mProcObjectType2 = 0;
555 if (procIterator->GetEntries() > 0) {
556 mProcObjectType = new TClass*[procIterator->GetEntries()];
557 mProcObjectType2 = new TClass*[procIterator->GetEntries()];
560 Char_t** selCmds = 0;
561 AliEveListAnalyserMacroType* mSelType = 0;
562 if (selIterator->GetEntries() > 0) {
563 selCmds = new Char_t*[selIterator->GetEntries()];
564 mSelType = new AliEveListAnalyserMacroType[selIterator->GetEntries()];
567 TClass** mSelObjectType = 0;
568 TClass** mSelObjectType2 = 0;
569 if (selIterator->GetEntries() > 0) {
570 mSelObjectType = new TClass*[selIterator->GetEntries()];
571 mSelObjectType2 = new TClass*[selIterator->GetEntries()];
574 Bool_t selectedByCorrSelMacro = kFALSE;
576 AliEveListAnalyserMacroType macroType = kUnknown;
577 Int_t numHistoMacros = 0;
580 TEveElement* object1 = 0;
581 TEveElement* object2 = 0;
582 TH1* returnedHist = 0x0;
584 // Collect the commands for each process macro and add them to "data-from-list"
585 for (Int_t i = 0; i < procIterator->GetEntries(); i++){
586 procCmds[i] = new Char_t[(fkMaxMacroPathNameLength + fkMaxApplyCommandLength)];
587 memset(procCmds[i], '\0', sizeof(Char_t) * (fkMaxMacroNameLength + fkMaxApplyCommandLength));
589 macro = (TGeneralMacroData*)fMacroList->GetValue(procIterator->At(i)->GetTitle());
592 Error("Apply process macros",
593 Form("Macro list is corrupted: Macro \"%s\" is not registered!",
594 procIterator->At(i)->GetTitle()));
598 #ifdef AliEveListAnalyser_DEBUG
599 printf("AliEveListAnalyser: Checking process macro: %s\n", macro->GetName());
602 // Find the object types of the macro
603 mProcObjectType[i] = macro->GetObjectType();
604 mProcObjectType2[i] = macro->GetObjectType2();
606 // Find the type of the process macro
607 macroType = macro->GetType();
608 if (macroType == kSingleObjectHisto || macroType == kCorrelObjectHisto){
609 mProcType[i] = macroType;
611 // Create the command
612 sprintf(procCmds[i], macro->GetCmd());
614 // Add to "data-from-list" -> Mark as a histo macro with the substring "(histo macro)"
615 fDataFromMacroList->Add(new TObjString(Form("%s (histo macro)", macro->GetName())));
616 } else if (macroType == kSingleObjectAnalyse || macroType == kCorrelObjectAnalyse) {
617 mProcType[i] = macroType;
618 // Create the command
619 sprintf(procCmds[i], macro->GetCmd());
621 // Add to "data-from-list"
622 fDataFromMacroList->Add(new TObjString(macro->GetName()));
624 Error("Apply process macros",
625 Form("Macro list corrupted: Macro \"%s/%s.C\" is not registered as a process macro!",
626 macro->GetPath(), macro->GetName()));
627 mProcType[i] = kUnknown;
631 // Collect the commands for each selection macro and add them to "data-from-list"
632 for (Int_t i = 0; i < selIterator->GetEntries(); i++){
633 selCmds[i] = new Char_t[(fkMaxMacroPathNameLength + fkMaxApplyCommandLength)];
634 memset(selCmds[i], '\0', sizeof(Char_t) * (fkMaxMacroNameLength + fkMaxApplyCommandLength));
636 macro = (TGeneralMacroData*)fMacroList->GetValue(selIterator->At(i)->GetTitle());
639 Error("Apply process macros",
640 Form("Macro list is corrupted: Macro \"%s\" is not registered!",
641 selIterator->At(i)->GetTitle()));
645 #ifdef AliEveListAnalyser_DEBUG
646 printf("AliEveListAnalyser: Checking selection macro: %s\n", macro->GetName());
649 // Find the object types of the macro
650 mSelObjectType[i] = macro->GetObjectType();
651 mSelObjectType2[i] = macro->GetObjectType2();
653 // Find the type of the process macro
654 macroType = macro->GetType();
656 // Single Object select macro
657 if (macroType == kSingleObjectSelect) {
658 // Has already been processed by ApplySOSelectionMacros(...)
659 mSelType[i] = macroType;
661 // Correlated Objects select macro
662 else if (macroType == kCorrelObjectSelect) {
663 mSelType[i] = macroType;
665 // Create the command
666 sprintf(selCmds[i], macro->GetCmd());
668 Error("Apply process macros",
669 Form("Macro list corrupted: Macro \"%s/%s.C\" is not registered as a selection macro!",
670 macro->GetPath(), macro->GetName()));
671 mSelType[i] = kUnknown;
675 // Allocate memory for the histograms
676 if (numHistoMacros > 0) histos = new TH1*[numHistoMacros];
677 for (Int_t i = 0; i < numHistoMacros; i++) histos[i] = 0x0;
679 Bool_t secondBeforeFirstObject = kTRUE;
682 //////////////////////////////////////
683 // WALK THROUGH THE LIST OF OBJECTS //
684 //////////////////////////////////////
685 for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter){
686 if(!(object1 = dynamic_cast<TEveElement*>(*iter))) continue;
688 // Skip objects that have not been selected
689 if (!object1->GetRnrState()) continue;
691 // Cast to the "real" object behind
692 gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object1));
693 gROOT->ProcessLineSync("TObject* automaticObject_1 = (TObject*)automaticEveElement->GetUserData();");
695 // Collect data for each macro
696 for (Int_t i = 0, histoIndex = 0; i < procIterator->GetEntries(); i++){
697 // Find the type of the object and relate it to the macro object type
698 // Only apply macro to this object, if...
699 // ... the macro takes objects of exactly this type.
700 // ... the macro object type is a child of this object's type.
701 // Otherwise: Continue
703 // Finally, via procCmds[i], the automatic objects are casted to the correct type and analysed by each macro!
704 if (((TObject*)object1->GetUserData())->IsA() != mProcObjectType[i] &&
705 !((TObject*)object1->GetUserData())->InheritsFrom(mProcObjectType[i])) continue;
708 // Single object histo
709 if (mProcType[i] == kSingleObjectHisto){
710 returnedHist = (TH1*)gROOT->ProcessLineSync(procCmds[i]);
713 if (!histos[histoIndex]) histos[histoIndex] = returnedHist;
716 histos[histoIndex]->Add((const TH1*)returnedHist);
722 // Correlated Objects histo
723 } else if (mProcType[i] == kCorrelObjectHisto) {
724 // To get all pairs, do the second loop over all objects.
725 // But: If a macro takes 2 pointers of the same type, we must take care that one gets the same pair, when we exchange the objects
726 // (this is not true, if we have different types - even if they inherit from the same classes!).
727 // Thus: If the latter case occurs, we ignore an object pair, if the second object is BEFORE the first object in the list.
728 // Since then the pair has already been taken into account.
729 // Furthermore, we have a pair of objects, if and only if both objects of the pair are selected (Rnr-state)
730 // and are not equal.
731 // The correlated objects process macro will be applied to all pairs that will be additionally selected by
732 // all correlated objects selection macros.
734 secondBeforeFirstObject = kTRUE;
735 for (TEveElement::List_i iter2 = this->BeginChildren(); iter2 != this->EndChildren(); ++iter2)
737 // If the objects are the same, it is not a pair -> continue. From now on: 2nd object BEHIND the 1st object in the list!
740 secondBeforeFirstObject = kFALSE;
743 if(!(object2 = dynamic_cast<TEveElement*>(*iter2))) continue;
745 // Skip objects that have not been selected
746 if (!object2->GetRnrState()) continue;
748 // Same check of the macro object type as before
749 if (((TObject*)object2->GetUserData())->IsA() != mProcObjectType2[i] &&
750 !((TObject*)object2->GetUserData())->InheritsFrom(mProcObjectType2[i])) continue;
751 // Do not process object pairs twice
752 if (secondBeforeFirstObject)
754 if (mProcObjectType[i] == mProcObjectType2[i]) continue;
757 // Cast to the "real" object behind
758 gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object2));
759 gROOT->ProcessLineSync("TObject* automaticObject_2 = (TObject*)automaticEveElement->GetUserData();");
761 // Select object by default (so it will be processed, if there are no correlated objects selection macros!)
762 selectedByCorrSelMacro = kTRUE;
763 for (Int_t j = 0; j < selIterator->GetEntries(); j++){
764 if (mSelType[j] == kCorrelObjectSelect){
765 // Check, whether the macro can deal with both objects. If not, skip it.
766 // Note: Again, via selCmds[i], the automatic objects are casted to the correct type!
767 if (((TObject*)object1->GetUserData())->IsA() != mSelObjectType[j] &&
768 !((TObject*)object1->GetUserData())->InheritsFrom(mSelObjectType[j])) continue;
769 if (((TObject*)object2->GetUserData())->IsA() != mSelObjectType2[j] &&
770 !((TObject*)object2->GetUserData())->InheritsFrom(mSelObjectType2[j])) continue;
772 selectedByCorrSelMacro = (Bool_t)gROOT->ProcessLineSync(selCmds[j]);
773 if (!selectedByCorrSelMacro) break;
777 // If the pair has not been selected by the correlated objects selection macros, skip it!
778 if (!selectedByCorrSelMacro) continue;
780 returnedHist = (TH1*)gROOT->ProcessLineSync(procCmds[i]);
783 if (!histos[histoIndex]) histos[histoIndex] = returnedHist;
786 histos[histoIndex]->Add((const TH1*)returnedHist);
795 // Single object analyse
796 else if (mProcType[i] == kSingleObjectAnalyse) {
797 // Create data pointers in CINT, execute the macro and get the data
798 gROOT->ProcessLineSync("Double_t* results = 0;");
799 gROOT->ProcessLineSync("Int_t n = 0;");
800 gROOT->ProcessLineSync(procCmds[i]);
801 Double_t* results = (Double_t*)gROOT->ProcessLineSync("results;");
802 Int_t nResults = (Int_t)gROOT->ProcessLineSync("n;");
805 Error("Apply macros", Form("Error reading data from macro \"%s\"", procIterator->At(i)->GetTitle()));
808 for (Int_t resInd = 0; resInd < nResults; resInd++){
809 (*fDataTree) << Form("ObjectData%d", i) << Form("Macro%d=", i) << results[resInd] << (Char_t*)"\n";
815 // Correlated objects analyse
816 else if (mProcType[i] == kCorrelObjectAnalyse){
817 // To get all pairs, do the second loop over all objects.
818 // But: If a macro takes 2 pointers of the same type, we must take care that one gets the same pair, when we exchange the objects
819 // (this is not true, if we have different types - even if they inherit from the same classes!).
820 // Thus: If the latter case occurs, we ignore an object pair, if the second object is BEFORE the first object in the list.
821 // Since then the pair has already been taken into account.
822 // Furthermore, we have a pair of objects, if and only if both objects of the pair are selected (Rnr-state)
823 // and are not equal.
824 // The correlated objects process macro will be applied to all pairs that will be additionally selected by
825 // all correlated objects selection macros.
827 secondBeforeFirstObject = kTRUE;
828 for (TEveElement::List_i iter2 = this->BeginChildren(); iter2 != this->EndChildren(); ++iter2)
830 // If the objects are the same, it is not a pair -> continue. From now on: 2nd object BEHIND the 1st object in the list!
833 secondBeforeFirstObject = kFALSE;
836 if(!(object2 = dynamic_cast<TEveElement*>(*iter2))) continue;
838 // Skip objects that have not been selected
839 if (!object2->GetRnrState()) continue;
841 // Same check of the macro object type as before
842 if (((TObject*)object2->GetUserData())->IsA() != mProcObjectType2[i] &&
843 !((TObject*)object2->GetUserData())->InheritsFrom(mProcObjectType2[i])) continue;
844 // Do not process object pairs twice
845 if (secondBeforeFirstObject)
847 if (mProcObjectType[i] == mProcObjectType2[i]) continue;
850 // Cast to the "real" object behind
851 gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object2));
852 gROOT->ProcessLineSync("TObject* automaticObject_2 = (TObject*)automaticEveElement->GetUserData();");
854 // Select object by default (so it will be processed, if there are no correlated objects selection macros!)
855 selectedByCorrSelMacro = kTRUE;
856 for (Int_t j = 0; j < selIterator->GetEntries(); j++) {
857 if (mSelType[j] == kCorrelObjectSelect) {
858 // Check, whether the macro can deal with both objects. If not, skip it.
859 // Note: Again, via selCmds[i], the automatic objects are casted to the correct type!
860 if (((TObject*)object1->GetUserData())->IsA() != mSelObjectType[j] &&
861 !((TObject*)object1->GetUserData())->InheritsFrom(mSelObjectType[j])) continue;
862 if (((TObject*)object2->GetUserData())->IsA() != mSelObjectType2[j] &&
863 !((TObject*)object2->GetUserData())->InheritsFrom(mSelObjectType2[j])) continue;
865 selectedByCorrSelMacro = (Bool_t)gROOT->ProcessLineSync(selCmds[j]);
866 if (!selectedByCorrSelMacro) break;
870 // If the pair has not been selected by the correlated objects selection macros, skip it!
871 if (!selectedByCorrSelMacro) continue;
873 // Create data pointers in CINT, execute the macro and get the data
874 gROOT->ProcessLineSync("Double_t* results = 0;");
875 gROOT->ProcessLineSync("Int_t n = 0;");
876 gROOT->ProcessLineSync(procCmds[i]);
877 Double_t* results = (Double_t*)gROOT->ProcessLineSync("results;");
878 Int_t nResults = (Int_t)gROOT->ProcessLineSync("n;");
881 Error("Apply macros", Form("Error reading data from macro \"%s\"", procIterator->At(i)->GetTitle()));
884 for (Int_t resInd = 0; resInd < nResults; resInd++) {
885 (*fDataTree) << Form("ObjectData%d", i) << Form("Macro%d=", i) << results[resInd] << (Char_t*)"\n";
895 for (Int_t i = 0, histoIndex = 0; i < procIterator->GetEntries() && histoIndex < numHistoMacros; i++) {
896 if (mProcType[i] == kSingleObjectHisto || mProcType[i] == kCorrelObjectHisto) {
897 // Might be empty (e.g. no objects have been selected)!
898 if (histos[histoIndex]) {
899 (*fDataTree) << Form("ObjectData%d", i) << Form("Macro%d=", i) << histos[histoIndex] << (Char_t*)"\n";
905 if (fDataTree != 0) delete fDataTree;
908 if (procCmds != 0) delete [] procCmds;
910 if (mProcObjectType != 0) delete mProcObjectType;
912 if (mProcObjectType2 != 0) delete mProcObjectType2;
913 mProcObjectType2 = 0;
914 if (mProcType != 0) delete [] mProcType;
917 if (selCmds != 0) delete [] selCmds;
919 if (mSelObjectType != 0) delete mSelObjectType;
921 if (mSelObjectType2 != 0) delete mSelObjectType2;
923 if (mSelType != 0) delete [] mSelType;
926 if (histos != 0) delete [] histos;
930 // A.B. gROOT->Reset();
932 // If there is data, select the first data set
933 if (procIterator->GetEntries() > 0) SETBIT(fHistoDataSelected, 0);
935 // Now the data is stored in "/tmp/ListAnalyserMacroData_$USER.root"
936 // The editor will access this file to display the data
940 //______________________________________________________
941 void AliEveListAnalyser::ApplySOSelectionMacros(const TList* iterator)
943 // Uses the iterator (for the selected selection macros) to apply the selected macros to the data.
944 // The rnr-states of the objects are set according to the result of the macro calls (kTRUE, if all
945 // macros return kTRUE for this object, otherwise: kFALSE).
946 // "SO" stands for "single object". This means that only single object selection macros are applied.
947 // Correlated objects selection macros will be used inside the call of ApplyProcessMacros(...)!
949 TGeneralMacroData* macro = 0;
950 AliEveListAnalyserMacroType macroType = kUnknown;
951 TEveElement* object1 = 0;
952 Bool_t selectedByMacro = kFALSE;
955 // A.B. gROOT->Reset();
957 // Select all objecs at first. A object is then deselected, if at least one selection macro
958 // returns kFALSE for this object.
959 // Enable all objects (Note: EnableListElements(..) will call "ElementChanged", which will cause unforeseen behaviour!)
960 for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter) ((TEveElement*)(*iter))->SetRnrState(kTRUE);
963 for (Int_t i = 0; i < iterator->GetEntries(); i++){
964 macro = (TGeneralMacroData*)fMacroList->GetValue(iterator->At(i)->GetTitle());
967 Error("Apply selection macros",
968 Form("Macro list is corrupted: Macro \"%s\" is not registered!", iterator->At(i)->GetTitle()));
972 #ifdef AliEveListAnalyser_DEBUG
973 printf("AliEveListAnalyser: Applying selection macro: %s\n", macro->GetName());
976 // Determine macro type
977 macroType = macro->GetType();
979 // Single object select macro
980 if (macroType == kSingleObjectSelect){
981 // Walk through the list of objects
982 for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter)
984 object1 = dynamic_cast<TEveElement*>(*iter);
986 if (!object1) continue;
988 // If the object has already been deselected, nothing is to do here
989 if (!object1->GetRnrState()) continue;
991 // Find the type of the object and relate it to the macro object type
992 // Only apply macro to this object, if...
993 // ... the macro takes objects of exactly this type.
994 // ... the macro object type is a child of this object's type.
995 // Otherwise: Continue
996 if (((TObject*)object1->GetUserData())->IsA() != macro->GetObjectType() &&
997 !((TObject*)object1->GetUserData())->InheritsFrom(macro->GetObjectType())) continue;
999 // Cast to the "real" object behind
1000 gROOT->ProcessLineSync(Form("TEveElement *automaticEveElement = (TEveElement*)0x%xl;", object1));
1001 gROOT->ProcessLineSync("TObject* automaticObject_1 = (TObject*)automaticEveElement->GetUserData();");
1003 // GetCmd() will cast the automatic objects to the correct type for each macro!
1004 selectedByMacro = (Bool_t)gROOT->ProcessLineSync(macro->GetCmd());
1005 object1->SetRnrState(selectedByMacro && object1->GetRnrState());
1008 // Correlated objects select macro
1009 else if (macroType == kCorrelObjectSelect){
1010 // Will be processed in ApplyProcessMacros(...)
1013 Error("Apply selection macros",
1014 Form("Macro list corrupted: Macro \"%s/%s.C\" is not registered as a selection macro!",
1015 macro->GetPath(), macro->GetName()));
1020 // A.B. gROOT->Reset();
1023 //______________________________________________________
1024 TClass* AliEveListAnalyser::GetMacroObjectType(const Char_t* name, Int_t argNum) const
1026 // Returns the type of object (of argument argNum) the macro with name "name" is dealing with;
1027 // e.g. if you have the signature:
1028 // void MyMacro(const AliTRDtrackV1* track, Double_t* &results, Int_t& nResults)
1029 // the call 'GetMacroObjectType("MyMacro")' yields the AliTRDtrackV1-class.
1030 // If the macro is not found (or there is an error), 0x0 is returned.
1032 if (argNum - 1 < 0) return 0x0;
1034 TFunction* f = gROOT->GetGlobalFunction(name, 0 , kTRUE);
1040 list = f->GetListOfMethodArgs();
1042 if (!list->IsEmpty())
1044 m = (TMethodArg*)list->At(argNum - 1);
1046 if (m) return TClass::GetClass(m->GetTypeName());
1054 //______________________________________________________
1055 AliEveListAnalyser::AliEveListAnalyserMacroType AliEveListAnalyser::GetMacroType(const Char_t* name, const Char_t* objectType,
1056 const Char_t* objectType2, Bool_t UseList) const
1058 // Returns the type of the corresponding macro, that accepts pointers of the classes "objectType" (first pointer) and
1059 // objectType2" (second pointer) as parametres.
1060 // If "UseList" is kTRUE, the type will be looked up in the internal list (very fast). But if this list
1061 // does not exist, you have to use kFALSE for this parameter. Then the type will be determined by the
1062 // prototype! NOTE: It is assumed that the macro has been compiled! If not, the return value is not
1063 // predictable, but normally will be kUnknown.
1064 // Note: AddMacro(Fast) will update the internal list and RemoveMacros respectively.
1066 AliEveListAnalyserMacroType type = kUnknown;
1068 TString* typeStr = 0;
1069 TString* typeStr2 = 0;
1071 if (objectType != 0)
1073 typeStr = new TString(objectType);
1074 // Remove white-spaces
1075 typeStr->ReplaceAll(" ", "");
1079 typeStr = new TString("TObject");
1081 if (objectType2 != 0)
1083 typeStr2 = new TString(objectType2);
1084 // Remove white-spaces
1085 typeStr2->ReplaceAll(" ", "");
1089 typeStr2 = new TString("TObject");
1092 TString* mangled1Str = new TString();
1093 TString* mangled2Str = new TString();
1094 TString* mangled3Str = new TString();
1095 TString* mangled4Str = new TString();
1096 TString* mangledArg1Str = new TString();
1097 TString* mangledArg2Str = new TString();
1099 // We want "const 'OBJECTTYPE'*"
1100 mangled1Str->Append("const ").Append(*typeStr).Append("*");
1102 // We want "const 'OBJECTTYPE'*, Double_t*&, Int_t&"
1103 mangled2Str->Append("const ").Append(*typeStr).Append("*, Double_t*&, Int_t&");
1105 // We want "const 'OBJECTTYPE'*, const 'OBJECTTYPE2'*"
1106 mangled3Str->Append("const ").Append(*typeStr).Append("*, const ").Append(*typeStr2).Append("*");
1108 // We want "const 'OBJECTTYPE'*, const 'OBJECTTYPE2'*, Double_t*&, Int_t&"
1109 mangled4Str->Append("const ").Append(*typeStr).Append("*, const ").Append(*typeStr2).Append("*, Double_t*&, Int_t&");
1111 // We want "oPconstsP'OBJECTTYPE'mUsP"
1112 mangledArg1Str->Append("oPconstsP").Append(*typeStr).Append("mUsP");
1114 // We want "cOconstsP'OBJECTTYPE2'mUsP"
1115 mangledArg2Str->Append("cOconstsP").Append(*typeStr2).Append("mUsP");
1117 // Re-do the check of the macro type
1119 // Single object select macro or single object histo macro?
1120 TFunction* f = gROOT->GetGlobalFunctionWithPrototype(name, mangled1Str->Data(), kTRUE);
1124 // Some additional check (is the parameter EXACTLY of the desired type?)
1125 if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0)
1127 // Single object select macro?
1128 if (!strcmp(f->GetReturnTypeName(), "Bool_t"))
1130 type = kSingleObjectSelect;
1132 // single object histo macro?
1133 else if (!strcmp(f->GetReturnTypeName(), "TH1*"))
1135 type = kSingleObjectHisto;
1139 // Single object analyse macro?
1140 else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, mangled2Str->Data(), kTRUE))
1143 if (!strcmp(f->GetReturnTypeName(), "void"))
1145 // Some additional check (are the parameters EXACTLY of the desired type?)
1146 if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0 &&
1147 strstr(f->GetMangledName(), "cODouble_tmUaNsP") != 0x0 &&
1148 strstr(f->GetMangledName(), "cOInt_taNsP") != 0x0)
1150 type = kSingleObjectAnalyse;
1154 // Correlated objects select macro or correlated objects histo macro?
1155 else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, mangled3Str->Data(), kTRUE))
1158 // Some additional check (is the parameter EXACTLY of the desired type?)
1159 if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0 &&
1160 strstr(f->GetMangledName(), mangledArg2Str->Data()) != 0x0)
1162 // Correlated objects select macro?
1163 if (!strcmp(f->GetReturnTypeName(), "Bool_t"))
1165 type = kCorrelObjectSelect;
1167 // Correlated objects histo macro?
1168 else if (!strcmp(f->GetReturnTypeName(), "TH1*"))
1170 type = kCorrelObjectHisto;
1174 // Correlated objects analyse macro?
1175 else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, mangled4Str->Data(), kTRUE))
1178 if (!strcmp(f->GetReturnTypeName(), "void"))
1180 // Some additional check (is the parameter EXACTLY of the desired type?)
1181 if (strstr(f->GetMangledName(), mangledArg1Str->Data()) != 0x0 &&
1182 strstr(f->GetMangledName(), mangledArg2Str->Data()) != 0x0 &&
1183 strstr(f->GetMangledName(), "cODouble_tmUaNsP") != 0x0 &&
1184 strstr(f->GetMangledName(), "cOInt_taNsP") != 0x0)
1186 type = kCorrelObjectAnalyse;
1191 // Use list to look up the macro type
1194 TGeneralMacroData* macro = 0;
1195 macro = (TGeneralMacroData*)fMacroList->GetValue(name);
1196 if (macro == 0) return kUnknown;
1198 type = macro->GetType();
1201 case kSingleObjectSelect:
1202 case kSingleObjectAnalyse:
1203 case kSingleObjectHisto:
1204 case kCorrelObjectSelect:
1205 case kCorrelObjectAnalyse:
1206 case kCorrelObjectHisto:
1215 if (mangled1Str != 0)
1217 mangled1Str->Clear();
1221 if (mangled2Str != 0)
1223 mangled2Str->Clear();
1227 if (mangled3Str != 0)
1229 mangled3Str->Clear();
1233 if (mangled4Str != 0)
1235 mangled4Str->Clear();
1239 if (mangledArg1Str != 0)
1241 mangledArg1Str->Clear();
1242 delete mangledArg1Str;
1245 if (mangledArg2Str != 0)
1247 mangledArg2Str->Clear();
1248 delete mangledArg2Str;
1270 //______________________________________________________
1271 void AliEveListAnalyser::RemovePrimSelectedObjects()
1273 // Removes the (primarily) selected objects in the viewer from the list (objects that are already in the list are ignored).
1274 // Hold the CTRL-key for multiple selection.
1276 TEveSelection* eveSel = gEve->GetSelection();
1280 Error("AliEveListAnalyser::RemovePrimSelectedObjects", "Failed to get the selection!\n");
1284 TEveElement* elem = 0x0;
1285 Bool_t changedSomething = kFALSE;
1287 for (TEveElement::List_i iter = eveSel->BeginChildren(); iter != eveSel->EndChildren(); ++iter)
1289 if(!(elem = dynamic_cast<TEveElement*>(*iter))) continue;
1291 // Check, if element is already there. If so, remove it!
1292 if (this->HasChild(elem) && elem != this)
1294 this->RemoveElement(elem);
1295 this->SetTitle(Form("Objects %d", this->NumChildren()));
1296 changedSomething = kTRUE;
1300 if (changedSomething) gEve->Redraw3D();
1304 //______________________________________________________
1305 void AliEveListAnalyser::RemoveSelectedMacros(const TList* iterator)
1307 // Uses the iterator (for the selected macros) to remove the selected macros from
1308 // the corresponding list.
1312 for (Int_t i = 0; i < iterator->GetEntries(); i++)
1314 entry = (TPair*)fMacroList->FindObject(iterator->At(i)->GetTitle());
1318 Error("AliEveListAnalyser::RemoveSelectedMacros", Form("Macro \"%s\" not found in list!",
1319 iterator->At(i)->GetTitle()));
1326 Error("AliEveListAnalyser::RemoveSelectedMacros", Form("Key for macro \"%s\" not found in list!",
1327 iterator->At(i)->GetTitle()));
1331 // Key and value will be deleted, too, since fMacroList is the owner of them
1332 Bool_t rem = fMacroList->DeleteEntry(key);
1336 #ifdef AliEveListAnalyser_DEBUG
1337 printf("AliEveListAnalyser::RemoveSelectedMacros(): Removed macro: %s\n", iterator->At(i)->GetTitle());
1342 Error("AliEveListAnalyser::RemoveSelectedMacros", Form("Macro \"%s\" could not be removed from the list!",
1343 iterator->At(i)->GetTitle()));
1348 //______________________________________________________
1349 void AliEveListAnalyser::ResetObjectList()
1351 // Removes all objects from the list.
1354 this->SetTitle(Form("Objects %d", this->NumChildren()));
1357 //______________________________________________________
1358 Bool_t AliEveListAnalyser::StartAddingObjects()
1360 // Starts adding objects for the analysis. Returns kTRUE on success.
1362 if (fConnected == kFALSE)
1364 fConnected = TQObject::Connect("TEvePointSet", "PointSelected(Int_t)", "AliEveListAnalyser", this, "AddSecSelectedSingleObjectToList(Int_t)");
1365 if (fConnected) fConnected = TQObject::Connect(gEve->GetSelection(), "SelectionAdded(TEveElement*)", "AliEveListAnalyser", this, "AddPrimSelectedObject(TEveElement*)");
1367 if (fConnected) return kTRUE;
1369 Error("AliEveListAnalyser::StartAddingObjects", "Connection failed!");
1371 // Connection of 2nd signal failed, but first connection succeeded -> Disconnect 1st signal.
1372 TQObject::Disconnect("TEvePointSet", "PointSelected(Int_t)", this, "AddObjectToList(Int_t)");
1378 //______________________________________________________
1379 Bool_t AliEveListAnalyser::StopAddingObjects()
1381 // Stops adding objects for the analysis. Returns kTRUE on success.
1385 Bool_t dis1 = kFALSE, dis2 = kFALSE;
1386 dis1 = TQObject::Disconnect("TEvePointSet", "PointSelected(Int_t)", this, "AddSecSelectedSingleObjectToList(Int_t)");
1387 dis2 = TQObject::Disconnect(gEve->GetSelection(), "SelectionAdded(TEveElement*)", this, "AddPrimSelectedObject(TEveElement*)");
1389 if (dis1 || dis2) fConnected = kFALSE;
1390 if (dis1 && dis2) return kTRUE;
1393 Error("AliEveListAnalyser::StopAddingObjects", "Disconnection failed!");