Belle II Software development
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
22using namespace Belle2;
23
24namespace {
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}
34InfoWidget::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
45InfoWidget::~InfoWidget()
46{
47}
48
49int 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
88void InfoWidget::show(const TObject* obj)
89{
90 show(URI::getURI(obj).Data(), false);
91}
92
93void 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
179TString 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
198TString 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}
207TString 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}
272TString 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
282TString 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
329TString 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
340InfoWidget::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}
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
StoreEntryMap & getStoreEntryMap(EDurability durability)
Get a reference to the object/array map.
Definition: DataStore.h:325
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.
T * object(int index) const
Get object with index.
size_t size() const
Get number of relations.
float weight(int index) const
Get weight with index.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
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