TBranchBrowsable.cxx

Go to the documentation of this file.
00001 // @(#)root/tree:$Id: TBranchBrowsable.cxx 37127 2010-11-30 21:23:22Z pcanal $
00002 // Author: Axel Naumann   14/10/2004
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TBranchBrowsable.h"
00013 #include "TBranchElement.h"
00014 #include "TBranchObject.h"
00015 #include "TMethod.h"
00016 #include "TBrowser.h"
00017 #include "TTree.h"
00018 #include "TLeafObject.h"
00019 #include "TClonesArray.h"
00020 #include "TVirtualPad.h"
00021 #include "TClass.h"
00022 #include "TBaseClass.h"
00023 #include "TDataMember.h"
00024 #include "TStreamerInfo.h"
00025 #include "TStreamerElement.h"
00026 #include "TVirtualCollectionProxy.h"
00027 #include "TRef.h"
00028 #include <algorithm>
00029 
00030 R__EXTERN TTree *gTree;
00031 
00032 ClassImp(TVirtualBranchBrowsable);
00033 
00034 //______________________________________________________________________________
00035 //
00036 // TVirtualBranchBrowsable is a base class (not really abstract, but useless
00037 // by itself) for helper objects that extend TBranch's browsing support.
00038 // Each registered derived class's generator method is called, which fills
00039 // all created helper objects into a list which can then be browsed.
00040 // For details of what these browser helper objects can do, see e.g. 
00041 // TMethodBrowsable, which allows methods to show up in the TBrowser.
00042 //
00043 // Only registered helper objects are created. By default, only 
00044 // TMethodBrowsable, TNonSplitBrowsable, and TCollectionPropertyBrowsable
00045 // are registered (see RegisterDefaultGenerators). You can prevent any of 
00046 // their objects to show up in the browser by unregistering the generator:
00047 //   TMethodBrowsable::Unregister()
00048 // will stop creating browsable method helper objects from that call on.
00049 // Note that these helper objects are cached (in TBranch::fBrowsables);
00050 // already created (and thus cached) browsables will still appear in the
00051 // browser even after unregistering the corresponding generator.
00052 //
00053 // You can implement your own browsable objects and thier generator; see
00054 // e.g. the simple TCollectionPropertyBrowsable. Note that you will have
00055 // to register your generator just like any other, and that you should 
00056 // implement the following methods for your own class, mainly for 
00057 // consistency reasons:
00058 //   static void Register() { 
00059 //     TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables); }
00060 //   static void Unregister() { 
00061 //     TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables); }
00062 // where GetBrowsables is a static member function of your class, that 
00063 // creates the browsable helper objects, and has the signature
00064 //   static Int_t GetBrowsables(TList& list, const TBranch* branch,
00065 //                              const TVirtualBranchBrowsable* parent=0);
00066 // It has to return the number of browsable helper objects for parent
00067 // (or, if NULL, for branch) which are added to the list.
00068 //______________________________________________________________________________
00069 
00070 std::list<TVirtualBranchBrowsable::MethodCreateListOfBrowsables_t> 
00071    TVirtualBranchBrowsable::fgGenerators;
00072 Bool_t TVirtualBranchBrowsable::fgGeneratorsSet=kFALSE;
00073 
00074 //______________________________________________________________________________
00075 TVirtualBranchBrowsable::TVirtualBranchBrowsable(const TBranch* branch, TClass* type, 
00076                                                  Bool_t typeIsPointer, 
00077                                                  const TVirtualBranchBrowsable* parent /*=0*/):
00078 fBranch(branch), fParent(parent), fLeaves(0), fClass(type), fTypeIsPointer(typeIsPointer) 
00079 {
00080    // constructor setting all members according to parameters.
00081    if (!fgGeneratorsSet) RegisterDefaultGenerators();
00082    if (!branch) 
00083       Warning("TVirtualBranchBrowsable", "branch is NULL!");
00084 }
00085 
00086 //______________________________________________________________________________
00087 TVirtualBranchBrowsable::~TVirtualBranchBrowsable() 
00088 {
00089    // Destructor. Delete our leaves.
00090    delete fLeaves;
00091 }
00092 
00093 //______________________________________________________________________________
00094 void TVirtualBranchBrowsable::Browse(TBrowser *b) 
00095 {
00096 // Calls TTree::Draw on the method if return type is not a class;
00097 // otherwise expands returned object's "folder"
00098 
00099    if (!fClass) {
00100       TString name;
00101       GetScope(name);
00102 
00103       // If this is meant to be run on the collection
00104       // we need to "move" the "@" from branch.@member
00105       // to branch@.member
00106       name.ReplaceAll(".@","@.");
00107       name.ReplaceAll("->@","@->");
00108 
00109       TTree* tree=0;
00110       if (!fBranch) {
00111          Warning("Browse", "branch not set - might access wrong tree!");
00112          tree=gTree;
00113       } else tree=fBranch->GetTree();
00114       tree->Draw(name, "", b ? b->GetDrawOption() : "");
00115       if (gPad) gPad->Update();
00116    } else 
00117       if (GetLeaves()) GetLeaves()->Browse(b);
00118 }
00119 
00120 //______________________________________________________________________________
00121 Int_t TVirtualBranchBrowsable::FillListOfBrowsables(TList& li, const TBranch* branch, 
00122    const TVirtualBranchBrowsable* parent /* =0 */) 
00123 {
00124 // Askes all registered generators to fill their browsables into
00125 // the list. The browsables are generated for a given parent,
00126 // or (if 0), for a given branch. The branch is passed down to
00127 // leaves of TVirtualBranchBrowsable, too, as we need to access
00128 // the branch's TTree to be able to traw.
00129    if (!fgGeneratorsSet) RegisterDefaultGenerators();
00130    std::list<MethodCreateListOfBrowsables_t>::iterator iGenerator;
00131    Int_t numCreated=0;
00132    for (iGenerator=fgGenerators.begin(); iGenerator!=fgGenerators.end(); iGenerator++)
00133       numCreated+=(*(*iGenerator))(li, branch, parent);
00134    return numCreated;
00135 }
00136 
00137 //______________________________________________________________________________
00138 TClass* TVirtualBranchBrowsable::GetCollectionContainedType(const TBranch* branch, 
00139                                                             const TVirtualBranchBrowsable* parent,
00140                                                             TClass* &contained) 
00141 {
00142 // Check whether the branch (or the parent) contains a collection. 
00143 // If it does, set "contained" to the contained type (if we can 
00144 // retrieve it) and return the TClass for the collection. Set 
00145 // "contained" to the branch's (or parent's) contained object's 
00146 // class for non-collections, returning 0.
00147 //
00148 // Only one of "branch" or "parent" can ge given (depending on whether
00149 // we are creating browsable objects for a branch or for another
00150 // browsable object)
00151    contained=0;
00152    TClass* type=0;
00153    if (parent)
00154       type=parent->GetClassType();
00155    else if (branch) {
00156       if (branch->IsA()==TBranchElement::Class()) {
00157          // could be a split TClonesArray
00158          TBranchElement* be=(TBranchElement*) branch;
00159 
00160          // this is the contained type - if !=0
00161          const char* clonesname=be->GetClonesName();
00162          if (clonesname && strlen(clonesname))
00163             contained=TClass::GetClass(clonesname);
00164 
00165          // check if we're in a sub-branch of this class
00166          // we can only find out asking the streamer given our ID
00167          ULong_t *elems=0;
00168          TStreamerElement *element=0;
00169          if (be->GetID()>=0 && be->GetInfo() 
00170             && (be->GetID() < be->GetInfo()->GetNdata())
00171             && ((elems=be->GetInfo()->GetElems()))
00172             && ((element=(TStreamerElement *)elems[be->GetID()]))) {
00173             // if contained is set (i.e. GetClonesName was successful),
00174             // this element containes the container, otherwise it's the 
00175             // contained
00176             if (contained)
00177                // we have all we need
00178                return element->GetClassPointer();
00179             else 
00180                type=element->GetClassPointer();
00181          } else if (clonesname && strlen(clonesname)) {
00182             // we have a clones name, and the TCA is not split:
00183             contained=TClass::GetClass(clonesname);
00184             return TClass::GetClass(be->GetClassName());
00185          } else 
00186             type=TClass::GetClass(be->GetClassName());
00187       } else if (branch->IsA()==TBranchObject::Class()) {
00188          // could be an unsplit TClonesArray
00189          TBranchObject* bo=(TBranchObject*)branch;
00190          const char* clonesname=bo->GetClassName();
00191          contained=0;
00192          if (!clonesname || !strlen(clonesname)) return 0;
00193          type=TClass::GetClass(clonesname);
00194       }
00195    } else {
00196       if (gTree) gTree->Warning("GetCollectionContainedType", "Neither branch nor parent given!");
00197       return 0;
00198    }
00199 
00200    if (!type) return 0;
00201 
00202    TBranch* branchNonCost=const_cast<TBranch*>(branch);
00203    if (type->InheritsFrom(TClonesArray::Class()) 
00204       && branch->IsA()==TBranchObject::Class()
00205       && branchNonCost->GetListOfLeaves()
00206       && branchNonCost->GetListOfLeaves()->GetEntriesFast()==1) {
00207       // load first entry of the branch. Yes, this is bad, and might have
00208       // unexpected side effects for the user, esp as already looking at
00209       // (and not just drawing) a branch triggeres it.
00210       // To prove just how ugly it is, we'll also have to const_cast the
00211       // branch...
00212       if (branch->GetReadEntry()==-1) branchNonCost->GetEntry(0);
00213       // now get element
00214       TLeafObject* lo = (TLeafObject*)branchNonCost->GetListOfLeaves()->First();
00215       if (lo) {
00216          TObject* objContainer = lo->GetObject();
00217          if (objContainer && objContainer->IsA()==TClonesArray::Class()) {
00218             contained = ((TClonesArray*)objContainer)->GetClass();
00219          }
00220       }
00221       return type;
00222    } else    if (type->InheritsFrom(TClonesArray::Class()) 
00223       && branch->IsA()==TBranchElement::Class()
00224       && branchNonCost->GetListOfLeaves()
00225       && branchNonCost->GetListOfLeaves()->GetEntriesFast()==1) {
00226       // load first entry of the branch. Yes, this is bad, and might have
00227       // unexpected side effects for the user, esp as already looking at
00228       // (and not just drawing) a branch triggeres it.
00229       // To prove just how ugly it is, we'll also have to const_cast the
00230       // branch...
00231       
00232       //if (branch->GetReadEntry()==-1) branchNonCost->GetEntry(0);
00233       // now get element
00234       //TLeafObject* lo=(TLeafElement*)branchNonCost->GetListOfLeaves()->First();
00235       //TObject* objContainer=(TObject*)((TBranchElement*)branch)->GetValuePointer();
00236 
00237       //if (objContainer && objContainer->IsA()==TClonesArray::Class())
00238       //   contained=((TClonesArray*)objContainer)->GetClass();
00239 
00240       // Currently we can peer into the nested TClonesArray, we need
00241       // to update TBranchElement::GetValuePointer.
00242       return type;
00243    } else if (type->InheritsFrom(TCollection::Class())) {
00244       // some other container, and we don't know what the contained type is
00245       return type;
00246    } else if (type->GetCollectionProxy()) {
00247       contained=type->GetCollectionProxy()->GetValueClass();
00248       return type;
00249    } else if (type->InheritsFrom(TRef::Class()))
00250       // we don't do TRefs, so return contained and container as 0
00251       return 0;
00252    else contained=type;
00253    return 0;
00254 }
00255 
00256 //______________________________________________________________________________
00257 TList* TVirtualBranchBrowsable::GetLeaves() const 
00258 {
00259 // Return list of leaves. If not set up yet we'll create them.
00260    if (!fLeaves) {
00261       TList* leaves=new TList();
00262       leaves->SetOwner();
00263       FillListOfBrowsables(*leaves, GetBranch(), this);
00264       const_cast<TVirtualBranchBrowsable*>(this)->fLeaves=leaves;
00265    }
00266    return fLeaves; 
00267 }
00268 
00269 //______________________________________________________________________________
00270 std::list<TVirtualBranchBrowsable::MethodCreateListOfBrowsables_t>& TVirtualBranchBrowsable::GetRegisteredGenerators() 
00271 {
00272    // returns the list of registered generator methods
00273    return fgGenerators;
00274 }
00275 
00276 //______________________________________________________________________________
00277 void TVirtualBranchBrowsable::GetScope(TString & scope) const 
00278 {
00279 // Returns the full name for TTree::Draw to draw *this.
00280 // Recursively appends, starting at the top TBranch,
00281 // all method / object names with proper reference operators (->, .)
00282 // depending on fTypeIsPointer.
00283 
00284    if (fParent)
00285       fParent->GetScope(scope);
00286    else {
00287       scope=fBranch->GetName();
00288       Ssiz_t pos = scope.First('[');
00289       if (pos != kNPOS) {
00290          scope.Remove(pos);
00291       }
00292       if (!scope.EndsWith(".")) scope+=".";
00293       const TBranch* mother=fBranch;
00294       while (mother != mother->GetMother() && (mother=mother->GetMother())) {
00295          TString nameMother(mother->GetName());
00296          if (!nameMother.EndsWith(".")) {
00297             scope.Prepend(".");
00298             scope.Prepend(nameMother);
00299          } else {
00300             if (mother != mother->GetMother()) {
00301                // If the mother is the top level mother
00302                // and its ends ends with a ., the name is already
00303                // embedded!
00304                scope.Prepend(nameMother);
00305             }
00306          }
00307       }
00308    }
00309    if (GetName() && GetName()[0]=='.')
00310       scope+=(GetName()+1);
00311    else
00312       scope+=GetName();
00313    if (fClass && !scope.EndsWith(".")) { // otherwise we're a leaf, and no delimiter is appended
00314       if (fTypeIsPointer)
00315          scope+="->";
00316       else scope+=".";
00317    }
00318 }
00319 
00320 
00321 //______________________________________________________________________________
00322 void TVirtualBranchBrowsable::RegisterDefaultGenerators() 
00323 {
00324 // Adds the default generators. The user can remove any of them as follows:
00325 //   TMethodBrowsable::Unregister();
00326 // which will cause the browser not to show any methods.
00327    if (fgGeneratorsSet) return;
00328    // can't call RegisterGenerator - would be recusive infite loop
00329    fgGenerators.push_back(&TMethodBrowsable::GetBrowsables);
00330    fgGenerators.push_back(&TNonSplitBrowsable::GetBrowsables);
00331    fgGenerators.push_back(&TCollectionPropertyBrowsable::GetBrowsables);
00332    fgGeneratorsSet=kTRUE;
00333 }
00334 
00335 void TVirtualBranchBrowsable::RegisterGenerator(MethodCreateListOfBrowsables_t generator) 
00336 {
00337    // Adds a generator to be called when browsing branches.
00338    // Called by the Register method, which should be implemented 
00339    // for all derived classes (see e.g. TMethodBrowsable::Register())
00340    if (!fgGeneratorsSet) RegisterDefaultGenerators();
00341    // make sure we're not adding another copy
00342    fgGenerators.remove(generator);
00343    fgGenerators.push_back(generator);
00344 }
00345 
00346 void TVirtualBranchBrowsable::UnregisterGenerator(MethodCreateListOfBrowsables_t generator) 
00347 {
00348    // Removes a generator from the list of generators to be called when 
00349    // browsing branches. The user can remove any of the generators as follows:
00350    //   TMethodBrowsable::Unregister();
00351    // which will cause the browser not to show any methods.
00352    if (!fgGeneratorsSet) RegisterDefaultGenerators();
00353    fgGenerators.remove(generator);
00354 }
00355 
00356 
00357 ClassImp(TMethodBrowsable);
00358 
00359 //______________________________________________________________________________
00360 //
00361 //  This helper object allows the browsing of methods of objects stored in
00362 //  branches. They will be depicted by a leaf (or a branch, in case the method
00363 //  returns an object) with a red exclamation mark. Only a subset of all 
00364 //  methods will be shown in the browser (see IsMethodBrowsable for the
00365 //  criteria a method has to satisfy). 
00366 //
00367 //  Obviously, methods are only available if the library is loaded which 
00368 //  contains the dictionary for the class to be browsed!
00369 //
00370 //  If a branch contains a collection, TMethodBrowsable tries to find out 
00371 //  what the contained element is (it will only create methods for the 
00372 //  contained elements, but never for the collection). If it fails to extract
00373 //  the type of the contained elements, or if there is no guarantee that the
00374 //  type has any other common denominator than TObject (e.g. in the case of
00375 //  a TObjArray, which can hold any object deriving from TObject) no methods
00376 //  will be added.
00377 //______________________________________________________________________________
00378 
00379 
00380 //______________________________________________________________________________
00381 TMethodBrowsable::TMethodBrowsable(const TBranch* branch, TMethod* m,
00382                                    const TVirtualBranchBrowsable* parent /* =0 */):
00383    TVirtualBranchBrowsable(branch, 0, kFALSE, parent), fMethod(m) 
00384 {
00385 // Constructor.
00386 // Links a TBranchElement to a TMethod, allowing the TBrowser to
00387 // browse simple methods.
00388 //
00389 // The c'tor sets the name for a method "Class::Method(params) const"
00390 // to "Method(params)", title to TMethod::GetPrototype
00391    TString name(m->GetName());
00392    name+="()";
00393    if (name.EndsWith(" const")) name.Remove(name.Length()-6);
00394    SetName(name);
00395 
00396    name=m->GetPrototype();
00397    if (m->GetCommentString() && strlen(m->GetCommentString()))
00398       name.Append(" // ").Append(m->GetCommentString());
00399    SetTitle(name);
00400 
00401    TString plainReturnType(m->GetReturnTypeName());
00402    if (plainReturnType.EndsWith("*")) {
00403       SetTypeIsPointer();
00404       plainReturnType.Remove(plainReturnType.Length()-1);
00405       plainReturnType.Strip();
00406       if(plainReturnType.BeginsWith("const")) {
00407          plainReturnType.Remove(0,5);
00408          plainReturnType.Strip();
00409       }   
00410    }
00411    SetType(TClass::GetClass(plainReturnType));
00412 }
00413 
00414 //______________________________________________________________________________
00415 void TMethodBrowsable::GetBrowsableMethodsForClass(TClass* cl, TList& li) 
00416 {
00417 // Given a class, this methods fills list with TMethodBrowsables
00418 // for the class and its base classes, and returns the number of 
00419 // added elements. If called from a TBranch::Browse overload, "branch" 
00420 // should be set to the calling TBranch, otherwise "parent" should 
00421 // be set to the TVirtualBranchBrowsable being browsed, and branch
00422 // should be the branch of the parent.
00423 
00424    if (!cl) return;
00425    TList allClasses;
00426    allClasses.Add(cl);
00427    
00428    if (cl->IsLoaded()) {
00429       for(TObjLink* lnk=allClasses.FirstLink();
00430           lnk; lnk=lnk->Next()) {
00431          cl=(TClass*)lnk->GetObject();
00432          TList* bases=cl->GetListOfBases();
00433          TBaseClass* base;
00434          TIter iB(bases);
00435          while ((base=(TBaseClass*)iB())) {
00436             TClass* bc=base->GetClassPointer();
00437             if (bc) allClasses.Add(bc);
00438          }
00439       }
00440    } else {
00441       TVirtualStreamerInfo *info = cl->GetStreamerInfo();
00442       for(int el = 0; el < info->GetElements()->GetEntries(); ++el) {
00443          TStreamerElement *element = (TStreamerElement *)info->GetElements()->UncheckedAt(el);
00444          if (element->IsBase()) {
00445             TClass *bc = element->GetClassPointer();
00446             if (bc) allClasses.Add(bc);
00447          }
00448       }
00449    }
00450 
00451    TList allMethods;
00452    TIter iC(&allClasses);
00453    while ((cl=(TClass*)iC())) {
00454       TList* methods=cl->GetListOfMethods();
00455       if (!methods) continue;
00456       TMethod* method=0;
00457       TIter iM(methods);
00458       while ((method=(TMethod*)iM()))
00459          if (method && !allMethods.FindObject(method->GetName()))
00460             allMethods.Add(method);
00461    }
00462 
00463    TIter iM(&allMethods);
00464    TMethod* m=0;
00465    while ((m=(TMethod*)iM())) {
00466       if (TMethodBrowsable::IsMethodBrowsable(m)) {
00467          li.Add(m);
00468       }
00469    }
00470 }
00471 
00472 
00473 //______________________________________________________________________________
00474 Int_t TMethodBrowsable::GetBrowsables(TList& li, const TBranch* branch, 
00475                                       const TVirtualBranchBrowsable* parent /*=0*/) 
00476 {
00477 // This methods fills list with TMethodBrowsables
00478 // for the branch's or parent's class and its base classes, and returns 
00479 // the number of added elements. If called from a TBranch::Browse 
00480 // overload, "branch" should be set to the calling TBranch, otherwise 
00481 // "parent" should be set to the TVirtualBranchBrowsable being browsed.
00482    TClass* cl;
00483    // we don't care about collections, so only use the TClass argument,
00484    // and not the return value
00485    GetCollectionContainedType(branch, parent, cl);
00486    if (!cl) return 0;
00487 
00488    TList listMethods;
00489    GetBrowsableMethodsForClass(cl, listMethods);
00490    TMethod* method=0;
00491    TIter iMethods(&listMethods);
00492    while ((method=(TMethod*)iMethods())) {
00493       li.Add(new TMethodBrowsable(branch, method, parent));
00494    }
00495    return listMethods.GetSize();
00496 }
00497 
00498 //______________________________________________________________________________
00499 Bool_t TMethodBrowsable::IsMethodBrowsable(const TMethod* m) 
00500 {
00501 // A TMethod is browsable if it is const, public and not pure virtual,
00502 // if does not have any parameter without default value, and if it has 
00503 // a (non-void) return value.
00504 // A method called *, Get*, or get* will not be browsable if there is a 
00505 // persistent data member called f*, _*, or m*, as data member access is 
00506 // faster than method access. Examples: if one of fX, _X, or mX is a 
00507 // persistent data member, the methods GetX(), getX(), and X() will not 
00508 // be browsable.
00509 
00510    if (m->GetNargs()-m->GetNargsOpt()==0
00511        && (m->Property() & kIsConstant 
00512            & ~kIsPrivate & ~kIsProtected & ~kIsPureVirtual )
00513        && m->GetReturnTypeName()
00514        && strcmp("void",m->GetReturnTypeName())
00515        && !strstr(m->GetName(),"DeclFile")
00516        && !strstr(m->GetName(),"ImplFile")
00517        && strcmp(m->GetName(),"IsA")
00518        && strcmp(m->GetName(),"Class")
00519        && strcmp(m->GetName(),"CanBypassStreamer")
00520        && strcmp(m->GetName(),"Class_Name")
00521        && strcmp(m->GetName(),"ClassName")
00522        && strcmp(m->GetName(),"Clone")
00523        && strcmp(m->GetName(),"DrawClone")
00524        && strcmp(m->GetName(),"GetName")
00525        && strcmp(m->GetName(),"GetDrawOption")
00526        && strcmp(m->GetName(),"GetIconName")
00527        && strcmp(m->GetName(),"GetOption")
00528        && strcmp(m->GetName(),"GetTitle")
00529        && strcmp(m->GetName(),"GetUniqueID")
00530        && strcmp(m->GetName(),"Hash")
00531        && strcmp(m->GetName(),"IsFolder")
00532        && strcmp(m->GetName(),"IsOnHeap")
00533        && strcmp(m->GetName(),"IsSortable")
00534        && strcmp(m->GetName(),"IsZombie")) {
00535 
00536       // look for matching data member
00537       TClass* cl=m->GetClass();
00538       if (!cl) return kTRUE;
00539       TList* members=cl->GetListOfDataMembers();
00540       if (!members) return kTRUE;
00541       const char* baseName=m->GetName();
00542       if (!strncmp(m->GetName(), "Get", 3) ||
00543           !strncmp(m->GetName(), "get", 3))
00544          baseName+=3;
00545       if (!baseName[0]) return kTRUE;
00546       
00547       TObject* mem=0;
00548       const char* arrMemberNames[3]={"f%s","_%s","m%s"};
00549       for (Int_t i=0; !mem && i<3; i++)
00550          mem=members->FindObject(Form(arrMemberNames[i],baseName));
00551       return (!mem ||! ((TDataMember*)mem)->IsPersistent());
00552    };
00553    return kFALSE;
00554 }
00555 
00556 //______________________________________________________________________________
00557 void TMethodBrowsable::Register() 
00558 {
00559    // Wrapper for the registration method. Needed against MSVC, which 
00560    // assigned different addr to the same method, depending on what
00561    // translation unit you're in...
00562    TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables);
00563 }
00564 
00565 //______________________________________________________________________________
00566 void TMethodBrowsable::Unregister() 
00567 {
00568    // Wrapper for the registration method. Needed against MSVC, which 
00569    // assigned different addr to the same method, depending on what
00570    // translation unit you're in...
00571    TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables);
00572 }
00573 
00574 
00575 ClassImp(TNonSplitBrowsable);
00576 
00577 //______________________________________________________________________________
00578 //
00579 // Allows a TBrowser to browse non-split branches as if they were split. The
00580 // generator extracts the necessary information from the streamer info in 
00581 // memory (which does not have to be the same as the one on file, in case
00582 // a library was loaded containing the dictionary for this type), i.e. it 
00583 // also works without loading the class's library.
00584 //
00585 // Just as with TMethodBrowsables, if the generator finds a collection it 
00586 // only takes the contained objects into account, not the collections. If
00587 // it identifies a collection, but cannot extract the contained type, or the 
00588 // contained type can be anything deriving from a TObject (like for TObjArray)
00589 // or is not limited at all, no browser helper objects are created.
00590 //______________________________________________________________________________
00591 
00592 //______________________________________________________________________________
00593 TNonSplitBrowsable::TNonSplitBrowsable(const TStreamerElement* element, const TBranch* branch, 
00594                                        const TVirtualBranchBrowsable* parent /* =0 */):
00595    TVirtualBranchBrowsable(branch, element->GetClassPointer(), 
00596    element->IsaPointer(), parent) 
00597 {
00598 // Constructor. Creates a TNonSplitBrowsable from a TStreamerElement, containing branch 
00599 // and (if applicable) parent TVirtualBranchBrowsable.
00600    SetNameTitle(element->GetName(), element->GetTitle());
00601 }
00602 
00603 
00604 //______________________________________________________________________________
00605 Int_t TNonSplitBrowsable::GetBrowsables(TList& li, const TBranch* branch,
00606                                         const TVirtualBranchBrowsable* parent /* =0 */) 
00607 {
00608 // Given either a branch "branch" or a "parent" TVirtualBranchBrowsable, we fill
00609 // "list" with objects of type TNonSplitBrowsable which represent the members
00610 // of class "cl" (and its base classes' members).
00611 
00612    // branch has to be unsplit, i.e. without sub-branches
00613    if (parent==0 
00614        && (branch==0 ||
00615            (const_cast<TBranch*>(branch)->GetListOfBranches() 
00616             && const_cast<TBranch*>(branch)->GetListOfBranches()->GetEntries()!=0)
00617            )
00618        ) {
00619       return 0;
00620    }
00621    // we only expand our own parents
00622    //if (parent && parent->IsA()!=TNonSplitBrowsable::Class()) return 0;
00623 
00624    TClass* clContained=0;
00625    GetCollectionContainedType(branch, parent, clContained);
00626    TVirtualStreamerInfo* streamerInfo= clContained?clContained->GetStreamerInfo():0;
00627    if (!streamerInfo 
00628       || !streamerInfo->GetElements() 
00629       || !streamerInfo->GetElements()->GetSize())  return 0;
00630 
00631    if (!branch && parent) branch=parent->GetBranch();
00632 
00633    // we simply add all of our and the bases' members into one big list
00634    TList myStreamerElementsToCheck;
00635    myStreamerElementsToCheck.AddAll(streamerInfo->GetElements());
00636 
00637    Int_t numAdded=0;
00638    TStreamerElement* streamerElement=0;
00639    for (TObjLink *link = myStreamerElementsToCheck.FirstLink();
00640         link;
00641         link = link->Next() ) {
00642       streamerElement = (TStreamerElement*)link->GetObject();
00643       if (streamerElement->IsBase()) {
00644          // this is a base class place holder
00645          // continue with the base class's streamer info
00646          TClass* base=streamerElement->GetClassPointer();
00647          if (!base || !base->GetStreamerInfo()) continue;
00648 
00649          // add all of the base class's streamer elements 
00650          // (which in turn can be a base, which will be 
00651          // unfolded in a later iteration) to the list
00652          TObjArray* baseElements=base->GetStreamerInfo()->GetElements();
00653          if (!baseElements) continue;
00654          TIter iBaseSE(baseElements);
00655          TStreamerElement* baseSE=0;
00656          while ((baseSE=(TStreamerElement*)iBaseSE()))
00657             // we should probably check whether we're replacing something here...
00658             myStreamerElementsToCheck.Add(baseSE);
00659       } else if (!strcmp(streamerElement->GetName(),"This") 
00660          && !strcmp(clContained->GetName(), streamerElement->GetTypeName())) {
00661          // this is a collection of the real elements. 
00662          // So get the class ptr for these elements...
00663          TClass* clElements=streamerElement->GetClassPointer();
00664          TVirtualCollectionProxy* collProxy=clElements?clElements->GetCollectionProxy():0;
00665          clElements=collProxy?collProxy->GetValueClass():0;
00666          if (!clElements) continue;
00667 
00668          // now loop over the class's streamer elements
00669          streamerInfo= clElements->GetStreamerInfo();
00670          TIter iElem(streamerInfo->GetElements());
00671          TStreamerElement* elem=0;
00672          while ((elem=(TStreamerElement*)iElem())) {
00673             TNonSplitBrowsable* nsb=new TNonSplitBrowsable(elem, branch, parent);
00674             li.Add(nsb);
00675             numAdded++;
00676          }
00677       } else {
00678          // we have a basic streamer element
00679          TNonSplitBrowsable* nsb=new TNonSplitBrowsable(streamerElement, branch, parent);
00680          li.Add(nsb);
00681          numAdded++;
00682       }
00683    }
00684    return numAdded;
00685 }
00686 
00687 //______________________________________________________________________________
00688 void TNonSplitBrowsable::Register() 
00689 {
00690    // Wrapper for the registration method. Needed against MSVC, which 
00691    // assigned different addr to the same method, depending on what
00692    // translation unit you're in...
00693    TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables);
00694 }
00695 
00696 //______________________________________________________________________________
00697 void TNonSplitBrowsable::Unregister() 
00698 {
00699    // Wrapper for the registration method. Needed against MSVC, which 
00700    // assigned different addr to the same method, depending on what
00701    // translation unit you're in...
00702    TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables);
00703 }
00704 
00705 
00706 ClassImp(TCollectionPropertyBrowsable);
00707 
00708 //______________________________________________________________________________
00709 //
00710 // A tiny browser helper object (and its generator) for adding a virtual 
00711 // (as in "not actually part of the class", not in C++ virtual) "@size()" 
00712 // method to a collection. For all collections that derive from
00713 // TCollection, or have a TVirtualCollectionProxy associated with them,
00714 // a leaf is created that allows access to the number of elements in the 
00715 // collection. For TClonesArrays and types with an associated 
00716 // TVirtualCollectionProxy, this forwards to TTreeFormula's 
00717 // "@branch.size()" functionality. For all other collections, a method call
00718 // to the appropriate collection's member function is executed when drawing.
00719 //
00720 // These objects are of course only created for elements containing a 
00721 // collection; the generator has no effect on any other elements.
00722 //______________________________________________________________________________
00723 
00724 
00725 //______________________________________________________________________________
00726 void TCollectionPropertyBrowsable::Browse(TBrowser *b) 
00727 {
00728    // Browses a TCollectionPropertyBrowsable. The only difference to
00729    // the generic TVirtualBranchBrowsable::Browse is our fDraw
00730    GetBranch()->GetTree()->Draw(GetDraw(), "", b ? b->GetDrawOption() : "");
00731    if (gPad) gPad->Update();
00732 }
00733 
00734 //______________________________________________________________________________
00735 Int_t TCollectionPropertyBrowsable::GetBrowsables(TList& li, const TBranch* branch, 
00736                                                   const TVirtualBranchBrowsable* parent /* =0 */) 
00737 {
00738 // If the element to browse (given by either parent of branch) contains
00739 // a collection (TClonesArray or something for which a TVirtualCollectionProxy
00740 // exists), we will add some special objects to the browser. For now there is
00741 // just one object "@size", returning the size of the collection (as in
00742 // std::list::size(), or TClonesArray::GetEntries()).
00743 // The objects we create are simply used to forward strings (like "@size") to
00744 // TTreeFormula via our Browse method. These strings are stored in fName.
00745    TClass* clContained=0;
00746    TClass* clCollection=GetCollectionContainedType(branch, parent, clContained);
00747    if (!clCollection || !clContained) return 0;
00748 
00749    // Build the fDraw string. Start with our scope.
00750    TString scope;
00751    if (parent) {
00752       parent->GetScope(scope);
00753       branch=parent->GetBranch();
00754    } else if (branch){
00755       scope=branch->GetName();
00756       scope+=".";
00757       const TBranch* mother=branch;
00758       while (mother != mother->GetMother() && (mother=mother->GetMother())) {
00759          TString nameMother(mother->GetName());
00760          if (!nameMother.EndsWith(".")) {
00761             scope.Prepend(".");
00762             scope.Prepend(nameMother);
00763          } else {
00764             if (mother != mother->GetMother()) {
00765                // If the mother is the top level mother
00766                // and its ends ends with a ., the name is already
00767                // embedded!
00768                scope.Prepend(nameMother);
00769             }
00770          }
00771       }
00772    } else {
00773       if (gTree)
00774          gTree->Warning("GetBrowsables", "Neither branch nor parent is set!");
00775       return 0;
00776    }
00777 
00778    // remove trailing delimiters
00779    if (scope.EndsWith(".")) scope.Remove(scope.Length()-1, 1);
00780    else if (scope.EndsWith("->")) scope.Remove(scope.Length()-2, 2);
00781 
00782    // now prepend "@" to the last element of the scope,
00783    // to access the collection and not its containees
00784    Ssiz_t lastDot=scope.Last('.');
00785    Ssiz_t lastArrow=scope.Last('>'); // assuming there's no branch name containing ">"...
00786    Ssiz_t lastPart=lastDot;
00787    if (lastPart==kNPOS || (lastArrow!=kNPOS && lastPart<lastArrow))
00788       lastPart=lastArrow;
00789    if (lastPart==kNPOS) lastPart=0;
00790    else lastPart++;
00791 
00792    TString size_title("size of ");
00793    size_title += clCollection->GetName();
00794    if (clContained) {
00795       size_title += " of ";
00796       size_title += clContained->GetName();
00797    }
00798 
00799    if (clCollection->GetCollectionProxy() || clCollection==TClonesArray::Class()) {
00800    // the collection is one for which TTree::Draw supports @coll.size()
00801 
00802       TCollectionPropertyBrowsable* cpb;
00803       if ( clCollection->GetCollectionProxy() && 
00804            ( (clCollection->GetCollectionProxy()->GetValueClass()==0) 
00805            ||(clCollection->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()!=0 
00806               && clCollection->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()->GetValueClass()==0)
00807             )) {
00808          // If the contained type is not a class, we need an explitcit handle to get to the data.
00809          cpb = new TCollectionPropertyBrowsable("values", "values in the container", 
00810                                                 scope, branch, parent);
00811          li.Add(cpb);
00812       }
00813       scope.Insert(lastPart, "@");
00814       cpb = new TCollectionPropertyBrowsable("@size", size_title, 
00815                                             scope+".size()", branch, parent);
00816       li.Add(cpb);
00817       return 1;
00818    } // if a collection proxy or TClonesArray
00819    else if (clCollection->InheritsFrom(TCollection::Class())) {
00820       // generic TCollection - we'll build size() ourselves, by mapping
00821       // it to the proper member function of the collection
00822       if (clCollection->InheritsFrom(TObjArray::Class()))
00823          scope+="@.GetEntries()";
00824       else scope+="@.GetSize()";
00825       TCollectionPropertyBrowsable* cpb=
00826          new TCollectionPropertyBrowsable("@size", size_title, scope, branch, parent);
00827       li.Add(cpb);
00828       return 1;
00829    }
00830    return 0;
00831 }
00832 
00833 //______________________________________________________________________________
00834 void TCollectionPropertyBrowsable::Register() 
00835 {
00836    // Wrapper for the registration method. Needed against MSVC, which 
00837    // assigned different addr to the same method, depending on what
00838    // translation unit you're in...
00839    TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables);
00840 }
00841 
00842 //______________________________________________________________________________
00843 void TCollectionPropertyBrowsable::Unregister() 
00844 {
00845    // Wrapper for the registration method. Needed against MSVC, which 
00846    // assigned different addr to the same method, depending on what
00847    // translation unit you're in...
00848    TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables);
00849 }
00850 
00851 
00852 ClassImp(TCollectionMethodBrowsable);
00853 
00854 //______________________________________________________________________________
00855 //
00856 // TCollectionMethodBrowsable extends TCollectionPropertyBrowsable by showing
00857 // all methods of the collection itself. If none are available - e.g. for STL 
00858 // classes like std::list, a TVirtualBranchBrowsable object is reated instead. 
00859 // The methods' names will have a "@" prepended, to distinguish them from the 
00860 // contained elements' methods.
00861 //
00862 // This browser helper object is not part of the default list of registered
00863 // generators (see TVirtualBranchBrowsable::RegisterDefaultGenerators()). 
00864 // If you want to use it, you should call 
00865 //   TCollectionMethodBrowsable::Register();
00866 // As it extends the functionality of TVirtualBranchBrowsable, one might want 
00867 // to unregister the generator of the "@size()" method by calling
00868 //   TCollectionPropertyBrowsable::Unregister();
00869 //______________________________________________________________________________
00870 
00871 
00872 //______________________________________________________________________________
00873 TCollectionMethodBrowsable::TCollectionMethodBrowsable(const TBranch* branch, TMethod* m, 
00874                                                        const TVirtualBranchBrowsable* parent /*=0*/):
00875 TMethodBrowsable(branch, m, parent) 
00876 {
00877    // Contructor, see TMethodBrowsable's constructor.
00878    // Prepends "@" to the name to make this method work on the container.
00879    SetName(TString("@")+GetName());
00880 }
00881 
00882 //______________________________________________________________________________
00883 Int_t TCollectionMethodBrowsable::GetBrowsables(TList& li, const TBranch* branch, 
00884                                                 const TVirtualBranchBrowsable* parent /*=0*/) 
00885 {
00886 // This methods fills list with TMethodBrowsables
00887 // for the branch's or parent's collection class and its base classes, 
00888 // and returns the number of added elements. If called from a TBranch::Browse 
00889 // overload, "branch" should be set to the calling TBranch, otherwise 
00890 // "parent" should be set to the TVirtualBranchBrowsable being browsed.
00891    TClass* clContained=0;
00892    // we don't care about the contained class, but only about the collections, 
00893    TClass* clContainer=GetCollectionContainedType(branch, parent, clContained);
00894    if (!clContainer || !clContained) return 0;
00895 
00896    TList listMethods;
00897    GetBrowsableMethodsForClass(clContainer, listMethods);
00898    TMethod* method=0;
00899    TIter iMethods(&listMethods);
00900    while ((method=(TMethod*)iMethods()))
00901       li.Add(new TCollectionMethodBrowsable(branch, method, parent));
00902 
00903    // if we have no methods, and if the class has a collection proxy, just add
00904    // the corresponding TCollectionPropertyBrowsable instead.
00905    // But only do that if TCollectionPropertyBrowsable is not generatated anyway
00906    // - we don't need two of them.
00907    if (!listMethods.GetSize() && clContainer->GetCollectionProxy()) {
00908       std::list<MethodCreateListOfBrowsables_t>& listGenerators=GetRegisteredGenerators();
00909       std::list<MethodCreateListOfBrowsables_t>::iterator iIsRegistered
00910          = std::find(listGenerators.begin(), listGenerators.end(), &TCollectionPropertyBrowsable::GetBrowsables);
00911       if (iIsRegistered==listGenerators.end()) {
00912          TCollectionPropertyBrowsable::GetBrowsables(li, branch, parent);
00913          return 1;
00914       }
00915    }
00916    return listMethods.GetSize();
00917 }
00918 
00919 //______________________________________________________________________________
00920 void TCollectionMethodBrowsable::Register() 
00921 {
00922    // Wrapper for the registration method. Needed against MSVC, which 
00923    // assigned different addr to the same method, depending on what
00924    // translation unit you're in...
00925    TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables);
00926 }
00927 
00928 //______________________________________________________________________________
00929 void TCollectionMethodBrowsable::Unregister() 
00930 {
00931    // Wrapper for the registration method. Needed against MSVC, which 
00932    // assigned different addr to the same method, depending on what
00933    // translation unit you're in...
00934    TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables);
00935 }

Generated on Tue Jul 5 15:33:35 2011 for ROOT_528-00b_version by  doxygen 1.5.1