]> git.uio.no Git - u/mrichter/AliRoot.git/blame - EVE/EveDet/AliEveTRDTrackList.cxx
extend user interface. New function for direct access to clusters
[u/mrichter/AliRoot.git] / EVE / EveDet / AliEveTRDTrackList.cxx
CommitLineData
caaf90d2 1// Uncomment to display debugging infos
2//#define ALIEVETRDTRACKLIST_DEBUG
3
2ef0687e 4#include "AliEveTRDTrackList.h"
5
caaf90d2 6#include <AliTRDtrackV1.h>
7#include <TFile.h>
8#include <TFunction.h>
c413e8d4 9#include <TH1.h>
caaf90d2 10#include <TList.h>
11#include <TObjString.h>
12#include <TROOT.h>
13#include <TSystem.h>
14#include <TTree.h>
15#include <TTreeStream.h>
16#include <EveDet/AliEveTRDData.h>
17
2ef0687e 18ClassImp(AliEveTRDTrackList)
19
20///////////////////////////////////////////////////////////
21///////////// AliEveTRDTrackList ////////////////////////
22///////////////////////////////////////////////////////////
23AliEveTRDTrackList::AliEveTRDTrackList(const Text_t* n, const Text_t* t, Bool_t doColor):
24 TEveElementList(n, t, doColor),
caaf90d2 25 fMacroList(0),
26 fMacroSelList(0),
27 fDataFromMacroList(0),
4f6473f6 28 fDataTree(0),
29 fHistoDataSelected(0),
30 fMacroListSelected(0),
31 fMacroSelListSelected(0),
32 fSelectedTab(1) // Standard tab: "Apply macros" (index 1)
2ef0687e 33{
caaf90d2 34 // Only accept childs of type AliEveTRDTrack
2ef0687e 35 SetChildClass(AliEveTRDTrack::Class());
36
caaf90d2 37 fMacroList = new TList();
38 fMacroSelList = new TList();
39 fDataFromMacroList = new TList();
40
4f6473f6 41 //fDataTree = new TTreeSRedirector("TRD.TrackListMacroData.root");
caaf90d2 42
43 AddStandardMacros();
44}
45
8e27fca1 46//______________________________________________________
caaf90d2 47AliEveTRDTrackList::~AliEveTRDTrackList()
48{
49 if (fMacroList != 0)
50 {
c413e8d4 51 fMacroList->Delete();
caaf90d2 52 delete fMacroList;
53 fMacroList = 0;
54 }
55 if (fMacroSelList != 0)
56 {
c413e8d4 57 fMacroSelList->Delete();
caaf90d2 58 delete fMacroSelList;
59 fMacroSelList = 0;
60 }
61 if (fDataFromMacroList != 0)
62 {
c413e8d4 63 fDataFromMacroList->Delete();
caaf90d2 64 delete fDataFromMacroList;
65 fDataFromMacroList = 0;
66 }
67 if (fDataTree != 0)
68 {
69 delete fDataTree;
70 fDataTree = 0;
71 }
ea24e1bc 72 if(!gSystem->AccessPathName(Form("/tmp/TRD.TrackListMacroData_%s.root", gSystem->Getenv("USER")))) gSystem->Exec(Form("rm /tmp/TRD.TrackListMacroData_%s.root", gSystem->Getenv("USER")));
caaf90d2 73}
74
8e27fca1 75//______________________________________________________
c413e8d4 76Int_t AliEveTRDTrackList::AddMacro(const Char_t* path, const Char_t* nameC, Bool_t forceReload)
caaf90d2 77{
78 // First check the type of the macro:
79 // If it has the signature of a selection macro:
80 // Bool_t MacroName(AliTRDtrackV1*)
81 // it is assumed to be a selection macro.
82 // If it has the signature of a process macro:
83 // void MacroName(AliTRDtrackV1*, Double_t*&, Int_t&)
84 // it is assumed to be a process macro.
85 // In all other cases: Macro is rejected
c413e8d4 86 Bool_t isHistoMacro = kFALSE;
caaf90d2 87 Bool_t isSelectionMacro = kFALSE;
88 Bool_t hasCorrectSignature = kFALSE;
89
90
91 Char_t* entryName = MakeMacroEntry(path, nameC);
92
4f6473f6 93 Char_t pathname[fkMaxMacroPathNameLength];
94 memset(pathname, '\0', sizeof(Char_t) * fkMaxMacroPathNameLength);
caaf90d2 95
96 // Expand the path and create the pathname
97 Char_t* systemPath = gSystem->ExpandPathName(path);
98 sprintf(pathname, "%s/%s", systemPath, nameC);
99 delete systemPath;
100 systemPath = 0;
101
102 // Delete ".C" from filename
4f6473f6 103 Char_t name[fkMaxMacroNameLength];
104 memset(name, '\0', sizeof(Char_t) * fkMaxMacroNameLength);
105
106 for (UInt_t ind = 0; ind < fkMaxMacroNameLength && ind < strlen(nameC) - 2; ind++) name[ind] = nameC[ind];
caaf90d2 107
108 // Check, if files exists
109 FILE* fp = 0;
110
111 fp = fopen(pathname, "rb");
112 if (fp != 0)
113 {
114 fclose(fp);
115 fp = 0;
116 }
117 else
118 {
caaf90d2 119 if (entryName != 0) delete entryName;
120 entryName = 0;
121
122 return NOT_EXIST_ERROR;
123 }
124
125 // Clean up root, load the desired macro and then check the type of the macro
126 //gROOT->Reset("a");
127 gROOT->Reset();
c413e8d4 128
129 if (forceReload) gROOT->ProcessLineSync(Form(".L %s++", pathname));
130 else gROOT->ProcessLineSync(Form(".L %s+", pathname));
caaf90d2 131
c413e8d4 132 // Selection macro or process macro of type 2 (histo)?
4f6473f6 133 TFunction* f = gROOT->GetGlobalFunctionWithPrototype(name, "const AliTRDtrackV1*", kTRUE);
8e27fca1 134 if (f != 0x0)
135 {
c413e8d4 136 // Some additional check (is the parameter EXACTLY of the desired type?)
137 if (strstr(f->GetMangledName(), "oPconstsPAliTRDtrackV1mUsP") != 0x0)
8e27fca1 138 {
c413e8d4 139 // Selection macro?
140 if (!strcmp(f->GetReturnTypeName(), "Bool_t"))
141 {
c04e790a 142 hasCorrectSignature = kTRUE;
143 isSelectionMacro = kTRUE;
c413e8d4 144 isHistoMacro = kFALSE;
145 }
146 // Process macro of type 2 (histo)?
147 else if (!strcmp(f->GetReturnTypeName(), "TH1*"))
148 {
149 hasCorrectSignature = kTRUE;
150 isSelectionMacro = kFALSE;
151 isHistoMacro = kTRUE;
c04e790a 152 }
caaf90d2 153 }
8e27fca1 154 }
c413e8d4 155 // Process macro of type 1?
156 else if ((f = gROOT->GetGlobalFunctionWithPrototype(name, "const AliTRDtrackV1*, Double_t*&, Int_t&", kTRUE)) != 0x0)
8e27fca1 157 {
c413e8d4 158 if (!strcmp(f->GetReturnTypeName(), "void"))
8e27fca1 159 {
c413e8d4 160 // Some additional check (are the parameters EXACTLY of the desired type?)
161 if (strstr(f->GetMangledName(), "oPconstsPAliTRDtrackV1mUsP") != 0x0 &&
162 strstr(f->GetMangledName(), "cODouble_tmUaNsP") != 0x0 &&
163 strstr(f->GetMangledName(), "cOInt_taNsP") != 0x0)
8e27fca1 164 {
c413e8d4 165 hasCorrectSignature = kTRUE;
166 isSelectionMacro = kFALSE;
167 isHistoMacro = kFALSE;
caaf90d2 168 }
169 }
170 }
171
4f6473f6 172 //// Clean up again / unload this function
173 //gROOT->ProcessLineSync(Form(".U %s", pathname));
caaf90d2 174 //gROOT->Reset("a");
4f6473f6 175 // Clean up again
caaf90d2 176 gROOT->Reset();
4f6473f6 177
caaf90d2 178 // Has not the correct signature!
179 if (!hasCorrectSignature)
180 {
181 if (entryName != 0) delete entryName;
182 entryName = 0;
183 return SIGNATURE_ERROR;
184 }
185
186 Int_t returnValue = WARNING;
187
188 // Only add macro, if it is not already in the list
189 if (!isSelectionMacro && fMacroList->FindObject(entryName) == 0)
190 {
191 fMacroList->Add(new TObjString(entryName));
192 fMacroList->Sort();
193
762c6e73 194 // We do not know, where the element has been inserted - deselect this list
195 fMacroListSelected = 0;
196
caaf90d2 197 returnValue = SUCCESS;
198 }
199 else if (isSelectionMacro && fMacroSelList->FindObject(entryName) == 0)
200 {
201 fMacroSelList->Add(new TObjString(entryName));
202 fMacroSelList->Sort();
762c6e73 203
204 // We do not know, where the element has been inserted - deselect this list
205 fMacroSelListSelected = 0;
caaf90d2 206
207 returnValue = SUCCESS;
208 }
209 else returnValue = WARNING;
210
211 if (entryName != 0) delete entryName;
212 entryName = 0;
213
214 return returnValue;
215}
c413e8d4 216
217//______________________________________________________
218void AliEveTRDTrackList::AddMacroFast(const Char_t* entry, Bool_t toSelectionList)
219{
220 if (toSelectionList)
221 {
222 fMacroSelList->Add(new TObjString(entry));
223 fMacroSelList->Sort();
762c6e73 224
225 // We do not know, where the element has been inserted - deselect this list
226 fMacroSelListSelected = 0;
c413e8d4 227 }
228 else
229 {
230 fMacroList->Add(new TObjString(entry));
231 fMacroList->Sort();
762c6e73 232
233 // We do not know, where the element has been inserted - deselect this list
234 fMacroListSelected = 0;
c413e8d4 235 }
236}
237
8e27fca1 238//______________________________________________________
caaf90d2 239void AliEveTRDTrackList::AddMacroFast(const Char_t* path, const Char_t* name, Bool_t toSelectionList)
240{
241 Char_t* entry = MakeMacroEntry(path, name);
8e27fca1 242 if (entry != 0)
243 {
c413e8d4 244 AddMacroFast(entry, toSelectionList);
caaf90d2 245
246#ifdef ALIEVETRDTRACKLIST_DEBUG
247 // Successfull add will only be displayed in debug mode
c413e8d4 248 printf("#AliEveTRDTrackList::AddMacroFast: Added macro \"%s/%s\" to %s list\n", path, name,
caaf90d2 249 (toSelectionList ? "selection" : "process"));
250#endif
c413e8d4 251
252 delete entry;
253 entry = 0;
8e27fca1 254 }
255 else
256 {
caaf90d2 257 // Error will always be displayed
c413e8d4 258 printf("#AliEveTRDTrackList::AddMacroFast: ERROR: Could not add macro \"%s/%s\" to %s list\n", path, name,
caaf90d2 259 (toSelectionList ? "selection" : "process"));
c413e8d4 260 }
caaf90d2 261}
c413e8d4 262
8e27fca1 263//______________________________________________________
caaf90d2 264void AliEveTRDTrackList::AddStandardMacros()
265{
266 // Add your standard macros here, e.g.:
267 // To add a macro without any checks (very fast, but unsafe):
268 // AddMacroFast("$(ALICE_ROOT)/myFolder", "myMacroName.C", isSelMacro);
269 // To add a macro with checks (slower, but safe):
270 // AddMacro("$(ALICE_ROOT)/myFolder", "myMacroName.C");
271 // -> If the file does not exist, nothing happens. So if you want to handle this,
272 // use the return value of AddMacro (NOT_EXIST_ERROR is returned, if file does not exist)
5715955a 273 // (-> You can also check for other return values (see AddMacro(...)))
caaf90d2 274 AddMacro("$(ALICE_ROOT)/TRD/qaRec/macros", "clusterSelection.C");
275 AddMacro("$(ALICE_ROOT)/TRD/qaRec/macros", "chargeDistr.C");
4f6473f6 276 AddMacro("$(ALICE_ROOT)/TRD/qaRec/macros", "clusterResiduals.C");
c413e8d4 277 AddMacro("$(ALICE_ROOT)/TRD/qaRec/macros", "PH.C");
caaf90d2 278}
279
8e27fca1 280//______________________________________________________
ea24e1bc 281Bool_t AliEveTRDTrackList::ApplyProcessMacros(TList* iterator)
caaf90d2 282{
ea24e1bc 283 // No process macros need to be processed
284 if (iterator->GetEntries() <= 0) return kTRUE;
285
286 // Clear root
287 gROOT->Reset();
288
289 // Clear old data and re-allocate
290 if (fDataTree == 0) fDataTree = new TTreeSRedirector(Form("/tmp/TRD.TrackListMacroData_%s.root", gSystem->Getenv("USER")));
291 if (!fDataTree)
292 {
293 Error("Apply process macros", "File \"TRD.TrackListMacroData.root\" could not be accessed properly!");
294 return kFALSE;
295 }
296
297 if (fDataFromMacroList != 0) delete fDataFromMacroList;
298 fDataFromMacroList = new TList();
299
300 fHistoDataSelected = 0;
301
8e27fca1 302
4f6473f6 303 Char_t name[fkMaxMacroNameLength];
8e27fca1 304 Char_t** cmds = new Char_t*[iterator->GetEntries()];
c413e8d4 305 Bool_t* isHistoMacro = new Bool_t[iterator->GetEntries()];
306
307 Int_t numHistoMacros = 0;
308 TH1** histos = 0;
caaf90d2 309
310 AliEveTRDTrack* track = 0;
311 AliTRDtrackV1 *trackv1 = 0;
762c6e73 312 TH1* returnedHist = 0x0;
caaf90d2 313
8e27fca1 314 // Collect the commands for each macro and add them to "data-from-list"
315 for (Int_t i = 0; i < iterator->GetEntries(); i++)
316 {
4f6473f6 317 memset(name, '\0', sizeof(Char_t) * fkMaxMacroNameLength);
318
319 cmds[i] = new Char_t[(fkMaxMacroPathNameLength + fkMaxApplyCommandLength)];
320 memset(cmds[i], '\0', sizeof(Char_t) * (fkMaxMacroNameLength + fkMaxApplyCommandLength));
8e27fca1 321
322#ifdef ALIEVETRDTRACKLIST_DEBUG
323 printf("AliEveTRDTrackList: Applying process macro: %s\n", iterator->At(i)->GetTitle());
324#endif
325
4f6473f6 326 // Extract the name
327 sscanf(iterator->At(i)->GetTitle(), "%s (Path: %*s)", name);
8e27fca1 328
4f6473f6 329 // Delete ".C" at the end
330 // -> Note: Physical address pointer, do NOT delete. / Changes "name" as well!
331 Char_t* dotC = (Char_t*)strrchr(name, '.');
332 if (dotC != 0)
333 {
334 *dotC = '\0';
335 dotC++;
336 *dotC = '\0';
337 }
338
8e27fca1 339 // Add to "data-from-list"
340 fDataFromMacroList->Add(new TObjString(name));
341
c413e8d4 342 // Find the type of the process macro
343 if (!IsHistogramMacro(name))
344 {
345 // Type 1
346 isHistoMacro[i] = kFALSE;
347 // Create the command
348 sprintf(cmds[i], "%s(automaticTrackV1, results, n);", name);
349 }
350 else
351 {
352 // Type 2 (histo)
353 isHistoMacro[i] = kTRUE;
354 numHistoMacros++;
355 // Create the command
356 sprintf(cmds[i], "%s(automaticTrackV1);", name);
357 }
8e27fca1 358 }
c413e8d4 359
360 // Allocate memory for the histograms
361 if (numHistoMacros > 0) histos = new TH1*[numHistoMacros];
362 for (Int_t i = 0; i < numHistoMacros; i++) histos[i] = 0;
caaf90d2 363
8e27fca1 364 // Walk through the list of tracks
365 for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter)
caaf90d2 366 {
367 track = dynamic_cast<AliEveTRDTrack*>(*iter);
368
369 if (!track) continue;
4f6473f6 370
caaf90d2 371 // Skip tracks that have not been selected
372 if (!track->GetRnrState()) continue;
373
374 trackv1 = (AliTRDtrackV1*)track->GetUserData();
375
376 track->ExportToCINT((Text_t*)"automaticTrack");
377 // Cast to AliTRDtrackV1
378 gROOT->ProcessLineSync("AliTRDtrackV1* automaticTrackV1 = (AliTRDtrackV1*)automaticTrack->GetUserData();");
379
380 // Collect data for each macro
c413e8d4 381 for (Int_t i = 0, histoIndex = 0; i < iterator->GetEntries(); i++)
caaf90d2 382 {
c413e8d4 383 // Process for macro type 2 (histo)
384 if (isHistoMacro[i])
caaf90d2 385 {
762c6e73 386 returnedHist = (TH1*)gROOT->ProcessLineSync(cmds[i]);
387 if (returnedHist != 0x0)
388 {
389 if (histos[histoIndex] == 0) histos[histoIndex] = (TH1*)gROOT->ProcessLineSync(cmds[i]);
390 else histos[histoIndex]->Add((const TH1*)gROOT->ProcessLineSync(cmds[i]));
391
392 delete returnedHist;
393 returnedHist = 0;
394 }
c413e8d4 395 histoIndex++;
caaf90d2 396 }
c413e8d4 397 // Process for macro type 1
398 else
caaf90d2 399 {
c413e8d4 400 // Create data pointers in CINT, execute the macro and get the data
401 gROOT->ProcessLineSync("Double_t* results = 0;");
402 gROOT->ProcessLineSync("Int_t n = 0;");
403 gROOT->ProcessLineSync(cmds[i]);
404 Double_t* results = (Double_t*)gROOT->ProcessLineSync("results;");
405 Int_t nResults = (Int_t)gROOT->ProcessLineSync("n;");
406
407 if (results == 0)
408 {
409 Error("Apply macros", Form("Error reading data from macro \"%s\"", iterator->At(i)->GetTitle()));
410 continue;
411 }
412 for (Int_t resInd = 0; resInd < nResults; resInd++)
413 {
414 (*fDataTree) << Form("TrackData%d", i) << Form("Macro%d=", i) << results[resInd] << (Char_t*)"\n";
415 }
caaf90d2 416
c413e8d4 417 delete results;
418 results = 0;
419 }
caaf90d2 420 }
421 }
caaf90d2 422
c413e8d4 423 for (Int_t i = 0, histoIndex = 0; i < iterator->GetEntries() && histoIndex < numHistoMacros; i++)
424 {
425 if (isHistoMacro[i])
5715955a 426 {
427 // Might be empty (e.g. no tracks have been selected)!
428 if (histos[histoIndex] != 0)
429 {
430 (*fDataTree) << Form("TrackData%d", i) << Form("Macro%d=", i) << histos[histoIndex] << (Char_t*)"\n";
431 }
432 histoIndex++;
433 }
c413e8d4 434 }
435
436 if (fDataTree != 0) delete fDataTree;
caaf90d2 437 fDataTree = 0;
438
8e27fca1 439 if (cmds != 0) delete [] cmds;
c413e8d4 440 if (isHistoMacro != 0) delete isHistoMacro;
441 isHistoMacro = 0;
442
443 if (histos != 0) delete [] histos;
444 histos = 0;
8e27fca1 445
caaf90d2 446 // Clear root
447 gROOT->Reset();
448
4f6473f6 449 // If there is data, select the first data set
450 if (iterator->GetEntries() > 0) SETBIT(fHistoDataSelected, 0);
451
caaf90d2 452 // Now the data is stored in "TRD.TrackListMacroData.root"
453 // The editor will access this file to display the data
ea24e1bc 454 return kTRUE;
caaf90d2 455}
456
8e27fca1 457//______________________________________________________
caaf90d2 458void AliEveTRDTrackList::ApplySelectionMacros(TList* iterator)
459{
4f6473f6 460 Char_t name[fkMaxMacroNameLength];
461 Char_t cmd[(fkMaxMacroNameLength + fkMaxApplyCommandLength)];
caaf90d2 462
463 AliEveTRDTrack* track = 0;
464 AliTRDtrackV1 *trackv1 = 0;
465 Bool_t selectedByMacro = kFALSE;
466
467 // Clear root
468 gROOT->Reset();
469
4f6473f6 470 // Select all tracks at first. A track is then deselect, if at least one selection macro
471 // returns kFALSE for this track
472 // Enable all tracks (Note: EnableListElements(..) will call "ElementChanged", which will cause unforseen behaviour!)
473 for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter)
474 {
475 ((TEveElement*)(*iter))->SetRnrState(kTRUE);
476 }
477 SetRnrState(kTRUE);
478
caaf90d2 479 for (Int_t i = 0; i < iterator->GetEntries(); i++)
480 {
4f6473f6 481
482 memset(name, '\0', sizeof(Char_t) * fkMaxMacroNameLength);
483 memset(cmd, '\0', sizeof(Char_t) * (fkMaxMacroNameLength + fkMaxApplyCommandLength));
caaf90d2 484
485#ifdef ALIEVETRDTRACKLIST_DEBUG
486 printf("AliEveTRDTrackList: Applying selection macro: %s\n", iterator->At(i)->GetTitle());
487#endif
caaf90d2 488
4f6473f6 489 // Extract the name
490 sscanf(iterator->At(i)->GetTitle(), "%s (Path: %*s)", name);
491 // Delete ".C" at the end
492 // -> Note: Physical address pointer, do NOT delete. / Changes "name" as well!
493 Char_t* dotC = (Char_t*)strrchr(name, '.');
494 if (dotC != 0)
495 {
496 *dotC = '\0';
497 dotC++;
498 *dotC = '\0';
499 }
500
501 // Create the command
502 sprintf(cmd, "%s(automaticTrackV1);", name);
caaf90d2 503
504 // Walk through the list of tracks
505 for (TEveElement::List_i iter = this->BeginChildren(); iter != this->EndChildren(); ++iter)
506 {
507 track = dynamic_cast<AliEveTRDTrack*>(*iter);
508
509 if (!track) continue;
510
511 trackv1 = (AliTRDtrackV1*)track->GetUserData();
512
513 track->ExportToCINT((Text_t*)"automaticTrack");
514 // Cast to AliTRDtrackV1
515 gROOT->ProcessLineSync("AliTRDtrackV1* automaticTrackV1 = (AliTRDtrackV1*)automaticTrack->GetUserData();");
516 selectedByMacro = (Bool_t)gROOT->ProcessLineSync(cmd);
4f6473f6 517 track->SetRnrState(selectedByMacro && track->GetRnrState());
caaf90d2 518 }
519 }
520
521 // Clear root
522 gROOT->Reset();
523}
524
8e27fca1 525//______________________________________________________
caaf90d2 526Char_t* AliEveTRDTrackList::MakeMacroEntry(const Char_t* path, const Char_t* name)
527{
4f6473f6 528 Char_t* entry = new Char_t[(fkMaxMacroPathNameLength + 30)];
529 memset(entry, '\0', sizeof(Char_t) * (fkMaxMacroPathNameLength + 30));
caaf90d2 530
531 Char_t* systemPath = gSystem->ExpandPathName(path);
532 sprintf(entry, "%s (Path: %s)", name, systemPath);
533 delete systemPath;
534 systemPath = 0;
535
536 return entry;
537}
538
c413e8d4 539//______________________________________________________
540Bool_t AliEveTRDTrackList::IsHistogramMacro(const Char_t* name)
541{
542 TFunction* f = 0x0;
543 if ((f = gROOT->GetGlobalFunctionWithPrototype(name, "const AliTRDtrackV1*", kTRUE)) != 0x0)
544 if (strcmp(f->GetReturnTypeName(), "TH1*") == 0) return kTRUE;
545
546 return kFALSE;
547}
548
8e27fca1 549//______________________________________________________
caaf90d2 550void AliEveTRDTrackList::RemoveProcessMacros(TList* iterator)
551{
c413e8d4 552 TObjString* obj = 0;
caaf90d2 553 for (Int_t i = 0; i < iterator->GetEntries(); i++)
554 {
c413e8d4 555 obj = (TObjString*)fMacroList->Remove(fMacroList->FindObject(iterator->At(i)->GetTitle()));
556
557 if (obj != 0) delete obj;
caaf90d2 558 }
c413e8d4 559 obj = 0;
caaf90d2 560}
561
8e27fca1 562//______________________________________________________
caaf90d2 563void AliEveTRDTrackList::RemoveSelectionMacros(TList* iterator)
564{
c413e8d4 565 TObjString* obj = 0;
caaf90d2 566 for (Int_t i = 0; i < iterator->GetEntries(); i++)
567 {
c413e8d4 568 obj = (TObjString*)fMacroSelList->Remove(fMacroSelList->FindObject(iterator->At(i)->GetTitle()));
569 if (obj != 0) delete obj;
caaf90d2 570 }
c413e8d4 571 obj = 0;
2ef0687e 572}
4f6473f6 573