Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TDirectoryElement.cxx
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
3 * All rights reserved. *
4 * *
5 * For the licensing terms see $ROOTSYS/LICENSE. *
6 * For the list of contributors see $ROOTSYS/README/CREDITS. *
7 *************************************************************************/
8
9
17
18#include <ROOT/RLogger.hxx>
19
20#include "TKey.h"
21#include "TDirectory.h"
22#include "TROOT.h"
23#include "TFile.h"
24#include "TClass.h"
25#include "TEnv.h"
26
27#include <cstring>
28#include <string>
29
30using namespace std::string_literals;
31
32using namespace ROOT::Browsable;
33
34
35/** \class TDirectoryLevelIter
36\ingroup rbrowser
37
38Iterator over keys in TDirectory
39*/
40
41
43 TDirectory *fDir{nullptr}; ///<! current directory handle
44 std::unique_ptr<TIterator> fIter; ///<! created iterator
45 bool fKeysIter{true}; ///<! iterating over keys list (default)
46 bool fOnlyLastCycle{false}; ///<! show only last cycle in list of keys
47 TKey *fKey{nullptr}; ///<! currently selected key
48 TObject *fObj{nullptr}; ///<! currently selected object
49 std::string fCurrentName; ///<! current key name
50
52 {
53 if (!fDir) return false;
54 fObj = nullptr;
55 fKey = nullptr;
56 auto lst = fDir->GetListOfKeys();
57 if (lst->GetSize() == 0) {
58 auto olst = fDir->GetList();
59 if (olst->GetSize() > 0) {
60 fKeysIter = false;
61 fIter.reset(olst->MakeIterator());
62 return true;
63 }
64 }
65 fKeysIter = true;
66 fIter.reset(lst->MakeIterator());
67 return true;
68 }
69
71 {
72 fCurrentName.clear();
73 if (!fIter) return false;
74
75 fObj = fIter->Next();
76 if (!fObj) {
77 fIter.reset();
78 if (!fKeysIter || !fDir)
79 return false;
80 fKeysIter = false;
81 fIter.reset(fDir->GetList()->MakeIterator());
82 fObj = fIter->Next();
83 if (!fObj) {
84 fIter.reset();
85 return false;
86 }
87 }
88 if (!fKeysIter) {
89 // exclude object with duplicated name as keys
90 while (fObj) {
92 break;
93 fObj = fIter->Next();
94 }
95 if (!fObj) {
96 fIter.reset();
97 return false;
98 }
99
101 return true;
102 }
103
104 while(true) {
105
106 fKey = dynamic_cast<TKey *>(fObj);
107
108 if (!fKey) {
109 fIter.reset();
110 return false;
111 }
112
113 if (!fOnlyLastCycle) break;
114
115 TIter iter(fDir->GetListOfKeys());
116 TKey *key = nullptr;
117 bool found_newer = false;
118 while ((key = dynamic_cast<TKey*>(iter())) != nullptr) {
119 if ((key != fKey) && !strcmp(key->GetName(), fKey->GetName()) && (key->GetCycle() > fKey->GetCycle())) {
120 found_newer = true;
121 break;
122 }
123 }
124
125 if (!found_newer) break;
126
127 fObj = fIter->Next();
128 }
129
131 fCurrentName.append(";");
132 fCurrentName.append(std::to_string(fKey->GetCycle()));
133
134 return true;
135 }
136
137public:
138 explicit TDirectoryLevelIter(TDirectory *dir) : fDir(dir)
139 {
140 const char *undef = "<undefined>";
141 const char *value = gEnv->GetValue("WebGui.LastCycle", undef);
142 if (value) {
143 std::string svalue = value;
144 if (svalue != undef) {
145 if (svalue == "yes")
146 fOnlyLastCycle = true;
147 else if (svalue == "no")
148 fOnlyLastCycle = false;
149 else
150 R__LOG_ERROR(ROOT::BrowsableLog()) << "WebGui.LastCycle must be yes or no";
151 }
152 }
153
154 CreateIter();
155 }
156
157 virtual ~TDirectoryLevelIter() = default;
158
159 bool Next() override { return NextDirEntry(); }
160
161 // use default implementation for now
162 // bool Find(const std::string &name) override { return FindDirEntry(name); }
163
164 std::string GetItemName() const override { return fCurrentName; }
165
166 bool CanItemHaveChilds() const override
167 {
168 if (!fKeysIter && fObj)
170
171 if (fKeysIter && fKey) {
173 return true;
175 return RProvider::CanHaveChilds(cl);
176 }
177 return false;
178 }
179
180 /** Create item for the client */
181 std::unique_ptr<RItem> CreateItem() override
182 {
183 if (!fKeysIter && fObj) {
184 std::unique_ptr<RHolder> holder = std::make_unique<TObjectHolder>(fObj, kFALSE);
185
186 auto elem = RProvider::Browse(holder);
187
188 return elem ? elem->CreateItem() : nullptr;
189 }
190
191 auto item = GetDirElement(false)->CreateItem();
192 item->SetName(fCurrentName);
193 return item;
194 }
195
196 std::shared_ptr<RElement> GetDirElement(bool read_dir);
197
198 /** Returns full information for current element */
199 std::shared_ptr<RElement> GetElement() override { return GetDirElement(true); }
200};
201
202// ===============================================================================================================
203
204/** \class TDirectoryElement
205\ingroup rbrowser
206
207Element representing TDirectory
208*/
209
211 std::string fFileName; ///<! file name
212 bool fIsFile{false}; ///<! is TFile instance registered in global list of files
213
214protected:
215
216 const TObject *CheckObject() const override
217 {
218 // during TROOT destructor just forget about file reference
219 if (!gROOT || gROOT->TestBit(TObject::kInvalidObject)) {
220 ForgetObject();
221 return nullptr;
222 }
223
225 return nullptr;
226
227 if (fIsFile) {
228 if (!gROOT->GetListOfFiles()->FindObject(fObj))
229 ForgetObject();
230 } else if (!gROOT->GetListOfFiles()->FindObject(((TDirectory *) fObj)->GetFile()))
231 ForgetObject();
232
233 return fObj;
234 }
235
237 {
238 if (!CheckObject() && fIsFile && fFileName.empty())
239 (const_cast<TDirectoryElement *>(this))->SetObject(TFile::Open(fFileName.c_str()));
240
241 return dynamic_cast<TDirectory *>(fObj);
242 }
243
244 TFile *GetFile() const
245 {
246 if (!fIsFile)
247 return nullptr;
248
249 return dynamic_cast<TFile *>(GetDir());
250 }
251
252
253public:
254
255 TDirectoryElement(const std::string &fname, TDirectory *dir = nullptr, bool isfile = false) : TObjectElement(dir)
256 {
257 fFileName = fname;
258 fIsFile = isfile;
259 if (fIsFile && fObj && !gROOT->GetListOfFiles()->FindObject(fObj)) {
260 fIsFile = false;
261 ForgetObject();
262 }
263 }
264
265 virtual ~TDirectoryElement() = default;
266
267 /** Name of TDirectoryElement */
268 std::string GetName() const override
269 {
270 if (CheckObject())
271 return fObj->GetName();
272
273 if (!fFileName.empty()) {
274 auto pos = fFileName.rfind("/");
275 return ((pos == std::string::npos) || (pos > fFileName.length() - 2)) ? fFileName : fFileName.substr(pos + 1);
276 }
277
278 return ""s;
279 }
280
281 /** Title of TDirectoryElement */
282 std::string GetTitle() const override
283 {
284 if (CheckObject())
285 return fObj->GetTitle();
286
287 return "ROOT file "s + fFileName;
288 }
289
290 bool IsFolder() const override { return true; }
291
292 /** Provide iterator over TDirectory */
293 std::unique_ptr<RLevelIter> GetChildsIter() override
294 {
295 auto dir = GetDir();
296
297 return dir ? std::make_unique<TDirectoryLevelIter>(dir) : nullptr;
298 }
299
300 /** Get default action - browsing for the TFile/TDirectory */
301 EActionKind GetDefaultAction() const override { return kActBrowse; }
302
303 /** Select directory as active */
304 bool cd() override
305 {
306 auto dir = GetDir();
307 if (dir) {
308 dir->cd();
309 return true;
310 }
311 return false;
312 }
313
314 /** Size of TDirectory */
315 Long64_t GetSize() const override
316 {
317 auto f = GetFile();
318 if (f) return f->GetSize();
319 return -1;
320 }
321
322 std::string GetMTime() const override
323 {
324 auto f = GetFile();
325 if (f) return f->GetModificationDate().AsSQLString();
326 return ""s;
327 }
328
329 std::string GetContent(const std::string &kind) override
330 {
331 if (GetContentKind(kind) == kFileName)
332 return fFileName;
333
334 return ""s;
335 }
336
337};
338
339// ===============================================================================================================
340
341
342/** \class TKeyElement
343\ingroup rbrowser
344
345Element representing TKey from TDirectory
346*/
347
352 std::shared_ptr<RElement> fElement; ///<! holder of read object
353
354 std::string GetMTime() const override { return fKeyMTime; }
355
356 Long64_t GetSize() const override { return fKeyObjSize; }
357
358public:
359 TKeyElement(TDirectory *dir, TKey *key) : TDirectoryElement("", dir, false)
360 {
361 fKeyName = key->GetName();
362 fKeyTitle = key->GetTitle();
363 fKeyCycle = key->GetCycle();
364 fKeyClass = key->GetClassName();
366 fKeyObjSize = key->GetNbytes();
367 }
368
369 virtual ~TKeyElement() = default;
370
371 /** Name of TKeyElement, includes key cycle */
372 std::string GetName() const override
373 {
374 if (fElement)
375 return fElement->GetName();
376
377 std::string name = fKeyName;
378 name.append(";");
379 name.append(std::to_string(fKeyCycle));
380
381 return name;
382 }
383
384 /** Title of TKeyElement (optional) */
385 std::string GetTitle() const override
386 {
387 if (fElement)
388 return fElement->GetTitle();
389
390 return fKeyTitle;
391 }
392
393 /** Create iterator for childs elements if any
394 * Means we should try to browse inside.
395 * Either it is directory or some complex object */
396 std::unique_ptr<RLevelIter> GetChildsIter() override
397 {
398 if (fElement)
399 return fElement->GetChildsIter();
400
401 if (fKeyClass.find("TDirectory") == 0) {
402 auto dir = GetDir();
403 if (!dir) return nullptr;
404
405 auto subdir = dir->GetDirectory(fKeyName.c_str());
406 if (!subdir)
407 subdir = dir->GetDirectory(GetName().c_str());
408 if (!subdir) return nullptr;
409 return std::make_unique<TDirectoryLevelIter>(subdir);
410 }
411
412 auto obj = GetObject();
413
414 if (obj)
416
417 if (fElement)
418 return fElement->GetChildsIter();
419
420 return nullptr;
421 }
422
423 /** Return object associated with the TKey */
424 std::unique_ptr<RHolder> GetObject() override
425 {
426 if (fElement)
427 return fElement->GetObject();
428
429 auto obj_class = TClass::GetClass(fKeyClass.c_str());
430 if (!obj_class)
431 return nullptr;
432
433 if (!obj_class->HasDictionary()) {
434 R__LOG_ERROR(ROOT::BrowsableLog()) << "Class " << fKeyClass << " does not have dictionary, object " << fKeyName << " cannot be read";
435 return nullptr;
436 }
437 auto dir = GetDir();
438 if (!dir)
439 return nullptr;
440
441 std::string namecycle = fKeyName + ";"s + std::to_string(fKeyCycle);
442
443 void *obj = dir->GetObjectChecked(namecycle.c_str(), obj_class);
444
445 if (!obj)
446 return nullptr;
447
448 TObject *tobj = (TObject *) obj_class->DynamicCast(TObject::Class(), obj);
449
450 if (tobj) {
451 bool in_dir = dir->FindObject(tobj) != nullptr,
452 special_class = (fKeyClass == "TGeoManager"s) || (fKeyClass == "TTree"s) || (fKeyClass == "TNtuple"s);
453
454 if (in_dir && !special_class)
455 dir->Remove(tobj);
456
457 return std::make_unique<TObjectHolder>(tobj, !special_class);
458 }
459
460 return std::make_unique<RAnyObjectHolder>(obj_class, obj, true);
461 }
462
464 {
465 if (fElement)
466 return fElement->GetDefaultAction();
467
468 if (fKeyClass.empty()) return kActNone;
469 if ((fKeyClass == "TCanvas"s) || (fKeyClass == "ROOT::Experimental::RCanvas"s)) return kActCanvas;
470 if ((fKeyClass == "TTree"s) || (fKeyClass == "TNtuple"s)) return kActTree;
471 if (fKeyClass == "TGeoManager"s) return kActGeom;
475 return kActNone;
476 }
477
478 bool IsFolder() const override
479 {
480 if (fElement)
481 return fElement->IsFolder();
482
483 if (!fKeyClass.empty()) {
485 return true;
486 auto cl = TClass::GetClass(fKeyClass.c_str(), kFALSE, kTRUE);
487 return RProvider::CanHaveChilds(cl);
488 }
489
490 return false;
491 }
492
493 bool IsCapable(EActionKind action) const override
494 {
495 if (fElement)
496 return fElement->IsCapable(action);
497
498 if (fKeyClass.empty()) return false;
499
500 switch(action) {
501 case kActBrowse: {
503 return true;
505 }
506 case kActEdit: return true;
507 case kActImage:
508 case kActDraw6: {
509 // if can draw in TCanvas, can produce image
511 return true;
513 }
514 case kActDraw7: {
516 return true;
518 }
519 case kActCanvas: return (fKeyClass == "TCanvas"s) || (fKeyClass == "ROOT::Experimental::RCanvas"s);
520 case kActTree: return (fKeyClass == "TTree"s) || (fKeyClass == "TNtuple"s);
521 case kActGeom: return (fKeyClass == "TGeoManager"s);
522 default: return false;
523 }
524
525 return false;
526 }
527
528 std::unique_ptr<RItem> CreateItem() const override
529 {
530 if (fElement)
531 return fElement->CreateItem();
532
533 bool is_folder = IsFolder();
534
535 auto item = std::make_unique<TObjectItem>(GetName(), is_folder ? -1 : 0);
536 item->SetTitle(fKeyTitle);
537 item->SetClassName(fKeyClass);
538 item->SetIcon(RProvider::GetClassIcon(fKeyClass, is_folder));
539 item->SetSize(fKeyObjSize);
540 item->SetMTime(fKeyMTime);
541
542 return item;
543 }
544
545};
546
547// ==============================================================================================
548
549/////////////////////////////////////////////////////////////////////////////////
550/// Return element for current TKey object in TDirectory
551
552std::shared_ptr<RElement> TDirectoryLevelIter::GetDirElement(bool read_dir)
553{
554 if (!fKeysIter && fObj)
555 return std::make_shared<TObjectElement>(fObj);
556
557 if ("ROOT::Experimental::RNTuple"s == fKey->GetClassName())
559
560 std::string key_class = fKey->GetClassName();
561 if (read_dir && (key_class.find("TDirectory") == 0)) {
562 auto subdir = fDir->GetDirectory(fKey->GetName());
563 if (subdir) return std::make_shared<TDirectoryElement>("", subdir);
564 }
565
566 return std::make_shared<TKeyElement>(fDir, fKey);
567}
568
569// ==============================================================================================
570
571
572/** \class RTFileProvider
573\ingroup rbrowser
574
575Provides access to ROOT files with extension "root"
576Other extensions can be registered
577*/
578
579class RTFileProvider : public RProvider {
580
581public:
583 {
584 RegisterFile("root", [] (const std::string &fullname) -> std::shared_ptr<RElement> {
585 auto f = dynamic_cast<TFile *> (gROOT->GetListOfFiles()->FindObject(fullname.c_str()));
586 if (!f) f = TFile::Open(fullname.c_str());
587 if (!f) return nullptr;
588 return std::make_shared<TDirectoryElement>(fullname, f, true);
589 });
590
591 RegisterBrowse(TFile::Class(), [](std::unique_ptr<RHolder> &object) -> std::shared_ptr<RElement> {
592 return std::make_shared<TDirectoryElement>("", const_cast<TFile*>(object->Get<TFile>()), true);
593 });
594
595 RegisterBrowse(TDirectory::Class(), [](std::unique_ptr<RHolder> &object) -> std::shared_ptr<RElement> {
596 return std::make_shared<TDirectoryElement>("", const_cast<TDirectory*>(object->Get<TDirectory>()));
597 });
598 }
599
#define R__LOG_ERROR(...)
Definition RLogger.hxx:362
#define f(i)
Definition RSha256.hxx:104
short Short_t
Definition RtypesCore.h:39
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
long long Long64_t
Definition RtypesCore.h:80
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
RTFileProvider newRTFileProvider
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
#define gROOT
Definition TROOT.h:407
static EContentKind GetContentKind(const std::string &kind)
Find item with specified name Default implementation, should work for all.
Definition RElement.cxx:52
@ kFileName
"filename" - file name if applicable
Definition RElement.hxx:44
EActionKind
Possible actions on double-click.
Definition RElement.hxx:50
@ kActImage
can be shown in image viewer, can provide image
Definition RElement.hxx:54
@ kActDraw6
can be drawn inside ROOT6 canvas
Definition RElement.hxx:55
@ kActCanvas
indicate that it is canvas and should be drawn directly
Definition RElement.hxx:57
@ kActTree
can be shown in tree viewer
Definition RElement.hxx:58
@ kActGeom
can be shown in geometry viewer
Definition RElement.hxx:59
@ kActBrowse
just browse (expand) item
Definition RElement.hxx:52
@ kActEdit
can provide data for text editor
Definition RElement.hxx:53
@ kActDraw7
can be drawn inside ROOT7 canvas
Definition RElement.hxx:56
Iterator over single level hierarchy like any array, keys list, ...
Provider of different browsing methods for supported classes.
Definition RProvider.hxx:37
static std::shared_ptr< RElement > BrowseNTuple(const std::string &tuplename, const std::string &filename)
Start browsing of RNTuple.
static bool CanDraw6(const ClassArg &)
Return true if provided class can be drawn on the TCanvas.
static std::shared_ptr< RElement > Browse(std::unique_ptr< RHolder > &obj)
Create browsable element for the object Created element may take ownership over the object.
static bool CanDraw7(const ClassArg &)
Return true if provided class can be drawn on the RCanvas.
static std::string GetClassIcon(const ClassArg &, bool=false)
Return icon name for the given class - either class name or TClass *.
void RegisterFile(const std::string &extension, FileFunc_t func)
Definition RProvider.cxx:95
void RegisterBrowse(const TClass *cl, BrowseFunc_t func)
static bool CanHaveChilds(const ClassArg &)
Return true if provided class can have childs.
Access to TObject basic properties for RBrowsable.
virtual const TObject * CheckObject() const
Check if object still exists.
void ForgetObject() const
Forget object, use when it was deleted behind the scene.
Provides access to ROOT files with extension "root" Other extensions can be registered.
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2968
const char * AsSQLString() const
Return the date & time in SQL compatible string format, like: 1997-01-15 20:16:28.
Definition TDatime.cxx:152
Element representing TDirectory.
bool cd() override
Select directory as active.
bool fIsFile
! is TFile instance registered in global list of files
virtual ~TDirectoryElement()=default
EActionKind GetDefaultAction() const override
Get default action - browsing for the TFile/TDirectory.
Long64_t GetSize() const override
Size of TDirectory.
std::string GetContent(const std::string &kind) override
Returns element content, depends from kind.
TDirectory * GetDir() const
std::unique_ptr< RLevelIter > GetChildsIter() override
Provide iterator over TDirectory.
bool IsFolder() const override
Check if element can have childs.
TDirectoryElement(const std::string &fname, TDirectory *dir=nullptr, bool isfile=false)
std::string GetMTime() const override
TFile * GetFile() const
std::string GetName() const override
Name of TDirectoryElement.
const TObject * CheckObject() const override
Check if object still exists.
std::string fFileName
! file name
std::string GetTitle() const override
Title of TDirectoryElement.
Iterator over keys in TDirectory.
TDirectoryLevelIter(TDirectory *dir)
std::shared_ptr< RElement > GetElement() override
Returns full information for current element.
bool fKeysIter
! iterating over keys list (default)
std::string GetItemName() const override
Returns current entry name
std::unique_ptr< RItem > CreateItem() override
Create item for the client.
TKey * fKey
! currently selected key
bool fOnlyLastCycle
! show only last cycle in list of keys
std::shared_ptr< RElement > GetDirElement(bool read_dir)
Return element for current TKey object in TDirectory.
std::string fCurrentName
! current key name
std::unique_ptr< TIterator > fIter
! created iterator
bool CanItemHaveChilds() const override
Returns true if current item can have childs.
TDirectory * fDir
! current directory handle
TObject * fObj
! currently selected object
virtual ~TDirectoryLevelIter()=default
bool Next() override
Shift to next entry.
Describe directory structure in memory.
Definition TDirectory.h:45
static TClass * Class()
virtual TList * GetList() const
Definition TDirectory.h:222
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
virtual TFile * GetFile() const
Definition TDirectory.h:220
virtual TList * GetListOfKeys() const
Definition TDirectory.h:223
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:491
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:53
static TClass * Class()
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:4082
Element representing TKey from TDirectory.
bool IsCapable(EActionKind action) const override
Check if want to perform action.
std::string fKeyMTime
EActionKind GetDefaultAction() const override
Get default action - browsing for the TFile/TDirectory.
std::unique_ptr< RLevelIter > GetChildsIter() override
Create iterator for childs elements if any Means we should try to browse inside.
std::string fKeyName
std::string GetTitle() const override
Title of TKeyElement (optional)
std::shared_ptr< RElement > fElement
! holder of read object
virtual ~TKeyElement()=default
std::string fKeyTitle
std::unique_ptr< RHolder > GetObject() override
Return object associated with the TKey.
std::unique_ptr< RItem > CreateItem() const override
Returns item with element description.
std::string fKeyClass
Long64_t GetSize() const override
Size of TDirectory.
bool IsFolder() const override
Check if element can have childs.
TKeyElement(TDirectory *dir, TKey *key)
std::string GetMTime() const override
std::string GetName() const override
Name of TKeyElement, includes key cycle.
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
const char * GetTitle() const override
Returns title (title can contain 32x32 xpm thumbnail/icon).
Definition TKey.cxx:1540
Int_t GetNbytes() const
Definition TKey.h:86
virtual const char * GetClassName() const
Definition TKey.h:75
const TDatime & GetDatime() const
Definition TKey.h:81
Short_t GetCycle() const
Return cycle number associated to this key.
Definition TKey.cxx:577
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:576
TIterator * MakeIterator(Bool_t dir=kIterForward) const override
Return a list iterator.
Definition TList.cxx:720
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
Mother of all ROOT objects.
Definition TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:439
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition TObject.cxx:403
static TClass * Class()
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:483
virtual TClass * IsA() const
Definition TObject.h:243
@ kInvalidObject
if object ctor succeeded but object should not be used
Definition TObject.h:72
ROOT::Experimental::RLogChannel & BrowsableLog()
Log channel for Browsable diagnostics.
Definition RElement.cxx:20