// @(#)root/tree:$Name: $:$Id: TBranchBrowsable.cxx,v 1.6 2005/07/18 21:05:03 pcanal Exp $
// Author: Axel Naumann 14/10/2004
/*************************************************************************
* 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. *
*************************************************************************/
#include "TBranchBrowsable.h"
#include "TBranchElement.h"
#include "TBranchObject.h"
#include "TMethod.h"
#include "TBrowser.h"
#include "TTree.h"
#include "TLeafObject.h"
#include "TPad.h"
#include "TClass.h"
#include "TBaseClass.h"
#include "TDataMember.h"
#include "TStreamerElement.h"
#include "TVirtualCollectionProxy.h"
#include "TRef.h"
#include <algorithm>
R__EXTERN TTree *gTree;
ClassImp(TVirtualBranchBrowsable);
//______________________________________________________________________________
//
// TVirtualBranchBrowsable is a base class (not really abstract, but useless
// by itself) for helper objects that extend TBranch's browsing support.
// Each registered derived class's generator method is called, which fills
// all created helper objects into a list which can then be browsed.
// For details of what these browser helper objects can do, see e.g.
// TMethodBrowsable, which allows methods to show up in the TBrowser.
//
// Only registered helper objects are created. By default, only
// TMethodBrowsable, TNonSplitBrowsable, and TCollectionPropertyBrowsable
// are registered (see RegisterDefaultGenerators). You can prevent any of
// their objects to show up in the browser by unregistering the generator:
// TMethodBrowsable::Unregister()
// will stop creating browsable method helper objects from that call on.
// Note that these helper objects are cached (in TBranch::fBrowsables);
// already created (and thus cached) browsables will still appear in the
// browser even after unregistering the corresponding generator.
//
// You can implement your own browsable objects and thier generator; see
// e.g. the simple TCollectionPropertyBrowsable. Note that you will have
// to register your generator just like any other, and that you should
// implement the following methods for your own class, mainly for
// consistency reasons:
// static void Register() {
// TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables); }
// static void Unregister() {
// TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables); }
// where GetBrowsables is a static member function of your class, that
// creates the browsable helper objects, and has the signature
// static Int_t GetBrowsables(TList& list, const TBranch* branch,
// const TVirtualBranchBrowsable* parent=0);
// It has to return the number of browsable helper objects for parent
// (or, if NULL, for branch) which are added to the list.
//______________________________________________________________________________
std::list<TVirtualBranchBrowsable::MethodCreateListOfBrowsables_t>
TVirtualBranchBrowsable::fgGenerators;
Bool_t TVirtualBranchBrowsable::fgGeneratorsSet=kFALSE;
//______________________________________________________________________________
TVirtualBranchBrowsable::TVirtualBranchBrowsable(const TBranch* branch, TClass* type,
Bool_t typeIsPointer,
const TVirtualBranchBrowsable* parent /*=0*/):
fBranch(branch), fParent(parent), fLeaves(0), fClass(type), fTypeIsPointer(typeIsPointer) {
// constructor setting all members according to parameters.
if (!fgGeneratorsSet) RegisterDefaultGenerators();
if (!branch)
Warning("TVirtualBranchBrowsable", "branch is NULL!");
}
//______________________________________________________________________________
TVirtualBranchBrowsable::~TVirtualBranchBrowsable() {
// Destructor. Delete our leaves.
delete fLeaves;
}
//______________________________________________________________________________
void TVirtualBranchBrowsable::Browse(TBrowser *b) {
// Calls TTree::Draw on the method if return type is not a class;
// otherwise expands returned object's "folder"
if (!fClass) {
TString name;
GetScope(name);
// If this is meant to be run on the collection
// we need to "move" the "@" from branch.@member
// to branch@.member
name.ReplaceAll(".@","@.");
name.ReplaceAll("->@","@->");
TTree* tree=0;
if (!fBranch) {
Warning("Browse", "branch not set - might access wrong tree!");
tree=gTree;
} else tree=fBranch->GetTree();
tree->Draw(name, "", b ? b->GetDrawOption() : "");
if (gPad) gPad->Update();
} else
if (GetLeaves()) GetLeaves()->Browse(b);
}
//______________________________________________________________________________
Int_t TVirtualBranchBrowsable::FillListOfBrowsables(TList& li, const TBranch* branch,
const TVirtualBranchBrowsable* parent /* =0 */) {
// Askes all registered generators to fill their browsables into
// the list. The browsables are generated for a given parent,
// or (if 0), for a given branch. The branch is passed down to
// leaves of TVirtualBranchBrowsable, too, as we need to access
// the branch's TTree to be able to traw.
if (!fgGeneratorsSet) RegisterDefaultGenerators();
std::list<MethodCreateListOfBrowsables_t>::iterator iGenerator;
Int_t numCreated=0;
for (iGenerator=fgGenerators.begin(); iGenerator!=fgGenerators.end(); iGenerator++)
numCreated+=(*(*iGenerator))(li, branch, parent);
return numCreated;
}
//______________________________________________________________________________
TClass* TVirtualBranchBrowsable::GetCollectionContainedType(const TBranch* branch,
const TVirtualBranchBrowsable* parent,
TClass* &contained) {
// Check whether the branch (or the parent) contains a collection.
// If it does, set "contained" to the contained type (if we can
// retrieve it) and return the TClass for the collection. Set
// "contained" to the branch's (or parent's) contained object's
// class for non-collections, returning 0.
//
// Only one of "branch" or "parent" can ge given (depending on whether
// we are creating browsable objects for a branch or for another
// browsable object)
contained=0;
TClass* type=0;
if (parent)
type=parent->GetClassType();
else if (branch) {
if (branch->IsA()==TBranchElement::Class()) {
// could be a split TClonesArray
TBranchElement* be=(TBranchElement*) branch;
// this is the contained type - if !=0
const char* clonesname=be->GetClonesName();
if (clonesname && strlen(clonesname))
contained=gROOT->GetClass(clonesname);
// check if we're in a sub-branch of this class
// we can only find out asking the streamer given our ID
ULong_t *elems=0;
TStreamerElement *element=0;
if (be->GetID()>=0 && be->GetInfo()
&& ((elems=be->GetInfo()->GetElems()))
&& ((element=(TStreamerElement *)elems[be->GetID()]))) {
// if contained is set (i.e. GetClonesName was successful),
// this element containes the container, otherwise it's the
// contained
if (contained)
// we have all we need
return element->GetClassPointer();
else
type=element->GetClassPointer();
} else if (clonesname && strlen(clonesname)) {
// we have a clones name, and the TCA is not split:
contained=gROOT->GetClass(clonesname);
return gROOT->GetClass(be->GetClassName());
} else
type=gROOT->GetClass(be->GetClassName());
} else if (branch->IsA()==TBranchObject::Class()) {
// could be an unsplit TClonesArray
TBranchObject* bo=(TBranchObject*)branch;
const char* clonesname=bo->GetClassName();
contained=0;
if (!clonesname || !strlen(clonesname)) return 0;
type=gROOT->GetClass(clonesname);
}
} else {
if (gTree) gTree->Warning("GetCollectionContainedType", "Neither branch nor parent given!");
return 0;
}
if (!type) return 0;
TBranch* branchNonCost=const_cast<TBranch*>(branch);
if (type->InheritsFrom(TClonesArray::Class())
&& branch->IsA()==TBranchObject::Class()
&& branchNonCost->GetListOfLeaves()
&& branchNonCost->GetListOfLeaves()->GetEntriesFast()==1) {
// load first entry of the branch. Yes, this is bad, and might have
// unexpected side effects for the user, esp as already looking at
// (and not just drawing) a branch triggeres it.
// To prove just how ugly it is, we'll also have to const_cast the
// branch...
if (branch->GetReadEntry()==-1) branchNonCost->GetEntry(0);
// now get element
TLeafObject* lo=(TLeafObject*)branchNonCost->GetListOfLeaves()->First();
TObject* objContainer=lo->GetObject();
if (lo && objContainer && objContainer->IsA()==TClonesArray::Class())
contained=((TClonesArray*)objContainer)->GetClass();
return type;
} else if (type->InheritsFrom(TClonesArray::Class())
&& branch->IsA()==TBranchElement::Class()
&& branchNonCost->GetListOfLeaves()
&& branchNonCost->GetListOfLeaves()->GetEntriesFast()==1) {
// load first entry of the branch. Yes, this is bad, and might have
// unexpected side effects for the user, esp as already looking at
// (and not just drawing) a branch triggeres it.
// To prove just how ugly it is, we'll also have to const_cast the
// branch...
//if (branch->GetReadEntry()==-1) branchNonCost->GetEntry(0);
// now get element
//TLeafObject* lo=(TLeafElement*)branchNonCost->GetListOfLeaves()->First();
//TObject* objContainer=(TObject*)((TBranchElement*)branch)->GetValuePointer();
//if (objContainer && objContainer->IsA()==TClonesArray::Class())
// contained=((TClonesArray*)objContainer)->GetClass();
// Currently we can peer into the nested TClonesArray, we need
// to update TBranchElement::GetValuePointer.
return type;
} else if (type->InheritsFrom(TCollection::Class())) {
// some other container, and we don't know what the contained type is
return type;
} else if (type->GetCollectionProxy()) {
contained=type->GetCollectionProxy()->GetValueClass();
return type;
} else if (type->InheritsFrom(TRef::Class()))
// we don't do TRefs, so return contained and container as 0
return 0;
else contained=type;
return 0;
}
//______________________________________________________________________________
TList* TVirtualBranchBrowsable::GetLeaves() const {
// Return list of leaves. If not set up yet we'll create them.
if (!fLeaves) {
TList* leaves=new TList();
leaves->SetOwner();
FillListOfBrowsables(*leaves, GetBranch(), this);
const_cast<TVirtualBranchBrowsable*>(this)->fLeaves=leaves;
}
return fLeaves;
}
//______________________________________________________________________________
std::list<TVirtualBranchBrowsable::MethodCreateListOfBrowsables_t>& TVirtualBranchBrowsable::GetRegisteredGenerators() {
// returns the list of registered generator methods
return fgGenerators;
}
//______________________________________________________________________________
void TVirtualBranchBrowsable::GetScope(TString & scope) const {
// Returns the full name for TTree::Draw to draw *this.
// Recursively appends, starting at the top TBranch,
// all method / object names with proper reference operators (->, .)
// depending on fTypeIsPointer.
if (fParent)
fParent->GetScope(scope);
else {
scope=fBranch->GetName();
if (!scope.EndsWith(".")) scope+=".";
const TBranch* mother=fBranch;
while (mother != mother->GetMother() && (mother=mother->GetMother())) {
TString nameMother(mother->GetName());
if (!nameMother.EndsWith(".")) {
scope.Prepend(".");
scope.Prepend(nameMother);
} else {
if (mother != mother->GetMother()) {
// If the mother is the top level mother
// and its ends ends with a ., the name is already
// embedded!
scope.Prepend(nameMother);
}
}
}
}
if (GetName() && GetName()[0]=='.')
scope+=(GetName()+1);
else
scope+=GetName();
if (fClass && !scope.EndsWith(".")) // otherwise we're a leaf, and no delimiter is appended
if (fTypeIsPointer)
scope+="->";
else scope+=".";
}
//______________________________________________________________________________
void TVirtualBranchBrowsable::RegisterDefaultGenerators() {
// Adds the default generators. The user can remove any of them as follows:
// TMethodBrowsable::Unregister();
// which will cause the browser not to show any methods.
if (fgGeneratorsSet) return;
// can't call RegisterGenerator - would be recusive infite loop
fgGenerators.push_back(&TMethodBrowsable::GetBrowsables);
fgGenerators.push_back(&TNonSplitBrowsable::GetBrowsables);
fgGenerators.push_back(&TCollectionPropertyBrowsable::GetBrowsables);
fgGeneratorsSet=kTRUE;
}
void TVirtualBranchBrowsable::RegisterGenerator(MethodCreateListOfBrowsables_t generator) {
// Adds a generator to be called when browsing branches.
// Called by the Register method, which should be implemented
// for all derived classes (see e.g. TMethodBrowsable::Register())
if (!fgGeneratorsSet) RegisterDefaultGenerators();
// make sure we're not adding another copy
fgGenerators.remove(generator);
fgGenerators.push_back(generator);
}
void TVirtualBranchBrowsable::UnregisterGenerator(MethodCreateListOfBrowsables_t generator) {
// Removes a generator from the list of generators to be called when
// browsing branches. The user can remove any of the generators as follows:
// TMethodBrowsable::Unregister();
// which will cause the browser not to show any methods.
if (!fgGeneratorsSet) RegisterDefaultGenerators();
fgGenerators.remove(generator);
}
ClassImp(TMethodBrowsable);
//______________________________________________________________________________
//
// This helper object allows the browsing of methods of objects stored in
// branches. They will be depicted by a leaf (or a branch, in case the method
// returns an object) with a red exclamation mark. Only a subset of all
// methods will be shown in the browser (see IsMethodBrowsable for the
// criteria a method has to satisfy).
//
// Obviously, methods are only available if the library is loaded which
// contains the dictionary for the class to be browsed!
//
// If a branch contains a collection, TMethodBrowsable tries to find out
// what the contained element is (it will only create methods for the
// contained elements, but never for the collection). If it fails to extract
// the type of the contained elements, or if there is no guarantee that the
// type has any other common denominator than TObject (e.g. in the case of
// a TObjArray, which can hold any object deriving from TObject) no methods
// will be added.
//______________________________________________________________________________
//______________________________________________________________________________
TMethodBrowsable::TMethodBrowsable(const TBranch* branch, TMethod* m,
const TVirtualBranchBrowsable* parent /* =0 */):
TVirtualBranchBrowsable(branch, 0, kFALSE, parent), fMethod(m) {
// Constructor.
// Links a TBranchElement to a TMethod, allowing the TBrowser to
// browse simple methods.
//
// The c'tor sets the name for a method "Class::Method(params) const"
// to "Method(params)", title to TMethod::GetPrototype
TString name(m->GetName());
name+="()";
if (name.EndsWith(" const")) name.Remove(name.Length()-6);
SetName(name);
name=m->GetPrototype();
if (m->GetCommentString() && strlen(m->GetCommentString()))
name.Append(" // ").Append(m->GetCommentString());
SetTitle(name);
TString plainReturnType(m->GetReturnTypeName());
if (plainReturnType.EndsWith("*")) {
SetTypeIsPointer();
plainReturnType.Remove(plainReturnType.Length()-1);
plainReturnType.Strip();
if(plainReturnType.BeginsWith("const")) {
plainReturnType.Remove(0,5);
plainReturnType.Strip();
}
}
SetType(gROOT->GetClass(plainReturnType));
}
//______________________________________________________________________________
void TMethodBrowsable::GetBrowsableMethodsForClass(TClass* cl, TList& li) {
// Given a class, this methods fills list with TMethodBrowsables
// for the class and its base classes, and returns the number of
// added elements. If called from a TBranch::Browse overload, "branch"
// should be set to the calling TBranch, otherwise "parent" should
// be set to the TVirtualBranchBrowsable being browsed, and branch
// should be the branch of the parent.
if (!cl) return;
TList allClasses;
allClasses.Add(cl);
for(TObjLink* lnk=allClasses.FirstLink();
lnk; lnk=lnk->Next()){
cl=(TClass*)lnk->GetObject();
TList* bases=cl->GetListOfBases();
TBaseClass* base;
TIter iB(bases);
while ((base=(TBaseClass*)iB())) {
TClass* bc=base->GetClassPointer();
if (bc) allClasses.Add(bc);
}
}
TList allMethods;
TIter iC(&allClasses);
while ((cl=(TClass*)iC())) {
TList* methods=cl->GetListOfMethods();
if (!methods) continue;
TMethod* method=0;
TIter iM(methods);
while ((method=(TMethod*)iM()))
if (method && !allMethods.FindObject(method->GetName()))
allMethods.Add(method);
}
TIter iM(&allMethods);
TMethod* m=0;
while ((m=(TMethod*)iM()))
if (TMethodBrowsable::IsMethodBrowsable(m))
li.Add(m);
}
//______________________________________________________________________________
Int_t TMethodBrowsable::GetBrowsables(TList& li, const TBranch* branch,
const TVirtualBranchBrowsable* parent /*=0*/) {
// This methods fills list with TMethodBrowsables
// for the branch's or parent's class and its base classes, and returns
// the number of added elements. If called from a TBranch::Browse
// overload, "branch" should be set to the calling TBranch, otherwise
// "parent" should be set to the TVirtualBranchBrowsable being browsed.
TClass* cl;
// we don't care about collections, so only use the TClass argument,
// and not the return value
GetCollectionContainedType(branch, parent, cl);
if (!cl) return 0;
TList listMethods;
GetBrowsableMethodsForClass(cl, listMethods);
TMethod* method=0;
TIter iMethods(&listMethods);
while ((method=(TMethod*)iMethods()))
li.Add(new TMethodBrowsable(branch, method, parent));
return listMethods.GetSize();
}
//______________________________________________________________________________
Bool_t TMethodBrowsable::IsMethodBrowsable(const TMethod* m) {
// A TMethod is browsable if it is const, public and not pure virtual,
// if does not have any parameter without default value, and if it has
// a (non-void) return value.
// A method called *, Get*, or get* will not be browsable if there is a
// persistent data member called f*, _*, or m*, as data member access is
// faster than method access. Examples: if one of fX, _X, or mX is a
// persistent data member, the methods GetX(), getX(), and X() will not
// be browsable.
if (m->GetNargs()-m->GetNargsOpt()==0
&& (m->Property() & kIsConstant
& ~kIsPrivate & ~kIsProtected & ~kIsPureVirtual )
&& m->GetReturnTypeName()
&& strcmp("void",m->GetReturnTypeName())
&& !strstr(m->GetName(),"DeclFile")
&& !strstr(m->GetName(),"ImplFile")
&& strcmp(m->GetName(),"IsA")
&& strcmp(m->GetName(),"Class")
&& strcmp(m->GetName(),"CanBypassStreamer")
&& strcmp(m->GetName(),"Class_Name")
&& strcmp(m->GetName(),"ClassName")
&& strcmp(m->GetName(),"Clone")
&& strcmp(m->GetName(),"DrawClone")
&& strcmp(m->GetName(),"GetName")
&& strcmp(m->GetName(),"GetDrawOption")
&& strcmp(m->GetName(),"GetIconName")
&& strcmp(m->GetName(),"GetOption")
&& strcmp(m->GetName(),"GetTitle")
&& strcmp(m->GetName(),"GetUniqueID")
&& strcmp(m->GetName(),"Hash")
&& strcmp(m->GetName(),"IsFolder")
&& strcmp(m->GetName(),"IsOnHeap")
&& strcmp(m->GetName(),"IsSortable")
&& strcmp(m->GetName(),"IsZombie")) {
// look for matching data member
TClass* cl=m->GetClass();
if (!cl) return kTRUE;
TList* members=cl->GetListOfDataMembers();
if (!members) return kTRUE;
const char* baseName=m->GetName();
if (!strncmp(m->GetName(), "Get", 3) ||
!strncmp(m->GetName(), "get", 3))
baseName+=3;
if (!baseName[0]) return kTRUE;
TObject* mem=0;
const char* arrMemberNames[3]={"f%s","_%s","m%s"};
for (Int_t i=0; !mem && i<3; i++)
mem=members->FindObject(Form(arrMemberNames[i],baseName));
return (!mem ||! ((TDataMember*)mem)->IsPersistent());
};
return kFALSE;
}
//______________________________________________________________________________
void TMethodBrowsable::Register() {
// Wrapper for the registration method. Needed against MSVC, which
// assigned different addr to the same method, depending on what
// translation unit you're in...
TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables);
}
//______________________________________________________________________________
void TMethodBrowsable::Unregister() {
// Wrapper for the registration method. Needed against MSVC, which
// assigned different addr to the same method, depending on what
// translation unit you're in...
TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables);
}
ClassImp(TNonSplitBrowsable);
//______________________________________________________________________________
//
// Allows a TBrowser to browse non-split branches as if they were split. The
// generator extracts the necessary information from the streamer info in
// memory (which does not have to be the same as the one on file, in case
// a library was loaded containing the dictionary for this type), i.e. it
// also works without loading the class's library.
//
// Just as with TMethodBrowsables, if the generator finds a collection it
// only takes the contained objects into account, not the collections. If
// it identifies a collection, but cannot extract the contained type, or the
// contained type can be anything deriving from a TObject (like for TObjArray)
// or is not limited at all, no browser helper objects are created.
//______________________________________________________________________________
//______________________________________________________________________________
TNonSplitBrowsable::TNonSplitBrowsable(const TStreamerElement* element, const TBranch* branch,
const TVirtualBranchBrowsable* parent /* =0 */):
TVirtualBranchBrowsable(branch, element->GetClassPointer(),
element->IsaPointer(), parent) {
// Constructor. Creates a TNonSplitBrowsable from a TStreamerElement, containing branch
// and (if applicable) parent TVirtualBranchBrowsable.
SetNameTitle(element->GetName(), element->GetTitle());
}
//______________________________________________________________________________
Int_t TNonSplitBrowsable::GetBrowsables(TList& li, const TBranch* branch,
const TVirtualBranchBrowsable* parent /* =0 */)
{
// Given either a branch "branch" or a "parent" TVirtualBranchBrowsable, we fill
// "list" with objects of type TNonSplitBrowsable which represent the members
// of class "cl" (and its base classes' members).
// branch has to be unsplit, i.e. without sub-branches
if (branch && const_cast<TBranch*>(branch)->GetListOfBranches()
&& const_cast<TBranch*>(branch)->GetListOfBranches()->GetEntries()!=0)
return 0;
// we only expand our own parents
//if (parent && parent->IsA()!=TNonSplitBrowsable::Class()) return 0;
TClass* clContained=0;
GetCollectionContainedType(branch, parent, clContained);
TStreamerInfo* streamerInfo=clContained?clContained->GetStreamerInfo():0;
if (!streamerInfo
|| !streamerInfo->GetElements()
|| !streamerInfo->GetElements()->GetSize()) return 0;
if (!branch && parent) branch=parent->GetBranch();
// we simply add all of our and the bases' members into one big list
TList myStreamerElementsToCheck;
myStreamerElementsToCheck.AddAll(streamerInfo->GetElements());
Int_t numAdded=0;
TStreamerElement* streamerElement=0;
TObjLink *link = myStreamerElementsToCheck.FirstLink();
while (link) {
streamerElement = (TStreamerElement*)link->GetObject();
if (streamerElement->IsBase()) {
// this is a base class place holder
// continue with the base class's streamer info
TClass* base=streamerElement->GetClassPointer();
if (!base || !base->GetStreamerInfo()) continue;
// add all of the base class's streamer elements
// (which in turn can be a base, which will be
// unfolded in a later iteration) to the list
TObjArray* baseElements=base->GetStreamerInfo()->GetElements();
if (!baseElements) continue;
TIter iBaseSE(baseElements);
TStreamerElement* baseSE=0;
while ((baseSE=(TStreamerElement*)iBaseSE()))
// we should probably check whether we're replacing something here...
myStreamerElementsToCheck.Add(baseSE);
} else if (!strcmp(streamerElement->GetName(),"This")
&& !strcmp(clContained->GetName(), streamerElement->GetTypeName())) {
// this is a collection of the real elements.
// So get the class ptr for these elements...
TClass* clElements=streamerElement->GetClassPointer();
TVirtualCollectionProxy* collProxy=clElements?clElements->GetCollectionProxy():0;
clElements=collProxy?collProxy->GetValueClass():0;
if (!clElements) continue;
// now loop over the class's streamer elements
TStreamerInfo* streamerInfo=clElements->GetStreamerInfo();
TIter iElem(streamerInfo->GetElements());
TStreamerElement* elem=0;
while ((elem=(TStreamerElement*)iElem())) {
TNonSplitBrowsable* nsb=new TNonSplitBrowsable(elem, branch, parent);
li.Add(nsb);
numAdded++;
}
} else {
// we have a basic streamer element
TNonSplitBrowsable* nsb=new TNonSplitBrowsable(streamerElement, branch, parent);
li.Add(nsb);
numAdded++;
}
link = link->Next();
}
return numAdded;
}
//______________________________________________________________________________
void TNonSplitBrowsable::Register() {
// Wrapper for the registration method. Needed against MSVC, which
// assigned different addr to the same method, depending on what
// translation unit you're in...
TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables);
}
//______________________________________________________________________________
void TNonSplitBrowsable::Unregister() {
// Wrapper for the registration method. Needed against MSVC, which
// assigned different addr to the same method, depending on what
// translation unit you're in...
TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables);
}
ClassImp(TCollectionPropertyBrowsable);
//______________________________________________________________________________
//
// A tiny browser helper object (and its generator) for adding a virtual
// (as in "not actually part of the class", not in C++ virtual) "@size()"
// method to a collection. For all collections that derive from
// TCollection, or have a TVirtualCollectionProxy associated with them,
// a leaf is created that allows access to the number of elements in the
// collection. For TClonesArrays and types with an associated
// TVirtualCollectionProxy, this forwards to TTreeFormula's
// "@branch.size()" functionality. For all other collections, a method call
// to the appropriate collection's member function is executed when drawing.
//
// These objects are of course only created for elements containing a
// collection; the generator has no effect on any other elements.
//______________________________________________________________________________
//______________________________________________________________________________
void TCollectionPropertyBrowsable::Browse(TBrowser *b) {
// Browses a TCollectionPropertyBrowsable. The only difference to
// the generic TVirtualBranchBrowsable::Browse is our fDraw
GetBranch()->GetTree()->Draw(GetDraw(), "", b ? b->GetDrawOption() : "");
if (gPad) gPad->Update();
}
//______________________________________________________________________________
Int_t TCollectionPropertyBrowsable::GetBrowsables(TList& li, const TBranch* branch,
const TVirtualBranchBrowsable* parent /* =0 */) {
// If the element to browse (given by either parent of branch) contains
// a collection (TClonesArray or something for which a TVirtualCollectionProxy
// exists), we will add some special objects to the browser. For now there is
// just one object "@size", returning the size of the collection (as in
// std::list::size(), or TClonesArray::GetEntries()).
// The objects we create are simply used to forward strings (like "@size") to
// TTreeFormula via our Browse method. These strings are stored in fName.
TClass* clContained=0;
TClass* clCollection=GetCollectionContainedType(branch, parent, clContained);
if (!clCollection || !clContained) return 0;
// Build the fDraw string. Start with our scope.
TString scope;
if (parent) {
parent->GetScope(scope);
branch=parent->GetBranch();
} else if (branch){
scope=branch->GetName();
scope+=".";
const TBranch* mother=branch;
while (mother != mother->GetMother() && (mother=mother->GetMother())) {
TString nameMother(mother->GetName());
if (!nameMother.EndsWith(".")) {
scope.Prepend(".");
scope.Prepend(nameMother);
} else {
if (mother != mother->GetMother()) {
// If the mother is the top level mother
// and its ends ends with a ., the name is already
// embedded!
scope.Prepend(nameMother);
}
}
}
} else {
if (gTree)
gTree->Warning("GetBrowsables", "Neither branch nor parent is set!");
return 0;
}
// remove trailing delimiters
if (scope.EndsWith(".")) scope.Remove(scope.Length()-1, 1);
else if (scope.EndsWith("->")) scope.Remove(scope.Length()-2, 2);
// now prepend "@" to the last element of the scope,
// to access the collection and not its containees
Ssiz_t lastDot=scope.Last('.');
Ssiz_t lastArrow=scope.Last('>'); // assuming there's no branch name containing ">"...
Ssiz_t lastPart=lastDot;
if (lastPart==kNPOS || lastArrow!=kNPOS && lastPart<lastArrow)
lastPart=lastArrow;
if (lastPart==kNPOS) lastPart=0;
else lastPart++;
if (clCollection->GetCollectionProxy() || clCollection==TClonesArray::Class()) {
// the collection is one for which TTree::Draw supports @coll.size()
scope.Insert(lastPart, "@");
TCollectionPropertyBrowsable* cpb=
new TCollectionPropertyBrowsable("@size", "size of the collection",
scope+".size()", branch, parent);
li.Add(cpb);
return 1;
} // if a collection proxy or TClonesArray
else if (clCollection->InheritsFrom(TCollection::Class())) {
// generic TCollection - we'll build size() ourselves, by mapping
// it to the proper member function of the collection
if (clCollection->InheritsFrom(TObjArray::Class()))
scope+="@.GetEntries()";
else scope+="@.GetSize()";
TCollectionPropertyBrowsable* cpb=
new TCollectionPropertyBrowsable("@size", "size of the collection", scope, branch, parent);
li.Add(cpb);
return 1;
}
return 0;
}
//______________________________________________________________________________
void TCollectionPropertyBrowsable::Register() {
// Wrapper for the registration method. Needed against MSVC, which
// assigned different addr to the same method, depending on what
// translation unit you're in...
TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables);
}
//______________________________________________________________________________
void TCollectionPropertyBrowsable::Unregister() {
// Wrapper for the registration method. Needed against MSVC, which
// assigned different addr to the same method, depending on what
// translation unit you're in...
TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables);
}
ClassImp(TCollectionMethodBrowsable);
//______________________________________________________________________________
//
// TCollectionMethodBrowsable extends TCollectionPropertyBrowsable by showing
// all methods of the collection itself. If none are available - e.g. for STL
// classes like std::list, a TVirtualBranchBrowsable object is reated instead.
// The methods' names will have a "@" prepended, to distinguish them from the
// contained elements' methods.
//
// This browser helper object is not part of the default list of registered
// generators (see TVirtualBranchBrowsable::RegisterDefaultGenerators()).
// If you want to use it, you should call
// TCollectionMethodBrowsable::Register();
// As it extends the functionality of TVirtualBranchBrowsable, one might want
// to unregister the generator of the "@size()" method by calling
// TCollectionPropertyBrowsable::Unregister();
//______________________________________________________________________________
//______________________________________________________________________________
TCollectionMethodBrowsable::TCollectionMethodBrowsable(const TBranch* branch, TMethod* m,
const TVirtualBranchBrowsable* parent /*=0*/):
TMethodBrowsable(branch, m, parent) {
// Contructor, see TMethodBrowsable's constructor.
// Prepends "@" to the name to make this method work on the container.
SetName(TString("@")+GetName());
}
//______________________________________________________________________________
Int_t TCollectionMethodBrowsable::GetBrowsables(TList& li, const TBranch* branch,
const TVirtualBranchBrowsable* parent /*=0*/) {
// This methods fills list with TMethodBrowsables
// for the branch's or parent's collection class and its base classes,
// and returns the number of added elements. If called from a TBranch::Browse
// overload, "branch" should be set to the calling TBranch, otherwise
// "parent" should be set to the TVirtualBranchBrowsable being browsed.
TClass* clContained=0;
// we don't care about the contained class, but only about the collections,
TClass* clContainer=GetCollectionContainedType(branch, parent, clContained);
if (!clContainer || !clContained) return 0;
TList listMethods;
GetBrowsableMethodsForClass(clContainer, listMethods);
TMethod* method=0;
TIter iMethods(&listMethods);
while ((method=(TMethod*)iMethods()))
li.Add(new TCollectionMethodBrowsable(branch, method, parent));
// if we have no methods, and if the class has a collection proxy, just add
// the corresponding TCollectionPropertyBrowsable instead.
// But only do that if TCollectionPropertyBrowsable is not generatated anyway
// - we don't need two of them.
if (!listMethods.GetSize() && clContainer->GetCollectionProxy()) {
std::list<MethodCreateListOfBrowsables_t>& listGenerators=GetRegisteredGenerators();
std::list<MethodCreateListOfBrowsables_t>::iterator iIsRegistered
= std::find(listGenerators.begin(), listGenerators.end(), &TCollectionPropertyBrowsable::GetBrowsables);
if (iIsRegistered==listGenerators.end()) {
TCollectionPropertyBrowsable::GetBrowsables(li, branch, parent);
return 1;
}
}
return listMethods.GetSize();
}
//______________________________________________________________________________
void TCollectionMethodBrowsable::Register() {
// Wrapper for the registration method. Needed against MSVC, which
// assigned different addr to the same method, depending on what
// translation unit you're in...
TVirtualBranchBrowsable::RegisterGenerator(GetBrowsables);
}
//______________________________________________________________________________
void TCollectionMethodBrowsable::Unregister() {
// Wrapper for the registration method. Needed against MSVC, which
// assigned different addr to the same method, depending on what
// translation unit you're in...
TVirtualBranchBrowsable::UnregisterGenerator(GetBrowsables);
}
ROOT page - Class index - Class Hierarchy - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.