    // @(#)root/base:$Name:  $:$Id: TFolder.cxx,v 1.22 2003/02/09 18:35:17 brun Exp $
    // Author: Rene Brun   02/09/2000

    /*************************************************************************
     * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/

    //______________________________________________________________________________
    //
    // A TFolder object is a collection of objects and folders.
    // Folders have a name and a title and are identified in the folder hierarchy
    // by a "Unix-like" naming mechanism. The root of all folders is //root.
    // New folders can be dynamically added or removed to/from a folder.
    // The folder hierarchy can be visualized via the TBrowser.
    //
    // The Root folders hierarchy can be seen as a whiteboard where objects
    // are posted. Other classes/tasks can access these objects by specifying
    // only a string pathname. This whiteboard facility greatly improves the
    // modularity of an application, minimizing the class relationship problem
    // that penalizes large applications.
    //
    // Pointers are efficient to communicate between classes.
    // However, one has interest to minimize direct coupling between classes
    // in the form of direct pointers. One better uses the naming and search
    // service provided by the Root folders hierarchy. This makes the classes
    // loosely coupled and also greatly facilitates I/O operations.
    // In a client/server environment, this mechanism facilitates the access
    // to any kind of object in //root stores running on different processes.
    //
    // A TFolder is created by invoking the TFolder constructor. It is placed
    // inside an existing folder via the TFolder::AddFolder method.
    // One can search for a folder or an object in a folder using the FindObject
    // method. FindObject analyzes the string passed as its argument and searches
    // in the hierarchy until it finds an object or folder matching the name.
    //
    // When a folder is deleted, its reference from the parent folder and
    // possible other folders is deleted.
    //
    // If a folder has been declared the owner of its objects/folders via
    // TFolder::SetOwner, then the contained objects are deleted when the
    // folder is deleted. By default, a folder does not own its contained objects.
    // NOTE that folder ownership can be set
    //   - via TFolder::SetOwner
    //   - or via TCollection::SetOwner on the collection specified to TFolder::AddFolder
    //
    // Standard Root objects are automatically added to the folder hierarchy.
    // For example, the following folders exist:
    //   //root/Files      with the list of currently connected Root files
    //   //root/Classes    with the list of active classes
    //   //root/Geometries with active geometries
    //   //root/Canvases   with the list of active canvases
    //   //root/Styles     with the list of graphics styles
    //   //root/Colors     with the list of active colors
    //
    // For example, if a file "myFile.root" is added to the list of files, one can
    // retrieve a pointer to the corresponding TFile object with a statement like:
    //   TFile *myFile = (TFile*)gROOT->FindObject("//root/Files/myFile.root");
    // The above statement can be abbreviated to:
    //   TFile *myFile = (TFile*)gROOT->FindObject("/Files/myFile.root");
    // or even to:
    //   TFile *myFile = (TFile*)gROOT->FindObjectAny("myFile.root");
    // In this last case, the TROOT::FindObjectAny function will scan the folder hierarchy
    // starting at //root and will return the first object named "myFile.root".
    //
    // Because a string-based search mechanism is expensive, it is recommended
    // to save the pointer to the object as a class member or local variable
    // if this pointer is used frequently or inside loops.
    //
    //

/* */ //

#include "Riostream.h" #include "Strlen.h" #include "TFolder.h" #include "TBrowser.h" #include "TROOT.h" #include "TClass.h" #include "TError.h" #include "TFile.h" #include "TRegexp.h" const int kMAXDEPTH = 64; static const char *d[kMAXDEPTH]; static Int_t level = -1; static char path[512]; ClassImp(TFolder) //______________________________________________________________________________ TFolder::TFolder() : TNamed() { // default constructor used by the Input functions // // This constructor should not be called by a user directly. // The normal way to create a folder is by calling TFolder::AddFolder fFolders = 0; fIsOwner = kFALSE; } //______________________________________________________________________________ TFolder::TFolder(const char *name, const char *title) : TNamed(name,title) { // create a normal folder. // use Add or AddFolder to add objects or folders to this folder fFolders = new TList(); fIsOwner = kFALSE; } //______________________________________________________________________________ TFolder::TFolder(const TFolder &folder) : TNamed(folder) { ((TFolder&)folder).Copy(*this); } //______________________________________________________________________________ TFolder::~TFolder() { // folder destructor. Remove all objects from its lists and delete // all its sub folders TCollection::StartGarbageCollection(); if (fFolders) { fFolders->Clear(); SafeDelete(fFolders); } TCollection::EmptyGarbageCollection(); if (gDebug) cerr << "TFolder dtor called for "<< GetName() << endl; } //______________________________________________________________________________ void TFolder::Add(TObject *obj) { // Add object to this folder. obj must be a TObject or a TFolder if (obj == 0 || fFolders == 0) return; obj->SetBit(kMustCleanup); fFolders->Add(obj); } //______________________________________________________________________________ TFolder *TFolder::AddFolder(const char *name, const char *title, TCollection *collection) { // Create a new folder and add it to the list of folders of this folder // return a pointer to the created folder // Note that a folder can be added to several folders // // if (collection is non NULL, the pointer fFolders is set to the existing // collection, otherwise a default collection (Tlist) is created // Note that the folder name cannot contain slashes. if (strchr(name,'/')) { ::Error("TFolder::TFolder","folder name cannot contain a slash", name); return 0; } if (strlen(GetName()) == 0) { ::Error("TFolder::TFolder","folder name cannot be \"\""); return 0; } TFolder *folder = new TFolder(); folder->SetName(name); folder->SetTitle(title); if (!fFolders) fFolders = new TList(); //only true when gROOT creates its 1st folder fFolders->Add(folder); if (collection) folder->fFolders = collection; else folder->fFolders = new TList(); return folder; } //______________________________________________________________________________ void TFolder::Browse(TBrowser *b) { // Browse this folder if (fFolders) fFolders->Browse(b); } //______________________________________________________________________________ void TFolder::Clear(Option_t *option) { // Delete all objects from a folder list if (fFolders) fFolders->Clear(option); } //______________________________________________________________________________ const char *TFolder::FindFullPathName(const char *name) const { // return the full pathname corresponding to subpath name // The returned path will be re-used by the next call to GetPath(). TObject *obj = FindObject(name); if (obj || !fFolders) { level++; d[level] = GetName(); path[0] = '/'; path[1] = 0; for (Int_t l=0;l<=level;l++) { strcat(path,"/"); strcat(path,d[l]); } strcat(path,"/"); strcat(path,name); level = -1; return path; } if (name[0] == '/') return 0; TIter next(fFolders); TFolder *folder; const char *found; level++; d[level] = GetName(); while ((obj=next())) { if (!obj->InheritsFrom(TFolder::Class())) continue; if (obj->InheritsFrom(TClass::Class())) continue; folder = (TFolder*)obj; found = folder->FindFullPathName(name); if (found) return found; } level--; return 0; } //______________________________________________________________________________ const char *TFolder::FindFullPathName(const TObject *) const { // return the full pathname corresponding to subpath name // The returned path will be re-used by the next call to GetPath(). Error("FindFullPathname","Not yet implemented"); return 0; } //______________________________________________________________________________ TObject *TFolder::FindObject(const TObject *) const { // find object in an folder Error("FindObject","Not yet implemented"); return 0; } //______________________________________________________________________________ TObject *TFolder::FindObject(const char *name) const { // search object identified by name in the tree of folders inside // this folder. // name may be of the forms: // A, specify a full pathname starting at the top ROOT folder // //root/xxx/yyy/name // // B, specify a pathname starting with a single slash. //root is assumed // /xxx/yyy/name // // C, Specify a pathname relative to this folder // xxx/yyy/name // name if (!fFolders) return 0; if (name == 0) return 0; if (name[0] == '/') { if (name[1] == '/') { if (!strstr(name,"//root/")) return 0; return gROOT->GetRootFolder()->FindObject(name+7); } else { return gROOT->GetRootFolder()->FindObject(name+1); } } char cname[1024]; strcpy(cname,name); TObject *obj; char *slash = strchr(cname,'/'); if (slash) { *slash = 0; obj = fFolders->FindObject(cname); if (!obj) return 0; return obj->FindObject(slash+1); } else { return fFolders->FindObject(name); } } //______________________________________________________________________________ TObject *TFolder::FindObjectAny(const char *name) const { // return a pointer to the first object with name starting at this folder TObject *obj = FindObject(name); if (obj || !fFolders) return obj; // if (!obj->InheritsFrom(TFolder::Class())) continue; if (name[0] == '/') return 0; TIter next(fFolders); TFolder *folder; TObject *found; if (level >= 0) d[level] = GetName(); while ((obj=next())) { if (!obj->InheritsFrom(TFolder::Class())) continue; if (obj->IsA() == TClass::Class()) continue; folder = (TFolder*)obj; found = folder->FindObjectAny(name); if (found) return found; } return 0; } //______________________________________________________________________________ Bool_t TFolder::IsOwner() const { // folder ownership has been set via // - TFolder::SetOwner // - TCollection::SetOwner on the collection specified to TFolder::AddFolder if (!fFolders) return kFALSE; return fFolders->IsOwner(); } //______________________________________________________________________________ void TFolder::ls(Option_t *option) const { // List folder contents // if option contains "dump", the Dump function of contained objects is called // if option contains "print", the Print function of contained objects is called // By default the ls function of contained objects is called. // Indentation is used to identify the folder tree // // The <regexp> will be used to match the name of the objects. // if (!fFolders) return; TROOT::IndentLevel(); cout <<ClassName()<<"*\t\t"<<GetName()<<"\t"<<GetTitle()<<endl; TROOT::IncreaseDirLevel(); TString opta = option; TString opt = opta.Strip(TString::kBoth); opt.ToLower(); TString reg = opt; Bool_t dump = opt.Contains("dump"); Bool_t print = opt.Contains("print"); TRegexp re(reg, kTRUE); TObject *obj; TIter nextobj(fFolders); while ((obj = (TObject *) nextobj())) { TString s = obj->GetName(); if (s.Index(re) == kNPOS) continue; if (dump) obj->Dump(); else if(print) obj->Print(option); else obj->ls(option); } TROOT::DecreaseDirLevel(); } //______________________________________________________________________________ Int_t TFolder::Occurence(const TObject *object) const { // Return occurence number of object in the list of objects of this folder. // The function returns the number of objects with the same name as object // found in the list of objects in this folder before object itself. // If only one object is found, return 0; Int_t n = 0; if (!fFolders) return 0; TIter next(fFolders); TObject *obj; while ((obj=next())) { if (strcmp(obj->GetName(),object->GetName()) == 0) n++; } if (n <=1) return n-1; n = 0; next.Reset(); while ((obj=next())) { if (strcmp(obj->GetName(),object->GetName()) == 0) n++; if (obj == object) return n; } return 0; } //______________________________________________________________________________ void TFolder::RecursiveRemove(TObject *obj) { // Recursively remove object from a Folder if (fFolders) fFolders->RecursiveRemove(obj); } //______________________________________________________________________________ void TFolder::Remove(TObject *obj) { // Remove object from this folder. obj must be a TObject or a TFolder if (obj == 0 || fFolders == 0) return; fFolders->Remove(obj); } //______________________________________________________________________________ void TFolder::SaveAs(const char *filename) { // Save all objects in this folder in filename // Each object in this folder will have a key in the file where the name of // the key will be the name of the object. TFile f(filename,"recreate"); if (f.IsZombie()) return; if (fFolders) fFolders->Write(); printf("Folder: %s saved to file: %s\n",GetName(),filename); } //______________________________________________________________________________ void TFolder::SetOwner(Bool_t owner) { // Set ownership // If the folder is declared owner, when the folder is deleted, all // the objects added via TFolder::Add are deleted via TObject::Delete, // otherwise TObject::Clear is called. // // NOTE that folder ownership can be set // - via TFolder::SetOwner // - or via TCollection::SetOwner on the collection specified to TFolder::AddFolder if (!fFolders) fFolders = new TList(); fFolders->SetOwner(owner); }