Belle II Software  release-08-01-10
InfoWidget.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include <display/InfoWidget.h>
9 #include <display/HtmlClassInspector.h>
10 #include <display/VisualRepMap.h>
11 #include <display/ObjectInfo.h>
12 
13 #include <framework/datastore/DataStore.h>
14 #include <framework/datastore/StoreArray.h>
15 #include <framework/datastore/StoreObjPtr.h>
16 #include <framework/datastore/RelationVector.h>
17 #include <framework/logging/Logger.h>
18 #include <framework/utilities/ColorPalette.h>
19 
20 #include <utility>
21 
22 using namespace Belle2;
23 
24 namespace {
25  DataStore::EDurability getDurability(TString d)
26  {
27  if (d == "persistent")
29  if (d == "event")
30  return DataStore::c_Event;
31  B2FATAL("Invalid URI scheme '" << d << "' specified!");
32  }
33 }
34 InfoWidget::InfoWidget(const TGWindow* p):
35  TGHtml(p, 400, 600, -1)
36 {
37  this->Connect("MouseDown(const char*)", "Belle2::InfoWidget", this, "show(const char*)");
38 
39  //magic to prevent the frame being empty.
40  MapSubwindows();
41  Resize();
42  MapWindow();
43 }
44 
45 InfoWidget::~InfoWidget()
46 {
47 }
48 
49 int InfoWidget::IsVisited(const char* uri)
50 {
51  //not actually sure why return type is 'int'...
52  return (bool)m_visited.count(uri);
53 }
54 
56 {
57  TString lastURI = "";
58  if (!m_history.empty()) {
59  lastURI = m_history.back();
60  }
61  m_visited.clear();
62  m_history.clear();
63 
64  //check if the object given by lastURI exists in the new event, too.
65  //array pages are ok, too
66  if (lastURI != "") {
67  URI parsedURI(lastURI);
68  if (!parsedURI.object and !lastURI.EndsWith("/")) {
69  //doesn't exist, go to main page
70  lastURI = "";
71  }
72  }
73 
74  if (lastURI == "")
75  lastURI = "main:";
76  show(lastURI);
77 }
78 
80 {
81  m_history.pop_back(); //drop current page
82  const TString lastURI = m_history.back();
83  m_history.pop_back(); //we'll go there promptly and re-add it
84 
85  show(lastURI);
86 }
87 
88 void InfoWidget::show(const TObject* obj)
89 {
90  show(URI::getURI(obj).Data(), false);
91 }
92 
93 void InfoWidget::show(const char* uri, bool clearSelection)
94 {
95  B2DEBUG(100, "Navigating to: " << uri);
96 
97  if (std::string(uri) == "back:") {
98  back();
99  return;
100  }
101 
102  m_visited.insert(uri);
103  m_history.push_back(uri);
104 
105  URI parsedURI = URI(uri);
106  TString info;
107  if (parsedURI.object) {
108  info = createObjectPage(parsedURI);
109 
110  //highlight in display
111  if (clearSelection)
114  } else if (parsedURI.entryName != "") {
115  info = createArrayPage(parsedURI);
116  } else {
117  info = createMainPage();
118  }
119  info = "<html><body>" + info + "</body></html>";
120 
121  Clear();
122  //string only passed to function taking const char*...
123  ParseText(const_cast<char*>(info.Data()));
124  Layout();
125 }
126 
128 {
129  TString info = getHeader();
130 
131  const char* schemes[] = {"event", "persistent"};
133  const char* durabilyNames[] = {"c_Event", "c_Persistent"};
134 
135  for (int i = 0; i < 2; i++) {
136  const TString scheme = schemes[i];
137  auto arrayNames = DataStore::Instance().getListOfArrays(TObject::Class(), durabilities[i]);
138  if (!arrayNames.empty()) {
139  info += "<h2>Arrays";
140  if (i > 0) {
141  info += " (<tt>";
142  info += durabilyNames[i];
143  info += "</tt>)";
144  }
145  info += "</h2>";
146  }
147  for (std::string name : arrayNames) {
148  const StoreArray<TObject> array(name, durabilities[i]);
149  int nEntries = array.getEntries();
150  if (nEntries)
151  info += TString::Format("<a href='%s:%s/'>%s (%d)</a><br>", scheme.Data(), name.c_str(), name.c_str(), nEntries);
152  else
153  info += TString::Format("%s (%d)<br>", name.c_str(), nEntries);
154  }
155 
156  auto objNames = DataStore::Instance().getListOfObjects(TObject::Class(), durabilities[i]);
157  if (!objNames.empty()) {
158  info += "<h2>Objects";
159  if (i > 0) {
160  info += " (<tt>";
161  info += durabilyNames[i];
162  info += "</tt>)";
163  }
164  info += "</h2>";
165  }
166  for (std::string name : objNames) {
167  const StoreObjPtr<TObject> obj(name, durabilities[i]);
168  if (obj)
169  info += TString::Format("<a href='%s:%s/'>%s</a><br>", scheme.Data(), name.c_str(), name.c_str());
170  else
171  info += TString::Format("%s<br>", name.c_str());
172  }
173  if (i == 0)
174  info += "<hr>";
175  }
176  return info;
177 }
178 
179 TString InfoWidget::createArrayPage(const URI& uri) const
180 {
181  const StoreArray<TObject> array(uri.entryName.Data(), getDurability(uri.scheme));
182  TString info = getHeader(uri);
183  if (array.getEntries() != 0) {
184  info += HtmlClassInspector::getClassInfo(array[0]->IsA());
185  }
186 
187  for (int i = 0; i < array.getEntries(); i++) {
188  TString name = ObjectInfo::getName(array[i]);
189  if (name != "")
190  name = " - " + name;
191  info += TString::Format("<a href='%s:%s/%d'>%s[%d]%s</a><br>",
192  uri.scheme.Data(), uri.entryName.Data(), i,
193  uri.entryName.Data(), i, name.Data());
194  }
195  return info;
196 }
197 
198 TString InfoWidget::createObjectPage(const URI& uri) const
199 {
200  TString info = getHeader(uri);
201  info += ObjectInfo::getInfo(uri.object);
202  info += getRelatedInfo(uri.object);
203  info += getContents(uri.object);
204 
205  return info;
206 }
207 TString InfoWidget::getHeader(const URI& uri) const
208 {
209  int numEntries = -1;
210  if (uri.entryName.Length() != 0 and (!uri.object or uri.arrayIndex != -1)) {
211  const StoreArray<TObject> array(uri.entryName.Data(), getDurability(uri.scheme));
212  numEntries = array.getEntries();
213  }
214 
215  TString col;
217  col = "#d2ede4"; //needs to be lighter than purple/blue used for links
218  else
219  col = TangoPalette::getHex("Aluminium", 1);
220  TString info;
221  info += "<table border=0 width=100% bgcolor=" + col + "><tr>";
222  //breadcrumbs
223  info += "<td>";
224  info += "<a href='main:'>DataStore</a> / ";
225  if (uri.arrayIndex != -1) {
226  info += "<a href='" + uri.scheme + ":" + uri.entryName + "/'>" + uri.entryName + "</a>";
227  info += TString::Format("<b>[%d]</b>", uri.arrayIndex);
228  } else {
229  info += "<b>" + uri.entryName + "</b>";
230  }
231  info += "</td>";
232 
233  //back button
234  if (m_history.size() <= 1) //current page is part of history, so we need at least two
235  info += "<td align=right>Back</td>";
236  else
237  info += "<td align=right><a href='back:'>Back</a></td>";
238 
239 
240  info += "</tr></table>";
241 
242  //short header for DataStore overview
243  if (uri.entryName == "")
244  return info;
245 
246  //title
247  if (uri.object) {
248  TString name = ObjectInfo::getName(uri.object);
249  if (name != "")
250  name = " - " + name;
251  info += "<h2>" + ObjectInfo::getIdentifier(uri.object) + name + "</h2>";
252  } else {
253  info += TString::Format("<h2>%s (%d)</h2>", uri.entryName.Data(), numEntries);
254  }
255 
256 
257  if (uri.arrayIndex != -1) { //this is an array
258  if (uri.arrayIndex == 0)
259  info += "Previous";
260  else
261  info += "<a href='" + uri.scheme + ":" + TString::Format("%s/%d", uri.entryName.Data(), uri.arrayIndex - 1) + "'>Previous</a>";
262  info += " ";
263  if (uri.arrayIndex == numEntries - 1)
264  info += "Next";
265  else
266  info += "<a href='" + uri.scheme + ":" + TString::Format("%s/%d", uri.entryName.Data(), uri.arrayIndex + 1) + "'>Next</a>";
267  info += "<br> <br>";
268  }
269 
270  return info;
271 }
272 TString InfoWidget::URI::getURI(const TObject* obj)
273 {
274  auto pos = ObjectInfo::getDataStorePosition(obj);
275  if (pos.first.empty()) {
276  B2DEBUG(100, "No DataStore entry found for " << obj->GetName() << ", using raw pointer.");
277  return TString::Format("raw:%lu", (long)obj);
278  }
279  return TString::Format("event:%s/%d", pos.first.c_str(), pos.second);
280 }
281 
282 TString InfoWidget::getRelatedInfo(const TObject* obj)
283 {
284  TString info;
285  info += "<h4>Related Objects</h4>";
286 
287  StoreEntry* storeEntry = nullptr;
288  int index = -1;
289  {
290  //relations from this
291  const RelationVector<TObject> relatedObjects(DataStore::Instance().getRelationsWith(DataStore::c_ToSide, obj, storeEntry, index,
292  TObject::Class(), "ALL", ""));
293  const TString pref = "this <b>-&gt;</b> ";
294  for (size_t i = 0; i < relatedObjects.size(); i++) {
295  const TObject* relObj = relatedObjects.object(i);
296  double weight = relatedObjects.weight(i);
297  TString name = ObjectInfo::getName(relObj);
298  if (name != "")
299  name = " - " + name;
300  info += pref + "<a href='" + URI::getURI(relObj) + "'>" + ObjectInfo::getIdentifier(relObj) + name + "</a>";
301  if (weight != 1.0)
302  info += TString::Format(" (weight: %.3g)", weight);
303  info += "<br>";
304  }
305  }
306 
307  info += " <br>"; //extra space needed!
308  {
309  //relations to this
310  const RelationVector<TObject> relatedObjects(DataStore::Instance().getRelationsWith(DataStore::c_FromSide, obj, storeEntry, index,
311  TObject::Class(), "ALL", ""));
312 
313  const TString pref = "this <b>&lt;-</b> ";
314  for (size_t i = 0; i < relatedObjects.size(); i++) {
315  const TObject* relObj = relatedObjects.object(i);
316  double weight = relatedObjects.weight(i);
317  TString name = ObjectInfo::getName(relObj);
318  if (name != "")
319  name = " - " + name;
320  info += pref + "<a href='" + URI::getURI(relObj) + "'>" + ObjectInfo::getIdentifier(relObj) + name + "</a>";
321  if (weight != 1.0)
322  info += TString::Format(" (weight: %.3g)", weight);
323  info += "<br>";
324  }
325  }
326  return info;
327 }
328 
329 TString InfoWidget::getContents(const TObject* obj)
330 {
331  TString info;
332 
333  info += "<h4>Object Details</h4>";
334  info += HtmlClassInspector::getClassInfo(obj->IsA());
336 
337  return info;
338 }
339 
340 InfoWidget::URI::URI(const TString& uri)
341 {
342  //split uri into schema:path (no double slash: only path after scheme)
343  Ssiz_t protStart = uri.First(":");
344  Ssiz_t protEnd = protStart + 1;
345  if (protStart >= uri.Length())
346  B2FATAL("URI has invalid format: " << uri);
347  scheme = uri(0, protStart);
348  TString path = uri(protEnd, uri.Length() - 1);
349 
350  if (scheme == "raw") {
351  //interpret path as pointer
352  object = reinterpret_cast<TObject*>(path.Atoll());
353  } else if (path.Length() > 0 and path != "/") {
354  //event/persistent
355  DataStore::EDurability durability = getDurability(scheme);
356 
357  Ssiz_t delim = path.Last('/');
358  Ssiz_t idxFieldLength = path.Length() - delim - 1;
359  if (delim >= path.Length())
360  B2FATAL("URI has invalid format: " << path);
361  //ok, set entryName
362  entryName = path(0, delim);
363  if (idxFieldLength > 0) {
364  //array index found
365  arrayIndex = TString(path(delim + 1, idxFieldLength)).Atoi();
366  const StoreArray<TObject> arr(entryName.Data(), durability);
367  if (arrayIndex < arr.getEntries())
368  object = arr[arrayIndex];
369  }
370  const auto& entries = DataStore::Instance().getStoreEntryMap(durability);
371  const auto& it = entries.find(entryName.Data());
372  if (it == entries.end()) {
373  B2ERROR("Given entry '" << entryName << "' not found in DataStore, invalid URI?");
374  } else if (!it->second.isArray) {
375  //also set object for StoreObjPtr
376  object = it->second.object;
377  }
378  }
379 }
StoreEntryMap & getStoreEntryMap(EDurability durability)
Get a reference to the object/array map.
Definition: DataStore.h:325
std::vector< std::string > getListOfArrays(const TClass *arrayClass, EDurability durability) const
Returns a list of names of arrays which are of type (or inherit from) arrayClass.
Definition: DataStore.cc:666
@ c_FromSide
Return relations/objects pointed from (to a given object).
Definition: DataStore.h:77
@ c_ToSide
Return relations/objects pointed to (from a given object).
Definition: DataStore.h:78
std::vector< std::string > getListOfObjects(const TClass *objClass, EDurability durability) const
Returns a list of names of StoreObjPtr-objects whose class is (or inherits from) objClass.
Definition: DataStore.cc:671
EDurability
Durability types.
Definition: DataStore.h:58
@ c_Persistent
Object is available during entire execution time.
Definition: DataStore.h:60
@ c_Event
Different object in each event, all objects/arrays are invalidated after event() function has been ca...
Definition: DataStore.h:59
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:54
static TString getMemberData(const TObject *obj)
Return table with member data contents.
static TString getClassInfo(const TClass *obj)
Get class name + description from comment after ClassDef().
static TString getRelatedInfo(const TObject *obj)
return HTML-formatted list of related objects.
Definition: InfoWidget.cc:282
void back()
navigate to previous page, clearing current page from history.
Definition: InfoWidget.cc:79
TString createObjectPage(const URI &uri) const
create object info.
Definition: InfoWidget.cc:198
std::set< TString > m_visited
list of all pages viewed in current event.
Definition: InfoWidget.h:93
virtual int IsVisited(const char *uri) override
Used to colour visited links.
Definition: InfoWidget.cc:49
InfoWidget(const TGWindow *p)
ctor.
Definition: InfoWidget.cc:34
void show(const char *uri="main:", bool clearSelection=true)
Navigate to given URI.
Definition: InfoWidget.cc:93
static TString getContents(const TObject *obj)
Get object contents (member data).
Definition: InfoWidget.cc:329
std::vector< TString > m_history
ordered list of all pages viewed in current event.
Definition: InfoWidget.h:95
void update()
reset for new event (try to show same object if it exists).
Definition: InfoWidget.cc:55
TString getHeader(const URI &uri=URI()) const
returns string with title, breadcrumbs, menu.
Definition: InfoWidget.cc:207
TString createArrayPage(const URI &uri) const
create list of array contents.
Definition: InfoWidget.cc:179
TString createMainPage() const
create DataStore overview.
Definition: InfoWidget.cc:127
Class for type safe access to objects that are referred to in relations.
size_t size() const
Get number of relations.
T * object(int index) const
Get object with index.
float weight(int index) const
Get weight with index.
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
void clearSelection() const
Clear existing selection in Eve Browser.
static VisualRepMap * getInstance()
get instance pointer.
Definition: VisualRepMap.cc:36
void select(const TObject *object) const
Select the representation of the given object.
Definition: VisualRepMap.cc:87
bool isVisualized(const TObject *obj)
Does obj have a visualization?
Definition: VisualRepMap.h:62
TString getName(const TObject *obj)
human-readable name (e.g.
Definition: ObjectInfo.cc:45
TString getIdentifier(const TObject *obj)
Where is this object in the datastore?
Definition: ObjectInfo.cc:105
std::pair< std::string, int > getDataStorePosition(const TObject *obj)
return entry name & index for arrays, with index = -1 for objects.
Definition: ObjectInfo.cc:78
TString getInfo(const TObject *obj)
Get object info HTML (e.g.
Definition: ObjectInfo.cc:55
const char * getHex(const std::string &tangoName, int tangoId=1)
Get six-digit hex code (#abcdef) for given name in tango colour palette.
Definition: ColorPalette.cc:18
Abstract base class for different kinds of events.
TString scheme
scheme name (part before first colon).
Definition: InfoWidget.h:72
const TObject * object
object referenced (or NULL).
Definition: InfoWidget.h:71
int arrayIndex
index in array, only valid if arrayName and object are filled.
Definition: InfoWidget.h:74
TString entryName
name of DataStore entry.
Definition: InfoWidget.h:73
static TString getURI(const TObject *obj)
get URI string to given object.
Definition: InfoWidget.cc:272
Wraps a stored array/object, stored under unique (name, durability) key.
Definition: StoreEntry.h:22