Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RBrowserData.cxx
Go to the documentation of this file.
1// Author: Sergey Linev <S.Linev@gsi.de>
2// Date: 2019-10-14
3// Warning: This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!
4
5/*************************************************************************
6 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#include <ROOT/RBrowserData.hxx>
14
21
22#include <ROOT/RLogger.hxx>
23
24#include "TFolder.h"
25#include "TROOT.h"
26#include "TBufferJSON.h"
27#include "TEnv.h"
28
29#include <algorithm>
30#include <regex>
31
32using namespace ROOT::Experimental;
33using namespace std::string_literals;
34
36 static RLogChannel sLog("ROOT.Browser");
37 return sLog;
38}
39
40namespace ROOT {
41namespace Experimental {
42
44
46
47public:
49
50 void RecursiveRemove(TObject *obj) override
51 {
53 }
54};
55}
56}
57
58
59/** \class ROOT::Experimental::RBrowserData
60\ingroup rbrowser
61\brief Way to browse (hopefully) everything in %ROOT
62*/
63
64
65/////////////////////////////////////////////////////////////////////
66/// Default constructor
67
69{
70 fCleanupHandle = std::make_unique<RBrowserDataCleanup>(*this);
72 gROOT->GetListOfCleanups()->Add(fCleanupHandle.get());
73}
74
75/////////////////////////////////////////////////////////////////////
76/// Destructor
77
79{
80 // should be here because of fCleanupHandle destructor
82 gROOT->GetListOfCleanups()->Remove(fCleanupHandle.get());
83}
84
85/////////////////////////////////////////////////////////////////////
86/// set top element for browsing
87
88void RBrowserData::SetTopElement(std::shared_ptr<Browsable::RElement> elem)
89{
90 fTopElement = elem;
91
93}
94
95/////////////////////////////////////////////////////////////////////
96/// set working directory relative to top element
97
99{
100 fWorkingPath = path;
101
103}
104
105/////////////////////////////////////////////////////////////////////
106/// Create default elements shown in the RBrowser
107
109{
110 auto comp = std::make_shared<Browsable::RGroup>("top","Root browser");
111
112 auto seldir = Browsable::RSysFile::ProvideTopEntries(comp);
113
114 std::unique_ptr<Browsable::RHolder> rootfold = std::make_unique<Browsable::TObjectHolder>(gROOT->GetRootFolder(), kFALSE);
115 auto elem_root = Browsable::RProvider::Browse(rootfold);
116 if (elem_root)
117 comp->Add(std::make_shared<Browsable::RWrapper>("root", elem_root));
118
119 std::unique_ptr<Browsable::RHolder> rootfiles = std::make_unique<Browsable::TObjectHolder>(gROOT->GetListOfFiles(), kFALSE);
120 auto elem_files = Browsable::RProvider::Browse(rootfiles);
121 if (elem_files) {
122 auto files = std::make_shared<Browsable::RWrapper>("ROOT Files", elem_files);
123 files->SetExpandByDefault(true);
124 comp->Add(files);
125 // if there are any open files, make them visible by default
126 if (elem_files->GetNumChilds() > 0)
127 seldir = {};
128 }
129
130 SetTopElement(comp);
131
132 SetWorkingPath(seldir);
133}
134
135/////////////////////////////////////////////////////////////////////
136/// Reset all data correspondent to last request
137
139{
140 fLastAllChilds = false;
141 fLastSortedItems.clear();
142 fLastSortMethod.clear();
143 fLastItems.clear();
144 if (with_element) {
145 fLastPath.clear();
146 fLastElement.reset();
147 }
148}
149
150/////////////////////////////////////////////////////////////////////////
151/// Decompose path to elements
152/// Returns array of names for each element in the path, first element either "/" or "."
153/// If returned array empty - it is error
154
155Browsable::RElementPath_t RBrowserData::DecomposePath(const std::string &strpath, bool relative_to_work_element)
156{
158 if (relative_to_work_element) arr = fWorkingPath;
159
160 if (strpath.empty())
161 return arr;
162
163 auto arr2 = Browsable::RElement::ParsePath(strpath);
164 arr.insert(arr.end(), arr2.begin(), arr2.end());
165 return arr;
166}
167
168/////////////////////////////////////////////////////////////////////////
169/// Process browser request
170
172{
173 auto path = fWorkingPath;
174 path.insert(path.end(), request.path.begin(), request.path.end());
175
176 if ((path != fLastPath) || !fLastElement) {
177
178 auto elem = GetSubElement(path);
179 if (!elem) return false;
180
182
183 fLastPath = path;
184 fLastElement = std::move(elem);
185
186 fLastElement->cd(); // set element active
187 } else if (request.reload) {
188 // only reload items from element, not need to reset element itself
190 }
191
192 // when request childs, always try to make elements
193 if (fLastItems.empty()) {
194
195 auto iter = fLastElement->GetChildsIter();
196
197 if (!iter) return false;
198 int id = 0;
199 fLastAllChilds = true;
200
201 while (iter->Next() && fLastAllChilds) {
202 fLastItems.emplace_back(iter->CreateItem());
203 if (id++ > 10000)
204 fLastAllChilds = false;
205 }
206
207 fLastSortedItems.clear();
208 fLastSortMethod.clear();
209 }
210
211 // create sorted array
212 if ((fLastSortedItems.size() != fLastItems.size()) ||
213 (fLastSortMethod != request.sort) ||
214 (fLastSortReverse != request.reverse)) {
215 fLastSortedItems.resize(fLastItems.size(), nullptr);
216 int id = 0;
217 if (request.sort.empty()) {
218 // no sorting, just move all folders up
219 for (auto &item : fLastItems)
220 if (item->IsFolder())
221 fLastSortedItems[id++] = item.get();
222 for (auto &item : fLastItems)
223 if (!item->IsFolder())
224 fLastSortedItems[id++] = item.get();
225 } else {
226 // copy items
227 for (auto &item : fLastItems)
228 fLastSortedItems[id++] = item.get();
229
230 if (request.sort != "unsorted")
231 std::sort(fLastSortedItems.begin(), fLastSortedItems.end(),
232 [request](const Browsable::RItem *a, const Browsable::RItem *b) { return a ? a->Compare(b, request.sort) : !b; });
233 }
234
235 if (request.reverse)
236 std::reverse(fLastSortedItems.begin(), fLastSortedItems.end());
237
238 fLastSortMethod = request.sort;
239 fLastSortReverse = request.reverse;
240 }
241
242 const std::regex expr(request.regex);
243
244 int id = 0;
245 for (auto &item : fLastSortedItems) {
246
247 // check if element is hidden
248 if (!request.hidden && item->IsHidden())
249 continue;
250
251 if (!request.regex.empty() && !item->IsFolder() && !std::regex_match(item->GetName(), expr))
252 continue;
253
254 if ((id >= request.first) && ((request.number == 0) || (id < request.first + request.number)))
255 reply.nodes.emplace_back(item);
256
257 id++;
258 }
259
260 reply.first = request.first;
261 reply.nchilds = id; // total number of childs
262
263 return true;
264}
265
266/////////////////////////////////////////////////////////////////////////
267/// Process browser request, returns string with JSON of RBrowserReply data
268
270{
271 if (request.lastcycle < 0)
272 gEnv->SetValue("WebGui.LastCycle", "no");
273 else if (request.lastcycle > 0)
274 gEnv->SetValue("WebGui.LastCycle", "yes");
275
276 RBrowserReply reply;
277
278 reply.path = request.path;
279 reply.first = 0;
280 reply.nchilds = 0;
281
282 ProcessBrowserRequest(request, reply);
283
285}
286
287/////////////////////////////////////////////////////////////////////////
288/// Returns element with path, specified as string
289
290std::shared_ptr<Browsable::RElement> RBrowserData::GetElement(const std::string &str)
291{
292 auto path = DecomposePath(str, true);
293
294 return GetSubElement(path);
295}
296
297/////////////////////////////////////////////////////////////////////////
298/// Returns element with path, specified as Browsable::RElementPath_t
299
300std::shared_ptr<Browsable::RElement> RBrowserData::GetElementFromTop(const Browsable::RElementPath_t &path)
301{
302 return GetSubElement(path);
303}
304
305/////////////////////////////////////////////////////////////////////////
306/// Returns sub-element starting from top, using cached data
307
308std::shared_ptr<Browsable::RElement> RBrowserData::GetSubElement(const Browsable::RElementPath_t &path)
309{
310 if (path.empty())
311 return fTopElement;
312
313 // validate cache - removes no longer actual elements
314 RemoveFromCache(nullptr);
315
316 // first check direct match in cache
317 for (auto &entry : fCache)
318 if (entry.first == path)
319 return entry.second;
320
321 // find best possible entry in cache
322 int pos = 0;
323 auto elem = fTopElement;
324
325 for (auto &entry : fCache) {
326 if (entry.first.size() >= path.size())
327 continue;
328
329 auto comp = Browsable::RElement::ComparePaths(path, entry.first);
330
331 if ((comp > pos) && (comp == (int) entry.first.size())) {
332 pos = comp;
333 elem = entry.second;
334 }
335 }
336
337 while (pos < (int) path.size()) {
338 std::string subname = path[pos];
339 int indx = Browsable::RElement::ExtractItemIndex(subname);
340
341 auto iter = elem->GetChildsIter();
342 if (!iter)
343 return nullptr;
344
345 if (!iter->Find(subname, indx)) {
346 if (indx < 0)
347 return nullptr;
348 iter = elem->GetChildsIter();
349 if (!iter || !iter->Find(subname))
350 return nullptr;
351 }
352
353 elem = iter->GetElement();
354
355 if (!elem)
356 return nullptr;
357
358 auto subpath = path;
359 subpath.resize(pos+1);
360 fCache.emplace_back(subpath, elem);
361 pos++; // switch to next element
362 }
363
364 return elem;
365}
366
367/////////////////////////////////////////////////////////////////////////
368/// Clear internal objects cache
369
371{
372 fCache.clear();
373}
374
375/////////////////////////////////////////////////////////////////////////
376/// Remove object from cache
377/// If nullptr specified - removes no-longer-valid elements
378/// Returns true if any element was removed
379
381{
382 unsigned pos = 0;
383
384 bool isany = false;
385
386 while (pos < fCache.size()) {
387 if (obj ? !fCache[pos].second->IsObject(obj) : fCache[pos].second->CheckValid()) {
388 pos++;
389 continue;
390 }
391
392 isany = true;
393 auto path = fCache[pos].first;
394 fCache.erase(fCache.begin() + pos);
395 if (RemoveFromCache(path))
396 pos = 0; // start scan from the beginning
397 }
398
399 return isany;
400}
401
402/////////////////////////////////////////////////////////////////////////
403/// Remove path (and all sub-paths) from cache
404/// Returns true if any element was removed
405
407{
408 if (path.size() == 0)
409 return false;
410
411 bool isany = false;
412 unsigned pos = 0;
413 while (pos < fCache.size()) {
414 if (Browsable::RElement::ComparePaths(path, fCache[pos].first) == (int) path.size()) {
415 fCache.erase(fCache.begin() + pos);
416 isany = true;
417 } else {
418 pos++;
419 }
420 }
421 return isany;
422}
#define b(i)
Definition RSha256.hxx:100
#define a(i)
Definition RSha256.hxx:99
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:405
#define R__LOCKGUARD(mutex)
static int ExtractItemIndex(std::string &name)
Extract index from name Index coded by client with ###<indx>$$$ suffix Such coding used by browser to...
Definition RElement.cxx:177
static int ComparePaths(const RElementPath_t &path1, const RElementPath_t &path2)
Compare two paths, Returns number of elements matches in both paths.
Definition RElement.cxx:144
static RElementPath_t ParsePath(const std::string &str)
Parse string path to produce RElementPath_t One should avoid to use string pathes as much as possible...
Definition RElement.cxx:115
Representation of single item in the browser.
Definition RItem.hxx:24
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 RElementPath_t ProvideTopEntries(std::shared_ptr< RGroup > &comp, const std::string &workdir="")
Provide top entries for file system On windows it is list of existing drivers, on Linux it is "Files ...
Definition RSysFile.cxx:535
void RecursiveRemove(TObject *obj) override
Recursively remove this object from a list.
Way to browse (hopefully) everything in ROOT.
void SetTopElement(std::shared_ptr< Browsable::RElement > elem)
set top element for browsing
std::string fLastSortMethod
! last sort method
bool RemoveFromCache(void *obj)
Remove object from cache If nullptr specified - removes no-longer-valid elements Returns true if any ...
std::shared_ptr< Browsable::RElement > GetSubElement(const Browsable::RElementPath_t &path)
Returns sub-element starting from top, using cached data.
Browsable::RElementPath_t DecomposePath(const std::string &path, bool relative_to_work_element)
Decompose path to elements Returns array of names for each element in the path, first element either ...
virtual ~RBrowserData()
Destructor.
bool ProcessBrowserRequest(const RBrowserRequest &request, RBrowserReply &reply)
Process browser request.
std::vector< std::pair< Browsable::RElementPath_t, std::shared_ptr< Browsable::RElement > > > fCache
! already requested elements
std::shared_ptr< Browsable::RElement > GetElementFromTop(const Browsable::RElementPath_t &path)
Returns element with path, specified as Browsable::RElementPath_t.
void ClearCache()
Clear internal objects cache.
std::vector< const Browsable::RItem * > fLastSortedItems
! sorted child items, used in requests
bool fLastAllChilds
! if all chlds were extracted
std::string ProcessRequest(const RBrowserRequest &request)
Process browser request, returns string with JSON of RBrowserReply data.
Browsable::RElementPath_t fWorkingPath
! path showed in Breadcrumb
bool fLastSortReverse
! last request reverse order
Browsable::RElementPath_t fLastPath
! path to last used element
std::shared_ptr< Browsable::RElement > fTopElement
! top element
void SetWorkingPath(const Browsable::RElementPath_t &path)
set working directory relative to top element
std::shared_ptr< Browsable::RElement > fLastElement
! last element used in request
std::unique_ptr< RBrowserDataCleanup > fCleanupHandle
! cleanup handle for RecursiveRemove
std::shared_ptr< Browsable::RElement > GetElement(const std::string &str)
Returns element with path, specified as string.
std::vector< std::unique_ptr< Browsable::RItem > > fLastItems
! created browser items - used in requests
void ResetLastRequestData(bool with_element)
Reset all data correspondent to last request.
void CreateDefaultElements()
Create default elements shown in the RBrowser.
RBrowserData()
Default constructor.
Reply on browser request.
std::vector< const Browsable::RItem * > nodes
list of pointers, no ownership!
std::vector< std::string > path
reply path
int nchilds
total number of childs in the node
int first
first node in returned list
Request send from client to get content of path element.
std::vector< std::string > path
requested path
int number
number of childs to request, 0 - all childs
std::string sort
kind of sorting
int lastcycle
show only last cycle, -1 - off, 0 - not change, +1 on,
A log configuration for a channel, e.g.
Definition RLogger.hxx:101
static TString ToJSON(const T *obj, Int_t compact=0, const char *member_name=nullptr)
Definition TBufferJSON.h:75
@ kSkipTypeInfo
do not store typenames in JSON
Definition TBufferJSON.h:48
@ kNoSpaces
no new lines plus remove all spaces around "," and ":" symbols
Definition TBufferJSON.h:39
virtual void SetValue(const char *name, const char *value, EEnvLevel level=kEnvChange, const char *type=nullptr)
Set the value of a resource or create a new resource.
Definition TEnv.cxx:736
Mother of all ROOT objects.
Definition TObject.h:41
const char * Data() const
Definition TString.h:380
std::vector< std::string > RElementPath_t
Definition RElement.hxx:21
RLogChannel & BrowserLog()
Log channel for Browser diagnostics.
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
Definition first.py:1