TreeWidget.cpp
Go to the documentation of this file.
1#include "TreeWidget.h"
2
3#include <QHeaderView>
4#include <QMenu>
5
6#include <SimoxUtility/algorithm/string.h>
7
8#include <RobotAPI/interface/armem/actions.h>
11
12namespace armarx::armem::gui
13{
14
16 {
17 initBuilders();
18 initWidget();
19 }
20
21 void
22 TreeWidget::initWidget()
23 {
24 clear();
25 QStringList columns;
26 columns.insert(int(Columns::KEY), "Key");
27 columns.insert(int(Columns::SIZE), "#");
28 columns.insert(int(Columns::TYPE), "Type");
29 columns.insert(int(Columns::LEVEL), "Level");
30 columns.insert(int(Columns::ID), "Memory ID");
31 setColumnCount(columns.size());
32 setHeaderLabels(columns);
33
34 header()->setMinimumSectionSize(25);
35 header()->resizeSection(int(Columns::KEY), 250);
36 header()->resizeSection(int(Columns::SIZE), 40);
37 header()->setTextElideMode(Qt::TextElideMode::ElideRight);
38
39
40 connect(this, &This::updated, this, &This::handleSelection);
41 connect(this, &QTreeWidget::currentItemChanged, this, &This::handleSelection);
42
43 connect(this, &This::memorySelected, this, &This::itemSelected);
44 connect(this, &This::coreSegmentSelected, this, &This::itemSelected);
46 connect(this, &This::entitySelected, this, &This::itemSelected);
47 connect(this, &This::snapshotSelected, this, &This::itemSelected);
48 connect(this, &This::instanceSelected, this, &This::itemSelected);
49
50 setContextMenuPolicy(Qt::CustomContextMenu);
51 connect(
52 this, &QTreeWidget::customContextMenuRequested, this, &This::prepareTreeContextMenu);
53 }
54
55 void
56 TreeWidget::initBuilders()
57 {
58 memoryBuilder.setExpand(true);
59 memoryBuilder.setMakeItemFn([this](const std::string& name, const wm::Memory* memory)
60 { return makeItem(name, *memory); });
61 memoryBuilder.setUpdateItemFn(
62 [this](const std::string&, const wm::Memory* memory, QTreeWidgetItem* memoryItem)
63 {
64 updateContainerItem(*memory, memoryItem);
65 if (memoryItem)
66 {
67 updateChildren(*memory, memoryItem);
68 }
69 return true;
70 });
71
72 auto nameFn = [](const auto& element) { return element.name(); };
73
74 coreSegmentBuilder.setExpand(true);
75 coreSegmentBuilder.setNameFn(nameFn, int(Columns::KEY));
76 coreSegmentBuilder.setMakeItemFn([this](const wm::CoreSegment& coreSeg)
77 { return makeItem(coreSeg.name(), coreSeg); });
78 coreSegmentBuilder.setUpdateItemFn(
79 [this](const wm::CoreSegment& coreSeg, QTreeWidgetItem* coreSegItem)
80 {
81 updateContainerItem(coreSeg, coreSegItem);
82 updateChildren(coreSeg, coreSegItem);
83 return true;
84 });
85
86 provSegmentBuilder.setExpand(true);
87 provSegmentBuilder.setNameFn(nameFn, int(Columns::KEY));
88 provSegmentBuilder.setMakeItemFn([this](const wm::ProviderSegment& provSeg)
89 { return makeItem(provSeg.name(), provSeg); });
90 provSegmentBuilder.setUpdateItemFn(
91 [this](const wm::ProviderSegment& provSeg, QTreeWidgetItem* provSegItem)
92 {
93 updateContainerItem(provSeg, provSegItem);
94 updateChildren(provSeg, provSegItem);
95 return true;
96 });
97
98 // entityBuilder.setExpand(true);
99 entityBuilder.setNameFn(nameFn, int(Columns::KEY));
100 entityBuilder.setMakeItemFn([this](const wm::Entity& entity)
101 { return makeItem(entity.name(), entity); });
102 entityBuilder.setUpdateItemFn(
103 [this](const wm::Entity& entity, QTreeWidgetItem* entityItem)
104 {
105 updateContainerItem(entity, entityItem);
106 updateChildren(entity, entityItem);
107 return true;
108 });
109
110 snapshotBuilder.setMakeItemFn(
111 [this](const wm::EntitySnapshot& snapshot)
112 {
113 QTreeWidgetItem* item = makeItem(toDateTimeMilliSeconds(snapshot.time()), snapshot);
114 item->setData(
115 int(Columns::KEY),
116 Qt::ItemDataRole::UserRole,
117 QVariant(static_cast<qlonglong>(snapshot.time().toMicroSecondsSinceEpoch())));
118 return item;
119 });
120 snapshotBuilder.setCompareFn(
121 [](const wm::EntitySnapshot& snapshot, QTreeWidgetItem* item)
122 {
124 static_cast<qlonglong>(snapshot.time().toMicroSecondsSinceEpoch()),
125 item->data(int(Columns::KEY), Qt::ItemDataRole::UserRole).toLongLong());
126 });
127 snapshotBuilder.setUpdateItemFn(
128 [this](const wm::EntitySnapshot& snapshot, QTreeWidgetItem* snapshotItem)
129 {
130 updateContainerItem(snapshot, snapshotItem);
131 updateChildren(snapshot, snapshotItem);
132 return true;
133 });
134
135 instanceBuilder.setMakeItemFn(
136 [this](const wm::EntityInstance& instance)
137 {
138 QTreeWidgetItem* item = makeItem("", instance);
139 return item;
140 });
141 instanceBuilder.setCompareFn(
142 [](const wm::EntityInstance& lhs, QTreeWidgetItem* rhsItem)
143 { return armarx::detail::compare(lhs.index(), rhsItem->text(0).toInt()); });
144 instanceBuilder.setUpdateItemFn(
145 [this](const wm::EntityInstance& instance, QTreeWidgetItem* instanceItem)
146 {
147 updateItemItem(instance, instanceItem);
148 updateChildren(instance, instanceItem);
149 return true;
150 });
151 }
152
153 void
155 {
156 // Removing elements during the update can create unwanted signals triggering selection handling.
157 handleSelections = false;
158 updateChildren(memory, this);
159 handleSelections = true;
160 emit updated();
161 }
162
163 void
164 TreeWidget::update(const std::map<std::string, const armem::wm::Memory*>& memories)
165 {
166 handleSelections = false;
167 updateChildren(memories, this);
168 handleSelections = true;
169 emit updated();
170 }
171
172 std::optional<MemoryID>
174 {
175 return _selectedID;
176 }
177
178 void
179 TreeWidget::handleSelection()
180 {
181 if (!handleSelections)
182 {
183 return;
184 }
185 QTreeWidgetItem* item = this->currentItem();
186 if (!item)
187 {
188 return;
189 }
190
191 MemoryID id(item->data(int(Columns::ID), Qt::UserRole).toString().toStdString());
192
193 // Has the selection changed due to an update? If yes, signal this.
194 if (!_selectedID || id != *_selectedID)
195 {
196 _selectedID = id;
197
198 const std::string levelName =
199 item->data(int(Columns::LEVEL), Qt::UserRole).toString().toStdString();
200 if (levelName == wm::Memory::getLevelName())
201 {
202 emit memorySelected(*_selectedID);
203 }
204 else if (levelName == wm::CoreSegment::getLevelName())
205 {
206 emit coreSegmentSelected(*_selectedID);
207 }
208 else if (levelName == wm::ProviderSegment::getLevelName())
209 {
210 emit providerSegmentSelected(*_selectedID);
211 }
212 else if (levelName == wm::Entity::getLevelName())
213 {
214 emit entitySelected(*_selectedID);
215 }
216 else if (levelName == wm::EntitySnapshot::getLevelName())
217 {
218 emit snapshotSelected(*_selectedID);
219 }
220 else if (levelName == wm::EntityInstance::getLevelName())
221 {
222 emit instanceSelected(*_selectedID);
223 }
224 }
225
226 // Either selection or its contents have changed.
227 emit selectedItemChanged(*_selectedID);
228 }
229
230 template <class ContainerT>
231 static auto
232 makeIteratorFn(const ContainerT& container)
233 {
234 return [&container](auto&& elementFn) { container.forEachChild(elementFn); };
235 }
236
237 void
238 TreeWidget::updateChildren(const armem::wm::Memory& memory, QTreeWidget* tree)
239 {
240 updateChildren(std::map<std::string, const armem::wm::Memory*>{{memory.name(), &memory}},
241 tree);
242 }
243
244 void
245 TreeWidget::updateChildren(const std::map<std::string, const armem::wm::Memory*>& memories,
246 QTreeWidget* tree)
247 {
248 memoryBuilder.updateTree(tree, memories);
249 }
250
251 void
252 TreeWidget::updateChildren(const armem::wm::Memory& memory, QTreeWidgetItem* memoryItem)
253 {
254 coreSegmentBuilder.updateTreeWithIterator(memoryItem, makeIteratorFn(memory));
255 }
256
257 void
258 TreeWidget::updateChildren(const armem::wm::CoreSegment& coreSeg, QTreeWidgetItem* coreSegItem)
259 {
260 provSegmentBuilder.updateTreeWithIterator(coreSegItem, makeIteratorFn(coreSeg));
261 }
262
263 void
264 TreeWidget::updateChildren(const armem::wm::ProviderSegment& provSeg,
265 QTreeWidgetItem* provSegItem)
266 {
267 entityBuilder.updateTreeWithIterator(provSegItem, makeIteratorFn(provSeg));
268 }
269
270 void
271 TreeWidget::updateChildren(const armem::wm::Entity& entity, QTreeWidgetItem* entityItem)
272 {
273 snapshotBuilder.updateTreeWithIterator(entityItem, makeIteratorFn(entity));
274 }
275
276 void
277 TreeWidget::updateChildren(const armem::wm::EntitySnapshot& snapshot,
278 QTreeWidgetItem* snapshotItem)
279 {
280 instanceBuilder.updateTreeWithIterator(snapshotItem, makeIteratorFn(snapshot));
281 }
282
283 void
284 TreeWidget::updateChildren(const armem::wm::EntityInstance& data, QTreeWidgetItem* dataItem)
285 {
286 (void)data, (void)dataItem;
287 }
288
289 void
290 TreeWidget::prepareTreeContextMenu(const QPoint& pos)
291 {
292 const QTreeWidgetItem* item = this->itemAt(pos);
293 if (item == nullptr)
294 {
295 return;
296 }
297
298 MemoryID memoryID(item->data(int(Columns::ID), Qt::UserRole).toString().toStdString());
299 emit actionsMenuRequested(memoryID, this, mapToGlobal(pos), nullptr);
300 }
301
302 template <class MemoryItemT>
303 QTreeWidgetItem*
304 TreeWidget::makeItem(const std::string& key, const MemoryItemT& memoryItem)
305 {
306 (void)key;
307 return makeItem(memoryItem.getKeyString(), MemoryItemT::getLevelName(), memoryItem.id());
308 }
309
310 QTreeWidgetItem*
311 TreeWidget::makeItem(const std::string& key, const std::string& levelName, const MemoryID& id)
312 {
313 QStringList columns;
314 columns.insert(int(Columns::KEY), QString::fromStdString(key));
315 columns.insert(int(Columns::SIZE), "");
316 columns.insert(int(Columns::TYPE), "");
317 columns.insert(int(Columns::LEVEL),
318 QString::fromStdString(simox::alg::capitalize_words(levelName)));
319 columns.insert(int(Columns::ID), QString::fromStdString(id.str()));
320
321 QTreeWidgetItem* item = new QTreeWidgetItem(columns);
322 item->setData(int(Columns::LEVEL), Qt::UserRole, QString::fromStdString(levelName));
323 item->setData(int(Columns::ID), Qt::UserRole, QString::fromStdString(id.str()));
324 item->setTextAlignment(int(Columns::SIZE), Qt::AlignRight);
325 return item;
326 }
327
328 void
329 TreeWidget::updateItemItem(const armem::base::detail::MemoryItem& level, QTreeWidgetItem* item)
330 {
331 (void)level, (void)item;
332 }
333
334 template <class ContainerT>
335 void
336 TreeWidget::updateContainerItem(const ContainerT& container, QTreeWidgetItem* item)
337 {
338 updateItemItem(container, item);
339 item->setText(int(Columns::SIZE), QString::number(container.size()));
340
341 // Does not work
342 if constexpr (std::is_base_of_v<base::detail::AronTyped, ContainerT>)
343 {
344 const base::detail::AronTyped& cast =
345 static_cast<const base::detail::AronTyped&>(container);
346 std::string typeName;
347 if (cast.aronType())
348 {
349 typeName = cast.aronType()->getFullName();
350 typeName = instance::sanitizeTypeName(typeName);
351 }
352 else
353 {
354 typeName = "(no Aron type)";
355 }
356 item->setText(int(Columns::TYPE), QString::fromStdString(typeName));
357 }
358 }
359
360} // namespace armarx::armem::gui
std::string str(const T &t)
void entitySelected(const MemoryID &id)
void selectedItemChanged(const MemoryID &id)
The selected item or its contents have changed.
void actionsMenuRequested(const MemoryID &memoryID, QWidget *parent, const QPoint &pos, QMenu *menu)
void updated()
Tree contents have changed.
void update(const armem::wm::Memory &memory)
void snapshotSelected(const MemoryID &id)
void instanceSelected(const MemoryID &id)
void itemSelected(const MemoryID &id)
void coreSegmentSelected(const MemoryID &id)
std::optional< MemoryID > selectedID() const
void memorySelected(const MemoryID &id)
void providerSegmentSelected(const MemoryID &id)
Client-side working memory.
std::int64_t toMicroSecondsSinceEpoch() const
Definition DateTime.cpp:87
Brief description of class memory.
Definition memory.h:39
std::string sanitizeTypeName(const std::string &typeName)
const MemoryID memoryID
armem::wm::EntitySnapshot EntitySnapshot
armem::wm::EntityInstance EntityInstance
std::string toDateTimeMilliSeconds(const Time &time, int decimals=6)
Returns timeas e.g.
Definition Time.cpp:35
CvT cast(const auto &pt)
Definition opencv.h:33
int compare(const T &lhs, const T &rhs)
const armem::MemoryID MemoryID
Definition memory_ids.cpp:6