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