Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TFolder.cxx
Go to the documentation of this file.
1 // @(#)root/base:$Id$
2 // Author: Rene Brun 02/09/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 
13 /** \class TFolder
14 \ingroup Base
15 
16 A TFolder object is a collection of objects and folders.
17 Folders have a name and a title and are identified in the folder hierarchy
18 by a "Unix-like" naming mechanism. The root of all folders is //root.
19 New folders can be dynamically added or removed to/from a folder.
20 The folder hierarchy can be visualized via the TBrowser.
21 
22 \image html base_browser.png
23 
24 The Root folders hierarchy can be seen as a whiteboard where objects
25 are posted. Other classes/tasks can access these objects by specifying
26 only a string pathname. This whiteboard facility greatly improves the
27 modularity of an application, minimizing the class relationship problem
28 that penalizes large applications.
29 
30 Pointers are efficient to communicate between classes.
31 However, one has interest to minimize direct coupling between classes
32 in the form of direct pointers. One better uses the naming and search
33 service provided by the Root folders hierarchy. This makes the classes
34 loosely coupled and also greatly facilitates I/O operations.
35 In a client/server environment, this mechanism facilitates the access
36 to any kind of object in //root stores running on different processes.
37 
38 A TFolder is created by invoking the TFolder constructor. It is placed
39 inside an existing folder via the TFolder::AddFolder method.
40 One can search for a folder or an object in a folder using the FindObject
41 method. FindObject analyses the string passed as its argument and searches
42 in the hierarchy until it finds an object or folder matching the name.
43 
44 When a folder is deleted, its reference from the parent folder and
45 possible other folders is deleted.
46 
47 If a folder has been declared the owner of its objects/folders via
48 TFolder::SetOwner, then the contained objects are deleted when the
49 folder is deleted. By default, a folder does not own its contained objects.
50 
51 NOTE that folder ownership can be set
52  - via TFolder::SetOwner
53  - or via TCollection::SetOwner on the collection specified to TFolder::AddFolder
54 
55 Standard Root objects are automatically added to the folder hierarchy.
56 For example, the following folders exist:
57  //root/Files with the list of currently connected Root files
58  //root/Classes with the list of active classes
59  //root/Geometries with active geometries
60  //root/Canvases with the list of active canvases
61  //root/Styles with the list of graphics styles
62  //root/Colors with the list of active colors
63 
64 For example, if a file "myFile.root" is added to the list of files, one can
65 retrieve a pointer to the corresponding TFile object with a statement like:
66 ~~~ {.cpp}
67  TFile *myFile = (TFile*)gROOT->FindObject("//root/Files/myFile.root");
68 ~~~
69 The above statement can be abbreviated to:
70 ~~~ {.cpp}
71  TFile *myFile = (TFile*)gROOT->FindObject("/Files/myFile.root");
72 ~~~
73 or even to:
74 ~~~ {.cpp}
75  TFile *myFile = (TFile*)gROOT->FindObjectAny("myFile.root");
76 ~~~
77 In this last case, the TROOT::FindObjectAny function will scan the folder hierarchy
78 starting at //root and will return the first object named "myFile.root".
79 
80 Because a string-based search mechanism is expensive, it is recommended
81 to save the pointer to the object as a class member or local variable
82 if this pointer is used frequently or inside loops.
83 */
84 
85 #include "Riostream.h"
86 #include "Strlen.h"
87 #include "TFolder.h"
88 #include "TBrowser.h"
89 #include "TROOT.h"
90 #include "TClass.h"
91 #include "TError.h"
92 #include "TRegexp.h"
93 
94 static const char *gFolderD[64];
95 static Int_t gFolderLevel = -1;
96 static char gFolderPath[512];
97 
98 enum { kOwnFolderList = BIT(15) };
99 
100 ClassImp(TFolder);
101 
102 ////////////////////////////////////////////////////////////////////////////////
103 /// Default constructor used by the Input functions.
104 ///
105 /// This constructor should not be called by a user directly.
106 /// The normal way to create a folder is by calling TFolder::AddFolder.
107 
108 TFolder::TFolder() : TNamed()
109 {
110  fFolders = 0;
111  fIsOwner = kFALSE;
112 }
113 
114 ////////////////////////////////////////////////////////////////////////////////
115 /// Create a normal folder.
116 /// Use Add or AddFolder to add objects or folders to this folder.
117 
118 TFolder::TFolder(const char *name, const char *title) : TNamed(name,title)
119 {
120  fFolders = new TList();
121  SetBit(kOwnFolderList);
122  fIsOwner = kFALSE;
123 }
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// Copy constructor.
127 
128 TFolder::TFolder(const TFolder &folder) : TNamed(folder),fFolders(0),fIsOwner(kFALSE)
129 {
130  ((TFolder&)folder).Copy(*this);
131 }
132 
133 ////////////////////////////////////////////////////////////////////////////////
134 /// Folder destructor. Remove all objects from its lists and delete
135 /// all its sub folders.
136 
137 TFolder::~TFolder()
138 {
139  TCollection::StartGarbageCollection();
140 
141  if (fFolders) {
142  if (fFolders->IsOwner()) {
143  fFolders->Delete();
144  }
145  if (TestBit(kOwnFolderList)) {
146  TObjLink *iter = ((TList*)fFolders)->FirstLink();
147  while (iter) {
148  TObject *obj = iter->GetObject();
149  TObjLink *next = iter->Next();
150  if (obj && obj->IsA() == TFolder::Class()) {
151  ((TList*)fFolders)->Remove(iter);
152  delete obj;
153  }
154  iter = next;
155  }
156  fFolders->Clear("nodelete");
157  SafeDelete(fFolders);
158  }
159  }
160 
161  TCollection::EmptyGarbageCollection();
162 
163  if (gDebug)
164  std::cerr << "TFolder dtor called for "<< GetName() << std::endl;
165 }
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// Add object to this folder. obj must be a TObject or a TFolder.
169 
170 void TFolder::Add(TObject *obj)
171 {
172  if (obj == 0 || fFolders == 0) return;
173  obj->SetBit(kMustCleanup);
174  fFolders->Add(obj);
175 }
176 
177 ////////////////////////////////////////////////////////////////////////////////
178 /// Create a new folder and add it to the list of folders of this folder,
179 /// return a pointer to the created folder.
180 /// Note that a folder can be added to several folders.
181 ///
182 /// If collection is non NULL, the pointer fFolders is set to the existing
183 /// collection, otherwise a default collection (Tlist) is created.
184 /// Note that the folder name cannot contain slashes.
185 
186 TFolder *TFolder::AddFolder(const char *name, const char *title, TCollection *collection)
187 {
188  if (strchr(name,'/')) {
189  ::Error("TFolder::TFolder","folder name cannot contain a slash: %s", name);
190  return 0;
191  }
192  if (strlen(GetName()) == 0) {
193  ::Error("TFolder::TFolder","folder name cannot be \"\"");
194  return 0;
195  }
196  TFolder *folder = new TFolder();
197  folder->SetName(name);
198  folder->SetTitle(title);
199  if (!fFolders) {
200  fFolders = new TList(); //only true when gROOT creates its 1st folder
201  SetBit(kOwnFolderList);
202  }
203  fFolders->Add(folder);
204 
205  if (collection) {
206  folder->fFolders = collection;
207  } else {
208  folder->fFolders = new TList();
209  folder->SetBit(kOwnFolderList);
210  }
211  return folder;
212 }
213 
214 ////////////////////////////////////////////////////////////////////////////////
215 /// Browse this folder.
216 
217 void TFolder::Browse(TBrowser *b)
218 {
219  if (fFolders) fFolders->Browse(b);
220 }
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 /// Delete all objects from a folder list.
224 
225 void TFolder::Clear(Option_t *option)
226 {
227  if (fFolders) fFolders->Clear(option);
228 }
229 
230 ////////////////////////////////////////////////////////////////////////////////
231 /// Return the full pathname corresponding to subpath name if the node is
232 /// gROOT->GetRootFolder() and return a relative path otherwise.
233 /// The returned path will be re-used by the next call to FindFullPathName().
234 
235 const char *TFolder::FindFullPathName(const char *name) const
236 {
237  TObject *obj = FindObject(name);
238  if (obj || !fFolders) {
239  gFolderLevel++;
240  gFolderD[gFolderLevel] = GetName();
241  if (strcmp(gFolderD[0],"root")==0) {
242  strlcpy(gFolderPath,"//root/", sizeof(gFolderPath));
243  } else {
244  gFolderPath[0] = '\0';
245  }
246  for (Int_t l = 1; l<=gFolderLevel;l++) {
247  strlcat(gFolderPath, gFolderD[l], sizeof(gFolderPath));
248  strlcat(gFolderPath, "/", sizeof(gFolderPath));
249  }
250  strlcat(gFolderPath,name, sizeof(gFolderPath));
251  gFolderLevel = -1;
252  return gFolderPath;
253  }
254  if (name[0] == '/') return 0;
255  TIter next(fFolders);
256  TFolder *folder;
257  const char *found;
258  gFolderLevel++;
259  gFolderD[gFolderLevel] = GetName();
260  while ((obj=next())) {
261  // For a TClass object, InheritsFrom does not check the inheritance of
262  // the object but the inheritance of the class described by the object,
263  // so we need to explicitly call IsA
264  if (obj->IsA()->InheritsFrom(TClass::Class())) continue;
265  // For any other object IsA is called by InheritsFrom
266  if (!obj->InheritsFrom(TFolder::Class())) continue;
267  folder = (TFolder*)obj;
268  found = folder->FindFullPathName(name);
269  if (found) return found;
270  }
271  gFolderLevel--;
272  return 0;
273 }
274 
275 
276 ////////////////////////////////////////////////////////////////////////////////
277 /// Return the full pathname corresponding to subpath name.
278 /// The returned path will be re-used by the next call to FindFullPathName().
279 
280 const char *TFolder::FindFullPathName(const TObject *) const
281 {
282  Error("FindFullPathname","Not yet implemented");
283  return 0;
284 }
285 
286 ////////////////////////////////////////////////////////////////////////////////
287 /// Find object in an folder.
288 
289 TObject *TFolder::FindObject(const TObject *) const
290 {
291  Error("FindObject","Not yet implemented");
292  return 0;
293 }
294 
295 ////////////////////////////////////////////////////////////////////////////////
296 /// Search object identified by name in the tree of folders inside
297 /// this folder.
298 /// Name may be of the forms:
299 ///
300 /// A. Specify a full pathname starting at the top ROOT folder
301 /// //root/xxx/yyy/name
302 ///
303 /// B. Specify a pathname starting with a single slash. //root is assumed
304 /// /xxx/yyy/name
305 ///
306 /// C. Specify a pathname relative to this folder
307 /// xxx/yyy/name
308 /// name
309 
310 TObject *TFolder::FindObject(const char *name) const
311 {
312  if (!fFolders) return 0;
313  if (name == 0) return 0;
314  if (name[0] == '/') {
315  if (name[1] == '/') {
316  if (!strstr(name,"//root/")) return 0;
317  return gROOT->GetRootFolder()->FindObject(name+7);
318  } else {
319  return gROOT->GetRootFolder()->FindObject(name+1);
320  }
321  }
322  Int_t nch = strlen(name);
323  char *cname;
324  char csname[128];
325  if (nch < (int)sizeof(csname))
326  cname = csname;
327  else
328  cname = new char[nch+1];
329  strcpy(cname, name);
330  TObject *obj;
331  char *slash = strchr(cname,'/');
332  if (slash) {
333  *slash = 0;
334  obj = fFolders->FindObject(cname);
335  if (!obj) {
336  if (nch >= (int)sizeof(csname)) delete [] cname;
337  return 0;
338  }
339  TObject *ret = obj->FindObject(slash+1);
340  if (nch >= (int)sizeof(csname)) delete [] cname;
341  return ret;
342  } else {
343  TObject *ret = fFolders->FindObject(cname);
344  if (nch >= (int)sizeof(csname)) delete [] cname;
345  return ret;
346  }
347 }
348 
349 ////////////////////////////////////////////////////////////////////////////////
350 /// Return a pointer to the first object with name starting at this folder.
351 
352 TObject *TFolder::FindObjectAny(const char *name) const
353 {
354  TObject *obj = FindObject(name);
355  if (obj || !fFolders) return obj;
356 
357  //if (!obj->InheritsFrom(TFolder::Class())) continue;
358  if (name[0] == '/') return 0;
359  TIter next(fFolders);
360  TFolder *folder;
361  TObject *found;
362  if (gFolderLevel >= 0) gFolderD[gFolderLevel] = GetName();
363  while ((obj=next())) {
364  if (!obj->InheritsFrom(TFolder::Class())) continue;
365  if (obj->IsA() == TClass::Class()) continue;
366  folder = (TFolder*)obj;
367  found = folder->FindObjectAny(name);
368  if (found) return found;
369  }
370  return 0;
371 }
372 
373 ////////////////////////////////////////////////////////////////////////////////
374 /// Folder ownership has been set via
375 /// - TFolder::SetOwner
376 /// - TCollection::SetOwner on the collection specified to TFolder::AddFolder
377 
378 Bool_t TFolder::IsOwner() const
379 {
380  if (!fFolders) return kFALSE;
381  return fFolders->IsOwner();
382 }
383 
384 ////////////////////////////////////////////////////////////////////////////////
385 /// List folder contents.
386 ///
387 /// If option contains "dump", the Dump function of contained objects is called.
388 ///
389 /// If option contains "print", the Print function of contained objects is called.
390 ///
391 /// By default the ls function of contained objects is called.
392 ///
393 /// Indentation is used to identify the folder tree.
394 ///
395 /// The if option contains a `<regexp>` it be used to match the name of the objects.
396 
397 void TFolder::ls(Option_t *option) const
398 {
399  if (!fFolders) return;
400  TROOT::IndentLevel();
401  std::cout <<ClassName()<<"*\t\t"<<GetName()<<"\t"<<GetTitle()<<std::endl;
402  TROOT::IncreaseDirLevel();
403 
404  TString opt = option;
405  Ssiz_t dump = opt.Index("dump", 0, TString::kIgnoreCase);
406  if (dump != kNPOS)
407  opt.Remove(dump, 4);
408  Ssiz_t print = opt.Index("print", 0, TString::kIgnoreCase);
409  if (print != kNPOS)
410  opt.Remove(print, 5);
411  opt = opt.Strip(TString::kBoth);
412  if (opt == "")
413  opt = "*";
414  TRegexp re(opt, kTRUE);
415 
416  TObject *obj;
417  TIter nextobj(fFolders);
418  while ((obj = (TObject *) nextobj())) {
419  TString s = obj->GetName();
420  if (s.Index(re) == kNPOS) continue;
421  if (dump != kNPOS)
422  obj->Dump();
423  if (print != kNPOS)
424  obj->Print(option);
425  obj->ls(option);
426  }
427  TROOT::DecreaseDirLevel();
428 }
429 
430 ////////////////////////////////////////////////////////////////////////////////
431 /// Return occurence number of object in the list of objects of this folder.
432 /// The function returns the number of objects with the same name as object
433 /// found in the list of objects in this folder before object itself.
434 /// If only one object is found, return 0.
435 
436 Int_t TFolder::Occurence(const TObject *object) const
437 {
438  Int_t n = 0;
439  if (!fFolders) return 0;
440  TIter next(fFolders);
441  TObject *obj;
442  while ((obj=next())) {
443  if (strcmp(obj->GetName(),object->GetName()) == 0) n++;
444  }
445  if (n <=1) return n-1;
446  n = 0;
447  next.Reset();
448  while ((obj=next())) {
449  if (strcmp(obj->GetName(),object->GetName()) == 0) n++;
450  if (obj == object) return n;
451  }
452  return 0;
453 }
454 
455 ////////////////////////////////////////////////////////////////////////////////
456 /// Recursively remove object from a folder.
457 
458 void TFolder::RecursiveRemove(TObject *obj)
459 {
460  if (fFolders) fFolders->RecursiveRemove(obj);
461 }
462 
463 ////////////////////////////////////////////////////////////////////////////////
464 /// Remove object from this folder. obj must be a TObject or a TFolder.
465 
466 void TFolder::Remove(TObject *obj)
467 {
468  if (obj == 0 || fFolders == 0) return;
469  fFolders->Remove(obj);
470 }
471 
472 ////////////////////////////////////////////////////////////////////////////////
473 /// Save all objects in this folder in filename.
474 /// Each object in this folder will have a key in the file where the name of
475 /// the key will be the name of the object.
476 
477 void TFolder::SaveAs(const char *filename, Option_t *option) const
478 {
479  if (gDirectory) gDirectory->SaveObjectAs(this,filename,option);
480 }
481 
482 ////////////////////////////////////////////////////////////////////////////////
483 /// Set ownership.
484 /// If the folder is declared owner, when the folder is deleted, all
485 /// the objects added via TFolder::Add are deleted via TObject::Delete,
486 /// otherwise TObject::Clear is called.
487 ///
488 /// NOTE that folder ownership can be set:
489 /// - via TFolder::SetOwner
490 /// - or via TCollection::SetOwner on the collection specified to TFolder::AddFolder
491 
492 void TFolder::SetOwner(Bool_t owner)
493 {
494  if (!fFolders) fFolders = new TList();
495  fFolders->SetOwner(owner);
496 }