DataView.cpp
Go to the documentation of this file.
1
2#include "DataView.h"
3
4#include <functional>
5
6#include <QApplication>
7#include <QBrush>
8#include <QClipboard>
9#include <QColor>
10#include <QHBoxLayout>
11#include <QHeaderView>
12#include <QLabel>
13#include <QSplitter>
14#include <QTreeWidget>
15
16#include <SimoxUtility/color/cmaps.h>
17#include <SimoxUtility/math/SoftMinMax.h>
18
20#include <RobotAPI/libraries/armem/aron/MemoryID.aron.generated.h>
34
36{
38 splitter(new QSplitter(Qt::Orientation::Vertical)), tree(new QTreeWidget(this))
39 {
40 Logging::setTag("DataView");
41
42 QLayout* layout = new QVBoxLayout();
43 this->setLayout(layout);
44 int margin = 3;
45 layout->setContentsMargins(margin, margin, margin, margin);
46
47 layout->addWidget(splitter);
48
49 splitter->addWidget(tree);
50
51 QStringList columns;
52 columns.insert(int(Columns::KEY), "Key");
53 columns.insert(int(Columns::VALUE), "Value");
54 columns.insert(int(Columns::TYPE), "Type");
55 tree->setColumnCount(columns.size());
56 tree->setHeaderLabels(columns);
57
58 tree->header()->resizeSection(int(Columns::KEY), 250);
59 tree->header()->resizeSection(int(Columns::VALUE), 250);
60
61 treeItemData = new QTreeWidgetItem({"Data"});
62 tree->addTopLevelItem(treeItemData);
63 treeItemData->setExpanded(true);
64 tree->setContextMenuPolicy(Qt::CustomContextMenu);
65 connect(tree,
66 &QTreeWidget::customContextMenuRequested,
67 this,
69 }
70
71 void
73 {
74 this->statusLabel = statusLabel;
75 }
76
77 void
79 {
80 this->useTypeInfo = enable;
81 update();
82 emit useTypeInfoChanged(enable);
83 }
84
85 void
97
98 std::optional<MemoryID>
100 {
101 return std::nullopt;
102 }
103
104 void
106 {
107 // ARMARX_IMPORTANT << "Adding instance view with toolbar for instance: " << instance.id();
108 dataView->setStatusLabel(statusLabel);
109 dataView->setUseTypeInfo(useTypeInfo);
111
112 auto* child = new WidgetsWithToolbar();
113 child->addWidget(dataView);
114
115
116 splitter->addWidget(child);
117
118 // Propagate these signals upwards.
119 connect(dataView,
121 this,
124 connect(this, &DataView::useTypeInfoChanged, dataView, &DataView::setUseTypeInfo);
125 }
126
127 void
129 {
130 if (!data)
131 {
132 treeItemData->setText(int(Columns::TYPE), QString::fromStdString(""));
133
135 QTreeWidgetItem* item = new QTreeWidgetItem({"(No data.)"});
136 treeItemData->addChild(item);
137 }
138 else if (useTypeInfo && aronType)
139 {
140 treeItemData->setText(
141 int(Columns::TYPE),
142 QString::fromStdString(sanitizeTypeName(aronType->getFullName())));
143
144 TypedDataTreeBuilder builder;
145 builder.setColumns(int(Columns::KEY), int(Columns::VALUE), int(Columns::TYPE));
146 builder.updateTree(treeItemData, *aronType, *data);
147 }
148 else
149 {
150 treeItemData->setText(int(Columns::TYPE), QString::fromStdString(""));
151
152 DataTreeBuilder builder;
153 builder.setColumns(int(Columns::KEY), int(Columns::VALUE), int(Columns::TYPE));
154 builder.updateTree(treeItemData, data);
155 }
156 treeItemData->setExpanded(true);
157
159 }
160
161 void
162 DataView::showErrorMessage(const std::string& message)
163 {
164 if (statusLabel)
165 {
166 statusLabel->setText(QString::fromStdString(message));
167 }
168 }
169
170 std::optional<aron::Path>
171 DataView::getElementPath(const QTreeWidgetItem* item)
172 {
173 QStringList qpath = item->data(int(Columns::KEY), Qt::UserRole).toStringList();
174 if (qpath.empty())
175 {
176 return std::nullopt;
177 }
178 else
179 {
180 aron::Path path = deserializePath(qpath);
181 return path;
182 }
183 }
184
185 std::optional<MemoryID>
187 {
189 if (!data)
190 {
191 showErrorMessage("Cannot get Memory ID for null element.");
192 return std::nullopt;
193 }
194
196 try
197 {
198 element = data->navigateAbsolute(elementPath);
199 }
200 // This can happen when the underlying entity structure changes (a new entity has been selected).
201 catch (const aron::error::AronException&)
202 {
203 // showErrorMessage(e.what());
204 return std::nullopt;
205 }
206 catch (const armarx::LocalException& e)
207 {
208 showErrorMessage(e.what());
209 return std::nullopt;
210 }
211
212 std::stringstream couldNotParseMsg;
213 couldNotParseMsg << "Element " << elementPath.toString()
214 << " could not be parsed as MemoryID.";
215
216 auto dictElement = std::dynamic_pointer_cast<aron::data::Dict>(element);
217 if (!dictElement)
218 {
219 showErrorMessage(couldNotParseMsg.str() + " (Failed to cast to DictNavigator.)");
220 return std::nullopt;
221 }
222
223 try
224 {
225 arondto::MemoryID dto;
226 dto.fromAron(dictElement);
227
228 MemoryID id;
229 armem::fromAron(dto, id);
230 return id;
231 }
233 {
234 showErrorMessage(couldNotParseMsg.str());
235 return std::nullopt;
236 }
237 }
238
239 QAction*
240 DataView::makeActionResolveMemoryID(const MemoryID& id)
241 {
242 auto* action = new QAction("Resolve memory ID");
243
244 if (not(id.hasEntityName() and id.isWellDefined()))
245 {
246 action->setDisabled(true);
247 action->setText(action->text() + " (incomplete Memory ID)");
248 }
249 connect(action,
250 &QAction::triggered,
251 [this, id]()
252 {
253 // ARMARX_IMPORTANT << "emit memoryIdResolutionRequested(id = " << id << ")";
255 });
256
257 return action;
258 }
259
260 QAction*
262 {
263 QAction* action = new QAction("Copy memory ID to clipboard");
264
265 connect(action,
266 &QAction::triggered,
267 [/*this,*/ id]() // `this` for ARMARX_IMPORTANT
268 {
269 const QString idStr = QString::fromStdString(id.str());
270
271 // ARMARX_IMPORTANT << "Copy '" << idStr.toStdString() << "' to clipboard.";
272 QClipboard* clipboard = QApplication::clipboard();
273 clipboard->setText(idStr);
274 QApplication::processEvents();
275 });
276
277 return action;
278 }
279
280 std::vector<QAction*>
281 DataView::makeActionsCopyDataToClipboard()
282 {
283 auto data = getData();
284 if (!data)
285 {
286 return {};
287 }
288 return makeCopyActions(data, currentAronType);
289 }
290
291 std::vector<QAction*>
292 DataView::makeActionsCopyDataToClipboard(const aron::Path& path)
293 {
294 auto data = getData();
295 if (!data)
296 {
297 return {};
298 }
299 try
300 {
301 aron::data::VariantPtr element = data->navigateAbsolute(path);
302 aron::type::VariantPtr elementType = nullptr;
303 if (currentAronType)
304 {
305 // There doesn't seem to be a way to check whether the path exists
306 // without potentially throwing an exception.
307 try
308 {
309 elementType = currentAronType->navigateAbsolute(path);
310 }
311 catch (const aron::error::AronException& e)
312 {
313 // No type available, elementType remains nullptr.
314 }
315 }
316 return makeCopyActions(element, elementType);
317 }
318 catch (const aron::error::AronException& e)
319 {
320 ARMARX_WARNING << "Could not convert Aron data to JSON: " << e.getReason();
321 }
322 return {};
323 }
324
325 std::vector<QAction*>
326 DataView::makeCopyActions(const aron::data::VariantPtr& element,
327 const aron::type::VariantPtr& elementType)
328 {
329 auto* easyJsonAction = new QAction("Copy data to clipboard as easy JSON");
330 connect(easyJsonAction,
331 &QAction::triggered,
332 [this, element, elementType]()
333 {
334 try
335 {
336 TreeTypedJSONConverter conv;
337 armarx::aron::data::visitRecursive(conv, element, elementType);
338 QClipboard* clipboard = QApplication::clipboard();
339 clipboard->setText(QString::fromStdString(conv.getJSON().dump(2)));
340 QApplication::processEvents();
341 }
342 catch (const aron::error::AronException& e)
343 {
344 ARMARX_WARNING << "Could not convert Aron data to JSON: " << e.getReason();
345 }
346 });
347
348 auto* aronJsonAction = new QAction("Copy data to clipboard as aron JSON");
349 connect(aronJsonAction,
350 &QAction::triggered,
351 [this, element]()
352 {
353 try
354 {
355 nlohmann::json json =
357 element);
358 QClipboard* clipboard = QApplication::clipboard();
359 clipboard->setText(QString::fromStdString(json.dump(2)));
360 QApplication::processEvents();
361 }
362 catch (const aron::error::AronException& e)
363 {
364 ARMARX_WARNING << "Could not convert Aron data to JSON: " << e.getReason();
365 }
366 });
367
368 return {easyJsonAction, aronJsonAction};
369 }
370
371 QMenu*
372 DataView::buildActionsMenu(const QPoint& pos)
373 {
374 QMenu* menu = new QMenu(this);
375
376 const QTreeWidgetItem* item = tree->itemAt(pos);
377 if (item == nullptr)
378 {
379 return menu; // Nothing was clicked on.
380 }
381
382 if (item == this->treeItemData && getData() != nullptr)
383 {
384 auto actions = makeActionsCopyDataToClipboard();
385 for (const auto& action : actions)
386 {
387 if (action)
388 {
389 menu->addAction(action);
390 }
391 }
392 }
393
395 item->data(int(Columns::TYPE), Qt::UserRole).toInt());
396 switch (type)
397 {
399 {
400 if (const std::optional<aron::Path> path = getElementPath(item))
401 {
402 QAction* viewAction = new QAction("Show image");
403 menu->addAction(viewAction);
404 connect(viewAction,
405 &QAction::triggered,
406 [this, path]() { this->showImageView(path.value()); });
407
408 try
409 {
410 aron::data::VariantPtr element =
411 getData() != nullptr ? getData()->navigateAbsolute(path.value())
412 : nullptr;
413 if (auto imageData = aron::data::NDArray::DynamicCast(element))
414 {
415 const std::vector<int> shape = imageData->getShape();
416 if (std::find(shape.begin(), shape.end(), 0) != shape.end())
417 {
418 viewAction->setText(viewAction->text() + " (image is empty)");
419 viewAction->setEnabled(false);
420 }
421 }
422 }
423 catch (const aron::error::AronException&)
424 {
425 }
426 catch (const armarx::LocalException&)
427 {
428 }
429 }
430 }
431 break;
432 default:
433 break;
434 }
435
436 // Type name based actions
437 const std::string typeName = item->text(int(Columns::TYPE)).toStdString();
439 {
440 if (const std::optional<aron::Path> path = getElementPath(item))
441 {
442 if (std::optional<MemoryID> id = getElementMemoryID(path.value()))
443 {
444 if (QAction* action = makeActionCopyMemoryID(id.value()))
445 {
446 menu->addAction(action);
447 }
448 if (QAction* action = makeActionResolveMemoryID(id.value()))
449 {
450 menu->addAction(action);
451 }
452 }
453 }
454 }
455
456 const std::optional<aron::Path> elementPath = getElementPath(item);
457 if (elementPath)
458 {
459 auto actions = makeActionsCopyDataToClipboard(elementPath.value());
460 for (const auto& action : actions)
461 {
462 if (action)
463 {
464 menu->addAction(action);
465 }
466 }
467
469 {
470 if (const std::optional<MemoryID> entityID = getCurrentEntityID())
471 {
472 std::vector<aron::Path> leafPaths;
473 try
474 {
475 if (const aron::data::DictPtr data = getData())
476 {
477 leafPaths = collectPlottableLeafPaths(
478 data->navigateAbsolute(elementPath.value()));
479 }
480 }
481 catch (const aron::error::AronException&)
482 {
483 }
484 catch (const armarx::LocalException&)
485 {
486 }
487
488 if (not leafPaths.empty())
489 {
490 menu->addAction(makeActionToggleLivePlot(entityID.value(), leafPaths));
491 }
492 }
493 }
494 }
495 return menu;
496 }
497
498 std::vector<aron::Path>
499 DataView::collectPlottableLeafPaths(const aron::data::VariantPtr& element)
500 {
501 std::vector<aron::Path> result;
502 if (not element)
503 {
504 return result;
505 }
506
507 switch (element->getDescriptor())
508 {
515 result.push_back(element->getPath());
516 break;
518 if (const auto array = aron::data::NDArray::DynamicCast(element);
519 array and
521 {
522 result.push_back(element->getPath());
523 }
524 break;
526 for (const aron::data::VariantPtr& child : element->getChildren())
527 {
528 const std::vector<aron::Path> childLeaves = collectPlottableLeafPaths(child);
529 result.insert(result.end(), childLeaves.begin(), childLeaves.end());
530 }
531 break;
532 default:
533 break;
534 }
535 return result;
536 }
537
538 QAction*
539 DataView::makeActionToggleLivePlot(const MemoryID& entityID,
540 const std::vector<aron::Path>& leafPaths)
541 {
542 std::vector<armem::client::util::MemoryValueID> ids;
543 ids.reserve(leafPaths.size());
544 for (const aron::Path& path : leafPaths)
545 {
546 ids.push_back({entityID, path});
547 }
548
549 QAction* action = new QAction(leafPaths.size() > 1
550 ? "Live plot values to Debug Observer"
551 : "Live plot to Debug Observer");
552 action->setCheckable(true);
553 action->setChecked(_livePlotController->allPlotted(ids));
554
555 if (not _livePlotController->hasDebugObserver())
556 {
557 action->setText(action->text() + " (no Debug Observer connected)");
558 action->setEnabled(false);
559 }
560
561 connect(action,
562 &QAction::toggled,
563 [this, ids](bool checked) { _livePlotController->setPlotted(ids, checked); });
564
565 return action;
566 }
567
568 void
570 {
571 if (not _livePlotController)
572 {
573 return;
574 }
575
576 const std::optional<MemoryID> entityID = getCurrentEntityID();
577
578 static const QColor highlightColor(180, 230, 180);
579
580 std::function<void(QTreeWidgetItem*)> walk = [&](QTreeWidgetItem* item)
581 {
582 bool highlight = false;
583 if (entityID)
584 {
585 if (const std::optional<aron::Path> path = getElementPath(item))
586 {
587 highlight = _livePlotController->isPlotted({entityID.value(), path.value()});
588 }
589 }
590
591 const QBrush brush = highlight ? QBrush(highlightColor) : QBrush();
592 for (int col = 0; col < tree->columnCount(); ++col)
593 {
594 item->setBackground(col, brush);
595 }
596
597 for (int i = 0; i < item->childCount(); ++i)
598 {
599 walk(item->child(i));
600 }
601 };
602 walk(treeItemData);
603 }
604
605 void
607 {
608 auto* menu = buildActionsMenu(pos);
609
610 if (menu->actions().isEmpty())
611 {
612 emit actionsMenuRequested(MemoryID(), this, tree->mapToGlobal(pos), nullptr);
613 }
614 else
615 {
616 emit actionsMenuRequested(MemoryID(), this, tree->mapToGlobal(pos), menu);
617 }
618 }
619
620 void
622 {
623 auto data = getData();
624 if (!data)
625 {
626 return;
627 }
628 if (!imageView)
629 {
630 WidgetsWithToolbar* toolbar = new WidgetsWithToolbar();
631
632 imageView = new ImageView();
633 imageView->toolbar = toolbar;
634 toolbar->addWidget(imageView);
635
636 splitter->addWidget(toolbar);
637
638 connect(toolbar, &WidgetsWithToolbar::closing, [this]() { imageView = nullptr; });
639 }
640 imageView->elementPath = elementPath;
642 }
643
644 void
646 {
647 imageView->toolbar->close();
648 imageView = nullptr;
649 }
650
651 QImage
653 {
654 const std::vector<int> shape = aron.getShape();
655 ARMARX_CHECK_EQUAL(shape.size(), 3);
656 ARMARX_CHECK_EQUAL(shape.at(2), 4) << "Expected Depth32 image to have 4 bytes per pixel.";
657
658 const int rows = shape.at(0);
659 const int cols = shape.at(1);
660
661 // Rendering seems to be optimized for RGB32
662 // rows go along 0 = height, cols go along 1 = width
663 QImage image(cols, rows, QImage::Format::Format_RGB32);
664 const float* data = reinterpret_cast<float*>(aron.getData());
665
666 auto updateLimits = [](float value, Limits& limits)
667 {
668 if (value > 0) // Exclude 0 from normalization (it may be only background)
669 {
670 limits.min = std::min(limits.min, value);
671 }
672 limits.max = std::max(limits.max, value);
673 };
674
675 // Find data range and adapt cmap.
676 Limits limits;
677 if (limitsHistory.empty())
678 {
679 const float* sourceRow = data;
680 for (int row = 0; row < rows; ++row)
681 {
682 for (int col = 0; col < cols; ++col)
683 {
684 float value = sourceRow[col];
685 updateLimits(value, limits);
686 }
687 sourceRow += cols;
688 }
689 cmap.set_vlimits(limits.min, limits.max);
690 }
691 // Only do it at the beginning and stop after enough samples were collected.
692 else if (limitsHistory.size() < limitsHistoryMaxSize)
693 {
694 simox::math::SoftMinMax softMin(0.25, limitsHistory.size());
695 simox::math::SoftMinMax softMax(0.25, limitsHistory.size());
696
697 for (auto& l : limitsHistory)
698 {
699 softMin.add(l.min);
700 softMax.add(l.max);
701 }
702
703 cmap.set_vlimits(softMin.getSoftMin(), softMax.getSoftMax());
704 }
705
706 // Update image
707 {
708 const float* sourceRow = data;
709
710 const int bytesPerLine = image.bytesPerLine();
711 uchar* targetRow = image.bits();
712
713 for (int row = 0; row < rows; ++row)
714 {
715 for (int col = 0; col < cols; ++col)
716 {
717 float value = sourceRow[col];
718 simox::Color color = value <= 0 ? simox::Color::white() : cmap(value);
719 targetRow[col * 4 + 0] = color.b;
720 targetRow[col * 4 + 1] = color.g;
721 targetRow[col * 4 + 2] = color.r;
722 targetRow[col * 4 + 3] = color.a;
723
724 updateLimits(value, limits);
725 }
726 sourceRow += cols;
727 targetRow += bytesPerLine;
728 }
729 }
731 {
732 limitsHistory.push_back(limits);
733 }
734
735 return image;
736 }
737
738 void
740 {
742
743 if (not imageView)
744 {
745 return;
746 }
747 if (not data)
748 {
750 return;
751 }
752
754 try
755 {
756 element = data->navigateAbsolute(imageView->elementPath);
757 }
758 // This can happen when the underlying entity structure changes (a new entity has been selected).
759 // In this case, we disable the image view.
760 catch (const aron::error::AronException&)
761 {
762 // showErrorMessage(e.what());
764 return;
765 }
766 catch (const armarx::LocalException&)
767 {
768 // showErrorMessage(e.what());
770 return;
771 }
772
773 NDArray::PointerType imageData = NDArray::DynamicCast(element);
774 if (not imageData)
775 {
776 showErrorMessage("Expected NDArrayNavigator, but got: " +
777 simox::meta::get_type_name(element));
778 return;
779 }
780
781 const std::vector<int> shape = imageData->getShape();
782 if (shape.size() != 3)
783 {
784 showErrorMessage("Expected array shape with 3 dimensions, but got: " +
785 NDArray::DimensionsToString(shape));
786 return;
787 }
788 const int rows = shape.at(0);
789 const int cols = shape.at(1);
790
791 using aron::type::image::PixelType;
792 std::optional<PixelType> pixelType;
793 try
794 {
795 // TODO We cannot know what the str in the pixeltype belongs to (e.g. coming from java, python, c++ it may contain different values!
796 // pixelType = aron::type::Image::pixelTypeFromName(imageData->getType());
797
798 // For now we assume it comes from c++ where '5' means CV_32FC1 (=5)
799 pixelType = (imageData->getType() == "5" ? PixelType::DEPTH32 : PixelType::RGB24);
800 }
801 catch (const aron::error::AronException&)
802 {
803 }
804
805 bool clearLimitsHistory = true;
806 std::optional<QImage> image;
807 if (pixelType)
808 {
809 switch (pixelType.value())
810 {
811 case PixelType::RGB24:
812 ARMARX_CHECK_EQUAL(shape.at(2), 3)
813 << "Expected Rgb24 image to have 3 bytes per pixel.";
814 image = QImage(imageData->getData(), cols, rows, QImage::Format::Format_RGB888);
815 break;
816
817 case PixelType::DEPTH32:
818 image = imageView->convertDepth32ToRGB32(*imageData);
819 clearLimitsHistory = false;
820 break;
821 }
822 }
823 else
824 {
825 QImage::Format format = QImage::Format_Invalid;
826 switch (shape.at(2))
827 {
828 case 1:
829 format = QImage::Format::Format_Grayscale8;
830 break;
831
832 case 3:
833 format = QImage::Format::Format_RGB888;
834 break;
835
836 default:
837 showErrorMessage("Expected 1 or 3 elements in last dimension, but got shape: " +
838 NDArray::DimensionsToString(shape));
839 return;
840 }
841 image = QImage(imageData->getData(), cols, rows, format);
842 }
843
844 ARMARX_CHECK(image.has_value());
845
846 std::stringstream title;
847 title << "Image element '" << imageView->elementPath.toString()
848 << "'"; // of entity instance " << currentInstance->id();
849 imageView->setTitle(QString::fromStdString(title.str()));
850 imageView->view->setImage(image.value());
851
852 if (clearLimitsHistory)
853 {
854 imageView->limitsHistory.clear();
855 }
856 }
857
859 cmap(simox::color::cmaps::plasma().reversed()), limitsHistoryMaxSize(32)
860 {
861 setLayout(new QHBoxLayout());
862 int margin = 2;
863 layout()->setContentsMargins(margin, margin, margin, margin);
864 if (/* DISABLES CODE */ (false))
865 {
866 QFont font = this->font();
867 font.setPointSizeF(font.pointSize() * 0.75);
868 setFont(font);
869 }
870
872 layout()->addWidget(view);
873 }
874
875} // namespace armarx::armem::gui::instance
uint8_t data[1]
std::string str(const T &t)
void setTag(const LogTag &tag)
Definition Logging.cpp:54
static std::vector< std::pair< std::string, double > > decomposeNDArray(const aron::data::NDArray &array, int maxSize=16)
Decompose a numeric NDArray (vector, matrix, pose) into scalar datafields.
Streams selected memory values to the DebugObserver for live plotting.
void updateTree(QTreeWidgetItem *parent, const aron::data::DictPtr &data)
const size_t limitsHistoryMaxSize
In this context, n.
Definition DataView.h:143
QImage convertDepth32ToRGB32(const aron::data::NDArray &aron)
Definition DataView.cpp:652
simox::ColorMap cmap
Color map to visualize depth images.
Definition DataView.h:139
std::deque< Limits > limitsHistory
History over first n extremal depth values used to calibrate the colormap.
Definition DataView.h:141
void memoryIdResolutionRequested(const MemoryID &id)
void setLivePlotController(controller::LivePlotController *controller)
Definition DataView.cpp:86
void addDataView(DataView *dataView)
Definition DataView.cpp:105
controller::LivePlotController * _livePlotController
Definition DataView.h:150
QAction * makeActionCopyMemoryID(const MemoryID &id)
Definition DataView.cpp:261
void actionsMenuRequested(const MemoryID &memoryID, QWidget *parent, const QPoint &pos, QMenu *menu)
virtual void updateData(const aron::data::DictPtr &data, aron::type::ObjectPtr aronType=nullptr)
Definition DataView.cpp:128
virtual aron::data::DictPtr getData()=0
void showErrorMessage(const std::string &message)
Definition DataView.cpp:162
virtual std::optional< MemoryID > getCurrentEntityID() const
Definition DataView.cpp:99
static std::optional< aron::Path > getElementPath(const QTreeWidgetItem *item)
Definition DataView.cpp:171
void updateImageView(const aron::data::DictPtr &data)
Definition DataView.cpp:739
void showImageView(const aron::Path &elementPath)
Definition DataView.cpp:621
aron::type::ObjectPtr currentAronType
Definition DataView.h:112
virtual QMenu * buildActionsMenu(const QPoint &pos)
Definition DataView.cpp:372
void setStatusLabel(QLabel *statusLabel)
Definition DataView.cpp:72
std::optional< MemoryID > getElementMemoryID(const aron::Path &elementPath)
Definition DataView.cpp:186
virtual void prepareTreeContextMenu(const QPoint &pos)
Definition DataView.cpp:606
A widget drawing an image in itself.
Definition ImageView.h:34
void updateTree(QTreeWidgetItem *parent, const aron::type::Dict &type, const aron::data::Dict &data)
The Path class.
Definition Path.h:36
std::string toString() const
Definition Path.cpp:127
static nlohmann::json ConvertToNlohmannJSON(const data::VariantPtr &)
A base class for aron exceptions.
Definition Exception.h:37
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
aron::Path deserializePath(const QStringList &qpath)
std::string sanitizeTypeName(const std::string &typeName)
const std::string sanitizedMemoryIDTypeName
void fromAron(const arondto::MemoryID &dto, MemoryID &bo)
std::shared_ptr< Dict > DictPtr
Definition Dict.h:42
std::shared_ptr< Variant > VariantPtr
void visitRecursive(RecursiveVisitorImplementation &v, typename RecursiveVisitorImplementation::Input &o)
std::shared_ptr< Object > ObjectPtr
Definition Object.h:36
std::shared_ptr< Variant > VariantPtr
void clearItem(QTreeWidgetItem *item)
Clear a tree widget item.
Definition gui_utils.cpp:35
int toInt(const std::string &input)
Definition Impl.cpp:41