diff --git a/scenarios/ArMemExample/config/ExampleMemory.cfg b/scenarios/ArMemExample/config/ExampleMemory.cfg index 7989108bc28741f5c638fe53de5608ecaf8c7612..251382f2af086afccf73924421ea31a2aad01017 100644 --- a/scenarios/ArMemExample/config/ExampleMemory.cfg +++ b/scenarios/ArMemExample/config/ExampleMemory.cfg @@ -143,21 +143,12 @@ ArmarX.ArMemExampleMemory.tpc.pub.MemoryListener = MemoryUpdates # ArmarX.ExampleMemory.mem.MemoryName = Example -# ArmarX.ExampleMemory.mem.ltm..buffer.storeFreq: Frequency to store the buffer to the LTM in Hz. +# ArmarX.ExampleMemory.mem.ltm.configuration: # Attributes: -# - Default: 10 +# - Default: {} # - Case sensitivity: yes # - Required: no -# ArmarX.ExampleMemory.mem.ltm..buffer.storeFreq = 10 - - -# ArmarX.ExampleMemory.mem.ltm.depthImageExtractor.Enabled: -# Attributes: -# - Default: true -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.ExampleMemory.mem.ltm.depthImageExtractor.Enabled = true +# ArmarX.ExampleMemory.mem.ltm.configuration = {} # ArmarX.ExampleMemory.mem.ltm.enabled: @@ -169,100 +160,6 @@ ArmarX.ArMemExampleMemory.tpc.pub.MemoryListener = MemoryUpdates # ArmarX.ExampleMemory.mem.ltm.enabled = false -# ArmarX.ExampleMemory.mem.ltm.exrConverter.Enabled: -# Attributes: -# - Default: true -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.ExampleMemory.mem.ltm.exrConverter.Enabled = true - - -# ArmarX.ExampleMemory.mem.ltm.imageExtractor.Enabled: -# Attributes: -# - Default: true -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.ExampleMemory.mem.ltm.imageExtractor.Enabled = true - - -# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.Enabled: -# Attributes: -# - Default: false -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.Enabled = false - - -# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.WaitingTime: Waiting time in MS after each LTM update. -# Attributes: -# - Default: -1 -# - Case sensitivity: yes -# - Required: no -# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.WaitingTime = -1 - - -# ArmarX.ExampleMemory.mem.ltm.pngConverter.Enabled: -# Attributes: -# - Default: true -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.ExampleMemory.mem.ltm.pngConverter.Enabled = true - - -# ArmarX.ExampleMemory.mem.ltm.sizeToCompressDataInMegaBytes: The size in MB to compress away the current export. Exports are numbered (lower number means newer). -# Attributes: -# - Default: 1024 -# - Case sensitivity: yes -# - Required: no -# ArmarX.ExampleMemory.mem.ltm.sizeToCompressDataInMegaBytes = 1024 - - -# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.Enabled: -# Attributes: -# - Default: false -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.Enabled = false - - -# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.MaxWaitingTime: Max Waiting time in MS after each Entity update. -# Attributes: -# - Default: -1 -# - Case sensitivity: yes -# - Required: no -# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.MaxWaitingTime = -1 - - -# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.Enabled: -# Attributes: -# - Default: false -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.Enabled = false - - -# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.WaitingTime: Waiting time in MS after each Entity update. -# Attributes: -# - Default: -1 -# - Case sensitivity: yes -# - Required: no -# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.WaitingTime = -1 - - -# ArmarX.ExampleMemory.mem.ltm.storagepath: The path to the memory storage (the memory will be stored in a seperate subfolder). -# Attributes: -# - Default: Default value not mapped. -# - Case sensitivity: yes -# - Required: no -# ArmarX.ExampleMemory.mem.ltm.storagepath = Default value not mapped. - - # ArmarX.ExampleMemory.mns.MemoryNameSystemEnabled: Whether to use (and depend on) the Memory Name System (MNS). # Set to false to use this memory as a stand-alone. # Attributes: diff --git a/scenarios/SkillProviderTest/config/SkillsMemory.cfg b/scenarios/SkillProviderTest/config/SkillsMemory.cfg index 711047a4029175550111268cf857a613c2dd48b2..8b2bf04855a21e5a8ca955da89ba3a309460241e 100644 --- a/scenarios/SkillProviderTest/config/SkillsMemory.cfg +++ b/scenarios/SkillProviderTest/config/SkillsMemory.cfg @@ -167,21 +167,12 @@ # ArmarX.SkillMemory.mem.MemoryName = Skill -# ArmarX.SkillMemory.mem.ltm..buffer.storeFreq: Frequency to store the buffer to the LTM in Hz. +# ArmarX.SkillMemory.mem.ltm.configuration: # Attributes: -# - Default: 10 +# - Default: {} # - Case sensitivity: yes # - Required: no -# ArmarX.SkillMemory.mem.ltm..buffer.storeFreq = 10 - - -# ArmarX.SkillMemory.mem.ltm.depthImageExtractor.Enabled: -# Attributes: -# - Default: true -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillMemory.mem.ltm.depthImageExtractor.Enabled = true +# ArmarX.SkillMemory.mem.ltm.configuration = {} # ArmarX.SkillMemory.mem.ltm.enabled: @@ -193,100 +184,6 @@ # ArmarX.SkillMemory.mem.ltm.enabled = false -# ArmarX.SkillMemory.mem.ltm.exrConverter.Enabled: -# Attributes: -# - Default: true -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillMemory.mem.ltm.exrConverter.Enabled = true - - -# ArmarX.SkillMemory.mem.ltm.imageExtractor.Enabled: -# Attributes: -# - Default: true -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillMemory.mem.ltm.imageExtractor.Enabled = true - - -# ArmarX.SkillMemory.mem.ltm.memFreqFilter.Enabled: -# Attributes: -# - Default: false -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillMemory.mem.ltm.memFreqFilter.Enabled = false - - -# ArmarX.SkillMemory.mem.ltm.memFreqFilter.WaitingTime: Waiting time in MS after each LTM update. -# Attributes: -# - Default: -1 -# - Case sensitivity: yes -# - Required: no -# ArmarX.SkillMemory.mem.ltm.memFreqFilter.WaitingTime = -1 - - -# ArmarX.SkillMemory.mem.ltm.pngConverter.Enabled: -# Attributes: -# - Default: true -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillMemory.mem.ltm.pngConverter.Enabled = true - - -# ArmarX.SkillMemory.mem.ltm.sizeToCompressDataInMegaBytes: The size in MB to compress away the current export. Exports are numbered (lower number means newer). -# Attributes: -# - Default: 1024 -# - Case sensitivity: yes -# - Required: no -# ArmarX.SkillMemory.mem.ltm.sizeToCompressDataInMegaBytes = 1024 - - -# ArmarX.SkillMemory.mem.ltm.snapEqFilter.Enabled: -# Attributes: -# - Default: false -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillMemory.mem.ltm.snapEqFilter.Enabled = false - - -# ArmarX.SkillMemory.mem.ltm.snapEqFilter.MaxWaitingTime: Max Waiting time in MS after each Entity update. -# Attributes: -# - Default: -1 -# - Case sensitivity: yes -# - Required: no -# ArmarX.SkillMemory.mem.ltm.snapEqFilter.MaxWaitingTime = -1 - - -# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.Enabled: -# Attributes: -# - Default: false -# - Case sensitivity: yes -# - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.Enabled = false - - -# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.WaitingTime: Waiting time in MS after each Entity update. -# Attributes: -# - Default: -1 -# - Case sensitivity: yes -# - Required: no -# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.WaitingTime = -1 - - -# ArmarX.SkillMemory.mem.ltm.storagepath: The path to the memory storage (the memory will be stored in a seperate subfolder). -# Attributes: -# - Default: Default value not mapped. -# - Case sensitivity: yes -# - Required: no -# ArmarX.SkillMemory.mem.ltm.storagepath = Default value not mapped. - - # ArmarX.SkillMemory.mns.MemoryNameSystemEnabled: Whether to use (and depend on) the Memory Name System (MNS). # Set to false to use this memory as a stand-alone. # Attributes: diff --git a/source/RobotAPI/components/ArViz/Client/Elements.cpp b/source/RobotAPI/components/ArViz/Client/Elements.cpp index f479f4ef5456fc7a88d0f3a0fa87d2e77e9aab66..d97fea3b03d55ddb82a379628197a5f04ffc3d74 100644 --- a/source/RobotAPI/components/ArViz/Client/Elements.cpp +++ b/source/RobotAPI/components/ArViz/Client/Elements.cpp @@ -107,9 +107,9 @@ namespace armarx::viz float angle = std::acos(naturalDir.dot(dir)); if (cross.squaredNorm() < 1.0e-12f) { - // Directions are almost colinear ==> Do no rotation + // Directions are almost colinear ==> Angle is either 0 or 180 deg cross = Eigen::Vector3f::UnitX(); - angle = 0.0f; + // Keep angle } Eigen::Vector3f axis = cross.normalized(); Eigen::Quaternionf ori(Eigen::AngleAxisf(angle, axis)); diff --git a/source/RobotAPI/components/ArViz/Example/ArVizExample.cpp b/source/RobotAPI/components/ArViz/Example/ArVizExample.cpp index 2c93faf7fa4a464909bd6dea214c74022571474f..e52609fa085feac2dc4ef8fc93f68127aef8b040 100644 --- a/source/RobotAPI/components/ArViz/Example/ArVizExample.cpp +++ b/source/RobotAPI/components/ArViz/Example/ArVizExample.cpp @@ -275,13 +275,18 @@ namespace armarx void fillExampleLayer(viz::Layer& layer, double timeInSeconds) { + for (int i = 0; i < 6; ++i) { - Eigen::Vector3f pos = Eigen::Vector3f::Zero(); - pos.z() = +300.0f; + Eigen::Vector3f pos = Eigen::Vector3f(-200.0, 200.0, 300); + pos.x() += -300 * i; + + Eigen::Vector3f normal = Eigen::Vector3f::Zero(); + normal(i / 2) = (i % 2 == 0 ? 1.0 : -1.0); - viz::ArrowCircle circle = viz::ArrowCircle("circle") + viz::ArrowCircle circle = viz::ArrowCircle("circle " + std::to_string(i)) .position(pos) .radius(100.0f) + .normal(normal) .width(10.0f) .color(viz::Color::fromRGBA(255, 0, 255)); diff --git a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp index bc50155edc0d42a775c63ade67e35f38e34fd8c5..985ef8171792570e6dad35d7a0abb09d78492006 100644 --- a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp +++ b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp @@ -20,6 +20,8 @@ namespace armarx::skills::provider default_params.some_float = 5; default_params.some_int = 42; default_params.some_text = "YOLO"; + default_params.some_list_of_matrices.push_back(Eigen::Matrix3f::Zero()); + //default_params.some_matrix = Eigen::Matrix3f::Zero(); return SkillDescription{ "HelloWorld", diff --git a/source/RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.xml b/source/RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.xml index 553a93ad0898ddc40d112e097af9c95ca801da55..a2423c560b8548c265af0ae14602b8771fe46218 100644 --- a/source/RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.xml +++ b/source/RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.xml @@ -1,6 +1,17 @@ <?xml version="1.0" encoding="UTF-8" ?> <AronTypeDefinition> <GenerateTypes> + <IntEnum name="HelloWorldInteEnum"> + <EnumValue key="INT_ENUM_VALUE_0" value="0" /> + <EnumValue key="INT_ENUM_VALUE_1" value="1" /> + <EnumValue key="INT_ENUM_VALUE_2" value="2" /> + <EnumValue key="INT_ENUM_VALUE_3" value="3" /> + <EnumValue key="INT_ENUM_VALUE_4" value="4" /> + <EnumValue key="INT_ENUM_VALUE_5" value="5" /> + <EnumValue key="INT_ENUM_VALUE_6" value="6" /> + <EnumValue key="INT_ENUM_VALUE_7" value="7" /> + <EnumValue key="INT_ENUM_VALUE_8" value="8" /> + </IntEnum> <Object name='armarx::skills::Example::HelloWorldAcceptedType'> <ObjectChild key='some_int'> <Int /> @@ -11,6 +22,23 @@ <ObjectChild key='some_text'> <String /> </ObjectChild> + + <ObjectChild key='some_list_of_matrices'> + <List> + <Matrix rows="3" cols="3" type="float32" /> + </List> + </ObjectChild> + + <ObjectChild key='some_dict_of_matrices'> + <Dict> + <Matrix rows="3" cols="3" type="float32" /> + </Dict> + </ObjectChild> + + <ObjectChild key='some_matrix'> + <Matrix rows="3" cols="3" type="float32" /> + </ObjectChild> + </Object> </GenerateTypes> diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt index 89a90ab482f9916ff11ad149faa1a3fc1b7d483c..b40d5a2fcf9c480a71f0576d049ad0a311813815 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt @@ -9,15 +9,22 @@ set(SOURCES aronTreeWidget/visitors/AronTreeWidgetConverter.cpp aronTreeWidget/visitors/AronTreeWidgetSetter.cpp aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp + aronTreeWidget/visitors/AronTreeWidgetContextMenu.cpp aronTreeWidget/Data.cpp + aronTreeWidget/widgets/CustomWidget.cpp + aronTreeWidget/widgets/EditMatrixWidget.cpp + aronTreeWidget/widgets/IntEnumWidget.cpp + aronTreeWidget/ListDictHelper.cpp + aronTreeWidget/widgets/QuaternionWidget.cpp aronTreeWidget/AronTreeWidgetItem.cpp aronTreeWidget/AronTreeWidgetController.cpp - aronTreeWidget/modal/AronTreeWidgetModal.cpp - aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.cpp - aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp - aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.cpp aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.cpp aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp + aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp + aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.cpp + aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.cpp + aronTreeWidget/modal/AronTreeWidgetModal.cpp + ColorPalettes.cpp SkillManagerMonitorWidgetController.cpp ) @@ -26,25 +33,29 @@ set(HEADERS aronTreeWidget/visitors/AronTreeWidgetConverter.h aronTreeWidget/visitors/AronTreeWidgetSetter.h aronTreeWidget/visitors/AronTreeWidgetModalCreator.h + aronTreeWidget/visitors/AronTreeWidgetContextMenu.h aronTreeWidget/Data.h + aronTreeWidget/widgets/NDArrayHelper.h + aronTreeWidget/widgets/EditMatrixWidget.h + aronTreeWidget/widgets/CustomWidget.h + aronTreeWidget/widgets/IntEnumWidget.h + aronTreeWidget/ListDictHelper.h + aronTreeWidget/widgets/QuaternionWidget.h aronTreeWidget/AronTreeWidgetItem.h aronTreeWidget/AronTreeWidgetController.h aronTreeWidget/modal/AronTreeWidgetModal.h - aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.h - aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.h - aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.h aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.h aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.h + aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.h + aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.h + aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.h + ColorPalettes.h SkillManagerMonitorWidgetController.h ) set(GUI_UIS SkillManagerMonitorWidget.ui - aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModal.ui - aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModal.ui - aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModal.ui aronTreeWidget/modal/text/AronTreeWidgetTextInputModal.ui - aronTreeWidget/modal/dict/AronTreeWidgetDictInputModal.ui ) # Add more libraries you depend on here, e.g. ${QT_LIBRARIES}. diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05cd7a5cc08224561af8df64cf6be2347adb3e37 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.cpp @@ -0,0 +1,32 @@ +#include "ColorPalettes.h" + +namespace armarx::gui_color_palette +{ + QPalette + getErrorPalette() + { + QPalette errorPalette; + errorPalette.setColor(QPalette::Base, Qt::red); + return errorPalette; + } + QPalette + getNormalPalette() + { + + QPalette normalPalette; + + normalPalette.setColor(QPalette::Base, Qt::white); + return normalPalette; + } + + QPalette + getIndirectErrorPalette() + { + QPalette indirectErr; + static QColor orange = QColor::fromRgb(255, 165, 0); + // orange color + indirectErr.setColor(QPalette::Base, orange); + return indirectErr; + } + +} // namespace armarx::gui_color_palette diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.h new file mode 100644 index 0000000000000000000000000000000000000000..ea2c247a9428559de4be7bdb8fc1497c14b1ea00 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/ColorPalettes.h @@ -0,0 +1,11 @@ +#pragma once +#include <QPalette> + +namespace armarx::gui_color_palette +{ + QPalette getNormalPalette(); + + QPalette getErrorPalette(); + + QPalette getIndirectErrorPalette(); +} // namespace armarx::gui_color_palette diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui index 3aa3984c65aad167af2b49e94ab34130c880c998..1e80202efb18b2aca77e8ba45b87827e362ae233 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui @@ -6,145 +6,187 @@ <rect> <x>0</x> <y>0</y> - <width>1015</width> - <height>498</height> + <width>1060</width> + <height>657</height> </rect> </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="windowTitle"> <string>SkillManagerMonitorWidget</string> </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QGroupBox" name="groupBoxActiveSkills"> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <widget class="QSplitter" name="splitter_2"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="title"> - <string>Active Skills</string> - </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <widget class="QListWidget" name="listWidgetActiveSkills"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QSplitter" name="splitter"> <property name="orientation"> - <enum>Qt::Horizontal</enum> + <enum>Qt::Vertical</enum> + </property> + <property name="childrenCollapsible"> + <bool>false</bool> </property> - <widget class="QGroupBox" name="groupBoxSkills"> + <widget class="QGroupBox" name="groupBoxActiveSkills"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="title"> - <string>Manager</string> + <string>Active Skills</string> </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Update Frequency:</string> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <widget class="QListWidget" name="listWidgetActiveSkills"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> </widget> </item> - <item row="3" column="0" colspan="3"> - <widget class="QTreeWidget" name="treeWidgetSkills"> - <column> + </layout> + </widget> + <widget class="QSplitter" name="splitter"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QGroupBox" name="groupBoxSkills"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Manager</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="2" column="0"> + <widget class="QLabel" name="label"> <property name="text"> - <string>Skill</string> + <string>Update Frequency:</string> </property> - </column> - <column> - <property name="text"> - <string>HasType</string> + </widget> + </item> + <item row="3" column="0" colspan="3"> + <widget class="QTreeWidget" name="treeWidgetSkills"> + <column> + <property name="text"> + <string>Skill</string> + </property> + </column> + <column> + <property name="text"> + <string>HasType</string> + </property> + </column> + <column> + <property name="text"> + <string>State</string> + </property> + </column> + </widget> + </item> + <item row="2" column="1"> + <widget class="QDoubleSpinBox" name="doubleSpinBoxUpdateFreq"/> + </item> + </layout> + </widget> + <widget class="QGroupBox" name="groupBoxSkillDetails"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Skill Details</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="0" colspan="4"> + <widget class="QTreeWidget" name="treeWidgetSkillDetails"> + <property name="contextMenuPolicy"> + <enum>Qt::CustomContextMenu</enum> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set> </property> - </column> - <column> + <column> + <property name="text"> + <string>Key</string> + </property> + </column> + <column> + <property name="text"> + <string>Value</string> + </property> + </column> + <column> + <property name="text"> + <string>Type</string> + </property> + </column> + <column> + <property name="text"> + <string>defaultValue</string> + </property> + </column> + </widget> + </item> + <item row="6" column="3"> + <widget class="QPushButton" name="pushButtonExecuteSkill"> <property name="text"> - <string>State</string> + <string>Request Execution</string> </property> - </column> - </widget> - </item> - <item row="2" column="1"> - <widget class="QDoubleSpinBox" name="doubleSpinBoxUpdateFreq"/> - </item> - </layout> - </widget> - <widget class="QGroupBox" name="groupBoxSkillDetails"> - <property name="title"> - <string>Skill Details</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="1" column="0" colspan="4"> - <widget class="QTreeWidget" name="treeWidgetSkillDetails"> - <column> + </widget> + </item> + <item row="0" column="0"> + <widget class="QPushButton" name="pushButtonPaste"> <property name="text"> - <string>Key</string> + <string>Set from clipboard</string> </property> - </column> - <column> + </widget> + </item> + <item row="6" column="0"> + <widget class="QPushButton" name="pushButtonStopSkill"> <property name="text"> - <string>Value</string> + <string>Stop current skill</string> </property> - </column> - <column> + </widget> + </item> + <item row="0" column="3"> + <widget class="QPushButton" name="pushButtonReset"> <property name="text"> - <string>Type</string> + <string>Reset args</string> </property> - </column> - <column> + </widget> + </item> + <item row="0" column="1"> + <widget class="QPushButton" name="pushButtonCopy"> <property name="text"> - <string>defaultValue</string> + <string>Copy args to clipboard</string> </property> - </column> - </widget> - </item> - <item row="6" column="3"> - <widget class="QPushButton" name="pushButtonExecuteSkill"> - <property name="text"> - <string>Request Execution</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QPushButton" name="pushButtonPaste"> - <property name="text"> - <string>Set from clipboard</string> - </property> - </widget> - </item> - <item row="6" column="0"> - <widget class="QPushButton" name="pushButtonStopSkill"> - <property name="text"> - <string>Stop current skill</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QPushButton" name="pushButtonReset"> - <property name="text"> - <string>Reset args</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="pushButtonCopy"> - <property name="text"> - <string>Copy args to clipboard</string> - </property> - </widget> - </item> - </layout> + </widget> + </item> + </layout> + </widget> </widget> </widget> </item> diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp index 27a954593ad99d252410ffec11d086689c1d9e07..edc9eebb6d619dd09de033ac2959b4858d263246 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp @@ -20,52 +20,57 @@ * GNU General Public License */ +#include "SkillManagerMonitorWidgetController.h" + #include <string> -#include "SkillManagerMonitorWidgetController.h" +#include <RobotAPI/libraries/skills/provider/Skill.h> -#include "aronTreeWidget/visitors/AronTreeWidgetCreator.h" #include "aronTreeWidget/visitors/AronTreeWidgetConverter.h" +#include "aronTreeWidget/visitors/AronTreeWidgetCreator.h" #include "aronTreeWidget/visitors/AronTreeWidgetModalCreator.h" -#include <RobotAPI/libraries/skills/provider/Skill.h> - // modals #include "aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.h" // debug -#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> - -#include <QDoubleSpinBox> #include <QClipboard> +#include <QDoubleSpinBox> + +#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> #include "aronTreeWidget/Data.h" //config namespace armarx { - QPointer<QDialog> SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent) + QPointer<QDialog> + SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent) { if (!dialog) { dialog = new SimpleConfigDialog(parent); - dialog->addProxyFinder<skills::manager::dti::SkillManagerInterfacePrx>("SkillManager", "", "Skill*"); + dialog->addProxyFinder<skills::manager::dti::SkillManagerInterfacePrx>( + "SkillManager", "", "Skill*"); } return qobject_cast<SimpleConfigDialog*>(dialog); } - void SkillManagerMonitorWidgetController::configured() + void + SkillManagerMonitorWidgetController::configured() { observerName = dialog->getProxyName("SkillManager"); } - void SkillManagerMonitorWidgetController::loadSettings(QSettings* settings) + void + SkillManagerMonitorWidgetController::loadSettings(QSettings* settings) { observerName = settings->value("SkillManager", "SkillManager").toString().toStdString(); } - void SkillManagerMonitorWidgetController::saveSettings(QSettings* settings) + void + SkillManagerMonitorWidgetController::saveSettings(QSettings* settings) { settings->setValue("SkillManager", QString::fromStdString(observerName)); } -} +} // namespace armarx // Others namespace armarx @@ -81,29 +86,40 @@ namespace armarx widget.doubleSpinBoxUpdateFreq->setSuffix(" Hz"); refreshSkillsResultTimer = new QTimer(this); - refreshSkillsResultTimer->setInterval(1000 / 5); // Keep this stable. + refreshSkillsResultTimer->setInterval(1000 / 5); // Keep this stable. refreshSkillsResultTimer->start(); - connect(widget.doubleSpinBoxUpdateFreq, &QDoubleSpinBox::editingFinished, - this, &SkillManagerMonitorWidgetController::updateTimerFrequency); - connect(refreshSkillsResultTimer, &QTimer::timeout, - this, &SkillManagerMonitorWidgetController::refreshSkills); - - connect(widget.pushButtonCopy, &QPushButton::clicked, - this, &SkillManagerMonitorWidgetController::copyCurrentConfig); - connect(widget.pushButtonPaste, &QPushButton::clicked, - this, &SkillManagerMonitorWidgetController::pasteCurrentConfig); - - connect(widget.pushButtonExecuteSkill, &QPushButton::clicked, - this, &SkillManagerMonitorWidgetController::executeSkill); - connect(widget.pushButtonStopSkill, &QPushButton::clicked, - this, &SkillManagerMonitorWidgetController::stopSkill); - - connect(widget.treeWidgetSkills, &QTreeWidget::currentItemChanged, - this, &SkillManagerMonitorWidgetController::skillSelectionChanged); - - connect(widget.treeWidgetSkillDetails, &QTreeWidget::itemDoubleClicked, - this, &SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked); + connect(widget.doubleSpinBoxUpdateFreq, + &QDoubleSpinBox::editingFinished, + this, + &SkillManagerMonitorWidgetController::updateTimerFrequency); + connect(refreshSkillsResultTimer, + &QTimer::timeout, + this, + &SkillManagerMonitorWidgetController::refreshSkills); + + connect(widget.pushButtonCopy, + &QPushButton::clicked, + this, + &SkillManagerMonitorWidgetController::copyCurrentConfig); + connect(widget.pushButtonPaste, + &QPushButton::clicked, + this, + &SkillManagerMonitorWidgetController::pasteCurrentConfig); + + connect(widget.pushButtonExecuteSkill, + &QPushButton::clicked, + this, + &SkillManagerMonitorWidgetController::executeSkill); + connect(widget.pushButtonStopSkill, + &QPushButton::clicked, + this, + &SkillManagerMonitorWidgetController::stopSkill); + + connect(widget.treeWidgetSkills, + &QTreeWidget::currentItemChanged, + this, + &SkillManagerMonitorWidgetController::skillSelectionChanged); } SkillManagerMonitorWidgetController::~SkillManagerMonitorWidgetController() @@ -111,25 +127,38 @@ namespace armarx } - void SkillManagerMonitorWidgetController::onInitComponent() + void + SkillManagerMonitorWidgetController::reconnectToSkillManager() + { + if (connected) + { + getProxy(manager, observerName, 1000); + } + } + + void + SkillManagerMonitorWidgetController::onInitComponent() { usingProxy(observerName); } - void SkillManagerMonitorWidgetController::onConnectComponent() + void + SkillManagerMonitorWidgetController::onConnectComponent() { - getProxy(manager, observerName); widget.groupBoxSkills->setTitle(QString::fromStdString(observerName)); - widget.treeWidgetSkillDetails->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers); + widget.treeWidgetSkillDetails->setEditTriggers( + QAbstractItemView::EditTrigger::NoEditTriggers); widget.treeWidgetSkillDetails->setColumnHidden(3, true); connected = true; } - void SkillManagerMonitorWidgetController::onDisconnectComponent() + void + SkillManagerMonitorWidgetController::onDisconnectComponent() { connected = false; + manager = nullptr; // reset all skills.clear(); @@ -140,25 +169,30 @@ namespace armarx selectedSkill.skillName = ""; } - void SkillManagerMonitorWidgetController::updateTimerFrequency() + void + SkillManagerMonitorWidgetController::updateTimerFrequency() { int f = static_cast<int>(std::round(1000 / widget.doubleSpinBoxUpdateFreq->value())); refreshSkillsResultTimer->setInterval(f); } - void SkillManagerMonitorWidgetController::refreshSkills() + void + SkillManagerMonitorWidgetController::refreshSkills() { - static std::map<skills::provider::dto::Execution::Status, std::string> ExecutionStatus2String = { - {skills::provider::dto::Execution::Status::Aborted, "Aborted"}, - {skills::provider::dto::Execution::Status::Failed, "Failed"}, - {skills::provider::dto::Execution::Status::Idle, "Not yet started"}, - {skills::provider::dto::Execution::Status::Running, "Running"}, - {skills::provider::dto::Execution::Status::Scheduled, "Scheduled"}, - {skills::provider::dto::Execution::Status::Succeeded, "Succeeded"} - }; - - if (!connected) + static std::map<skills::provider::dto::Execution::Status, std::string> + ExecutionStatus2String = { + {skills::provider::dto::Execution::Status::Aborted, "Aborted"}, + {skills::provider::dto::Execution::Status::Failed, "Failed"}, + {skills::provider::dto::Execution::Status::Idle, "Not yet started"}, + {skills::provider::dto::Execution::Status::Running, "Running"}, + {skills::provider::dto::Execution::Status::Scheduled, "Scheduled"}, + {skills::provider::dto::Execution::Status::Succeeded, "Succeeded"}}; + + if (!manager) + { + reconnectToSkillManager(); return; + } /* CHECK OWN SKILLS LIST */ // remove non-existing ones @@ -196,7 +230,9 @@ namespace armarx while (i < widget.treeWidgetSkills->topLevelItemCount()) { QTreeWidgetItem* item = widget.treeWidgetSkills->topLevelItem(i); - if (std::find(removedProviders.begin(), removedProviders.end(), item->text(0).toStdString()) != removedProviders.end()) + if (std::find(removedProviders.begin(), + removedProviders.end(), + item->text(0).toStdString()) != removedProviders.end()) { delete widget.treeWidgetSkills->takeTopLevelItem(i); } @@ -209,7 +245,8 @@ namespace armarx // add new providers for (const auto& [providerName, providerSkills] : skills) { - if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName); it != newProviders.end()) + if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName); + it != newProviders.end()) { auto item = new QTreeWidgetItem(widget.treeWidgetSkills); item->setText(0, QString::fromStdString(providerName)); @@ -225,7 +262,7 @@ namespace armarx // update status and active skills window std::map<skills::SkillID, std::string> activeSkillsAndPrefixes; auto managerStatuses = manager->getSkillExecutionStatuses(); - for (int i = 0; i < widget.treeWidgetSkills->topLevelItemCount(); ++i) + for (int i = 0; i < widget.treeWidgetSkills->topLevelItemCount(); ++i) { try { @@ -240,11 +277,15 @@ namespace armarx skills::SkillID currentSkillId(providerName, skillItem->text(0).toStdString()); auto statusForSkill = allStatusesForProvider.at(currentSkillId.skillName); - skillItem->setText(2, QString::fromStdString(ExecutionStatus2String.at(statusForSkill.header.status))); + skillItem->setText(2, + QString::fromStdString(ExecutionStatus2String.at( + statusForSkill.header.status))); - if (not statusForSkill.header.executorName.empty()) // it means that the skill was called by someone + if (not statusForSkill.header.executorName + .empty()) // it means that the skill was called by someone { - activeSkillsAndPrefixes.insert({currentSkillId, statusForSkill.header.executorName}); + activeSkillsAndPrefixes.insert( + {currentSkillId, statusForSkill.header.executorName}); } } } @@ -261,7 +302,8 @@ namespace armarx { auto prefixedStr = id.toString(prefix); bool longest = true; - for (const auto& [id2, prefix2] : activeSkillsAndPrefixes) // check if there is a deeper skill currently executing + for (const auto& [id2, prefix2] : + activeSkillsAndPrefixes) // check if there is a deeper skill currently executing { auto prefixedStr2 = id.toString(prefix2); if (prefixedStr == prefixedStr2) @@ -278,12 +320,14 @@ namespace armarx if (longest) { - widget.listWidgetActiveSkills->addItem(QString::fromStdString(id.toString() + ": " + id.toString(prefix))); + widget.listWidgetActiveSkills->addItem( + QString::fromStdString(id.toString() + ": " + id.toString(prefix))); } } } - void SkillManagerMonitorWidgetController::executeSkill() + void + SkillManagerMonitorWidgetController::executeSkill() { if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty()) { @@ -307,12 +351,14 @@ namespace armarx exInfo.skillId = {selectedSkill.providerName, selectedSkill.skillName}; exInfo.params = aron::data::Dict::ToAronDictDTO(data); - ARMARX_IMPORTANT << "Executing skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName << ". The data was: " << data; + ARMARX_IMPORTANT << "Executing skill from GUI: " << selectedSkill.providerName << "/" + << selectedSkill.skillName << ". The data was: " << data; // Note that we execute the skill in a seperate thread so that the GUI thread does not freeze. manager->begin_executeSkill(exInfo); } - void SkillManagerMonitorWidgetController::stopSkill() + void + SkillManagerMonitorWidgetController::stopSkill() { if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty()) { @@ -325,11 +371,14 @@ namespace armarx return; } - ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName; + ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.providerName << "/" + << selectedSkill.skillName; manager->abortSkill(selectedSkill.providerName, selectedSkill.skillName); } - void SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem*) + void + SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, + QTreeWidgetItem*) { widget.groupBoxSkillDetails->setEnabled(false); @@ -352,10 +401,12 @@ namespace armarx newSelectedSkill.skillName = current->text(0).toStdString(); // setup groupBox - widget.groupBoxSkillDetails->setTitle(QString::fromStdString(newSelectedSkill.providerName + "/" + newSelectedSkill.skillName)); + widget.groupBoxSkillDetails->setTitle(QString::fromStdString( + newSelectedSkill.providerName + "/" + newSelectedSkill.skillName)); widget.groupBoxSkillDetails->setEnabled(true); - if (newSelectedSkill.providerName == selectedSkill.providerName and newSelectedSkill.skillName == selectedSkill.skillName) + if (newSelectedSkill.providerName == selectedSkill.providerName and + newSelectedSkill.skillName == selectedSkill.skillName) { return; } @@ -370,37 +421,46 @@ namespace armarx auto skillDesc = skills.at(selectedSkill.providerName).at(selectedSkill.skillName); { - auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, - {QString::fromStdString("Name"), QString::fromStdString(skillDesc.skillName)}); + auto it = new QTreeWidgetItem( + widget.treeWidgetSkillDetails, + {QString::fromStdString("Name"), QString::fromStdString(skillDesc.skillName)}); widget.treeWidgetSkillDetails->addTopLevelItem(it); } { - auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, - {QString::fromStdString("Robot"), QString::fromStdString(simox::alg::join(skillDesc.robots, ", "))}); + auto it = new QTreeWidgetItem( + widget.treeWidgetSkillDetails, + {QString::fromStdString("Robot"), + QString::fromStdString(simox::alg::join(skillDesc.robots, ", "))}); widget.treeWidgetSkillDetails->addTopLevelItem(it); } { auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, - {QString::fromStdString("Description"), QString::fromStdString(skillDesc.description)}); + {QString::fromStdString("Description"), + QString::fromStdString(skillDesc.description)}); widget.treeWidgetSkillDetails->addTopLevelItem(it); } { - auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, - {QString::fromStdString("Timeout"), QString::fromStdString(std::to_string(skillDesc.timeoutMs)) + " ms"}); + auto it = new QTreeWidgetItem( + widget.treeWidgetSkillDetails, + {QString::fromStdString("Timeout"), + QString::fromStdString(std::to_string(skillDesc.timeoutMs)) + " ms"}); widget.treeWidgetSkillDetails->addTopLevelItem(it); } - skillsArgumentsTreeWidgetItem = new QTreeWidgetItem(widget.treeWidgetSkillDetails, {QString::fromStdString("Arguments")}); + skillsArgumentsTreeWidgetItem = new QTreeWidgetItem(widget.treeWidgetSkillDetails, + {QString::fromStdString("Arguments")}); auto aron_args = aron::type::Object::FromAronObjectDTO(skillDesc.acceptedType); auto default_args = aron::data::Dict::FromAronDictDTO(skillDesc.defaultParams); - aronTreeWidgetController = std::make_shared<AronTreeWidgetController>(widget.treeWidgetSkillDetails, skillsArgumentsTreeWidgetItem, aron_args, default_args); + aronTreeWidgetController = std::make_shared<AronTreeWidgetController>( + widget.treeWidgetSkillDetails, skillsArgumentsTreeWidgetItem, aron_args, default_args); } - aron::data::DictPtr SkillManagerMonitorWidgetController::getConfigAsAron() const + aron::data::DictPtr + SkillManagerMonitorWidgetController::getConfigAsAron() const { // create argument aron (if there is an accepted type set) if (aronTreeWidgetController) @@ -410,7 +470,8 @@ namespace armarx return nullptr; } - void SkillManagerMonitorWidgetController::copyCurrentConfig() + void + SkillManagerMonitorWidgetController::copyCurrentConfig() { auto data = getConfigAsAron(); if (!data) @@ -423,7 +484,8 @@ namespace armarx clipboard->setText(QString::fromStdString(json.dump(2))); } - void SkillManagerMonitorWidgetController::pasteCurrentConfig() + void + SkillManagerMonitorWidgetController::pasteCurrentConfig() { QClipboard* clipboard = QApplication::clipboard(); std::string s = clipboard->text().toStdString(); @@ -438,34 +500,10 @@ namespace armarx aronTreeWidgetController->setFromAron(data); } - void SkillManagerMonitorWidgetController::resetCurrentConfig() + void + SkillManagerMonitorWidgetController::resetCurrentConfig() { // TODO } - void SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column) - { - if (!item) - { - return; - } - - if (column == 1) - { - if (item->flags() & Qt::ItemIsEditable) // we use the flag to indicate whether the item is editable or not - { - // we assume its aron item - AronTreeWidgetItem* aItem = AronTreeWidgetItem::DynamicCastAndCheck(item); - std::string name = aItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME).toStdString(); - std::string type = aItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_TYPE).toStdString(); - - // why visitor?!?!? - AronTreeWidgetModalCreatorVisitor v(name, aItem, widget.treeWidgetSkillDetails); - aron::type::visit(v, aItem->aronType); - auto modal = v.createdModal; - modal->exec(); - } - } - } -} - +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h index 64256f2d6530d766726df37ec5fc60c9429d3e70..d9a9379bdfdea0ee56c9c5f3e601ef68a5ce75b5 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h @@ -22,25 +22,24 @@ #pragma once #include <stack> -#include <vector> #include <thread> +#include <vector> + +#include <QTimer> + #include <ArmarXCore/core/system/ImportExportComponent.h> -#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> #include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> #include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h> -#include <RobotAPI/interface/skills/SkillMemoryInterface.h> - #include <RobotAPI/gui-plugins/SkillManagerPlugin/ui_SkillManagerMonitorWidget.h> - -#include "aronTreeWidget/AronTreeWidgetController.h" - -#include <RobotAPI/libraries/aron/core/type/variant/All.h> +#include <RobotAPI/interface/skills/SkillMemoryInterface.h> #include <RobotAPI/libraries/aron/core/data/variant/All.h> +#include <RobotAPI/libraries/aron/core/type/variant/All.h> #include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h> -#include <QTimer> +#include "aronTreeWidget/AronTreeWidgetController.h" namespace armarx { @@ -71,6 +70,8 @@ namespace armarx return "Skills.Manager"; } + void reconnectToSkillManager(); + void onInitComponent() override; void onConnectComponent() override; void onDisconnectComponent() override; @@ -88,7 +89,6 @@ namespace armarx void pasteCurrentConfig(); void resetCurrentConfig(); - void onTreeWidgetItemDoubleClicked(QTreeWidgetItem * item, int column); private: aron::data::DictPtr getConfigAsAron() const; @@ -120,11 +120,13 @@ namespace armarx AronTreeWidgetControllerPtr aronTreeWidgetController = nullptr; // others - std::atomic_bool connected = false; QTimer* refreshSkillsResultTimer; // skillExecutions std::vector<std::thread> executions; + + // connected flag + std::atomic_bool connected = false; }; } diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/TODO b/source/RobotAPI/gui-plugins/SkillManagerPlugin/TODO new file mode 100644 index 0000000000000000000000000000000000000000..d25aead078c039b5724f9a6f05abe669ed1caf50 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/TODO @@ -0,0 +1,3 @@ +- keep set values around to not loose precision of values that have not been manipulated (in AronTreeWidgetItem, as well as Matrix and Quaternion) +- get rid of any todos present + diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.cpp index 0ef63ff506ebb1f624f7380e61309f02c522b915..52110b494a2bfc38a361d8354eb18efccc760617 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.cpp @@ -1,43 +1,62 @@ #include "AronTreeWidgetController.h" +#include <RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h> + +#include "visitors/AronTreeWidgetContextMenu.h" #include "visitors/AronTreeWidgetConverter.h" #include "visitors/AronTreeWidgetSetter.h" + namespace armarx { - AronTreeWidgetController::AronTreeWidgetController(QTreeWidget* tree, QTreeWidgetItem* parent, const aron::type::ObjectPtr& type, const aron::data::DictPtr& data): - parent(parent), - tree(tree), - type(type) + AronTreeWidgetController::AronTreeWidgetController(QTreeWidget* tree, + QTreeWidgetItem* parent, + const aron::type::ObjectPtr& type, + const aron::data::DictPtr& data) : + parent(parent), tree(tree), type(type) { - if (type) // if there is a type set, we create a tree widget from the typp + connect(tree, + SIGNAL(customContextMenuRequested(const QPoint&)), + this, + SLOT(ShowContextMenu(const QPoint&))); + connect(tree, + &QTreeWidget::itemDoubleClicked, + this, + &AronTreeWidgetController::onTreeWidgetItemDoubleClicked); + + if (type) // if there is a type set, we create a tree widget from the type { - AronTreeWidgetCreatorVisitor v; + AronTreeWidgetCreatorVisitor v(parent); + v.setTopLevelWidget(tree); aron::type::visit(v, type); - if (v.createdQWidgetItem) - { - parent->addChild(v.createdQWidgetItem); - } - if (data) // check if there is a default argument set. Prefill the GUI with it { setFromAron(data); } } - else if(data) // there is no type but a default configuration. Prefill the GUI with the default arguments + // there is no type but a default configuration. Prefill the GUI with the default arguments + else if (data) { + // TODO: There is no visitor for that (yet)... // create type from data, ... } else { new QTreeWidgetItem(parent, {QString::fromStdString("No args")}); } + + // connect change handling after args init + connect(tree, + &QTreeWidget::itemChanged, + this, + &AronTreeWidgetController::onTreeWidgetItemChanged); } - aron::data::DictPtr AronTreeWidgetController::convertToAron() const + aron::data::DictPtr + AronTreeWidgetController::convertToAron() const { - if (parent) + if (parent && type) { AronTreeWidgetConverterVisitor v(parent, 0); aron::type::visit(v, type); @@ -48,7 +67,8 @@ namespace armarx return nullptr; } - void AronTreeWidgetController::setFromAron(const aron::data::DictPtr& data) + void + AronTreeWidgetController::setFromAron(const aron::data::DictPtr& data) { if (parent) { @@ -56,4 +76,87 @@ namespace armarx aron::data::visit(v, data); } } -} + void + AronTreeWidgetController::ShowContextMenu(const QPoint& pos) + { + tree->blockSignals(true); + + auto idx = tree->indexAt(pos); + AronTreeWidgetItem* clickedItem = AronTreeWidgetItem::DynamicCast(tree->itemAt(pos)); + if (clickedItem) + { + AronTreeWidgetContextMenuVisitor visitor(clickedItem, pos, tree, idx.row()); + + aron::type::visit(visitor, clickedItem->aronType); + visitor.showMenuAndExecute(); + } + + tree->blockSignals(false); + } + void + AronTreeWidgetController::onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column) + { + if (!item) + { + return; + } + tree->blockSignals(true); + + auto* aronItem = AronTreeWidgetItem::DynamicCast(item); + if (column == 1 && aronItem) + { + + + std::string name = + aronItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME).toStdString(); + // depending on aron type, create extra gui element. + AronTreeWidgetModalCreatorVisitor v(name, aronItem, tree); + aron::type::visit(v, aronItem->aronType); + auto modal = v.createdModal; + + // if no modal is created, we instead use the edit field directly + if (modal) + { + modal->exec(); + } + else if (aronItem->col1Editable) + { + item->treeWidget()->editItem(item, column); + } + } + else if (column == 0 && aronItem && aronItem->col0Editable) + { + item->treeWidget()->editItem(item, column); + } + + tree->blockSignals(false); + } + + void + AronTreeWidgetController::onTreeWidgetItemChanged(QTreeWidgetItem* item, int column) + { + tree->blockSignals(true); + + auto* aronElem = AronTreeWidgetItem::DynamicCast(item); + if (aronElem) + { + aronElem->onUserChange(column); + } + // start conversion for entire tree -- this also sets the highlighting + if (parent->childCount() == 1) + { + auto* aronTreeRoot = AronTreeWidgetItem::DynamicCast(parent->child(0)); + aronTreeRoot->resetError(); + if (aronTreeRoot) + { + AronTreeWidgetConverterVisitor v(parent, 0); + aron::type::visit(v, type); + aronTreeRoot->setValueErrorState(v.hasDirectError(), v.onlyChildFailedConversion()); + } + } + // else perhaps the GUI was stopped or died. + + tree->blockSignals(false); + } + +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.h index c70b0277b41684a7144319a3c9d07fcf7dd31668..c3c2c9c2c913fba11fdd4dfc362e98297c4338f4 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetController.h @@ -1,24 +1,30 @@ #pragma once #include <stack> -#include <ArmarXCore/core/system/ImportExportComponent.h> -#include "Data.h" +#include <QTreeWidget> + +#include <ArmarXCore/core/system/ImportExportComponent.h> -#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> #include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> -#include <QTreeWidget> -#include "visitors/AronTreeWidgetCreator.h" #include "AronTreeWidgetItem.h" +#include "Data.h" +#include "visitors/AronTreeWidgetCreator.h" namespace armarx { - class AronTreeWidgetController + // Main controller for any AronTreeWidget GUI. It attaches itself to the parent and needs the active widget. + // It's responsible to handle all signals for non-widget fields and click events. + class AronTreeWidgetController : public QObject { - + Q_OBJECT public: - AronTreeWidgetController(QTreeWidget* tree, QTreeWidgetItem* parent, const aron::type::ObjectPtr& type, const aron::data::DictPtr& data = nullptr); + AronTreeWidgetController(QTreeWidget* tree, + QTreeWidgetItem* parent, + const aron::type::ObjectPtr& type, + const aron::data::DictPtr& data = nullptr); aron::data::DictPtr convertToAron() const; void setFromAron(const aron::data::DictPtr&); @@ -28,7 +34,19 @@ namespace armarx QTreeWidget* tree; aron::type::ObjectPtr type; + + private slots: + // allows most primitive fields to be directly editable in the tree + // only String will open up a new widget + void onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column); + // check the new user input. Maybe undo if the field must not be edited. + // Also highlight if the input cannot be parsed. (Or the errors are now fixed) + void onTreeWidgetItemChanged(QTreeWidgetItem* item, int column); + + public slots: + // hook for items to show a context menu (add / delete element) + void ShowContextMenu(const QPoint&); }; using AronTreeWidgetControllerPtr = std::shared_ptr<AronTreeWidgetController>; -} +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.cpp index e53161bb8b2ee4aee0c34ac2fc82c3214894f0cd..29d895f7b0f9666ebf42acd2bf3046ac90d7f1db 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.cpp @@ -1,21 +1,24 @@ #include "AronTreeWidgetItem.h" +#include <QAction> +#include <QMenu> + #include <RobotAPI/libraries/aron/core/type/variant/All.h> +#include "../ColorPalettes.h" +#include "visitors/AronTreeWidgetConverter.h" +#include "widgets/CustomWidget.h" + namespace armarx { - AronTreeWidgetItem* AronTreeWidgetItem::DynamicCast(QTreeWidgetItem* i) + AronTreeWidgetItem* + AronTreeWidgetItem::DynamicCast(QTreeWidgetItem* i) { return dynamic_cast<AronTreeWidgetItem*>(i); } - AronTreeWidgetItem* AronTreeWidgetItem::copy() - { - AronTreeWidgetItem* ret = new AronTreeWidgetItem(*this); - return ret; - } - - AronTreeWidgetItem* AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem* i) + AronTreeWidgetItem* + AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem* i) { if (!i) { @@ -25,4 +28,174 @@ namespace armarx ARMARX_CHECK_NOT_NULL(c); return c; } -} + + bool + AronTreeWidgetItem::isValueErrorneous() + { + return itemValueError; + } + + void + AronTreeWidgetItem::setValueErrorState(bool isErrorSource, bool isTransitiveError) + { + itemValueError |= isErrorSource; + transitiveValueError |= isTransitiveError; + + + if (CustomWidget::DynamicCast(treeWidget()->itemWidget(this, 1))) + { + // The widgets handle errors themselves + return; + } + auto palette = gui_color_palette::getNormalPalette(); + if (itemValueError) + { + palette = gui_color_palette::getErrorPalette(); + } + else if (transitiveValueError) + { + palette = gui_color_palette::getIndirectErrorPalette(); + } + + QTreeWidgetItem::setBackground(1, QBrush(palette.color(QPalette::Base))); + } + + void + AronTreeWidgetItem::setKeyErrorState(bool hasError) + { + ARMARX_CHECK(col0Editable); //only editable keys should call this function! + auto palette = + hasError ? gui_color_palette::getErrorPalette() : gui_color_palette::getNormalPalette(); + + keyValueError = hasError; + + QTreeWidgetItem::setBackground(1, QBrush(palette.color(QPalette::Base))); + } + + void + AronTreeWidgetItem::resetError() + { + keyValueError = false; + itemValueError = false; + transitiveValueError = false; + // also reset children + for (int i = 0; i < childCount(); ++i) + { + auto* arChild = AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem::child(i)); + arChild->resetError(); + } + } + + + void + AronTreeWidgetItem::checkKeyValidityOfChildren() + { + ARMARX_CHECK(aronType->getDescriptor() == aron::type::Descriptor::DICT); + // return if check failed + if (aronType->getDescriptor() != aron::type::Descriptor::DICT) + { + return; + } + // iterate through children; memorize keys + std::map<QString, std::vector<int>> found_keys; + auto numChildren = childCount(); + for (int i = 0; i < numChildren; ++i) + { + auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i)); + if (!casted) + { + // soft error here, we already report it above. - Definetly programming error + continue; + } + auto& vec = found_keys[casted->text(0)]; + vec.push_back(i); + } + // highlight keys that conflict + // memorize children that are not ok + std::set<int> errorneous_indices; + for (auto [key, vals] : found_keys) + { + if (vals.size() > 1) + { + for (int i : vals) + { + auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i)); + if (!casted) + { + // soft error here, we already report it above. - Definetly programming error + continue; + } + casted->setKeyErrorState(true); + errorneous_indices.emplace(i); + } + } + } + // clear potential error state of other elements + for (int i = 0; i < numChildren; ++i) + { + if (errorneous_indices.find(i) != errorneous_indices.end()) + { + continue; + } + auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i)); + if (!casted) + { + // soft error here, we already report it above. - Definetly programming error + continue; + } + casted->setKeyErrorState(false); + } + } + + void + AronTreeWidgetItem::onUserChange(int changedColumn) + { + QTreeWidgetItem* qParent = QTreeWidgetItem::parent(); + ARMARX_CHECK(qParent); + AronTreeWidgetItem* aronParent = DynamicCast(qParent); + if (changedColumn == 0) + { + if (col0Editable) + { + // Topmost should always be an Object and col0 is not editable in the child then... + // -> aronParent should never be nullptr + ARMARX_CHECK(aronParent); + // check if the element is child of a dict. If so, validate uniqueness of keys + if (aronParent->aronType->getDescriptor() == aron::type::Descriptor::DICT) + { + aronParent->checkKeyValidityOfChildren(); + } + } + else + { + // maybe while editing keys, we try to edit a key that should not change by tabbing. + // Catch that here and undo the edit + preventIllegalKeyChange(); + } + } + } + + void + AronTreeWidgetItem::preventIllegalKeyChange() + { + if (!col0Editable) + { + setText(0, unchangeableKey); + } + } + + AronTreeWidgetItem::AronTreeWidgetItem(bool editKey, + bool editVal, + QString key, + aron::type::VariantPtr type) : + aronType(type), col0Editable(editKey), col1Editable(editVal) + { + this->setText(0, key); + // add hook to check for edited keys for children of dictionaries + if (!editKey) + { + unchangeableKey = std::move(key); + } + } + +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.h index 3d6d0c2a329c5a4376fb24a406dadf706d6b898b..9106cb3192526f15355445deb0c6f1654921c17a 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/AronTreeWidgetItem.h @@ -1,39 +1,65 @@ #pragma once -#include <stack> -#include <ArmarXCore/core/system/ImportExportComponent.h> +#include <QTreeWidget> -#include "Data.h" +#include <ArmarXCore/core/system/ImportExportComponent.h> -#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> #include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> #include <RobotAPI/libraries/aron/core/type/variant/Variant.h> -#include <QTreeWidget> +#include "Data.h" namespace armarx { + // Internal derived QtTreeWidgetItem class. Contains additional information to compare its data agains aron types. + // It contains 3 columns: Key ; Value ; Type + // The key can only be edited if the parent object is a dict class AronTreeWidgetItem : public QObject, public QTreeWidgetItem { Q_OBJECT public: - AronTreeWidgetItem(const AronTreeWidgetItem& other) : - QObject(), - QTreeWidgetItem(other) - { - aronType = other.aronType; - } + AronTreeWidgetItem(bool editKey, bool editVal, QString key, aron::type::VariantPtr type); using QTreeWidgetItem::QTreeWidgetItem; - AronTreeWidgetItem* copy(); // differs from clone!!!! - static AronTreeWidgetItem* DynamicCast(QTreeWidgetItem*); - static AronTreeWidgetItem* DynamicCastAndCheck(QTreeWidgetItem*); aron::type::VariantPtr aronType; + // if editing the first column should be allowed + const bool col0Editable = false; + // if editing the second column should be allowed + const bool col1Editable = false; + + bool isValueErrorneous(); + // marks the gui in a specific color. Also stores if there is currently an error. + // the only way to reset the color back to normal is with resetError() (error is sticky) + void setValueErrorState(bool isErrorSource, bool isTransitiveError); + void setKeyErrorState(bool hasError); + // reset error storage that influences coloring for this and all children + void resetError(); + + // Checks if the children of a dict are unique + // should not be called on other types! (does nothing then) + void checkKeyValidityOfChildren(); + + // main logic on changes. Gets called from the onTreeWidgetItemChanged() slot in AronTreeWidgetController. + // (This class cannot directly consume this signal, at least I did not find a nice way...) + void onUserChange(int changedColumn); + + private: + // because the editable keyword counts for all columns, it is possible to TAB into uneditable keys. + // We do not want those to change, so just change them back once they finished editing. + void preventIllegalKeyChange(); + bool itemValueError = false; + bool transitiveValueError = false; + bool keyValueError = false; + // hacky storage of previous key value for items that usually should not be editable. + // Problem: Dict-keys are editable, one can tab from that to any other value field and edit it. + // Fix: Once the change is commited, the AronTreeWidgetController notices the change and checks if it was allowed. + QString unchangeableKey = ""; }; -} +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9866e8bc9f8c35a00e6411331461511e4c031e9f --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.cpp @@ -0,0 +1,28 @@ +#include "ListDictHelper.h" + +namespace armarx::misc +{ + QString + generateNumElementsText(int num) + { + QString numElemsText = "<"; + if (num == 0) + { + numElemsText.append("no"); + } + else + { + numElemsText.append(QString::number(num)); + } + if (num > 1 || num == 0) + { + numElemsText.append(" elements>"); + } + else + { + numElemsText.append(" element>"); + } + return numElemsText; + } + +} // namespace armarx::misc diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..c5d991ad2861aef5c32fc82c033c9090070f13b5 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/ListDictHelper.h @@ -0,0 +1,8 @@ +#include <QString> + + +namespace armarx::misc +{ + // helper that generates a string on how many items are available + QString generateNumElementsText(int num); +} // namespace armarx::misc diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp index f7d83d98b6cde491cad878822b69b50adb34d355..71a88e54fcf49d77ea5de6804ef06a11e90e6ae8 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp @@ -1,6 +1,7 @@ #include "AronTreeWidgetDictInputModalController.h" #include <RobotAPI/libraries/aron/core/type/variant/All.h> + #include "../../visitors/AronTreeWidgetCreator.h" namespace armarx @@ -29,7 +30,7 @@ namespace armarx { for (const auto& added : addedItems) { - item->addChild(added->copy()); + //item->addChild(added->copy()); } AronTreeWidgetModal::submit(); @@ -59,12 +60,14 @@ namespace armarx auto d = aron::type::Dict::DynamicCastAndCheck(t); auto ac = d->getAcceptedType(); - AronTreeWidgetCreatorVisitor v; + AronTreeWidgetCreatorVisitor v(nullptr); + v.setTopLevelWidget(widget.treeWidgetDict); aron::type::visit(v, ac); if (v.createdQWidgetItem) { - v.createdQWidgetItem->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME, s); + v.createdQWidgetItem->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME, + s); addedItems.push_back(v.createdQWidgetItem); widget.treeWidgetDict->addTopLevelItem(v.createdQWidgetItem); } diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98e271cd81c8180af051e094169f63b58176b0e8 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.cpp @@ -0,0 +1,243 @@ +#include "AronTreeWidgetContextMenu.h" + +#include <QMenu> +#include <QPoint> +#include <QTreeWidget> +#include <QTreeWidgetItem> + +#include "../AronTreeWidgetItem.h" +#include "../ListDictHelper.h" +#include "AronTreeWidgetCreator.h" + +namespace armarx +{ + AronTreeWidgetContextMenuVisitor::AronTreeWidgetContextMenuVisitor( + AronTreeWidgetItem* i, + const QPoint& pos, + QTreeWidget* contextMenuParent, + int x) : + parentItem(i), contextMenuParent(contextMenuParent), pos(pos), index(x) + { + } + + void + AronTreeWidgetContextMenuVisitor::addDeleteAction() + { + auto* castedParent = AronTreeWidgetItem::DynamicCast(parentItem->QTreeWidgetItem::parent()); + if (!castedParent) + { + // must be top level element + return; + } + auto aronType = castedParent->aronType->getDescriptor(); + if (aron::type::Descriptor::DICT == aronType || aron::type::Descriptor::LIST == aronType) + { + QMenu contextMenu("Context menu", contextMenuParent); + actions.emplace_back("remove element", contextMenuParent); + action_callbacks.push_back([this]() mutable { this->executeDelete(); }); + } + } + + void + AronTreeWidgetContextMenuVisitor::executeDelete() + { + auto* containerPtr = parentItem->QTreeWidgetItem::parent(); + containerPtr->removeChild(parentItem); + auto* castedContainer = AronTreeWidgetItem::DynamicCast(containerPtr); + + // if the parent item is a List, we need to redo the numbers + if (castedContainer && + castedContainer->aronType->getDescriptor() == aron::type::Descriptor::LIST) + { + // start renumbering from the removed child onwards + for (int i = index; i < castedContainer->childCount(); ++i) + { + std::string numberString = std::to_string(i); + castedContainer->child(i)->setText(0, numberString.c_str()); + } + // This displays the number of children also when the list is collapsed + QString numElemsText = misc::generateNumElementsText(castedContainer->childCount()); + containerPtr->setText(1, numElemsText); + // set italic + auto currFont = castedContainer->font(1); + currFont.setItalic(true); + castedContainer->setFont(1, currFont); + } + } + + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::ObjectPtr&) + { + addDeleteAction(); + } + + // lol + void + armarx::AronTreeWidgetContextMenuVisitor::addAddAction() + { + actions.emplace_back("Add element", contextMenuParent); + action_callbacks.push_back([this]() mutable { this->executeAddElement(); }); + } + + void + AronTreeWidgetContextMenuVisitor::executeAddElement() + { + AronTreeWidgetCreatorVisitor creator(parentItem); + aron::type::visit(creator, parentItem->aronType->getChildren()[0]); + + if (!creator.createdQWidgetItem) + { + throw std::runtime_error("Creation of TreeElementChild failed unexpectedly"); + } + // if it is a list, we update the number of children at the top + auto* castedContainer = AronTreeWidgetItem::DynamicCast(parentItem); + + // if the parent item is a List, we need to redo the numbers + if (castedContainer && + castedContainer->aronType->getDescriptor() == aron::type::Descriptor::LIST) + { + // This displays the number of children also when the list is collapsed + auto numElemsText = misc::generateNumElementsText(castedContainer->childCount()); + castedContainer->setText(1, numElemsText); + // set italic + auto currFont = castedContainer->font(1); + currFont.setItalic(true); + castedContainer->setFont(1, currFont); + } + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::DictPtr&) + { + addAddAction(); + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::PairPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::TuplePtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::ListPtr&) + { + addAddAction(); + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::NDArrayPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::MatrixPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::QuaternionPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::ImagePtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::PointCloudPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::IntEnumPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::IntPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::LongPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::FloatPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::DoublePtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::BoolPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::StringPtr&) + { + addDeleteAction(); + } + + void + AronTreeWidgetContextMenuVisitor::visitUnknown(Input&) + { + ARMARX_WARNING << "Tried to open Context menu on unknown aron type"; + } + + void + AronTreeWidgetContextMenuVisitor::showMenuAndExecute() + { + QMenu menu("Context Menu", contextMenuParent); + for (auto& el : actions) + { + menu.addAction(&el); + } + auto* chosenAction = menu.exec(contextMenuParent->mapToGlobal(pos)); + + if (!chosenAction) + { + return; + } + + // not elegant, but is a small loop anyway + auto it = actions.begin(); + size_t count = 0; + while (it != actions.end()) + { + if (chosenAction == &*it) + { + action_callbacks[count](); + break; + } + ++it; + ++count; + } + } +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.h new file mode 100644 index 0000000000000000000000000000000000000000..510f68292b91bf9934dcecd4300d698e64d516b3 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetContextMenu.h @@ -0,0 +1,67 @@ +#pragma once + + +#include <QAction> + +#include <RobotAPI/libraries/aron/core/data/variant/All.h> +#include <RobotAPI/libraries/aron/core/type/variant/All.h> +#include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h> + +class QTreeWidget; +class QPoint; + +namespace armarx +{ + + class AronTreeWidgetItem; + + // Visitor on aron types. It creates a context menu dependent on the type of the AronTreeWidgetItem. + // Its only used for Lists and Dicts. + class AronTreeWidgetContextMenuVisitor : public armarx::aron::type::ConstVariantVisitor + { + + AronTreeWidgetItem* parentItem; + QTreeWidget* contextMenuParent; + const QPoint& pos; + int index; + + public: + AronTreeWidgetContextMenuVisitor() = delete; + AronTreeWidgetContextMenuVisitor(AronTreeWidgetItem* i, + const QPoint& pos, + QTreeWidget* contextMenuParent, + int x); + + void visitAronVariant(const aron::type::ObjectPtr&) final; + void visitAronVariant(const aron::type::DictPtr&) final; + void visitAronVariant(const aron::type::PairPtr&) final; + void visitAronVariant(const aron::type::TuplePtr&) final; + void visitAronVariant(const aron::type::ListPtr&) final; + void visitAronVariant(const aron::type::NDArrayPtr&) final; + void visitAronVariant(const aron::type::MatrixPtr&) final; + void visitAronVariant(const aron::type::QuaternionPtr&) final; + void visitAronVariant(const aron::type::ImagePtr&) final; + void visitAronVariant(const aron::type::PointCloudPtr&) final; + void visitAronVariant(const aron::type::IntEnumPtr&) final; + void visitAronVariant(const aron::type::IntPtr&) final; + void visitAronVariant(const aron::type::LongPtr&) final; + void visitAronVariant(const aron::type::FloatPtr&) final; + void visitAronVariant(const aron::type::DoublePtr&) final; + void visitAronVariant(const aron::type::BoolPtr&) final; + void visitAronVariant(const aron::type::StringPtr&) final; + void visitUnknown(Input&) final; + + void showMenuAndExecute(); + + private: + std::list<QAction> actions; + std::vector<std::function<void()>> action_callbacks; + + // Creates a remove option if the element is a direct child of a list or dict + void addDeleteAction(); + void executeDelete(); + + void addAddAction(); + void executeAddElement(); + }; +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.cpp index 7d78147bca4aa47088e8a605e7494f38b2ea5776..c0a8088db7b5ad4e4e1db955b42e9316164038b3 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.cpp @@ -26,16 +26,68 @@ #include "AronTreeWidgetConverter.h" // armarx +#include <SimoxUtility/algorithm/string.h> + #include <ArmarXCore/core/logging/Logging.h> +#include "RobotAPI/libraries/aron/core/data/variant/All.h" + // qt #include <QTreeWidgetItem> +#include "../widgets/EditMatrixWidget.h" +#include "../widgets/IntEnumWidget.h" +#include "../widgets/QuaternionWidget.h" + + namespace armarx { + bool + AronTreeWidgetConverterVisitor::isConversionSuccessful() + { + return !isDirectError && !hasTransitiveError; + } + + bool + AronTreeWidgetConverterVisitor::onlyChildFailedConversion() + { + return hasTransitiveError; + } + + bool + AronTreeWidgetConverterVisitor::hasDirectError() const + { + return isDirectError; + } + + void + AronTreeWidgetConverterVisitor::handleErrors(AronTreeWidgetConverterVisitor childV, + bool ownFault) + { + ARMARX_TRACE; + isDirectError |= ownFault; + hasTransitiveError |= childV.isDirectError || childV.hasTransitiveError; + + auto* aronItem = AronTreeWidgetItem::DynamicCast(parentItem->child(index)); + ARMARX_CHECK(aronItem); + aronItem->setValueErrorState(isDirectError, hasTransitiveError); + } + + void + AronTreeWidgetConverterVisitor::handleErrors(bool ownFault) + { + ARMARX_TRACE; + isDirectError = ownFault; + auto* aronItem = AronTreeWidgetItem::DynamicCast(parentItem->child(index)); + ARMARX_CHECK(aronItem); + aronItem->setValueErrorState(isDirectError, false); + } + + void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ObjectPtr& i) { + ARMARX_TRACE; auto createdAronDict = std::make_shared<aron::data::Dict>(i->getPath()); createdAron = createdAronDict; QTreeWidgetItem* el = parentItem->child(index); @@ -43,16 +95,22 @@ namespace armarx unsigned int x = 0; for (const auto& [key, value] : i->getMemberTypes()) { + ARMARX_TRACE; AronTreeWidgetConverterVisitor v(el, x++); aron::type::visit(v, value); - createdAronDict->addElement(key, v.createdAron); + handleErrors(v); + if (v.isConversionSuccessful()) + { + createdAronDict->addElement(key, v.createdAron); + } } } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::DictPtr& i) { + ARMARX_TRACE; auto createdAronDict = std::make_shared<aron::data::Dict>(i->getPath()); createdAron = createdAronDict; QTreeWidgetItem* el = parentItem->child(index); @@ -62,38 +120,72 @@ namespace armarx auto it = el->child(x); AronTreeWidgetConverterVisitor v(el, x); aron::type::visit(v, i->getAcceptedType()); - - if (v.createdAron) + auto key = it->text(0).toStdString(); + // TODO: handle key errors more elegantly / separately, fine for now + handleErrors(v, createdAronDict->hasElement(key)); + if (v.createdAron && v.isConversionSuccessful() && !createdAronDict->hasElement(key)) { - createdAronDict->addElement(it->text(0).toStdString(), v.createdAron); + createdAronDict->addElement(key, v.createdAron); } } } void - AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::PairPtr& i) + AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ListPtr& i) { - // TODO + ARMARX_TRACE; + auto createdAronList = std::make_shared<aron::data::List>(i->getPath()); + createdAron = createdAronList; + auto* elem = parentItem->child(index); + auto childrenTypes = i->getChildren(); + ARMARX_CHECK(childrenTypes.size() == 1); + for (int j = 0; j < elem->childCount(); ++j) + { + AronTreeWidgetConverterVisitor convVisitor(elem, j); + aron::type::visit(convVisitor, childrenTypes[0]); + handleErrors(convVisitor); + + if (convVisitor.createdAron && convVisitor.isConversionSuccessful()) + { + createdAronList->addElement(convVisitor.createdAron); + } + } } + void - AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::TuplePtr& i) + AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::PairPtr& i) { - // TODO + ARMARX_TRACE; + auto createdAronPair = std::make_shared<aron::data::List>(i->getPath()); + createdAron = createdAronPair; + auto* elem = parentItem->child(index); + + for (int j = 0; j < 2; ++j) + { + AronTreeWidgetConverterVisitor convVisitor(elem, j); + handleErrors(convVisitor); + if (convVisitor.createdAron && convVisitor.isConversionSuccessful()) + { + createdAronPair->addElement(convVisitor.createdAron); + } + } } void - AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ListPtr& i) + AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::TuplePtr& i) { + ARMARX_TRACE; auto createdAronList = std::make_shared<aron::data::List>(i->getPath()); createdAron = createdAronList; QTreeWidgetItem* el = parentItem->child(index); for (int x = 0; x < el->childCount(); ++x) { - auto it = el->child(x); - AronTreeWidgetConverterVisitor v(el, x); - aron::type::visit(v, i->getAcceptedType()); + auto* it = el->child(x); + AronTreeWidgetConverterVisitor v(it, x); + aron::type::visit(v, i->getAcceptedType(x)); + handleErrors(v); if (v.createdAron) { @@ -105,42 +197,129 @@ namespace armarx void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::NDArrayPtr& i) { - // TODO + ARMARX_TRACE; + ARMARX_ERROR << "Currently do not support supplying raw NDArrays!"; } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::MatrixPtr& i) { - // TODO + ARMARX_TRACE; + auto createdMatrix = std::make_shared<aron::data::NDArray>(i->getPath()); + int dataSize = 0; + switch (i->getElementType()) + { + case armarx::aron::type::matrix::INT16: + dataSize = 2; + break; + case armarx::aron::type::matrix::INT32: + case armarx::aron::type::matrix::FLOAT32: + dataSize = 4; + break; + case armarx::aron::type::matrix::FLOAT64: + case armarx::aron::type::matrix::INT64: + dataSize = 8; + break; + }; + createdMatrix->setShape({i->getRows(), i->getCols(), dataSize}); + createdMatrix->setType(i->getFullName()); + int totalByteSize = i->getRows() * i->getCols() * dataSize; + createdAron = createdMatrix; + + auto* currElem = parentItem->child(index); + auto* rootWidget = currElem->treeWidget(); + ARMARX_CHECK(rootWidget); + auto* widget = rootWidget->itemWidget(currElem, 1); + auto* matrixWidget = EditMatrixWidget::DynamicCastAndCheck(widget); + + handleErrors(matrixWidget->hasParseErrors()); + if (matrixWidget->hasParseErrors()) + { + return; + } + // write to aron data + std::vector<unsigned char> elems; + elems.reserve(totalByteSize); + // CAUTION: Raw data has column based storage + for (size_t col = 0; col < (size_t)i->getCols(); ++col) + { + for (size_t row = 0; row < (size_t)i->getRows(); ++row) + { + // gets us directly the byte wise format + auto parsed = matrixWidget->parseElement(row, col); + // append vector to vector + elems.insert(elems.end(), parsed.begin(), parsed.end()); + } + } + createdMatrix->setData(totalByteSize, elems.data()); } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::QuaternionPtr& i) { - // TODO + ARMARX_TRACE; + auto createdQuat = std::make_shared<aron::data::NDArray>(i->getPath()); + createdAron = createdQuat; + int dataSize = i->getElementType() == aron::type::quaternion::ElementType::FLOAT32 ? 4 : 8; + createdQuat->setShape({1, 4, dataSize}); + createdQuat->setType(i->getFullName()); + auto* currTreeElem = parentItem->child(index); + auto* itemWidget = currTreeElem->treeWidget()->itemWidget(currTreeElem, 1); + auto* quatWidget = QuaternionWidget::DynamicCastAndCheck(itemWidget); + + // error handling + handleErrors(quatWidget->hasParseErrors()); + if (quatWidget->hasParseErrors()) + { + return; + } + + // write to aron data + auto serialized = quatWidget->parseAllToNDArray(); + if ((int)serialized.size() != dataSize * 4) + { + ARMARX_ERROR + << "serialized quaternions did not return byte sequence of correct length!"; + } + createdQuat->setData(serialized.size(), serialized.data()); } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ImagePtr& i) { + ARMARX_TRACE; // TODO } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::PointCloudPtr& i) { + ARMARX_TRACE; // TODO } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::IntEnumPtr& i) { - // TODO + ARMARX_TRACE; + QTreeWidgetItem* el = parentItem->child(index); + auto* genericWidget = el->treeWidget()->itemWidget(el, 1); + auto* intEnumWidget = IntEnumWidget::DynamicCastAndCheck(genericWidget); + if (!intEnumWidget) + { + // already reporting error; continue here + return; + } + bool success; + std::tie(success, createdAron) = intEnumWidget->parseToAron(); + + handleErrors(!success); } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::IntPtr& i) { + ARMARX_TRACE; auto createdAronInt = std::make_shared<aron::data::Int>(i->getPath()); createdAron = createdAronInt; QTreeWidgetItem* el = parentItem->child(index); @@ -151,14 +330,25 @@ namespace armarx createdAronInt->setValue(0); return; } - - int val = std::stoi(str); - createdAronInt->setValue(val); + try + { + int val = simox::alg::to_<int>(str); + createdAronInt->setValue(val); + } + catch (const simox::error::SimoxError& err) + { + handleErrors(); + ARMARX_VERBOSE << "Conversion from String to Int failed. Error:\"" << err.what() + << "\""; + return; + } + handleErrors(false); } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::LongPtr& i) { + ARMARX_TRACE; auto createdAronLong = std::make_shared<aron::data::Long>(i->getPath()); createdAron = createdAronLong; QTreeWidgetItem* el = parentItem->child(index); @@ -166,15 +356,27 @@ namespace armarx std::string str = el->text(1).toStdString(); if (str.empty()) { + //TODO: similar behaviour for rest? str = el->text(3).toStdString(); } - - createdAronLong->fromString(str); + try + { + createdAronLong->setValue(simox::alg::to_<long>(str)); + } + catch (const simox::error::SimoxError& err) + { + handleErrors(); + ARMARX_VERBOSE << "Conversion from String to Long failed. Error:\"" << err.what() + << "\""; + return; + } + handleErrors(false); } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::FloatPtr& i) { + ARMARX_TRACE; auto createdAronFloat = std::make_shared<aron::data::Float>(i->getPath()); createdAron = createdAronFloat; QTreeWidgetItem* el = parentItem->child(index); @@ -184,13 +386,24 @@ namespace armarx { str = el->text(3).toStdString(); } - - createdAronFloat->fromString(str); + try + { + createdAronFloat->setValue(simox::alg::to_<float>(str)); + } + catch (const simox::error::SimoxError& err) + { + handleErrors(); + ARMARX_VERBOSE << "Conversion from String to Float failed. Error:\"" << err.what() + << "\""; + return; + } + handleErrors(false); } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::DoublePtr& i) { + ARMARX_TRACE; auto createdAronDouble = std::make_shared<aron::data::Double>(i->getPath()); createdAron = createdAronDouble; QTreeWidgetItem* el = parentItem->child(index); @@ -200,13 +413,24 @@ namespace armarx { str = el->text(3).toStdString(); } - - createdAronDouble->fromString(str); + try + { + createdAronDouble->setValue(simox::alg::to_<double>(str)); + } + catch (const simox::error::SimoxError& err) + { + handleErrors(); + ARMARX_VERBOSE << "Conversion from String to Double failed. Error:\"" << err.what() + << "\""; + return; + } + handleErrors(false); } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::BoolPtr& i) { + ARMARX_TRACE; auto createdAronBool = std::make_shared<aron::data::Bool>(i->getPath()); createdAron = createdAronBool; QTreeWidgetItem* el = parentItem->child(index); @@ -216,24 +440,36 @@ namespace armarx { str = el->text(3).toStdString(); } - - createdAronBool->fromString(str); + try + { + createdAronBool->setValue(simox::alg::to_<bool>(str)); + } + catch (const simox::error::SimoxError& err) + { + handleErrors(); + ARMARX_VERBOSE << "Conversion from String to Bool failed. Error:\"" << err.what() + << "\""; + return; + } + handleErrors(false); } void AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::StringPtr& i) { + ARMARX_TRACE; auto createdAronString = std::make_shared<aron::data::String>(i->getPath()); createdAron = createdAronString; QTreeWidgetItem* el = parentItem->child(index); std::string str = el->text(1).toStdString(); - createdAronString->fromString(str); + createdAronString->setValue(str); } - void AronTreeWidgetConverterVisitor::visitUnknown(Input&) + void + AronTreeWidgetConverterVisitor::visitUnknown(Input&) { - ARMARX_WARNING_S << "Received an unknown type when trying to convert a skill argument type to an aron data object."; + ARMARX_WARNING_S << "Received an unknown type when trying to convert a skill argument type " + "to an aron data object."; } -} - +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.h index eb056cdc2a65f14ef4d884124d6cb14ac2e9ed7e..c127ac5e49276e878221dc39a5db8a7b821ccec7 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetConverter.h @@ -21,8 +21,8 @@ */ #pragma once -#include <RobotAPI/libraries/aron/core/type/variant/All.h> #include <RobotAPI/libraries/aron/core/data/variant/All.h> +#include <RobotAPI/libraries/aron/core/type/variant/All.h> #include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h> // forward declarations of qt @@ -32,8 +32,7 @@ class QTreeWidgetItem; namespace armarx { // Conversion from TreeView to aron data - class AronTreeWidgetConverterVisitor : - public armarx::aron::type::ConstVariantVisitor + class AronTreeWidgetConverterVisitor : public armarx::aron::type::ConstVariantVisitor { public: QTreeWidgetItem* parentItem; @@ -41,10 +40,27 @@ namespace armarx aron::data::VariantPtr createdAron = nullptr; AronTreeWidgetConverterVisitor() = delete; - AronTreeWidgetConverterVisitor(QTreeWidgetItem* i, int x) : - parentItem(i), index(x) - {} + AronTreeWidgetConverterVisitor(QTreeWidgetItem* i, int x) : parentItem(i), index(x) + { + } + // if the conversion was successful after calling visit() + bool isConversionSuccessful(); + // returns true if this type itself was sucessfully parsed, but some contained object failed. + // also false if there is no error + bool onlyChildFailedConversion(); + + bool hasDirectError() const; + + private: + bool isDirectError = false; + bool hasTransitiveError = false; + // adds all errors from other visitor to our own error collection -> collecting errors + // with ownFault, we also add this node to the collection + void handleErrors(AronTreeWidgetConverterVisitor childV, bool ownFault = false); + // we are the cause... + void handleErrors(bool ownFault = true); + public: void visitAronVariant(const aron::type::ObjectPtr&) final; void visitAronVariant(const aron::type::DictPtr&) final; void visitAronVariant(const aron::type::PairPtr&) final; @@ -64,6 +80,4 @@ namespace armarx void visitAronVariant(const aron::type::StringPtr&) final; void visitUnknown(Input&) final; }; -} - - +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.cpp index ee43334bb26862322610746269fee97a16d0cccd..84cb58585e3b4e7f3a058db66f3b5f3a40f54aea 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.cpp @@ -22,28 +22,98 @@ #include <string> +#include "../widgets/EditMatrixWidget.h" +#include "../widgets/IntEnumWidget.h" +#include "../widgets/QuaternionWidget.h" + // base class #include "AronTreeWidgetCreator.h" // data +#include <QComboBox> + #include "../AronTreeWidgetItem.h" #include "../Data.h" +#include "../ListDictHelper.h" +#include "AronTreeWidgetContextMenu.h" namespace armarx { + + AronTreeWidgetCreatorVisitor::AronTreeWidgetCreatorVisitor(QTreeWidgetItem* parentInstance) : + parentOfCreatedObj(parentInstance) + { + // The parent of the root aron Tree Widget will not be aron type. + // there an explicit setTopLevelWidget() is required. + auto* aronParent = AronTreeWidgetItem::DynamicCast(parentInstance); + if (aronParent) + { + toplevelWidget = aronParent->treeWidget(); + } + } + + std::string + AronTreeWidgetCreatorVisitor::generateUniqueKeyFromSet(std::set<std::string>&& usedKeys) + { + size_t num = 0; + while (true) + { + std::string proposedName = this->defaultMapKeyName + std::to_string(num); + auto it = usedKeys.find(proposedName); + if (it == usedKeys.end()) + { + break; + } + ++num; + } + return this->defaultMapKeyName + std::to_string(num); + } + void - AronTreeWidgetCreatorVisitor::createSimpleTreeViewWidget(Input& i, const std::string& defaul) + AronTreeWidgetCreatorVisitor::insertNewTreeViewWidget(Input& i, const std::string& defaul) { ARMARX_CHECK_NOT_NULL(i); auto key = i->getPath().getLastElement(); - createdQWidgetItem = new AronTreeWidgetItem(); - createdQWidgetItem->aronType = i; - createdQWidgetItem->setText(0, QString::fromStdString(key)); + bool isDictChild = false; + // edit key, to be a unique string, if the parent is a dict + auto* aronParent = AronTreeWidgetItem::DynamicCast(parentOfCreatedObj); + if (aronParent && aronParent->aronType->getDescriptor() == aron::type::Descriptor::DICT) + { + isDictChild = true; + std::set<std::string> usedKeys; + for (int i = 0; i < parentOfCreatedObj->childCount(); ++i) + { + auto* sibling = AronTreeWidgetItem::DynamicCast(parentOfCreatedObj->child(i)); + if (sibling) + { + usedKeys.insert(sibling->text(0).toStdString()); + } + } + key = generateUniqueKeyFromSet(std::move(usedKeys)); + } + // if it's a list -> choose the right number + else if (aronParent && + aronParent->aronType->getDescriptor() == aron::type::Descriptor::LIST) + { + key = std::to_string(parentOfCreatedObj->childCount()); + } + + createdQWidgetItem = + new AronTreeWidgetItem(isDictChild, editableValue, QString::fromStdString(key), i); createdQWidgetItem->setText(1, QString::fromStdString(defaul)); createdQWidgetItem->setText(2, QString::fromStdString(i->getShortName())); - createdQWidgetItem->setText(3, QString::fromStdString(aron_tree_widget::constantes::ITEM_EMPTY_MESSAGE) /*QString::fromStdString(i->getDefaultFromString())*/); - createdQWidgetItem->setFlags(createdQWidgetItem->flags() | Qt::ItemIsEditable); + createdQWidgetItem->setText( + 3, + QString::fromStdString( + aron_tree_widget::constantes:: + ITEM_EMPTY_MESSAGE) /*QString::fromStdString(i->getDefaultFromString())*/); + + if (editableValue || isDictChild) + { + createdQWidgetItem->setFlags(createdQWidgetItem->flags() | Qt::ItemIsEditable); + } + parentOfCreatedObj->addChild(createdQWidgetItem); } void @@ -57,73 +127,203 @@ namespace armarx key = i->getPath().getLastElement(); } - createdQWidgetItem = new AronTreeWidgetItem(); - createdQWidgetItem->setText(0, QString::fromStdString(key)); + createdQWidgetItem = + new AronTreeWidgetItem(editableValue, false, QString::fromStdString(key), i); + parentOfCreatedObj->addChild(createdQWidgetItem); for (const auto& [key, value] : i->getMemberTypes()) { - AronTreeWidgetCreatorVisitor v; + AronTreeWidgetCreatorVisitor v(createdQWidgetItem); aron::type::visit(v, value); - if (v.createdQWidgetItem) - { - createdQWidgetItem->addChild(v.createdQWidgetItem); - } + assert(v.createdQWidgetItem); } } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::DictPtr& i) - { createSimpleTreeViewWidget(i, ""); } + { + ARMARX_CHECK_NOT_NULL(i); + + insertNewTreeViewWidget(i, ""); + // The DictType has only one member, its key-type. This also must be present + ARMARX_CHECK_EQUAL(i->getChildren().size(), 1); + } void - AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::PairPtr& i) - { createSimpleTreeViewWidget(i, ""); } + AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::PairPtr& pair) + { + // create default, uneditable tree widget item. + insertNewTreeViewWidget(pair, ""); + // attach two children + ARMARX_CHECK(pair->getChildren().size() == 2); + for (size_t i = 0; i < 2; ++i) + { + AronTreeWidgetCreatorVisitor v(createdQWidgetItem); + aron::type::visit(v, pair->getChildren()[i]); + if (v.createdQWidgetItem) + { + std::string descr = "p[" + std::to_string(i) + "]"; + v.createdQWidgetItem->setText(0, descr.c_str()); + } + } + } void - AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::TuplePtr& i) - { createSimpleTreeViewWidget(i, ""); } + AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::TuplePtr& tuple) + { + // CAUTION; UNTESTED + // create default, uneditable tree widget item. + insertNewTreeViewWidget(tuple, ""); + // attach all children + for (size_t i = 0; i < tuple->getChildren().size(); ++i) + { + AronTreeWidgetCreatorVisitor v(createdQWidgetItem); + aron::type::visit(v, tuple->getChildren()[i]); + if (v.createdQWidgetItem) + { + std::string descr = "tup[" + std::to_string(i) + "]"; + v.createdQWidgetItem->setText(0, descr.c_str()); + } + } + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::ListPtr& i) - { createSimpleTreeViewWidget(i, ""); } + { + insertNewTreeViewWidget(i, ""); + auto txt = misc::generateNumElementsText(0); + createdQWidgetItem->setText(1, txt); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::NDArrayPtr& i) - { createSimpleTreeViewWidget(i, ""); } + { + insertNewTreeViewWidget(i, ""); + } + void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::MatrixPtr& i) - { createSimpleTreeViewWidget(i, ""); } + { + editableValue = false; + insertNewTreeViewWidget(i, ""); + // special code to print the type of base type used + QString type = ""; + switch (i->getElementType()) + { + case armarx::aron::type::matrix::INT16: + type = "<int16>"; + break; + case armarx::aron::type::matrix::INT32: + type = "<int32>"; + break; + case armarx::aron::type::matrix::INT64: + type = "<int64>"; + break; + case armarx::aron::type::matrix::FLOAT32: + type = "<float>"; + break; + case armarx::aron::type::matrix::FLOAT64: + type = "<double>"; + break; + } + type = createdQWidgetItem->text(2) + type; + createdQWidgetItem->setText(2, type); + + // Widget fiddling source: https://blog.manash.io/quick-qt-6-how-to-add-qpushbutton-or-widgets-to-a-qtreewidget-as-qtreewidgetitem-2ae9f54c0e5f + // overlay custom widget in column 1 + auto* toplevelWidget = createdQWidgetItem->treeWidget(); + EditMatrixWidget* matWidget = new EditMatrixWidget( + i->getRows(), i->getCols(), i->getElementType(), createdQWidgetItem); + toplevelWidget->setItemWidget(createdQWidgetItem, 1, matWidget); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::QuaternionPtr& i) - { createSimpleTreeViewWidget(i, ""); } + { + editableValue = false; + insertNewTreeViewWidget(i, ""); + // special code to print the type of base type used + QString type = ""; + switch (i->getElementType()) + { + case armarx::aron::type::quaternion::FLOAT32: + type = "<float>"; + break; + case armarx::aron::type::quaternion::FLOAT64: + type = "<double>"; + break; + } + type = createdQWidgetItem->text(2) + type; + createdQWidgetItem->setText(2, type); + + auto* toplevelWidget = createdQWidgetItem->treeWidget(); + QuaternionWidget* quatWidget = + new QuaternionWidget(i->getElementType(), createdQWidgetItem); + toplevelWidget->setItemWidget(createdQWidgetItem, 1, quatWidget); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::ImagePtr& i) - { createSimpleTreeViewWidget(i, ""); } + { + insertNewTreeViewWidget(i, ""); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::PointCloudPtr& i) - { createSimpleTreeViewWidget(i, ""); } + { + insertNewTreeViewWidget(i, ""); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::IntEnumPtr& i) - { createSimpleTreeViewWidget(i, ""); } + { + editableValue = false; + ARMARX_CHECK_NOT_NULL(i); + ARMARX_CHECK_GREATER(i->getAcceptedValueNames().size(), 0); + + insertNewTreeViewWidget(i, ""); + IntEnumWidget* widget = new IntEnumWidget(i, createdQWidgetItem); + createdQWidgetItem->treeWidget()->setItemWidget(createdQWidgetItem, 1, widget); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::IntPtr& i) - { createSimpleTreeViewWidget(i, "0"); } + { + editableValue = true; + insertNewTreeViewWidget(i, "0"); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::LongPtr& i) - { createSimpleTreeViewWidget(i, "0"); } + { + editableValue = true; + insertNewTreeViewWidget(i, "0"); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::FloatPtr& i) - { createSimpleTreeViewWidget(i, "0.0"); } + { + editableValue = true; + insertNewTreeViewWidget(i, "0.0"); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::DoublePtr& i) - { createSimpleTreeViewWidget(i, "0.0"); } + { + editableValue = true; + insertNewTreeViewWidget(i, "0.0"); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::BoolPtr& i) - { createSimpleTreeViewWidget(i, "false"); } + { + editableValue = true; + insertNewTreeViewWidget(i, "false"); + } void AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::StringPtr& i) - { createSimpleTreeViewWidget(i, ""); } + { + insertNewTreeViewWidget(i, ""); + } - void AronTreeWidgetCreatorVisitor::visitUnknown(Input&) + void + AronTreeWidgetCreatorVisitor::visitUnknown(Input&) { - ARMARX_WARNING_S << "Received an unknown type when trying to create a tree view widget for a skill argument type."; + ARMARX_WARNING_S << "Received an unknown type when trying to create a tree view widget for " + "a skill argument type."; } -} + void + AronTreeWidgetCreatorVisitor::setTopLevelWidget(QTreeWidget* widget) + { + toplevelWidget = widget; + } +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.h index 63dde7ef0be04d8d790c5f8434ae1b82faeb107a..b3d2ffb54cca6bf7fe8aac2395d733f3ba458817 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetCreator.h @@ -21,8 +21,10 @@ */ #pragma once -#include <RobotAPI/libraries/aron/core/type/variant/All.h> +#include <QTreeWidgetItem> + #include <RobotAPI/libraries/aron/core/data/variant/All.h> +#include <RobotAPI/libraries/aron/core/type/variant/All.h> #include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h> namespace armarx @@ -30,15 +32,20 @@ namespace armarx class AronTreeWidgetItem; // Convert aron type to tree widgets - class AronTreeWidgetCreatorVisitor : - public armarx::aron::type::ConstVariantVisitor + class AronTreeWidgetCreatorVisitor : public armarx::aron::type::ConstVariantVisitor { public: - AronTreeWidgetItem* createdQWidgetItem; + AronTreeWidgetItem* createdQWidgetItem = nullptr; + + AronTreeWidgetCreatorVisitor() = delete; - AronTreeWidgetCreatorVisitor() = default; + // Takes the parent tree element and attaches the newly crated object during visit() to it. + // This allows us to also use information of the parent object during creation (like if this child is a dict entry or part of a list) + // IMPORTANT: For the root element, manually set the topLevelWidget after this constructor + AronTreeWidgetCreatorVisitor(QTreeWidgetItem* parentInstance); + + void insertNewTreeViewWidget(Input& i, const std::string&); - void createSimpleTreeViewWidget(Input& i, const std::string&); void visitAronVariant(const aron::type::ObjectPtr&) final; void visitAronVariant(const aron::type::DictPtr& i) final; @@ -58,7 +65,17 @@ namespace armarx void visitAronVariant(const aron::type::BoolPtr& i) final; void visitAronVariant(const aron::type::StringPtr& i) final; void visitUnknown(Input&) final; - }; -} + // setter for the widget attachment point. Only needs to be manually set for the root element. + void setTopLevelWidget(QTreeWidget* widget); + private: + void handleEditable(); + std::string generateUniqueKeyFromSet(std::set<std::string>&& usedKeys); + QTreeWidgetItem* parentOfCreatedObj = nullptr; + QTreeWidget* toplevelWidget = nullptr; + const std::string defaultMapKeyName = "key_"; + // controls, if values (column 1) can be edited directly + bool editableValue = false; + }; +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp index 7ff248bd58499028bcf43a158f83f67c1259b43c..fc58634bb9bc02834d4e72663e3c16ffe36d6de6 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp @@ -28,7 +28,7 @@ // modals #include "../modal/text/AronTreeWidgetTextInputModalController.h" -#include "../modal/dict/AronTreeWidgetDictInputModalController.h" +//#include "../modal/dict/AronTreeWidgetDictInputModalController.h" // qt #include <QTreeWidget> @@ -37,84 +37,6 @@ namespace armarx { - void AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::ObjectPtr& i) - { - // should not happen, right? - } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::DictPtr& i) - { - createdModal = std::make_shared<AronTreeWidgetDictInputModalController>(label, item, parent); - } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::PairPtr& i) - { - } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::TuplePtr& i) - { } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::ListPtr& i) - { } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::NDArrayPtr& i) - { } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::MatrixPtr& i) - { } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::QuaternionPtr& i) - { } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::ImagePtr& i) - { } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::PointCloudPtr& i) - { } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::IntEnumPtr& i) - { } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::IntPtr& i) - { - createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent); - } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::LongPtr& i) - { - createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent); - } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::FloatPtr& i) - { - createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent); - } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::DoublePtr& i) - { - createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent); - } - - void - AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::BoolPtr& i) - { - createdModal = std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent); - } - void AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::StringPtr& i) { diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h index e22930a1080977d0feb6475c72a3b6c848d5d8e5..f4c8f0223a039c6b9be926d6bddf360bce32f629 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h @@ -29,15 +29,17 @@ namespace armarx { - // Convert aron type to tree widget + // Convert aron type to tree widget. + // (Widgets are only created for string types to enter longer texts. + // However, the visitor implementation allows modals for differnt types. Might be useful in the future..) class AronTreeWidgetModalCreatorVisitor : public armarx::aron::type::ConstVariantVisitor { public: - std::string label; - AronTreeWidgetItem* item; - QTreeWidget* parent; - AronTreeWidgetModalControllerPtr createdModal; + std::string label = ""; + AronTreeWidgetItem* item = nullptr; + QTreeWidget* parent = nullptr; + AronTreeWidgetModalControllerPtr createdModal = nullptr; AronTreeWidgetModalCreatorVisitor() = delete; AronTreeWidgetModalCreatorVisitor(const std::string& label, AronTreeWidgetItem* item, QTreeWidget* parent) : @@ -46,22 +48,6 @@ namespace armarx parent(parent) {} - void visitAronVariant(const aron::type::ObjectPtr&) final; - void visitAronVariant(const aron::type::DictPtr& i) final; - void visitAronVariant(const aron::type::PairPtr& i) final; - void visitAronVariant(const aron::type::TuplePtr& i) final; - void visitAronVariant(const aron::type::ListPtr& i) final; - void visitAronVariant(const aron::type::NDArrayPtr& i) final; - void visitAronVariant(const aron::type::MatrixPtr& i) final; - void visitAronVariant(const aron::type::QuaternionPtr& i) final; - void visitAronVariant(const aron::type::ImagePtr& i) final; - void visitAronVariant(const aron::type::PointCloudPtr& i) final; - void visitAronVariant(const aron::type::IntEnumPtr& i) final; - void visitAronVariant(const aron::type::IntPtr& i) final; - void visitAronVariant(const aron::type::LongPtr& i) final; - void visitAronVariant(const aron::type::FloatPtr& i) final; - void visitAronVariant(const aron::type::DoublePtr& i) final; - void visitAronVariant(const aron::type::BoolPtr& i) final; void visitAronVariant(const aron::type::StringPtr& i) final; void visitUnknown(Input&) final; }; diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.cpp index 87d99fe162344661a0511f49563c5d601342fe11..cf719f8a2d1360d574fb8ebcac867378c3fd6f1b 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.cpp @@ -20,34 +20,106 @@ * GNU General Public License */ +#include "AronTreeWidgetSetter.h" + #include <string> -#include "AronTreeWidgetSetter.h" +#include "../ListDictHelper.h" +#include "../widgets/EditMatrixWidget.h" +#include "../widgets/IntEnumWidget.h" +#include "../widgets/QuaternionWidget.h" +#include "AronTreeWidgetContextMenu.h" +#include "AronTreeWidgetCreator.h" + + +template <typename T> +std::string +usString(T number, size_t precision = 3) +{ + std::stringstream ss; + const char* locale = "C"; + ss.imbue(std::locale(locale)); + + ss << std::fixed << std::setprecision(precision) << number; + return ss.str(); +} + //visitors namespace armarx { - bool AronTreeWidgetSetterVisitor::checkTreeWidgetItemForSimilarName(const std::string& name) const + bool + AronTreeWidgetSetterVisitor::checkTreeWidgetItemForSimilarName(const std::string& name) const { QTreeWidgetItem* el = parentItem->child(index); + + // do not check attribute name, if the element is part of a list or map + auto* castedThis = AronTreeWidgetItem::DynamicCast(el->parent()); + if (castedThis) + { + auto descr = castedThis->aronType->getDescriptor(); + if (descr == aron::type::Descriptor::LIST || descr == aron::type::Descriptor::DICT) + { + return true; + } + } std::string n = el->text(0).toStdString(); if (name != n) { - ARMARX_WARNING_S << "Could not set a tree widget value for the element with key '" << name << "' because it is different from the expected name '" << n << "'."; + ARMARX_WARNING_S << "Could not set a tree widget value for the element with key '" + << name << "' because it is different from the expected name '" << n + << "'."; return false; } return true; } - void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DictPtr& i) + void + AronTreeWidgetSetterVisitor::adjustNumberOfChildren(AronTreeWidgetItem* parent, + size_t numChildren) + { + if (((size_t)parent->childCount()) < numChildren) + { + // The type to create must be the only child of the current aron type + ARMARX_CHECK_EQUAL(parent->aronType->childrenSize(), 1); + size_t childrenToAdd = numChildren - parent->childCount(); + for (size_t j = 0; j < childrenToAdd; ++j) + { + AronTreeWidgetCreatorVisitor childCreator(parent); + aron::type::visit(childCreator, parent->aronType->getChildren()[0]); + ARMARX_CHECK_NOT_NULL(childCreator.createdQWidgetItem); + } + } + else if ((size_t)parent->childCount() > numChildren) + { + size_t numChilds = (size_t)parent->childCount() - numChildren; + // pop the last child + for (size_t j = 0; j < numChilds; ++j) + { + parent->removeChild(parent->child(parent->childCount() - 1)); + } + } + } + + + void + AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DictPtr& i) { - if (i->getPath().size() == 0 || checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) // either it is the root or it has a name + // either it is the root or it has a name + if (i->getPath().size() == 0 || + checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) { QTreeWidgetItem* el = parentItem->child(index); + auto* aronTreeWidget = AronTreeWidgetItem::DynamicCastAndCheck(el); + // allocate enough child items + adjustNumberOfChildren(aronTreeWidget, i->childrenSize()); + // write child values unsigned int x = 0; for (const auto& [key, value] : i->getElements()) { + el->child(x)->setText(0, {key.c_str()}); + AronTreeWidgetSetterVisitor v(el, x++); aron::data::visit(v, value); } @@ -55,72 +127,224 @@ namespace armarx } } - void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::ListPtr& i) + void + AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::ListPtr& i) { if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) { QTreeWidgetItem* el = parentItem->child(index); + auto* aronTreeWidget = AronTreeWidgetItem::DynamicCastAndCheck(el); + adjustNumberOfChildren(aronTreeWidget, i->childrenSize()); unsigned int x = 0; for (const auto& value : i->getElements()) { - AronTreeWidgetSetterVisitor v(el, x++); + AronTreeWidgetSetterVisitor v(el, x); aron::data::visit(v, value); + auto* currChild = el->child(x); + std::string listNum = usString(x); + currChild->setText(0, listNum.c_str()); + + ++x; + } + // This displays the number of children also when the list is collapsed + QString numElemsText = misc::generateNumElementsText(i->getElements().size()); + aronTreeWidget->setText(1, numElemsText); + // set italic + auto currFont = aronTreeWidget->font(1); + currFont.setItalic(true); + aronTreeWidget->setFont(1, currFont); + } + } + + + void + visitMatrix(EditMatrixWidget* matrixWidget, + const std::shared_ptr<armarx::aron::type::Matrix>& matrixType, + const aron::data::NDArrayPtr& arr) + { + auto elemType = matrixType->getElementType(); + auto* rawData = arr->getData(); + // string can convert any item + auto toString = [elemType, rawData](size_t elementNr) -> std::string + { + switch (elemType) + { + case aron::type::matrix::ElementType::FLOAT32: + { + static_assert(sizeof(float) == 4); + float* interpreted = reinterpret_cast<float*>(rawData); + float laundered = std::launder(interpreted)[elementNr]; + return usString<float>(laundered); + } + case aron::type::matrix::ElementType::FLOAT64: + { + static_assert(sizeof(double) == 8); + double* interpreted = reinterpret_cast<double*>(rawData); + float laundered = std::launder(interpreted)[elementNr]; + return usString<double>(laundered); + } + case aron::type::matrix::ElementType::INT16: + { + int16_t* interpreted = reinterpret_cast<int16_t*>(rawData); + int16_t laudered = std::launder(interpreted)[elementNr]; + return usString<int16_t>(laudered); + } + case aron::type::matrix::ElementType::INT32: + { + int32_t* interpreted = reinterpret_cast<int32_t*>(rawData); + int32_t laudered = std::launder(interpreted)[elementNr]; + return usString<int32_t>(laudered); + } + case aron::type::matrix::ElementType::INT64: + { + int64_t* interpreted = reinterpret_cast<int64_t*>(rawData); + int64_t laudered = std::launder(interpreted)[elementNr]; + return usString<int64_t>(laudered); + } + } + return "Error!"; + }; + + + for (size_t row = 0; (int)row < matrixType->getRows(); ++row) + { + for (size_t col = 0; (int)col < matrixType->getCols(); ++col) + { + matrixWidget->setText(row, col, toString(col * matrixType->getRows() + row)); + } + } + } + void + visitQuaternion(QuaternionWidget* quatWidget, + std::shared_ptr<armarx::aron::type::Quaternion>& quatType, + const aron::data::NDArrayPtr& arr) + { + auto elemType = quatType->getElementType(); + auto rawData = arr->getData(); + auto shape = arr->getShape(); + // string can convert any item + auto toString = [elemType, rawData](size_t elementNr) -> std::string + { + switch (elemType) + { + case aron::type::quaternion::ElementType::FLOAT32: + { + static_assert(sizeof(float) == 4); + float* interpreted = reinterpret_cast<float*>(rawData); + float laundered = std::launder(interpreted)[elementNr]; + return usString<float>(laundered); + } + case aron::type::quaternion::ElementType::FLOAT64: + { + static_assert(sizeof(double) == 8); + double* interpreted = reinterpret_cast<double*>(rawData); + + float laundered = std::launder(interpreted)[elementNr]; + return usString<double>(laundered); + } } + return "Error!"; + }; + for (size_t i = 0; i < 4; ++i) + { + quatWidget->setText((QuaternionWidget::QuaternionComponents)i, toString(i)); } } - void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::NDArrayPtr& i) + void + AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::NDArrayPtr& arr) { + // Matrices are handled as NDArray. Raw ndarrays cannot be created currently + auto* castedEl = AronTreeWidgetItem::DynamicCast(parentItem->child(index)); + ARMARX_CHECK(castedEl); + + auto matrixCast = aron::type::Matrix::DynamicCast(castedEl->aronType); + auto quaternionCast = aron::type::Quaternion::DynamicCast(castedEl->aronType); + + auto* rootWidget = castedEl->treeWidget(); + ARMARX_CHECK(rootWidget); + auto* matrixWidget = EditMatrixWidget::DynamicCast(rootWidget->itemWidget(castedEl, 1)); + auto* quaternionWidget = QuaternionWidget::DynamicCast(rootWidget->itemWidget(castedEl, 1)); + if (matrixCast && matrixWidget) + { + visitMatrix(matrixWidget, matrixCast, arr); + } + else if (quaternionCast && quaternionWidget) + { + visitQuaternion(quaternionWidget, quaternionCast, arr); + } + else + { + ARMARX_ERROR + << "we do not support raw NDArrays. Ask Fabian Peller for more information."; + } } - void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::IntPtr& i) + void + AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::IntPtr& i) { if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) { QTreeWidgetItem* el = parentItem->child(index); - el->setText(1, QString::fromStdString(std::to_string(i->getValue()))); + auto* enumWidget = IntEnumWidget::DynamicCast(el->treeWidget()->itemWidget(el, 1)); + auto newText = QString::fromStdString(usString<int>(i->getValue())); + if (enumWidget) + { + // Its an IntEnum! -> Ask the custom widget + enumWidget->setText(newText); + } + else + { + // Its just an int. -> do the QTreeWidgetItem call + el->setText(1, newText); + } } } - void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::LongPtr& i) + void + AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::LongPtr& i) { if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) { QTreeWidgetItem* el = parentItem->child(index); - el->setText(1, QString::fromStdString(std::to_string(i->getValue()))); + el->setText(1, QString::fromStdString(usString<long>(i->getValue()))); } } - void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::FloatPtr& i) + void + AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::FloatPtr& i) { if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) { QTreeWidgetItem* el = parentItem->child(index); - el->setText(1, QString::fromStdString(std::to_string(i->getValue()))); + el->setText(1, QString::fromStdString(usString<float>(i->getValue()))); } } - void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DoublePtr& i) + void + AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DoublePtr& i) { if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) { QTreeWidgetItem* el = parentItem->child(index); - el->setText(1, QString::fromStdString(std::to_string(i->getValue()))); + el->setText(1, QString::fromStdString(usString<double>(i->getValue()))); } } - void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::BoolPtr& i) + void + AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::BoolPtr& i) { if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) { QTreeWidgetItem* el = parentItem->child(index); - el->setText(1, QString::fromStdString(std::to_string(i->getValue()))); + el->setText(1, QString::fromStdString(usString<bool>(i->getValue()))); } } - void AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::StringPtr& i) + void + AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::StringPtr& i) { if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement())) { @@ -129,9 +353,10 @@ namespace armarx } } - void AronTreeWidgetSetterVisitor::visitUnknown(Input&) + void + AronTreeWidgetSetterVisitor::visitUnknown(Input&) { - ARMARX_WARNING_S << "Received an unknown type when trying to set a skill argument type from an aron data object."; + ARMARX_WARNING_S << "Received an unknown type when trying to set a skill argument type " + "from an aron data object."; } -} - +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.h index 336be31e20d4ff44496a8a2f8424d7dd3c1419f1..5090c12e82d28498efe8e1e63015e659f1e1abce 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetSetter.h @@ -23,17 +23,18 @@ #include <stack> -#include "../AronTreeWidgetItem.h" - -#include <RobotAPI/libraries/aron/core/type/variant/All.h> #include <RobotAPI/libraries/aron/core/data/variant/All.h> #include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h> +#include <RobotAPI/libraries/aron/core/type/variant/All.h> + +#include "../AronTreeWidgetItem.h" namespace armarx { - // Conversion from TreeView to aron data - class AronTreeWidgetSetterVisitor : - public armarx::aron::data::ConstVariantVisitor + // Conversion from aron data to Tree View data + // This should be used to programatically change data to be displayed in the GUI. + // This code will not be called, if changes are made on the GUI side. + class AronTreeWidgetSetterVisitor : public armarx::aron::data::ConstVariantVisitor { public: QTreeWidgetItem* parentItem; @@ -41,9 +42,9 @@ namespace armarx AronTreeWidgetItem* qWidgetItem; AronTreeWidgetSetterVisitor() = delete; - AronTreeWidgetSetterVisitor(QTreeWidgetItem* i, int x) : - parentItem(i), index(x) - {} + AronTreeWidgetSetterVisitor(QTreeWidgetItem* i, int x) : parentItem(i), index(x) + { + } virtual void visitAronVariant(const aron::data::DictPtr&) final; virtual void visitAronVariant(const aron::data::ListPtr&) final; @@ -58,7 +59,6 @@ namespace armarx private: bool checkTreeWidgetItemForSimilarName(const std::string& name) const; + void adjustNumberOfChildren(AronTreeWidgetItem* parent, size_t numChildren); }; -} - - +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51836fde9dc7a71fa44740c415fbaf03c3df79e7 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.cpp @@ -0,0 +1,42 @@ +#include "CustomWidget.h" + +#include "ArmarXCore/core/exceptions/local/ExpressionException.h" + +namespace armarx +{ + CustomWidget::CustomWidget(QTreeWidgetItem* overlayingItem) : overlayingItem(overlayingItem) + { + // connect to general QTreeWidgetItem callback. + // This also lets the conversion start for other objects. (Not just this widget) + ARMARX_CHECK(connect(this, + SIGNAL(elemChanged(QTreeWidgetItem*, int)), + overlayingItem->treeWidget(), + SIGNAL(itemChanged(QTreeWidgetItem*, int)))); + } + + CustomWidget* + CustomWidget::DynamicCast(QWidget* elem) + { + return dynamic_cast<CustomWidget*>(elem); + } + + CustomWidget* + CustomWidget::DynamicCastAndCheck(QWidget* elem) + { + if (!elem) + { + return nullptr; + } + auto* casted = DynamicCast(elem); + ARMARX_CHECK_NOT_NULL(casted); + return casted; + } + + void + CustomWidget::setSupressSignals(bool doSupress) + { + QObject::blockSignals(doSupress); + } + + +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..49477ffa148e6a5c38279015a356571e107dadb7 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/CustomWidget.h @@ -0,0 +1,26 @@ +#pragma once + +#include <QTreeWidgetItem> +#include <QWidget> + +namespace armarx +{ + + class CustomWidget : public QWidget + { + Q_OBJECT + + public: + CustomWidget(QTreeWidgetItem* overlayingItem); + static CustomWidget* DynamicCast(QWidget*); + static CustomWidget* DynamicCastAndCheck(QWidget*); + + virtual void setSupressSignals(bool doSupress); + + protected: + QTreeWidgetItem* overlayingItem; + + signals: + void elemChanged(QTreeWidgetItem* elem, int col); + }; +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e01710f03cf9fabe1f9f50b060bc058016099c8 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.cpp @@ -0,0 +1,250 @@ +#include "EditMatrixWidget.h" + +#include <QGridLayout> +#include <QLabel> + +#include "ArmarXCore/core/exceptions/local/ExpressionException.h" +#include "ArmarXCore/core/logging/Logging.h" + +#include "../../ColorPalettes.h" +#include "../visitors/AronTreeWidgetCreator.h" +#include "NDArrayHelper.h" + +namespace armarx +{ + EditMatrixWidget::EditMatrixWidget(long numRows, + long numCols, + aron::type::matrix::ElementType elemType, + QTreeWidgetItem* currentItem) : + CustomWidget(currentItem) + { + realRows = numRows; + realCols = numCols; + this->elemType = elemType; + // init surrounding layout + outerVerticalLayout = new QVBoxLayout(); + innerHorizontalLayout = new QHBoxLayout(); + outerVerticalLayout->addItem(innerHorizontalLayout); + + + QGridLayout* innerGrid = new QGridLayout(); + const long createRows = std::min(numRows, MAX_ROWS_DISPLAY); + const long createCols = std::min(numCols, MAX_COLS_DISPLAY); + + for (long i = 0; i < createRows * createCols; ++i) + { + auto* edit = new QLineEdit(); + dispElements.push_back(edit); + int currRow = i / createCols; + int currCol = i % createCols; + + innerGrid->addWidget(edit, currRow, currCol); + std::stringstream ss; + ss << "(" << currRow << ", " << currCol << ")"; + std::string text = ss.str(); + + edit->setText(text.c_str()); + } + innerHorizontalLayout->addItem(innerGrid); + + // check, if we need to signal to the user, that not all elements are displayed. + if (numRows > MAX_ROWS_DISPLAY) + { + QLabel* fullLabel = new QLabel("..."); + outerVerticalLayout->addWidget(fullLabel); + } + if (numCols > MAX_COLS_DISPLAY) + { + QLabel* fullLabel = new QLabel("..."); + innerHorizontalLayout->addWidget(fullLabel); + } + setLayout(outerVerticalLayout); + + // add hidden elements in vector + { + const auto hiddenCols = numCols - createCols; + // the 0th element holds all columns that are + // to the right of the displayed cols AND besides the displayed rows! + hiddenElems.push_back(std::vector<std::string>(hiddenCols * createRows, "")); + + // add all rows that are hidden + for (long i = 0; i < numRows - createRows; ++i) + { + // add full cols; everything is hidden here + hiddenElems.push_back(std::vector<std::string>(numCols, "")); + } + } + + for (size_t i = 0; i < dispElements.size(); ++i) + { + ARMARX_CHECK(connect( + dispElements[i], SIGNAL(editingFinished()), this, SLOT(matrixElementChanged()))); + } + } + + EditMatrixWidget* + EditMatrixWidget::DynamicCast(QWidget* elem) + { + return dynamic_cast<EditMatrixWidget*>(elem); + } + + EditMatrixWidget* + EditMatrixWidget::DynamicCastAndCheck(QWidget* elem) + { + if (!elem) + { + return nullptr; + } + auto* casted = DynamicCast(elem); + ARMARX_CHECK_NOT_NULL(casted); + return casted; + } + + void + EditMatrixWidget::setText(long row, long col, const std::string& str) + { + ARMARX_CHECK(row < realRows); + ARMARX_CHECK(col < realCols); + auto dispCols = getDisplayedCols(); + auto dispRows = getDisplayedRows(); + if (row < dispRows && col < dispCols) + { + dispElements[row * dispCols + col]->setText(str.c_str()); + dispElements[row * dispCols + col]->setCursorPosition(0); + } + else if (row < dispRows) + { + long idx = row * (realCols - dispCols) + col - dispCols; + hiddenElems.at(0).at(idx) = str; + } + else + { + hiddenElems.at(row - dispRows + 1).at(col) = str; + } + } + + std::string + EditMatrixWidget::getText(long row, long col) + { + ARMARX_CHECK(row < realRows); + ARMARX_CHECK(col < realCols); + const auto dispRows = getDisplayedRows(); + const auto dispCols = getDisplayedCols(); + if (row < dispRows && col < dispCols) + { + auto txt = dispElements.at(row * dispCols + col)->text(); + return txt.toStdString(); + } + else if (row < getDisplayedRows()) + { + // the stuff besides the displayed rows + long idx = row * (realCols - dispCols) + col - dispCols; + return hiddenElems.at(0).at(idx); + } + else + { + // stuff beneath displayed rows + return hiddenElems.at(row - dispRows + 1).at(col); + } + } + + void + EditMatrixWidget::highlightUnparsableEntries() + { + auto dispRows = getDisplayedRows(); + auto dispCols = getDisplayedCols(); + for (long row = 0; row < dispRows; ++row) + { + for (long col = 0; col < dispCols; ++col) + { + auto parsed = parseElement(row, col); + if (parsed.empty()) + { + dispElements.at(row * dispCols + col) + ->setPalette(gui_color_palette::getErrorPalette()); + } + else + { + dispElements.at(row * dispCols + col) + ->setPalette(gui_color_palette::getNormalPalette()); + } + } + } + } + + bool + EditMatrixWidget::hasParseErrors() + { + // also parse the hidden stuff! + for (long row = 0; row < realRows; ++row) + { + for (long col = 0; col < realCols; ++col) + { + auto parsed = parseElement(row, col); + if (parsed.empty()) + { + if (row >= getDisplayedRows() || col >= getDisplayedCols()) + { + ARMARX_ERROR + << "Programming error! Could not parse content in EditMatrixWidget " + "that was set programatically from inside the SkillManagerPlugin. " + "The error occured in row " + << row << " and col " << col << "."; + } + return true; + } + } + } + return false; + } + + std::vector<unsigned char> + EditMatrixWidget::parseElement(long row, long col) + { + std::string str = getText(row, col); + try + { + switch (elemType) + { + case armarx::aron::type::matrix::INT16: + return NDArrayHelper::toByteVector<int16_t>(str); + + case armarx::aron::type::matrix::INT32: + return NDArrayHelper::toByteVector<int32_t>(str); + + case armarx::aron::type::matrix::INT64: + return NDArrayHelper::toByteVector<int64_t>(str); + + case armarx::aron::type::matrix::FLOAT32: + return NDArrayHelper::toByteVector<float>(str); + + case armarx::aron::type::matrix::FLOAT64: + return NDArrayHelper::toByteVector<double>(str); + } + } + catch (const simox::error::SimoxError& err) + { + return {}; + } + return {}; + } + + long + EditMatrixWidget::getDisplayedRows() const + { + return std::min(realRows, MAX_ROWS_DISPLAY); + } + long + EditMatrixWidget::getDisplayedCols() const + { + return std::min(realCols, MAX_COLS_DISPLAY); + } + void + EditMatrixWidget::matrixElementChanged() + { + blockSignals(true); + highlightUnparsableEntries(); + blockSignals(false); + emit elemChanged(overlayingItem, 1); + } +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..1fdaaa9630a09ab4a73f83fc05fa065fd0663e4d --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/EditMatrixWidget.h @@ -0,0 +1,81 @@ +#pragma once +#include <vector> + +#include <QHBoxLayout> +#include <QLineEdit> +#include <QObject> +#include <QTreeWidgetItem> +#include <QVBoxLayout> + +#include "RobotAPI/libraries/aron/core/type/variant/ndarray/Matrix.h" + +#include "CustomWidget.h" + +namespace armarx +{ + // Custom Widget used to display Matrices + // MAX_ROWS_DISPLAY and MAX_COLS_DISPLAY are the maximal number of elements displayable + // everything else will not be displayed. However, there can still be made changes to this data with setText() + class EditMatrixWidget : public CustomWidget + { + Q_OBJECT + public: + EditMatrixWidget() = delete; + EditMatrixWidget(long numRows, + long numCols, + aron::type::matrix::ElementType elemType, + QTreeWidgetItem* currentWidget); + + static EditMatrixWidget* DynamicCast(QWidget*); + static EditMatrixWidget* DynamicCastAndCheck(QWidget*); + + // Sets the text on all visible rows and cols. + void setText(long row, long col, const std::string& str); + std::string getText(long row, long col); + void highlightUnparsableEntries(); + bool hasParseErrors(); + // returns an empty vector if parsing failed. Else, contains the individual bytes. + std::vector<unsigned char> parseElement(long row, long col); + + + private: + // Dimensions of the underlying Type to represent + long realRows = 1; + long realCols = 1; + + // maximum of rows / cols to display + static constexpr long MAX_ROWS_DISPLAY = 5; + static constexpr long MAX_COLS_DISPLAY = 5; + long getDisplayedRows() const; + long getDisplayedCols() const; + + // Want to add dots to show the user that not all is displayed. This needs some wrapping layouts + QVBoxLayout* outerVerticalLayout; + QHBoxLayout* innerHorizontalLayout; + + // Using row major layout + std::vector<QLineEdit*> dispElements; + // rows<cols<text>>: stores get and set messages for hidden elements (if there is not enough space for all elements) + std::vector<std::vector<std::string>> hiddenElems; + + template <typename T> + static std::vector<unsigned char> toByteVector(const std::string& str); + + // TODO: It would be nice to have this code somewhere else, this way, at least the GUI-responses + // are restricted to this Widget (signal & slot stuff) + aron::type::matrix::ElementType elemType; + + private slots: + void matrixElementChanged(); + }; + + template <typename T> + std::vector<unsigned char> + EditMatrixWidget::toByteVector(const std::string& str) + { + auto val = simox::alg::to_<T>(str); + std::vector<unsigned char> res(sizeof(val), 0); + *reinterpret_cast<T*>(res.data()) = val; + return res; + } +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bfe1be2bf154768ae5ff49eff04d13caf492d133 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.cpp @@ -0,0 +1,139 @@ +#include "IntEnumWidget.h" + +#include <QHBoxLayout> + +#include "RobotAPI/libraries/aron/core/type/variant/All.h" + +#include "../../ColorPalettes.h" +#include "../visitors/AronTreeWidgetConverter.h" + +namespace armarx +{ + IntEnumWidget::IntEnumWidget(const aron::type::IntEnumPtr& enumPtr, + QTreeWidgetItem* currentItem) : + CustomWidget(currentItem), element_type(enumPtr) + { + auto names = enumPtr->getAcceptedValueNames(); + auto outerLayout = new QHBoxLayout(); + outerLayout->setContentsMargins(0, 0, 0, 0); + innerWidget = new QComboBox(); + outerLayout->addWidget(innerWidget); + + for (const auto& n : names) + { + innerWidget->addItem(n.c_str()); + } + innerWidget->setInsertPolicy(QComboBox::NoInsert); + innerWidget->setEditable(true); + innerWidget->setCurrentIndex(0); + + setLayout(outerLayout); + ARMARX_CHECK(connect(innerWidget, + SIGNAL(currentTextChanged(const QString&)), + this, + SLOT(textChanged(const QString&)))); + } + + IntEnumWidget* + IntEnumWidget::DynamicCast(QWidget* widget) + { + return dynamic_cast<IntEnumWidget*>(widget); + } + + IntEnumWidget* + IntEnumWidget::DynamicCastAndCheck(QWidget* elem) + { + if (!elem) + { + return nullptr; + } + auto* casted = DynamicCast(elem); + ARMARX_CHECK_NOT_NULL(casted); + return casted; + } + + bool + IntEnumWidget::hasParseErrors() + { + return parseToAron().first; + } + + void + IntEnumWidget::setText(const QString& text) + { + innerWidget->setEditText(text); + highlightUnparsableEntries(); + } + + QString + IntEnumWidget::getText() + { + return innerWidget->currentText(); + } + + std::pair<bool, aron::data::IntPtr> + IntEnumWidget::parseToAron() + { + auto crAron = std::make_shared<aron::data::Int>(element_type->getPath()); + + // first look for strings in value map + auto valueMap = element_type->getAcceptedValueMap(); + std::string toParse = getText().toStdString(); + + auto searchRes = valueMap.find(toParse); + if (searchRes != valueMap.end()) + { + crAron->setValue(searchRes->second); + return {true, crAron}; + } + // maybe its the number directly + auto accVals = element_type->getAcceptedValues(); + int res; + try + { + res = simox::alg::to_<int>(toParse); + } + catch (const simox::error::SimoxError& err) + { + ARMARX_VERBOSE << "Failed to parse IntEnum: Could not convert \'" << toParse + << "\' to an int. It also was not one of the accepted strings."; + return {false, nullptr}; + } + if (std::find(accVals.begin(), accVals.end(), res) != accVals.end()) + { + + crAron->setValue(res); + } + else + { + ARMARX_VERBOSE << "Parsed int " << res + << "but this int is not part of the accepted values."; + return {false, nullptr}; + } + return {true, crAron}; + } + + void + IntEnumWidget::highlightUnparsableEntries() + { + auto parsed = parseToAron().first; + if (parsed) + { + innerWidget->setPalette(gui_color_palette::getNormalPalette()); + } + else + { + innerWidget->setPalette(gui_color_palette::getErrorPalette()); + } + } + + void + IntEnumWidget::textChanged(const QString&) + { + setSupressSignals(true); + highlightUnparsableEntries(); + setSupressSignals(false); + // fire change signal + emit CustomWidget::elemChanged(overlayingItem, 1); + } +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..095ea480f00a6962bb0ebf407c4f43a8379a59e3 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/IntEnumWidget.h @@ -0,0 +1,42 @@ +#pragma once + +#include <QComboBox> + +#include "RobotAPI/libraries/aron/core/data/variant/primitive/Int.h" +#include "RobotAPI/libraries/aron/core/type/variant/forward_declarations.h" + +#include "../AronTreeWidgetItem.h" +#include "CustomWidget.h" + +namespace armarx +{ + // Custom wrapper around the QComboBox widget to represent IntEnums + // This class handles parsing once the user edited the field and is also responsible + // to parse the according aron data from text + class IntEnumWidget : public CustomWidget + { + Q_OBJECT + public: + IntEnumWidget(const aron::type::IntEnumPtr&, QTreeWidgetItem* currentItem); + // needs to be called after the constructor, because qt needs the meta object to be fully constructed at this point + void postCtorCall(); + + static IntEnumWidget* DynamicCast(QWidget*); + static IntEnumWidget* DynamicCastAndCheck(QWidget*); + + bool hasParseErrors(); + void setText(const QString& text); + QString getText(); + std::pair<bool, aron::data::IntPtr> parseToAron(); + + private: + const aron::type::IntEnumPtr element_type; + QComboBox* innerWidget; + + bool noParseErrors = true; + + void highlightUnparsableEntries(); + private slots: + void textChanged(const QString&); + }; +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9599a2dbdfd456e1237542d34006f5d4c4c9bbf --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.cpp @@ -0,0 +1 @@ +#include "NDArrayHelper.h" diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..ed91b874cc5f91ee24cf95eb6b46013da7b9d590 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/NDArrayHelper.h @@ -0,0 +1,30 @@ +#pragma once +#include <string> +#include <vector> + +#include <SimoxUtility/algorithm/string.h> + +class NDArrayHelper +{ +public: + // Uses the simox utility to parse floatingpoint and fixed precision types + // it then writes the result into a byte vector + // an empty byte vector encodes a parsing error. + template <typename T> + std::vector<unsigned char> static toByteVector(const std::string& str) + { + try + { + auto val = simox::alg::to_<T>(str); + std::vector<unsigned char> res(sizeof(val), 0); + T* reinterpPtr = reinterpret_cast<T*>(res.data()); + T* laundered = std::launder(reinterpPtr); + *laundered = val; + return res; + } + catch (const simox::error::SimoxError& err) + { + return {}; + } + } +}; diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1d6fa3b946a704b180109c2598b663e2ba03bad --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.cpp @@ -0,0 +1,160 @@ +#include "QuaternionWidget.h" + +#include <QHBoxLayout> +#include <QLabel> +#include <QLineEdit> + +#include "../../ColorPalettes.h" +#include "NDArrayHelper.h" +namespace armarx +{ + + QuaternionWidget* + QuaternionWidget::DynamicCast(QWidget* elem) + { + return dynamic_cast<QuaternionWidget*>(elem); + } + + QuaternionWidget* + QuaternionWidget::DynamicCastAndCheck(QWidget* elem) + { + if (!elem) + { + return nullptr; + } + auto* casted = DynamicCast(elem); + ARMARX_CHECK_NOT_NULL(casted); + return casted; + } + + void + QuaternionWidget::setText(QuaternionComponents col, const std::string& str) + { + size_t idx = (size_t)col; + xyzw_components.at(idx)->setText(str.c_str()); + highlightUnparsableEntries(); + } + + bool + QuaternionWidget::hasParseErrors() + { + return parseErrors; + } + + armarx::QuaternionWidget::QuaternionWidget(aron::type::quaternion::ElementType elType, + QTreeWidgetItem* currentItem) : + CustomWidget(currentItem), element_type(elType) + { + auto outerLayout = new QHBoxLayout(); + auto labelCol1 = new QVBoxLayout(); + auto labelCol2 = new QVBoxLayout(); + auto xzEdit = new QVBoxLayout(); + auto ywEdit = new QVBoxLayout(); + + outerLayout->addLayout(labelCol1); + outerLayout->addLayout(xzEdit); + outerLayout->addLayout(labelCol2); + outerLayout->addLayout(ywEdit); + + xyzw_components.reserve(4); + for (size_t i = 0; i < 4; ++i) + { + xyzw_components.push_back(new QLineEdit()); + } + + // Tabbing order >> Viewing order. Thats why the indeces are a bit switched + labelCol1->addWidget(new QLabel("x")); + xzEdit->addWidget(xyzw_components.at(0)); + + labelCol2->addWidget(new QLabel("z")); + ywEdit->addWidget(xyzw_components.at(2)); + + labelCol1->addWidget(new QLabel("y")); + xzEdit->addWidget(xyzw_components.at(1)); + + labelCol2->addWidget(new QLabel("w")); + ywEdit->addWidget(xyzw_components.at(3)); + + for (const auto& el : xyzw_components) + { + ARMARX_CHECK( + connect(el, SIGNAL(editingFinished()), this, SLOT(quaternionElementChanged()))); + } + + setLayout(outerLayout); + highlightUnparsableEntries(); + } + + void + QuaternionWidget::highlightUnparsableEntries() + { + parseErrors = false; + for (size_t i = 0; i < 4; ++i) + { + bool ok = false; + switch (element_type) + { + case armarx::aron::type::quaternion::FLOAT32: + { + float flt; + std::tie(ok, flt) = parseQuatVals<float>((QuaternionComponents)i); + break; + } + case armarx::aron::type::quaternion::FLOAT64: + { + double dbl; + std::tie(ok, dbl) = parseQuatVals<double>((QuaternionComponents)i); + break; + } + } + if (ok) + { + xyzw_components.at(i)->setPalette(gui_color_palette::getNormalPalette()); + } + else + { + xyzw_components.at(i)->setPalette(gui_color_palette::getErrorPalette()); + parseErrors = true; + } + } + } + + std::vector<unsigned char> + QuaternionWidget::parseAllToNDArray() + { + std::vector<unsigned char> res; + bool success = true; + if (element_type == aron::type::quaternion::FLOAT32) + { + res.reserve(16); + for (size_t i = 0; i < 4; ++i) + { + auto bytevec = + NDArrayHelper::toByteVector<float>(xyzw_components.at(i)->text().toStdString()); + success &= !bytevec.empty(); + res.insert(res.end(), bytevec.begin(), bytevec.end()); + } + } + else + { + res.reserve(32); + for (size_t i = 0; i < 4; ++i) + { + auto bytevec = NDArrayHelper::toByteVector<double>( + xyzw_components.at(i)->text().toStdString()); + success &= !bytevec.empty(); + res.insert(res.end(), bytevec.begin(), bytevec.end()); + } + } + return (success) ? res : std::vector<unsigned char>(); + } + + void + QuaternionWidget::quaternionElementChanged() + { + CustomWidget::setSupressSignals(true); + highlightUnparsableEntries(); + CustomWidget::setSupressSignals(false); + emit CustomWidget::elemChanged(overlayingItem, 1); + } +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..d55d2bba35e2712d1d161c83ed86b06b300bcf2d --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/widgets/QuaternionWidget.h @@ -0,0 +1,68 @@ +#pragma once +#include <vector> + +#include <QLineEdit> +#include <QObject> +#include <QVBoxLayout> + +#include "RobotAPI/libraries/aron/core/type/variant/ndarray/Matrix.h" + +#include "CustomWidget.h" + + +namespace armarx +{ + // Custom Widget which represents a Quaternion - This class does not normalize the inputs + // It can parse its data to NDArray and also handles user edit signals itself. (And also the highlighting if errors occur) + class QuaternionWidget : public CustomWidget + { + Q_OBJECT + public: + QuaternionWidget(aron::type::quaternion::ElementType type, QTreeWidgetItem* currentItem); + + static QuaternionWidget* DynamicCast(QWidget*); + static QuaternionWidget* DynamicCastAndCheck(QWidget*); + + enum struct QuaternionComponents + { + X = 0, + Y, + Z, + W + }; + void setText(QuaternionComponents col, const std::string& str); + std::string getText(QuaternionComponents col); + bool hasParseErrors(); + std::vector<unsigned char> parseAllToNDArray(); + + private: + std::vector<QLineEdit*> xyzw_components; + aron::type::quaternion::ElementType element_type; + bool parseErrors = false; + + void highlightUnparsableEntries(); + template <typename T> + std::pair<bool, T> parseQuatVals(QuaternionComponents comp); + + private slots: + void quaternionElementChanged(); + }; + + template <typename T> + std::pair<bool, T> + QuaternionWidget::parseQuatVals(QuaternionWidget::QuaternionComponents comp) + { + // size_t data_size = element_type == aron::type::quaternion::ElementType::FLOAT32 ? 4 : 8; + try + { + T val = simox::alg::to_<T>(xyzw_components.at((size_t)comp)->text().toStdString()); + return {true, val}; + } + catch (const simox::error::SimoxError& err) + { + return {false, NAN}; + } + } + + +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/cache-v2 b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/cache-v2 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/cmakeFiles-v1 b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/cmakeFiles-v1 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/codemodel-v2 b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/.cmake/api/v1/query/codemodel-v2 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/qtcsettings.cmake b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/qtcsettings.cmake new file mode 100644 index 0000000000000000000000000000000000000000..fccf6a67eee120cbb1092f841fda5cca870a5a14 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/build/qtcsettings.cmake @@ -0,0 +1,8 @@ +# This file is managed by Qt Creator, do not edit! + +set("CMAKE_BUILD_TYPE" "RelWithDebInfo" CACHE "STRING" "" FORCE) +set("CMAKE_PROJECT_INCLUDE_BEFORE" "/common/homes/students/bodmer/opt/qtcreator/qtcreator/share/qtcreator/package-manager/auto-setup.cmake" CACHE "PATH" "" FORCE) +set("QT_QMAKE_EXECUTABLE" "/usr/lib/qt5/bin/qmake" CACHE "STRING" "" FORCE) +set("CMAKE_PREFIX_PATH" "/usr" CACHE "STRING" "" FORCE) +set("CMAKE_C_COMPILER" "/usr/bin/gcc" CACHE "STRING" "" FORCE) +set("CMAKE_CXX_COMPILER" "/usr/bin/g++" CACHE "STRING" "" FORCE) \ No newline at end of file diff --git a/source/RobotAPI/interface/CMakeLists.txt b/source/RobotAPI/interface/CMakeLists.txt index 5d9d3c04b278f8032125f98cf82d63aaa8253155..9e290598fee8047f853044e54ea3775b62ab49f7 100644 --- a/source/RobotAPI/interface/CMakeLists.txt +++ b/source/RobotAPI/interface/CMakeLists.txt @@ -108,6 +108,7 @@ set(SLICE_FILES aron.ice aron/Aron.ice + aron/test/AronConversionTestInterface.ice armem.ice diff --git a/source/RobotAPI/interface/aron/test/AronConversionTestInterface.ice b/source/RobotAPI/interface/aron/test/AronConversionTestInterface.ice new file mode 100644 index 0000000000000000000000000000000000000000..924f40c6d8664123c822eb9f7eb338d8d50b52d5 --- /dev/null +++ b/source/RobotAPI/interface/aron/test/AronConversionTestInterface.ice @@ -0,0 +1,61 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * package SpeechX::aron_cpp_to_python_conv_test + * author Rainer Kartmann ( rainer dot kartmann at kit dot edu ) + * date 2023 + * copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + + +#pragma once + +#include <RobotAPI/interface/aron/Aron.ice> + + +module armarx { module aron { module test +{ + +module dto +{ + + struct TestAronConversionRequest + { + string aronClassName; + ::armarx::aron::data::dto::Dict probe; + }; + struct TestAronConversionResponse + { + bool success; + string errorMessage; + + ::armarx::aron::data::dto::Dict probe; + }; + +}; + + +module dti +{ + + interface AronConversionTestInterface + { + dto::TestAronConversionResponse testAronConversion(dto::TestAronConversionRequest req); + }; + +}; + +};};}; diff --git a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h index 0b877909c4a35e5b867d21de7840b1625b5e74dc..02b2bcae49014e801c59d001fe9150dcae7a1b95 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h +++ b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h @@ -32,6 +32,12 @@ namespace armarx::armem::base /// An optional confidence, may be used for things like decay. float confidence = 1.0; + /// An optional value indicating the last access + Time lastAccessed = Time::Invalid(); + + /// A counter how often the instance has been accessed + unsigned long accessed = 0; + bool operator==(const EntityInstanceMetadata& other) const; inline bool operator!=(const EntityInstanceMetadata& other) const diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h index b6497f8ff421feb16b7f7b07ede1f2d3e57c2266..efc18d58c99ee298b71ce2e775a012d7e6050b04 100644 --- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h +++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h @@ -261,12 +261,12 @@ namespace armarx::armem::base * @param commit The commit. * @return The resulting memory IDs. */ - std::vector<UpdateResult> update(const Commit& commit) + std::vector<UpdateResult> update(const Commit& commit, const bool addMissingCoreSegmentDuringUpdate = false, const bool checkMemoryName = true) { std::vector<UpdateResult> results; for (const EntityUpdate& update : commit.updates) { - results.push_back(this->update(update)); + results.push_back(this->update(update, addMissingCoreSegmentDuringUpdate, checkMemoryName)); } return results; } @@ -276,11 +276,14 @@ namespace armarx::armem::base * @param update The update. * @return The resulting entity snapshot's ID. */ - UpdateResult update(const EntityUpdate& update) + UpdateResult update(const EntityUpdate& update, const bool addMissingCoreSegmentDuringUpdate = false, const bool checkMemoryName = true) { - this->_checkContainerName(update.entityID.memoryName, this->name()); + if (checkMemoryName) + { + this->_checkContainerName(update.entityID.memoryName, this->name()); + } - auto [inserted, coreSeg] = _addCoreSegmentIfMissing(update.entityID.coreSegmentName); + auto [inserted, coreSeg] = _addCoreSegmentIfMissing(update.entityID.coreSegmentName, addMissingCoreSegmentDuringUpdate); // Update entry. UpdateResult ret(coreSeg->update(update)); @@ -349,14 +352,14 @@ namespace armarx::armem::base protected: - std::pair<bool, CoreSegmentT*> _addCoreSegmentIfMissing(const std::string& coreSegmentName) + std::pair<bool, CoreSegmentT*> _addCoreSegmentIfMissing(const std::string& coreSegmentName, const bool addMissingCoreSegmentDuringUpdate) { CoreSegmentT* coreSeg = nullptr; auto it = this->_container.find(coreSegmentName); if (it == this->_container.end()) { - if (_addMissingCoreSegmentDuringUpdate) + if (addMissingCoreSegmentDuringUpdate) { // Insert into map. coreSeg = &addCoreSegment(coreSegmentName); @@ -373,13 +376,5 @@ namespace armarx::armem::base return {false, coreSeg}; } } - - - public: - - // ToDo: Remove from base structure - this should be specific to the server versions. - // If necessary at all. - bool _addMissingCoreSegmentDuringUpdate = false; - }; } diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.cpp index f2baa4865ff5d2a832e61acc857863d2c6ca545a..1495b275baa88a14aecb9487db781ac0236b57d5 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.cpp @@ -1,5 +1,6 @@ #include "JsonConverter.h" +#include <ArmarXCore/core/logging/Logging.h> #include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> namespace armarx::armem::server::ltm::converter::object diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.h index b975b352f007c8ebd3364af641ef75c3a7fc6a08..ebe21f4c1c35a03ab8a0b5219d26e57417c4533a 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.h @@ -65,7 +65,7 @@ namespace armarx::armem::server::ltm } /// iterate over all provider segments of this ltm - virtual bool forEachProviderSegment(std::function<void(ProviderSegmentT&)>&& func) const = 0; + virtual bool forEachProviderSegment(std::function<void(ProviderSegmentT&)> func) const = 0; /// find provider segment virtual std::shared_ptr<ProviderSegmentT> findProviderSegment(const std::string&) const = 0; diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.h b/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.h index 9dedb572fdc8b4ff31c6018f238009d45fde6763..15ebde328ec72b9f189f542087fd7753c2a3faf0 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.h @@ -59,11 +59,11 @@ namespace armarx::armem::server::ltm } /// iterate over all entity snapshots of this ltm - virtual bool forEachSnapshot(std::function<void(EntitySnapshotT&)>&& func) const = 0; - virtual bool forEachSnapshotInIndexRange(long first, long last, std::function<void(EntitySnapshotT&)>&& func) const = 0; - virtual bool forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshotT&)>&& func) const = 0; - virtual bool forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshotT&)>&& func) const = 0; - virtual bool forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshotT&)>&& func) const = 0; + virtual bool forEachSnapshot(std::function<void(EntitySnapshotT&)> func) const = 0; + virtual bool forEachSnapshotInIndexRange(long first, long last, std::function<void(EntitySnapshotT&)> func) const = 0; + virtual bool forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshotT&)> func) const = 0; + virtual bool forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshotT&)> func) const = 0; + virtual bool forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshotT&)> func) const = 0; /// find entity snapshot segment virtual std::shared_ptr<EntitySnapshotT> findSnapshot(const Time&) const = 0; diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryBase.h b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryBase.h index bec7576234c8f6bbc9064745f2d0cdc0f8ef333b..1b32ee2c9fc10bdb476b36b7046f46fc8518e462 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryBase.h @@ -123,10 +123,10 @@ namespace armarx::armem::server::ltm } /// iterate over all core segments of this ltm - virtual bool forEachCoreSegment(std::function<void(CoreSegmentT&)>&& func) const = 0; + virtual bool forEachCoreSegment(std::function<void(CoreSegmentT&)> func) const = 0; /// find core segment - virtual std::shared_ptr<CoreSegmentT> findCoreSegment(const std::string&) const = 0; + virtual std::shared_ptr<CoreSegmentT> findCoreSegment(const std::string&) const = 0; // TODO make unique!! /// default parameters. Implementation should use the configuration to configure virtual void createPropertyDefinitions(PropertyDefinitionsPtr& defs, const std::string& prefix) diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp index 6f38d6ea21317b44d37045c985f15d5efe2103da..d5318e1f1e6ec9933ddc7e6b50f3894044111917 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp @@ -33,4 +33,9 @@ namespace armarx::armem::server::ltm { return _id.getLeafItem(); } + + void MemoryItem::setMemoryName(const std::string& memoryName) + { + _id.memoryName = memoryName; + } } // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h index 570231509806a4f6a56d55ab4a4a2d7442de8807..b8d17fe471c17e62aa188406648515e5a32f384a 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h +++ b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h @@ -21,6 +21,7 @@ namespace armarx::armem::server::ltm std::string name() const; virtual void setMemoryID(const MemoryID&); + void setMemoryName(const std::string& memoryName); protected: std::shared_ptr<Processors> processors; diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/server/ltm/base/detail/ProviderSegmentBase.h index b5aa8f0ee95711001d378f06ef5c674266dc021b..c241d7889621f534991733baf82973e28428a641 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/ProviderSegmentBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/base/detail/ProviderSegmentBase.h @@ -65,7 +65,7 @@ namespace armarx::armem::server::ltm } /// iterate over all core segments of this ltm - virtual bool forEachEntity(std::function<void(EntityT&)>&& func) const = 0; + virtual bool forEachEntity(std::function<void(EntityT&)> func) const = 0; /// find entity segment virtual std::shared_ptr<EntityT> findEntity(const std::string&) const = 0; diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.cpp index 785276d04bd1e366be172ba7a07560a96a0c7755..cfc859a5f89418247c1d7f383cfea1b5bce8aa2a 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.cpp @@ -16,7 +16,7 @@ namespace armarx::armem::server::ltm::disk { } - bool CoreSegment::forEachProviderSegment(std::function<void(ProviderSegment&)>&& func) const + bool CoreSegment::forEachProviderSegment(std::function<void(ProviderSegment&)> func) const { auto mPath = getMemoryBasePathForMode(currentMode, currentExport); auto relPath = getRelativePathForMode(currentMode); diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.h b/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.h index 6dfc00e7e5e37814027cfc10a3be53dd83dff603..78ff8be3f12d35eeebbed370cc04559b37a57822 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.h +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.h @@ -18,7 +18,7 @@ namespace armarx::armem::server::ltm::disk CoreSegment(const std::filesystem::path& parentPath, const MemoryID& id, const std::shared_ptr<Processors>& p, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e); - bool forEachProviderSegment(std::function<void(ProviderSegment&)>&& func) const override; + bool forEachProviderSegment(std::function<void(ProviderSegment&)> func) const override; std::shared_ptr<ProviderSegment> findProviderSegment(const std::string&) const override; diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp index 6c87da45e576c10c18c6680141e00ed8c19aa3ba..8b00d8d39b8fa49de6c31d8b617549d97e6a45cb 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp @@ -21,7 +21,7 @@ namespace armarx::armem::server::ltm::disk { } - bool Entity::forEachSnapshot(std::function<void(EntitySnapshot&)>&& func) const + bool Entity::forEachSnapshot(std::function<void(EntitySnapshot&)> func) const { auto mPath = getMemoryBasePathForMode(currentMode, currentExport); auto relPath = getRelativePathForMode(currentMode); @@ -75,7 +75,7 @@ namespace armarx::armem::server::ltm::disk return true; } - bool Entity::forEachSnapshotInIndexRange(long first, long last, std::function<void(EntitySnapshot&)>&& func) const + bool Entity::forEachSnapshotInIndexRange(long first, long last, std::function<void(EntitySnapshot&)> func) const { ARMARX_WARNING << "PLEASE NOTE THAT QUERYING THE LTM INDEX WISE MAY BE BUGGY BECAUSE THE FILESYSTEM ITERATOR IS UNSORTED!"; @@ -106,7 +106,7 @@ namespace armarx::armem::server::ltm::disk return forEachSnapshot(std::move(f)); } - bool Entity::forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshot&)>&& func) const + bool Entity::forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshot&)> func) const { auto f = [&](EntitySnapshot& e) { @@ -120,7 +120,7 @@ namespace armarx::armem::server::ltm::disk return forEachSnapshot(std::move(f)); } - bool Entity::forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshot&)>&& func) const + bool Entity::forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshot&)> func) const { auto f = [&](EntitySnapshot& e) { @@ -134,7 +134,7 @@ namespace armarx::armem::server::ltm::disk return forEachSnapshot(std::move(f)); } - bool Entity::forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshot&)>&& func) const + bool Entity::forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshot&)> func) const { auto f = [&](EntitySnapshot& e) { diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.h b/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.h index 759b22733612c700ec0461541976cf3872d9df07..3d98ef1bf8abe315e005a110ad6fa807f373d7ba 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.h +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.h @@ -18,11 +18,11 @@ namespace armarx::armem::server::ltm::disk public: Entity(const std::filesystem::path& parentPath, const MemoryID& id, const std::shared_ptr<Processors>& p, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e); - bool forEachSnapshot(std::function<void(EntitySnapshot&)>&& func) const override; - bool forEachSnapshotInIndexRange(long first, long last, std::function<void(EntitySnapshot&)>&& func) const override; - bool forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshot&)>&& func) const override; - bool forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshot&)>&& func) const override; - bool forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshot&)>&& func) const override; + bool forEachSnapshot(std::function<void(EntitySnapshot&)> func) const override; + bool forEachSnapshotInIndexRange(long first, long last, std::function<void(EntitySnapshot&)> func) const override; + bool forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshot&)> func) const override; + bool forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshot&)> func) const override; + bool forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshot&)> func) const override; std::shared_ptr<EntitySnapshot> findSnapshot(const Time&) const override; std::shared_ptr<EntitySnapshot> findLatestSnapshot() const override; diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp index 72ed4653638d77adf1c1dc760354c8dcf12d43d3..f1706a545a0f3d81cee3637e3bef3f5eb7df0e17 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp @@ -80,6 +80,7 @@ namespace armarx::armem::server::ltm::disk if (std::find(allFilesInIndexFolder.begin(), allFilesInIndexFolder.end(), dataFilename) != allFilesInIndexFolder.end()) { + //ARMARX_INFO << "Convert data for entity " << id(); auto datafilecontent = util::readDataFromFile(mPath, relDataPath); auto dataaron = dictConverter.convert(datafilecontent, ""); datadict = aron::data::Dict::DynamicCastAndCheck(dataaron); @@ -110,6 +111,7 @@ namespace armarx::armem::server::ltm::disk ARMARX_ERROR << "Could not find the data file '" << relDataPath.string() << "'. Continuing without data."; } + //ARMARX_INFO << "Convert metadata for entity " << id(); if (std::find(allFilesInIndexFolder.begin(), allFilesInIndexFolder.end(), metadataFilename) != allFilesInIndexFolder.end()) { auto metadatafilecontent = util::readDataFromFile(mPath, relMetadataPath); diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.cpp index 6d0b4e1fa18ee244643c5fc45755af0468d056db..a2a374c6de24e4fd1dca370149841d79f85de027 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.cpp @@ -65,7 +65,7 @@ namespace armarx::armem::server::ltm::disk } } - bool Memory::forEachCoreSegment(std::function<void(CoreSegment&)>&& func) const + bool Memory::forEachCoreSegment(std::function<void(CoreSegment&)> func) const { for (unsigned long i = 0; i <= maxExportIndex; ++i) { diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.h b/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.h index c9f1e95b216a0dd0dac6ff67c9f28c9ef1b38d5c..afd3a09004eea72c406ebfea844ffa80b257fc84 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.h +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.h @@ -29,7 +29,7 @@ namespace armarx::armem::server::ltm::disk void configure(const nlohmann::json& config) final; - bool forEachCoreSegment(std::function<void(CoreSegment&)>&& func) const final; + bool forEachCoreSegment(std::function<void(CoreSegment&)> func) const final; std::shared_ptr<CoreSegment> findCoreSegment(const std::string& coreSegmentName) const final; protected: diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.cpp index ede13058b8a8abbca1eb348b3fa483234e4eae76..32500f7d6a799f678d5fdf1fce09024d93c4a796 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.cpp @@ -18,7 +18,7 @@ namespace armarx::armem::server::ltm::disk { } - bool ProviderSegment::forEachEntity(std::function<void(Entity&)>&& func) const + bool ProviderSegment::forEachEntity(std::function<void(Entity&)> func) const { auto mPath = getMemoryBasePathForMode(currentMode, currentExport); auto relPath = getRelativePathForMode(currentMode); diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.h b/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.h index 0402f4b98408b73719ea2d2889d02c195186aac6..dfa7c42714310a042dc344c043794eca4536ea00 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.h +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.h @@ -17,7 +17,7 @@ namespace armarx::armem::server::ltm::disk public: ProviderSegment(const std::filesystem::path& parentPath, const MemoryID& id, const std::shared_ptr<Processors>& p, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e); - bool forEachEntity(std::function<void(Entity&)>&& func) const override; + bool forEachEntity(std::function<void(Entity&)> func) const override; std::shared_ptr<Entity> findEntity(const std::string&) const override; diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp index daea3fcfc439326545a79ad00ac53e9133afa195..1a40e26a04923bccb123b4b07f00ab9be190efa9 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp @@ -1,5 +1,7 @@ #include "filesystem_util.h" +#include <algorithm> + #include <RobotAPI/libraries/armem/core/error/ArMemError.h> @@ -97,6 +99,7 @@ namespace armarx::armem::server::ltm::disk ret.push_back(subdirPath.filename()); } } + std::sort(ret.begin(), ret.end()); return ret; } @@ -111,6 +114,7 @@ namespace armarx::armem::server::ltm::disk ret.push_back(subdirPath.filename()); } } + std::sort(ret.begin(), ret.end()); return ret; } } diff --git a/source/RobotAPI/libraries/armem/server/plugins/Plugin.h b/source/RobotAPI/libraries/armem/server/plugins/Plugin.h index 02c89e5f323b4376ca4493f6b0f1e8efa22f3b60..aa6afd8171ff50cf43b955ff145a4770cf8f24b7 100644 --- a/source/RobotAPI/libraries/armem/server/plugins/Plugin.h +++ b/source/RobotAPI/libraries/armem/server/plugins/Plugin.h @@ -41,7 +41,7 @@ namespace armarx::armem::server::plugins public: - /// Set the name of the wm and the ltm (if enabled). + /// Set the name of the wm and the ltm void setMemoryName(const std::string& memoryName); diff --git a/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp b/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp index 7999a6a5752cd1bc9432f9caec95a6f928645a20..edaa7bb5c5d92b57b0edf3918d1674db34337680 100644 --- a/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp +++ b/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp @@ -31,9 +31,16 @@ #include <RobotAPI/libraries/aron/core/data/variant/All.h> #include <RobotAPI/libraries/aron/core/type/variant/All.h> +#include <RobotAPI/libraries/armem/server/ltm/disk/Memory.h> //#include "../core/io/diskWriter/NlohmannJSON/NlohmannJSONDiskWriter.h" +// TODO: REMOVE ME!! +#include <VirtualRobot/Robot.h> +#include <VirtualRobot/RobotNodeSet.h> +#include <VirtualRobot/Import/SimoxXMLFactory.h> +#include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.aron.generated.h> + #include <filesystem> #include <iostream> @@ -205,6 +212,61 @@ BOOST_AUTO_TEST_CASE(test_memory_export__easy_bool_setup) run<aron::type::Bool>("TestMemory_BoolSetup", "theBool"); } +BOOST_AUTO_TEST_CASE(test_memory_export__easy_fabian_setup) +{ + std::filesystem::path memoryExport = "/home/fabian/repos/projects/ltmtools/data/sim_2022_09_15"; + + armem::server::ltm::disk::Memory ltm(memoryExport, "Object"); + auto ltm_c_seg = ltm.findCoreSegment("Instance"); + + ltm_c_seg->forEachProviderSegment([](const armem::server::ltm::disk::ProviderSegment& ltm_p_seg){ + ltm_p_seg.forEachEntity([](const armem::server::ltm::disk::Entity& ltm_e){ + ltm_e.forEachSnapshot([](const armem::server::ltm::disk::EntitySnapshot& ltm_snapshot){ + armem::wm::EntitySnapshot s; + ltm_snapshot.loadAllReferences(s); + ltm_snapshot.resolve(s); + + auto i = s.getInstance(0); + auto data = i.data(); + + + + auto p = data->getElement("pose"); + auto p2 = armarx::aron::data::Dict::DynamicCastAndCheck(p); + + armarx::objpose::arondto::ObjectPose px; + px.fromAron(p2); + + auto a = p2->getElement("attachment"); + auto a2 = armarx::aron::data::Dict::DynamicCastAndCheck(a); + + armarx::objpose::arondto::ObjectAttachmentInfo ax; + ax.fromAron(a2); + + if (ax.agentName != "") + { + ARMARX_INFO << (ax.poseInFrame); + } + }); + }); + }); + + + //auto ltm_p_seg = ltm_c_seg->findProviderSegment("Armar3"); + //auto ltm_e = ltm_p_seg->findEntity("Armar3"); + + //armem::wm::Entity e; + //ltm_e->loadAllReferences(e); + //ltm_e->resolve(e); + + //std::function<void(armarx::armem::wm::EntitySnapshot)> f = [](armem::wm::EntitySnapshot s){ ARMARX_INFO << s.id(); }; + + //e.forEachSnapshot(f); + //auto wm = ltm.loadAllAndResolve(); + + +} + /* BOOST_AUTO_TEST_CASE(test_memory_export__easy_rainer_setup) { diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp index 622031b7aead835f8d91b9eeac4ac06362d731a1..b9c789398b0d8ce5c6fb17e0c2cb44fb5bc5b531 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp +++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp @@ -150,7 +150,7 @@ namespace armarx::armem::gui connect(this, &This::connected, this, &This::startPeriodicUpdateTimer); connect(updateWidget, &armem::gui::PeriodicUpdateWidget::update, this, &This::startQueries); - connect(periodicUpdateTimer, &QTimer::timeout, this, &This::updateAvailableMemories); + connect(periodicUpdateTimer, &QTimer::timeout, this, &This::updateListOfActiveMemories); connect(periodicUpdateTimer, &QTimer::timeout, this, &This::processQueryResults); connect(memoryGroup->queryWidget(), &armem::gui::QueryWidget::storeInLTM, this, &This::queryAndStoreInLTM); @@ -267,7 +267,7 @@ namespace armarx::armem::gui { std::stringstream ss; ss << "Memory name '" << memoryName - << "' is unknown. Known are: " << simox::alg::get_keys(memoryData); + << "' is unknown. Known are: " << simox::alg::join(simox::alg::get_keys(memoryData), ", "); statusLabel->setText(QString::fromStdString(ss.str())); return nullptr; } @@ -288,7 +288,7 @@ namespace armarx::armem::gui { TIMING_START(MemoryStore); - auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); + auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories(); for (auto& [name, reader] : memoryReaders) { // skip if memory should not be queried @@ -321,7 +321,7 @@ namespace armarx::armem::gui TIMING_START(MemoryStartRecording); - auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); + auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories(); for (auto& [name, reader] : memoryReaders) { // skip if memory should not be queried @@ -341,7 +341,7 @@ namespace armarx::armem::gui TIMING_START(MemoryStopRecording); - auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); + auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories(); for (auto& [name, reader] : memoryReaders) { // skip if memory should not be queried @@ -406,7 +406,8 @@ namespace armarx::armem::gui TIMING_START(MemoryExport) std::string status; - diskControl->storeOnDisk(directory, memoryData, &status); + std::vector<wm::Memory> memoryDataVec = simox::alg::get_values(memoryData); + diskControl->storeOnDisk(directory, memoryDataVec, &status); statusLabel->setText(QString::fromStdString(status)); TIMING_END_STREAM(MemoryExport, ARMARX_VERBOSE) @@ -418,19 +419,29 @@ namespace armarx::armem::gui { std::string status; - std::map<std::string, wm::Memory> data = + std::map<std::filesystem::path, wm::Memory> data = diskControl->loadFromDisk(directory, memoryGroup->queryInput(), &status); - for (auto& [name, memory] : data) + for (auto& [path, memory] : data) { + std::string name = memory.id().memoryName; + auto commit = armem::toCommit(memory); + if (memoryWriters.count(name) > 0) { - auto commit = armem::toCommit(memory); memoryWriters.at(name).commit(commit); } else { - ARMARX_WARNING << "No memory with name " << name << " available for commit."; + ARMARX_INFO << "No memory with name '" << name << "' available for commit. Create new virtual memory."; + + // Please note: Here we assume that a memory server with the same name does not exist. + // I think this assumption is ok, since nobody should use filepaths as memory name. + // Nonetheless, we did not restrict the user to do so... + std::string virtualMemoryName = name + " (at " + path.string() + ")"; + wm::Memory virtualMemory(virtualMemoryName); + virtualMemory.update(commit, true, false); + memoryData[virtualMemoryName] = virtualMemory; } } @@ -487,7 +498,7 @@ namespace armarx::armem::gui // Can't use a structured binding here because you can't capture those in a lambda // according to the C++ standard. - auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); + auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories(); for (const auto& pair : memoryReaders) { // skip if memory should not be queried @@ -592,7 +603,7 @@ namespace armarx::armem::gui } // Perhaps remove entries - auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); + auto enabledMemories = memoryGroup->queryWidget()->getEnabledMemories(); for (auto it = memoryData.begin(); it != memoryData.end();) { // Drop all entries in memoryData which are not in memoryReaders anymore. @@ -764,7 +775,7 @@ namespace armarx::armem::gui void - MemoryViewer::updateAvailableMemories() + MemoryViewer::updateListOfActiveMemories() { if (is_connected and mns) // mns must be connected and mns must be available { @@ -773,11 +784,13 @@ namespace armarx::armem::gui memoryReaders = mns.getAllReaders(true); memoryWriters = mns.getAllWriters(true); - std::vector<std::string> convVec; - std::transform(memoryReaders.begin(), memoryReaders.end(), std::back_inserter(convVec), [](const auto& p){return p.first;}); + std::vector<std::string> activeMemoryNames; + + // add all active memories to update list + std::transform(memoryReaders.begin(), memoryReaders.end(), std::back_inserter(activeMemoryNames), [](const auto& p){return p.first;}); TIMING_START(GuiUpdateAvailableMemories); - memoryGroup->queryWidget()->update(convVec); + memoryGroup->queryWidget()->update(activeMemoryNames); TIMING_END_STREAM(GuiUpdateAvailableMemories, ARMARX_VERBOSE); } catch (...) @@ -796,14 +809,16 @@ namespace armarx::armem::gui void MemoryViewer::updateMemoryTree() { - std::map<std::string, const armem::wm::Memory*> convMap; + std::map<std::string, const armem::wm::Memory*> memoriesToUpdate; + + //auto checkboxStates = memoryGroup->queryWidget()->getAvailableMemoryStates(); for (auto& [name, data] : memoryData) { - convMap[name] = &data; + memoriesToUpdate[name] = &data; } TIMING_START(GuiUpdateMemoryTree) - memoryGroup->tree()->update(convMap); + memoryGroup->tree()->update(memoriesToUpdate); TIMING_END_STREAM(GuiUpdateMemoryTree, ARMARX_VERBOSE) if (debugObserver) diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h index 7be0874b265375827d22067e4325edcbf6c4bd12..69fb59d1c2f83b53ebd6587cfd63c148bcab9b7f 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h +++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h @@ -110,7 +110,7 @@ namespace armarx::armem::gui void processQueryResults(); void updateMemoryTree(); - void updateAvailableMemories(); + void updateListOfActiveMemories(); signals: diff --git a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp index fe443952ce26bf9546c9238eaf1fa234f13368f6..a490d63436a484cee322d167a02675710c695260 100644 --- a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp @@ -78,7 +78,7 @@ namespace armarx::armem::gui::disk void ControlWidget::storeOnDisk( QString directory, - const std::map<std::string, wm::Memory> memoryData, + const std::vector<wm::Memory> memoryData, std::string* outStatus) { std::filesystem::path path(directory.toUtf8().constData()); @@ -92,8 +92,9 @@ namespace armarx::armem::gui::disk else { int numStored = 0; - for (const auto& [name, data] : memoryData) + for (const auto& data : memoryData) { + std::string name = data.id().memoryName; if (std::filesystem::is_regular_file(path / name)) { status << "Could not export memory '" << name << "' to " << path << ": Cannot overwrite existing file.\n"; @@ -116,7 +117,7 @@ namespace armarx::armem::gui::disk } - std::map<std::string, wm::Memory> + std::map<std::filesystem::path, wm::Memory> ControlWidget::loadFromDisk( QString directory, const armem::client::QueryInput& _queryInput, @@ -124,7 +125,7 @@ namespace armarx::armem::gui::disk { std::filesystem::path path(directory.toUtf8().constData()); - std::map<std::string, wm::Memory> memoryData; + std::map<std::filesystem::path, wm::Memory> memoryData; auto setStatus = [&](const std::string& s){ if (outStatus) @@ -161,7 +162,7 @@ namespace armarx::armem::gui::disk } } - // TODO: Only add data that matchs query? + // TODO: Only add data that matches query? // We use LTM as query target for the disk // armem::client::QueryInput queryInput = _queryInput; // queryInput.addQueryTargetToAll(armem::query::data::QueryTarget::LTM); @@ -172,8 +173,8 @@ namespace armarx::armem::gui::disk if (std::filesystem::is_directory(p)) { armem::server::ltm::disk::Memory ltm(p.parent_path(), p.filename()); - armem::wm::Memory memory = ltm.loadAllAndResolve(); // load list of references - memoryData[memory.name()] = std::move(memory); + armem::wm::Memory memory = ltm.loadAllAndResolve(); // load list of references and load data + memoryData[p] = memory; numLoaded++; } diff --git a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.h b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.h index b14c9b0a0810acbafba74638e6ebd87989e81165..5eb35b96057f0639a30d94df4dada8ecd38afd9a 100644 --- a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.h +++ b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.h @@ -5,6 +5,7 @@ #include <QWidget> #include <QString> +#include <filesystem> class QPushButton; @@ -26,10 +27,10 @@ namespace armarx::armem::gui::disk void storeOnDisk( QString directory, - const std::map<std::string, wm::Memory> memoryData, + const std::vector<wm::Memory> memoryData, std::string* outStatus = nullptr); - std::map<std::string, wm::Memory> + std::map<std::filesystem::path, wm::Memory> loadFromDisk( QString directory, const armem::client::QueryInput& queryInput, diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp index 54e5aaec313825ae63bf8f15351339fce9288129..a3ce95672ec49cf3a3cffb426f28a04be4b43ccc 100644 --- a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp @@ -162,8 +162,35 @@ namespace armarx::armem::gui return _dropDisabledCheckBox->isChecked(); } + std::map<std::string, QueryWidget::ActiveMemoryState> QueryWidget::getAvailableMemoryStates() const + { + std::scoped_lock l(enabledMemoriesMutex); + + std::map<std::string, QueryWidget::ActiveMemoryState> states; + int maxIndex = _availableMemoriesGroupBox->layout()->count(); + for (int i = 0; i < maxIndex; ++i) + { + auto w = _availableMemoriesGroupBox->layout()->itemAt(i)->widget(); + QCheckBox* box = static_cast<QCheckBox*>(w); + std::string memoryName = box->text().toStdString(); + if (box->isEnabled() && box->isChecked()) + { + states[memoryName] = ActiveMemoryState::FoundAndChecked; + } + else if (box->isEnabled() && !box->isChecked()) + { + states[memoryName] = ActiveMemoryState::FoundAndNotChecked; + } + else + { + states[memoryName] = ActiveMemoryState::NotFound; + } + } + return states; + } + - std::vector<std::string> QueryWidget::enabledMemories() const + std::vector<std::string> QueryWidget::getEnabledMemories() const { std::scoped_lock l(enabledMemoriesMutex); diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h index d3d534e5b4896d51d5d0a104852c1d6c64af982f..623b78c4126b6a09acd636c93b9d4c9b6f4934cf 100644 --- a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h +++ b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h @@ -22,6 +22,13 @@ namespace armarx::armem::gui public: + enum class ActiveMemoryState + { + FoundAndChecked, + FoundAndNotChecked, + NotFound + }; + QueryWidget(); armem::query::DataMode dataMode() const; @@ -31,7 +38,9 @@ namespace armarx::armem::gui int queryLinkRecursionDepth() const; - std::vector<std::string> enabledMemories() const; + std::map<std::string, ActiveMemoryState> getAvailableMemoryStates() const; + + std::vector<std::string> getEnabledMemories() const; void update(const std::vector<std::string>& memoryNames); diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp index 3b22bf1d1368a51be9e3ea71da20b8a343f3079b..c17ce69020b2b7f2c363219339754919fc805723 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp @@ -178,7 +178,7 @@ namespace armarx::armem::server::obj::instance objpose::ObjectPoseSeq newObjectPoses; stats.numUpdated = 0; - // timestamp used to reduce the rpc calls for robot sync + // timestamp used to reduce the rpc calls for robot sync Time robotSyncTimestamp = Time::Invalid(); for (const objpose::data::ProvidedObjectPose& provided : providedPoses) @@ -1317,7 +1317,7 @@ namespace armarx::armem::server::obj::instance if (robot) { - reader->synchronizeRobot(*robot, Clock::Now()); + ARMARX_CHECK(reader->synchronizeRobot(*robot, Clock::Now())); // Store robot if valid. loaded.emplace(robotName, robot); } diff --git a/source/RobotAPI/libraries/armem_objects/types.h b/source/RobotAPI/libraries/armem_objects/types.h index c7e4fe4897c46202543e3d12628cf22e8083b0b3..79fe9ac956f65869ceb03b35db8545155c4c963c 100644 --- a/source/RobotAPI/libraries/armem_objects/types.h +++ b/source/RobotAPI/libraries/armem_objects/types.h @@ -23,6 +23,7 @@ #include <Eigen/Geometry> +#include <RobotAPI/libraries/ArmarXObjects/ObjectPose.h> #include <RobotAPI/libraries/armem/core/MemoryID.h> #include <RobotAPI/libraries/armem/core/Time.h> #include <RobotAPI/libraries/armem_robot/types.h> @@ -31,6 +32,16 @@ #include "aron_forward_declarations.h" +namespace armarx::armem +{ + struct ObjectInstance + { + objpose::ObjectPose pose; + MemoryID classID; + MemoryID sourceID; + }; +} + namespace armarx::armem::attachment { using AgentID = armem::MemoryID; diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h index 19a184e8c4cee71e2a7866206f2ae55cd51f0d27..ab30cbc1317d98f802dc24cbe5d844da02b038e9 100644 --- a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h +++ b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h @@ -27,7 +27,6 @@ #include "RobotReader.h" - namespace armarx::armem::robot_state { /** @@ -47,7 +46,8 @@ namespace armarx::armem::robot_state void connect(); void registerPropertyDefinitions(::armarx::PropertyDefinitionsPtr& def); - bool synchronizeRobot(VirtualRobot::Robot& robot, const armem::Time& timestamp); + [[nodiscard]] bool synchronizeRobot(VirtualRobot::Robot& robot, + const armem::Time& timestamp); [[nodiscard]] VirtualRobot::RobotPtr getRobot(const std::string& name, @@ -70,14 +70,12 @@ namespace armarx::armem::robot_state private: - [[nodiscard]] VirtualRobot::RobotPtr _getSynchronizedRobot(const std::string& name, const armem::Time& timestamp = armem::Time::Invalid(), const VirtualRobot::RobotIO::RobotDescription& loadMode = - VirtualRobot::RobotIO::RobotDescription::eStructure, + VirtualRobot::RobotIO::RobotDescription::eStructure, bool blocking = true); - }; } // namespace armarx::armem::robot_state diff --git a/source/RobotAPI/libraries/aron/CMakeLists.txt b/source/RobotAPI/libraries/aron/CMakeLists.txt index ce4f7bc99cb8d923decfdd7fdb79390837e79150..e1ccc8560ff75b018fbc958d0f1febf0512d9590 100644 --- a/source/RobotAPI/libraries/aron/CMakeLists.txt +++ b/source/RobotAPI/libraries/aron/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(core) add_subdirectory(converter) add_subdirectory(codegeneration) add_subdirectory(common) +add_subdirectory(test) diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.cpp index 72a657218790d389d14283f7c22fb02ce183c357..85c6403e5e4452848c31ffbc3f59aa39c3fe46ee 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.cpp @@ -253,7 +253,6 @@ namespace armarx::aron::codegenerator::cpp c->addInherit("public armarx::aron::cpp::AronGeneratedClass"); // ctor - c->addCtor(generator.toCopyCtor(c->getName())); c->addCtor(generator.toInnerEnumCtor(c->getName())); // Specific methods @@ -336,6 +335,10 @@ namespace armarx::aron::codegenerator::cpp // ctor c->addCtor(gen.toCtor(c->getName())); + c->addCtor(gen.toCopyCtor(c->getName())); + + // dtor + c->addMethod(gen.toDtor(c->getName())); // Generic methods //std::cout << "Generate equals method" << std::endl; diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.cpp index 72f2eb78f04b610b0be55fc7a4d9fdabb90cab6d..be87200f51f745b314ef7f3f7c2a67beb18d332a 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.cpp @@ -41,6 +41,7 @@ namespace armarx::aron::codegenerator::cpp const std::string Generator::ARON_TEMPLATE_INSTANTIATIONS_ACCESSOR = Generator::ARON_VARIABLE_PREFIX + "_tmpls"; const std::string Generator::ARON_VARIANT_RETURN_ACCESSOR = Generator::ARON_VARIABLE_PREFIX + "_variant"; const std::string Generator::ARON_PATH_ACCESSOR = Generator::ARON_VARIABLE_PREFIX + "_p"; + const std::string Generator::ARON_OTHER_ACCESSOR = Generator::ARON_VARIABLE_PREFIX + "_o"; const SerializerFactoryPtr Generator::FACTORY = SerializerFactoryPtr(new GeneratorFactory()); @@ -168,17 +169,55 @@ namespace armarx::aron::codegenerator::cpp CppCtorPtr Generator::toCtor(const std::string& name) const { - CppCtorPtr c = CppCtorPtr(new CppCtor(name + "()")); - std::vector<std::pair<std::string, std::string>> initList = this->getCtorInitializers(""); - CppBlockPtr b = std::make_shared<CppBlock>(); - b->addLine("resetHard();"); - b->appendBlock(this->getCtorBlock("")); - c->addInitListEntries(initList); - c->setBlock(b); + CppBlockPtr b = this->getCtorBlock(""); + auto initList = this->getCtorInitializers(""); + + if (b->size() > 0 || initList.second) + { + CppCtorPtr c = CppCtorPtr(new CppCtor(name + "()")); + c->addInitListEntries(initList.first); + c->setBlock(b); + return c; + } + + CppCtorPtr c = CppCtorPtr(new CppCtor(name + "() = default;")); + return c; + } + CppCtorPtr Generator::toCopyCtor(const std::string& name) const + { + CppBlockPtr b = this->getCopyCtorBlock(""); + auto initList = this->getCopyCtorInitializers(""); + + if (b->size() > 0 || initList.second) + { + CppCtorPtr c = CppCtorPtr(new CppCtor(name + "(const " + name + "& " + ARON_OTHER_ACCESSOR + ")")); + c->addInitListEntries(initList.first); + c->setBlock(b); + return c; + } + + CppCtorPtr c = CppCtorPtr(new CppCtor(name + "(const " + name + "& " + ARON_OTHER_ACCESSOR + ") = default;")); return c; } + CppMethodPtr Generator::toDtor(const std::string& name) const + { + CppBlockPtr b = this->getDtorBlock(""); + if (b->size() > 0) + { + CppMethodPtr m = CppMethodPtr(new CppMethod("virtual ~" + name + "()")); + m->setBlock(b); + + m->setEnforceBlockGeneration(true); + return m; + } + + CppMethodPtr m = CppMethodPtr(new CppMethod("virtual ~" + name + "() = default;")); + m->setEnforceBlockGeneration(false); + return m; + } + CppMethodPtr Generator::toResetSoftMethod() const { std::stringstream doc; @@ -188,6 +227,8 @@ namespace armarx::aron::codegenerator::cpp CppMethodPtr m = CppMethodPtr(new CppMethod("virtual void resetSoft() override", doc.str())); CppBlockPtr b = this->getResetSoftBlock(""); m->setBlock(b); + + m->setEnforceBlockGeneration(true); return m; } @@ -200,6 +241,8 @@ namespace armarx::aron::codegenerator::cpp CppMethodPtr m = CppMethodPtr(new CppMethod("virtual void resetHard() override", doc.str())); CppBlockPtr b = this->getResetHardBlock(""); m->setBlock(b); + + m->setEnforceBlockGeneration(true); return m; } @@ -216,6 +259,8 @@ namespace armarx::aron::codegenerator::cpp std::string dummy; b->appendBlock(this->getWriteTypeBlock("", "", Path(), dummy)); m->setBlock(b); + + m->setEnforceBlockGeneration(true); return m; } @@ -237,6 +282,7 @@ namespace armarx::aron::codegenerator::cpp b->addLineAsBlock("throw ::armarx::aron::error::AronException(__PRETTY_FUNCTION__, std::string(\"An error occured during the write method of an aron generated class. The full error log was:\\n\") + " + ARON_VARIABLE_PREFIX + "_e.what());"); m->setBlock(b); + m->setEnforceBlockGeneration(true); return m; } @@ -260,6 +306,8 @@ namespace armarx::aron::codegenerator::cpp b->addLine("catch(const std::exception& " + ARON_VARIABLE_PREFIX + "_e)"); b->addLineAsBlock("throw ::armarx::aron::error::AronException(__PRETTY_FUNCTION__, std::string(\"An error occured during the read method of an aron generated class. The full error log was:\\n\") + " + ARON_VARIABLE_PREFIX + "_e.what());"); m->setBlock(b); + + m->setEnforceBlockGeneration(true); return m; } @@ -272,6 +320,8 @@ namespace armarx::aron::codegenerator::cpp CppMethodPtr m = CppMethodPtr(new CppMethod(info.returnType + " " + info.methodName + "() const", doc.str())); m->addLine(info.writerClassType + " writer;"); m->addLine("return " + info.enforceConversion + "(this->write(writer))" + info.enforceMemberAccess + ";"); + + m->setEnforceBlockGeneration(true); return m; } @@ -284,6 +334,8 @@ namespace armarx::aron::codegenerator::cpp CppMethodPtr m = CppMethodPtr(new CppMethod("void " + info.methodName + "(const " + info.argumentType + "& input)", doc.str())); m->addLine(info.readerClassType + " reader;"); m->addLine("this->read(reader, " + info.enforceConversion + "(input)" + info.enforceMemberAccess + ");"); + + m->setEnforceBlockGeneration(true); return m; } @@ -297,6 +349,8 @@ namespace armarx::aron::codegenerator::cpp m->addLine(info.returnType + " t;"); m->addLine("t.fromAron(input);"); m->addLine("return t;"); + + m->setEnforceBlockGeneration(true); return m; } @@ -309,6 +363,8 @@ namespace armarx::aron::codegenerator::cpp CppMethodPtr m = CppMethodPtr(new CppMethod("static " + info.returnType + " " + info.methodName + "()", doc.str())); m->addLine(info.writerClassType + " writer;"); m->addLine("return " + info.enforceConversion + "(writeType(writer))" + info.enforceMemberAccess + ";"); + + m->setEnforceBlockGeneration(true); return m; } @@ -323,6 +379,8 @@ namespace armarx::aron::codegenerator::cpp CppBlockPtr b = this->getEqualsBlock("", "i"); b->addLine("return true;"); m->setBlock(b); + + m->setEnforceBlockGeneration(true); return m; } @@ -337,9 +395,9 @@ namespace armarx::aron::codegenerator::cpp return {field}; } - std::vector<std::pair<std::string, std::string>> Generator::getCtorInitializers(const std::string&) const + std::pair<std::vector<std::pair<std::string, std::string>>, bool> Generator::getCtorInitializers(const std::string&) const { - return {}; + return {{}, false}; } CppBlockPtr Generator::getCtorBlock(const std::string&) const @@ -347,6 +405,27 @@ namespace armarx::aron::codegenerator::cpp return std::make_shared<CppBlock>(); } + std::pair<std::vector<std::pair<std::string, std::string>>, bool> Generator::getCopyCtorInitializers(const std::string& name) const + { + const auto& t = getType(); + if (t.getMaybe() == type::Maybe::UNIQUE_PTR || t.getMaybe() == type::Maybe::RAW_PTR) + { + return {{{name, ARON_OTHER_ACCESSOR + "." + name + " ? " + resolveMaybeGenerator("*" + ARON_OTHER_ACCESSOR + "." + name) + " : nullptr"}}, true}; + } + + return {{{name, ARON_OTHER_ACCESSOR + "." + name}}, false}; + } + + CppBlockPtr Generator::getCopyCtorBlock(const std::string&) const + { + return std::make_shared<CppBlock>(); + } + + CppBlockPtr Generator::getDtorBlock(const std::string&) const + { + return std::make_shared<CppBlock>(); + } + CppBlockPtr Generator::getResetHardBlock(const std::string& cppAccessor) const { CppBlockPtr block_if_data = std::make_shared<CppBlock>(); @@ -388,24 +467,35 @@ namespace armarx::aron::codegenerator::cpp return s; } - std::string Generator::resolveMaybeGenerator(const std::string& s) const + std::string Generator::resolveMaybeGenerator(const std::string& args) const { const auto& t = getType(); if (t.getMaybe() == type::Maybe::OPTIONAL) { - return s + " = std::make_optional<" + getInstantiatedCppTypename() + ">();"; + return "std::make_optional<" + getInstantiatedCppTypename() + ">(" + args + ")"; } if (t.getMaybe() == type::Maybe::RAW_PTR) { - return s + " = new " + getInstantiatedCppTypename() + "();"; + return "new " + getInstantiatedCppTypename() + "(" + args + ")"; } if (t.getMaybe() == type::Maybe::SHARED_PTR) { - return s + " = std::make_shared<" + getInstantiatedCppTypename() + ">();"; + return "std::make_shared<" + getInstantiatedCppTypename() + ">(" + args + ")"; } if (t.getMaybe() == type::Maybe::UNIQUE_PTR) { - return s + " = std::make_unique<" + getInstantiatedCppTypename() + ">();"; + return "std::make_unique<" + getInstantiatedCppTypename() + ">(" + args + ")"; + } + return ""; + + } + + std::string Generator::resolveMaybeGeneratorWithSetter(const std::string& s, const std::string& args) const + { + auto gen = resolveMaybeGenerator(args); + if (!gen.empty()) + { + return s + " = " + gen + ";"; } return ""; } @@ -496,7 +586,7 @@ namespace armarx::aron::codegenerator::cpp b->addLine("if (not (" + ARON_READER_ACCESSOR + ".readNull(" + variantAccessor + "))) // if aron contains data"); { CppBlockPtr ifb = std::make_shared<CppBlock>(); - ifb->addLine(resolveMaybeGenerator(cppAccessor)); + ifb->addLine(resolveMaybeGeneratorWithSetter(cppAccessor)); ifb->appendBlock(block_if_data); b->addBlock(ifb); } @@ -520,5 +610,3 @@ namespace armarx::aron::codegenerator::cpp return block_if_data; } } - - diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.h index 7b9c15a7d4c6f1409db4999b906933bff64f3370..18bec1e225a6fbae97c71c10a7bd82a21ba5604b 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/Generator.h @@ -91,9 +91,16 @@ namespace armarx::aron::codegenerator::cpp virtual std::vector<CppFieldPtr> getPublicVariableDeclarations(const std::string&) const; CppCtorPtr toCtor(const std::string&) const; - virtual std::vector<std::pair<std::string, std::string>> getCtorInitializers(const std::string&) const; + virtual std::pair<std::vector<std::pair<std::string, std::string>>, bool> getCtorInitializers(const std::string&) const; virtual CppBlockPtr getCtorBlock(const std::string&) const; + CppCtorPtr toCopyCtor(const std::string&) const; + virtual std::pair<std::vector<std::pair<std::string, std::string>>, bool> getCopyCtorInitializers(const std::string&) const; + virtual CppBlockPtr getCopyCtorBlock(const std::string&) const; + + CppMethodPtr toDtor(const std::string&) const; + virtual CppBlockPtr getDtorBlock(const std::string&) const; + CppMethodPtr toResetSoftMethod() const; virtual CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const; @@ -127,7 +134,8 @@ namespace armarx::aron::codegenerator::cpp std::string toPointerAccessor(const std::string&) const; std::string resolveMaybeAccessor(const std::string&) const; - std::string resolveMaybeGenerator(const std::string&) const; + std::string resolveMaybeGenerator(const std::string& args = "") const; + std::string resolveMaybeGeneratorWithSetter(const std::string&, const std::string& args = "") const; CppBlockPtr resolveMaybeResetHardBlock(const CppBlockPtr&, const std::string&) const; CppBlockPtr resolveMaybeResetSoftBlock(const CppBlockPtr&, const std::string&) const; @@ -144,6 +152,7 @@ namespace armarx::aron::codegenerator::cpp static const std::string ARON_WRITER_ACCESSOR; static const std::string ARON_TEMPLATE_INSTANTIATIONS_ACCESSOR; static const std::string ARON_VARIANT_RETURN_ACCESSOR; + static const std::string ARON_OTHER_ACCESSOR; private: static const SerializerFactoryPtr FACTORY; diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/container/Object.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/container/Object.cpp index 5b734427b84bbd9fa139f6518110b55b7daf48ae..617a658199e8380a3c6fe02ad13a5a13fad1e886 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/container/Object.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/container/Object.cpp @@ -57,7 +57,7 @@ namespace armarx::aron::codegenerator::cpp::generator bool b = std::find(x.disallowedBases.begin(), x.disallowedBases.end(), t.getPath().getRootIdentifier()) == x.disallowedBases.end(); return b; } - return true; + return false; } std::string checkForInstantiationTypenameReplacement(const type::Object& t) @@ -99,7 +99,8 @@ namespace armarx::aron::codegenerator::cpp::generator checkForInstantiationTypenameReplacement(e), checkForClassNameReplacement(e), simox::meta::get_type_name<data::dto::Dict>(), - simox::meta::get_type_name<type::dto::AronObject>(), e) + simox::meta::get_type_name<type::dto::AronObject>(), e), + has_been_replaced(checkForAllowedReplacement(e)) { } @@ -160,7 +161,7 @@ namespace armarx::aron::codegenerator::cpp::generator std::string escaped_accessor = EscapeAccessor(cppAccessor); std::string resolved_accessor = resolveMaybeAccessor(cppAccessor); - if (const auto reset = resolveMaybeGenerator(cppAccessor); !reset.empty()) + if (const auto reset = resolveMaybeGeneratorWithSetter(cppAccessor); !reset.empty()) { block_if_data->addLine(reset); } @@ -169,5 +170,31 @@ namespace armarx::aron::codegenerator::cpp::generator return resolveMaybeReadBlock(block_if_data, cppAccessor, variantAccessor); } + + + + CppBlockPtr Object::getResetHardBlock(const std::string& cppAccessor) const + { + if (has_been_replaced) + { + return Base::getResetHardBlock(cppAccessor); + } + + CppBlockPtr block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + nextEl() + "resetHard();"); + return resolveMaybeResetHardBlock(block_if_data, cppAccessor); + } + + CppBlockPtr Object::getResetSoftBlock(const std::string& cppAccessor) const + { + if (has_been_replaced) + { + return Base::getResetHardBlock(cppAccessor); + } + + auto block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + nextEl() + "resetSoft();"); + return this->resolveMaybeResetSoftBlock(block_if_data, cppAccessor); + } } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/container/Object.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/container/Object.h index b1a2995c443f4e680725fdcbfbf4ac6374d7c712..942dc161a8792b9b9455c08db5c40eba79260605 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/container/Object.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/container/Object.h @@ -37,12 +37,14 @@ namespace armarx::aron::codegenerator::cpp::generator std::string replacedInstantiatedTypename; std::vector<std::string> additionalIncludes; // additional includes for the replaced type and aron conversions - std::vector<std::string> disallowedBases; // disallow replacement if the used in a specific class + std::vector<std::string> disallowedBases; // disallow replacement if used in a specific class }; class Object : public detail::ContainerGenerator<type::Object, Object> { + using Base = detail::ContainerGenerator<type::Object, Object>; + public: // constructors Object(const type::Object&); @@ -53,5 +55,10 @@ namespace armarx::aron::codegenerator::cpp::generator CppBlockPtr getWriteTypeBlock(const std::string& typeAccessor, const std::string& cppAccessor, const Path&, std::string& variantAccessor) const final; CppBlockPtr getWriteBlock(const std::string& cppAccessor, const Path&, std::string& variantAccessor) const final; CppBlockPtr getReadBlock(const std::string& cppAccessor, const std::string& variantAccessor) const final; + CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const final; + CppBlockPtr getResetHardBlock(const std::string& cppAccessor) const final; + + private: + bool has_been_replaced = false; }; } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/enum/IntEnum.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/enum/IntEnum.cpp index c818db64a05d881f8f3efee3ae9d2a767c8383ed..00a9ab35d7f52eb757963c97355403377459737e 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/enum/IntEnum.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/enum/IntEnum.cpp @@ -88,7 +88,7 @@ namespace armarx::aron::codegenerator::cpp::generator CppBlockPtr IntEnum::getReadBlock(const std::string& cppAccessor, const std::string& variantAccessor) const { CppBlockPtr block_if_data = std::make_shared<CppBlock>(); - if (const auto reset = resolveMaybeGenerator(cppAccessor); !reset.empty()) + if (const auto reset = resolveMaybeGeneratorWithSetter(cppAccessor); !reset.empty()) { block_if_data->addLine(reset); } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Bool.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Bool.cpp index fb3572e26adb9a61cf7bcde1396a1a2cb4bfff26..7dcadbb33ae84d70a180e89763ca37a634946268 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Bool.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Bool.cpp @@ -49,4 +49,18 @@ namespace armarx::aron::codegenerator::cpp::generator "armarx::aron::Path("+ARON_PATH_ACCESSOR+", {"+simox::alg::join(p.getPath(), ", ")+"})); // of " + typeAccessor); return b; } + + CppBlockPtr Bool::getResetHardBlock(const std::string& cppAccessor) const + { + CppBlockPtr block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = false;"); + return resolveMaybeResetHardBlock(block_if_data, cppAccessor); + } + + CppBlockPtr Bool::getResetSoftBlock(const std::string& cppAccessor) const + { + auto block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = false;"); + return this->resolveMaybeResetSoftBlock(block_if_data, cppAccessor); + } } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Bool.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Bool.h index 85172f3de8745ac5b2feb465cd9ff8408e94cd56..381adec7bc759c7a20aedd54229dd499253110d1 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Bool.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Bool.h @@ -40,5 +40,7 @@ namespace armarx::aron::codegenerator::cpp::generator /* virtual implementations */ CppBlockPtr getWriteTypeBlock(const std::string& typeAccessor, const std::string& cppAccessor, const Path& p, std::string& variantAccessor) const final; + CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const final; + CppBlockPtr getResetHardBlock(const std::string& cppAccessor) const final; }; } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Double.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Double.cpp index 7076794550d8e149f496677c079da4a3b7517e03..735f3ad9dc4efdf0f00a34093671644aebb0eb3f 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Double.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Double.cpp @@ -50,4 +50,18 @@ namespace armarx::aron::codegenerator::cpp::generator "armarx::aron::Path("+ARON_PATH_ACCESSOR+", {"+simox::alg::join(p.getPath(), ", ")+"})); // of " + typeAccessor); return b; } + + CppBlockPtr Double::getResetHardBlock(const std::string& cppAccessor) const + { + CppBlockPtr block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = 0.0;"); + return resolveMaybeResetHardBlock(block_if_data, cppAccessor); + } + + CppBlockPtr Double::getResetSoftBlock(const std::string& cppAccessor) const + { + auto block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = 0.0;"); + return this->resolveMaybeResetSoftBlock(block_if_data, cppAccessor); + } } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Double.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Double.h index e109cc626500ce4004f2b69b670ed9574c947ea5..b9a96a077e225aad5b0871882e86e20f85fb3685 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Double.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Double.h @@ -39,5 +39,7 @@ namespace armarx::aron::codegenerator::cpp::generator /* virtual implementations */ CppBlockPtr getWriteTypeBlock(const std::string& typeAccessor, const std::string& cppAccessor, const Path& p, std::string& variantAccessor) const final; + CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const final; + CppBlockPtr getResetHardBlock(const std::string& cppAccessor) const final; }; } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Float.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Float.cpp index 6c740a79206d323e0b6e9bf0b66c19d82eb1593a..d3d27ea6c34713b3d81074c1ab64e37ed696d69c 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Float.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Float.cpp @@ -50,4 +50,18 @@ namespace armarx::aron::codegenerator::cpp::generator "armarx::aron::Path("+ARON_PATH_ACCESSOR+", {"+simox::alg::join(p.getPath(), ", ")+"})); // of " + typeAccessor); return b; } + + CppBlockPtr Float::getResetHardBlock(const std::string& cppAccessor) const + { + CppBlockPtr block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = 0.0f;"); + return resolveMaybeResetHardBlock(block_if_data, cppAccessor); + } + + CppBlockPtr Float::getResetSoftBlock(const std::string& cppAccessor) const + { + auto block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = 0.0f;"); + return this->resolveMaybeResetSoftBlock(block_if_data, cppAccessor); + } } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Float.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Float.h index a2f52f4fb7d78ebcefcd96ba3eba8d0b31fc7dcb..f1c88c502f92b7d86afc7668eda0710f0f3351b7 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Float.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Float.h @@ -39,5 +39,7 @@ namespace armarx::aron::codegenerator::cpp::generator /* virtual implementations */ CppBlockPtr getWriteTypeBlock(const std::string& typeAccessor, const std::string& cppAccessor, const Path& p, std::string& variantAccessor) const final; + CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const final; + CppBlockPtr getResetHardBlock(const std::string& cppAccessor) const final; }; } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Int.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Int.cpp index 9242126f54ae10d3ee26fd6e242de8014c6a23f7..7a976bd83fffa4ad52bec05c2a5392bbf7400798 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Int.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Int.cpp @@ -50,4 +50,18 @@ namespace armarx::aron::codegenerator::cpp::generator "armarx::aron::Path("+ARON_PATH_ACCESSOR+", {"+simox::alg::join(p.getPath(), ", ")+"})); // of " + typeAccessor); return b; } + + CppBlockPtr Int::getResetHardBlock(const std::string& cppAccessor) const + { + CppBlockPtr block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = 0;"); + return resolveMaybeResetHardBlock(block_if_data, cppAccessor); + } + + CppBlockPtr Int::getResetSoftBlock(const std::string& cppAccessor) const + { + auto block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = 0;"); + return this->resolveMaybeResetSoftBlock(block_if_data, cppAccessor); + } } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Int.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Int.h index eb18e445473f402c2be373da523ba92336a4ab48..b21abee9cef1850a1d55da0369a530b65585c210 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Int.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Int.h @@ -39,5 +39,7 @@ namespace armarx::aron::codegenerator::cpp::generator /* virtual implementations */ CppBlockPtr getWriteTypeBlock(const std::string& typeAccessor, const std::string& cppAccessor, const Path& p, std::string& variantAccessor) const final; + CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const final; + CppBlockPtr getResetHardBlock(const std::string& cppAccessor) const final; }; } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Long.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Long.cpp index 2231f3305264746bb5c31855cac0e6a5c3d712b0..fe6cd5e87f6f3db26873c351987f91d86556d27b 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Long.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Long.cpp @@ -50,4 +50,18 @@ namespace armarx::aron::codegenerator::cpp::generator "armarx::aron::Path("+ARON_PATH_ACCESSOR+", {"+simox::alg::join(p.getPath(), ", ")+"})); // of " + typeAccessor); return b; } + + CppBlockPtr Long::getResetHardBlock(const std::string& cppAccessor) const + { + CppBlockPtr block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = 0;"); + return resolveMaybeResetHardBlock(block_if_data, cppAccessor); + } + + CppBlockPtr Long::getResetSoftBlock(const std::string& cppAccessor) const + { + auto block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = 0;"); + return this->resolveMaybeResetSoftBlock(block_if_data, cppAccessor); + } } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Long.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Long.h index 8e74bf85b421ff3101af4f86a3edcdc91858559a..09d923e487108a7c2c0927156af77c21fddf79ec 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Long.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/Long.h @@ -39,5 +39,7 @@ namespace armarx::aron::codegenerator::cpp::generator /* virtual implementations */ CppBlockPtr getWriteTypeBlock(const std::string& typeAccessor, const std::string& cppAccessor, const Path& p, std::string& variantAccessor) const final; + CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const final; + CppBlockPtr getResetHardBlock(const std::string& cppAccessor) const final; }; } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/String.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/String.cpp index a335fafcbd33ffca5c0a1658aaa1da5ccfeb4cc6..d51ee9ed159a5abb82442a5501ffebb3500aad15 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/String.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/String.cpp @@ -50,4 +50,18 @@ namespace armarx::aron::codegenerator::cpp::generator "armarx::aron::Path("+ARON_PATH_ACCESSOR+", {"+simox::alg::join(p.getPath(), ", ")+"})); // of " + typeAccessor); return b; } + + CppBlockPtr String::getResetHardBlock(const std::string& cppAccessor) const + { + CppBlockPtr block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = \"\";"); + return resolveMaybeResetHardBlock(block_if_data, cppAccessor); + } + + CppBlockPtr String::getResetSoftBlock(const std::string& cppAccessor) const + { + auto block_if_data = std::make_shared<CppBlock>(); + block_if_data->addLine(cppAccessor + " = \"\";"); + return this->resolveMaybeResetSoftBlock(block_if_data, cppAccessor); + } } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/String.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/String.h index 7db96c8713e04a479d4f1623043f633d4d429f84..fd854ccee807d549fbe1448643eb31a4f069bcc8 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/String.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/primitive/String.h @@ -39,5 +39,7 @@ namespace armarx::aron::codegenerator::cpp::generator /* virtual implementations */ CppBlockPtr getWriteTypeBlock(const std::string& typeAccessor, const std::string& cppAccessor, const Path& p, std::string& variantAccessor) const final; + CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const final; + CppBlockPtr getResetHardBlock(const std::string& cppAccessor) const final; }; } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.cpp index 4e5b54e5c6a41bd74147a5445d4d5abdb298b5a4..f5463258db1423ba317c428b2d604907b913755a 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.cpp @@ -150,12 +150,18 @@ namespace armarx::aron::codegenerator::cpp::generator } - CppCtorPtr IntEnumClass::toCopyCtor(const std::string& name) const + /*CppCtorPtr IntEnumClass::toCopyCtor(const std::string& name) const { CppCtorPtr c = std::make_shared<CppCtor>(name + "(const " + getFullInstantiatedCppTypename() + "& i)"); std::vector<std::pair<std::string, std::string>> initList = {{"value", "i.value"}}; c->addInitListEntries(initList); + c->setBlock(std::make_shared<CppBlock>()); return c; + }*/ + + std::pair<std::vector<std::pair<std::string, std::string>>, bool> IntEnumClass::getCopyCtorInitializers(const std::string&) const + { + return {{{"value", ARON_OTHER_ACCESSOR + ".value"}}, false}; } CppCtorPtr IntEnumClass::toInnerEnumCtor(const std::string& name) const @@ -163,6 +169,7 @@ namespace armarx::aron::codegenerator::cpp::generator CppCtorPtr c = std::make_shared<CppCtor>(name + "(const " + std::string(IMPL_ENUM) + " e)"); std::vector<std::pair<std::string, std::string>> initList = {{"value", "e"}}; c->addInitListEntries(initList); + c->setBlock(std::make_shared<CppBlock>()); return c; } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.h index b03310d425bb6783f618e9548d573a87b87c77dc..10d6ca0c14d8100e71d78944f24fd3f46870b8e1 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.h @@ -42,6 +42,9 @@ namespace armarx::aron::codegenerator::cpp::generator // virtual implementations std::vector<CppFieldPtr> getPublicVariableDeclarations(const std::string&) const final; + + std::pair<std::vector<std::pair<std::string, std::string>>, bool> getCopyCtorInitializers(const std::string&) const final; + CppBlockPtr getResetHardBlock(const std::string& cppAccessor) const final; CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const final; CppBlockPtr getWriteTypeBlock(const std::string& typeAccessor, const std::string& cppAccessor, const Path&, std::string& variantAccessor) const final; @@ -50,7 +53,7 @@ namespace armarx::aron::codegenerator::cpp::generator CppBlockPtr getEqualsBlock(const std::string&, const std::string&) const final; // TODO: Move some of those methods to upper class for enums (if we want to support multiple enums) - CppCtorPtr toCopyCtor(const std::string&) const; + //CppCtorPtr toCopyCtor(const std::string&) const; CppCtorPtr toInnerEnumCtor(const std::string&) const; CppEnumPtr toInnerEnumDefinition() const; CppMethodPtr toIntMethod() const; diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.cpp index 5d5409792c245220df2a0f4918c02ef9412fa6af..e3af89daa12ecc2de2f4fe60d9269dd48f729c9a 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.cpp @@ -238,4 +238,25 @@ namespace armarx::aron::codegenerator::cpp::generator } return block_if_data; } + + std::pair<std::vector<std::pair<std::string, std::string>>, bool> ObjectClass::getCopyCtorInitializers(const std::string&) const + { + std::vector<std::pair<std::string, std::string>> ret; + + if (type.getExtends() != nullptr) + { + const auto extends_s = FromAronType(*type.getExtends()); + ret.push_back({extends_s->getFullInstantiatedCppTypename(), ARON_OTHER_ACCESSOR}); + } + + bool anyComplex = false; + for (const auto& [key, child] : type.getMemberTypes()) + { + auto child_s = FromAronType(*child); + auto initList = child_s->getCopyCtorInitializers(key); + simox::alg::append(ret, initList.first); + anyComplex = anyComplex || initList.second; + } + return {ret, anyComplex}; + } } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.h index dd8e7d3d95bb291a54aeba45d46bae8bbf336834..772d138cb7cc521753ce6bd3086bb076d475b462 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.h @@ -40,6 +40,9 @@ namespace armarx::aron::codegenerator::cpp::generator // virtual implementations std::vector<std::string> getRequiredIncludes() const final; std::vector<CppFieldPtr> getPublicVariableDeclarations(const std::string&) const final; + + std::pair<std::vector<std::pair<std::string, std::string>>, bool> getCopyCtorInitializers(const std::string&) const final; + CppBlockPtr getResetHardBlock(const std::string& cppAccessor) const final; CppBlockPtr getResetSoftBlock(const std::string& cppAccessor) const final; CppBlockPtr getWriteTypeBlock(const std::string& typeAccessor, const std::string& cppAccessor, const Path&, std::string& variantAccessor) const final; diff --git a/source/RobotAPI/libraries/aron/converter/binary/CMakeLists.txt b/source/RobotAPI/libraries/aron/converter/binary/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7fa2684a23d3ef1e887a5f11b1c5aa83cbbe4b8f --- /dev/null +++ b/source/RobotAPI/libraries/aron/converter/binary/CMakeLists.txt @@ -0,0 +1,34 @@ +set(LIB_NAME aronivtconverter) + +armarx_component_set_name("${LIB_NAME}") +armarx_set_target("Library: ${LIB_NAME}") + +armarx_build_if(IVT_FOUND "IVT not available") +armarx_build_if(OpenCV_FOUND "OpenCV not available") + +set(LIBS + aron + ivt + ivtopencv + + ${IVT_LIBRARIES} +) + +set(LIB_FILES + IVTConverter.cpp +) + +set(LIB_HEADERS + IVTConverter.h +) + +armarx_add_library("${LIB_NAME}" "${LIB_FILES}" "${LIB_HEADERS}" "${LIBS}") + +if(IVT_FOUND) + target_include_directories(aronivtconverter + SYSTEM PUBLIC + ${IVT_INCLUDE_DIRS} + ) +endif() + +add_library(RobotAPI::aron::converter::ivt ALIAS aronivtconverter) diff --git a/source/RobotAPI/libraries/aron/converter/binary/LTMVectorRepresentationConverter.cpp b/source/RobotAPI/libraries/aron/converter/binary/LTMVectorRepresentationConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..999359d6b79ef56bbe7352263556ad71316e7384 --- /dev/null +++ b/source/RobotAPI/libraries/aron/converter/binary/LTMVectorRepresentationConverter.cpp @@ -0,0 +1,53 @@ +/* + * This file is part of ArmarX. + * + * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T), + * Karlsruhe Institute of Technology (KIT), all rights reserved. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @author Fabian Peller-Konrad (fabian dot peller-konrad at kit dot edu) + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +// STD/STL +#include <numeric> + +// Header +#include "IVTConverter.h" + +namespace armarx::aron::converter +{ + std::shared_ptr<CByteImage> AronIVTConverter::ConvertToCByteImage(const data::NDArrayPtr& nav) + { + ARMARX_CHECK_NOT_NULL(nav); + + if (nav->getShape().size() != 3) // +1 for bytes per pixel + { + throw error::AronException(__PRETTY_FUNCTION__, "The size of an NDArray does not match.", nav->getPath()); + } + auto dims = nav->getShape(); + + auto ret = std::make_shared<CByteImage>(); + ret->Set(dims[0], dims[1], static_cast<CByteImage::ImageType>(std::stoi(nav->getType()))); + memcpy(reinterpret_cast<unsigned char*>(ret->pixels), nav->getData(), std::accumulate(std::begin(dims), std::end(dims), 1, std::multiplies<int>())); + return ret; + } + + data::NDArrayPtr ConvertFromCByteImage(const std::shared_ptr<CByteImage>& img) + { + // TODO: + return nullptr; + } +} diff --git a/source/RobotAPI/libraries/aron/converter/binary/LTMVectorRepresentationConverter.h b/source/RobotAPI/libraries/aron/converter/binary/LTMVectorRepresentationConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..6d0c23d3b598c7dc55334c7181fa39885ee15ce4 --- /dev/null +++ b/source/RobotAPI/libraries/aron/converter/binary/LTMVectorRepresentationConverter.h @@ -0,0 +1,45 @@ +/* +* This file is part of ArmarX. +* +* ArmarX is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* ArmarX is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* @author Fabian Peller (fabian dot peller at kit dot edu) +* @copyright http://www.gnu.org/licenses/gpl-2.0.txt +* GNU General Public License +*/ + +#pragma once + +// STD/STL +#include <memory> +#include <string> + +// IVT +#include <Image/ByteImage.h> + +// ArmarX +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <RobotAPI/interface/aron.h> +#include <RobotAPI/libraries/aron/core/data/variant/complex/NDArray.h> + + +namespace armarx::aron::converter +{ + class AronIVTConverter + { + AronIVTConverter() = delete; + public: + static std::shared_ptr<CByteImage> ConvertToCByteImage(const data::NDArrayPtr&); + static data::NDArrayPtr ConvertFromCByteImage(const std::shared_ptr<CByteImage>&); + }; +} diff --git a/source/RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.cpp b/source/RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.cpp index e6429e7fe75ba54fea8a38c6f41398c0d149d2a5..3729e90a5812a192c256f2deaaa13bbecad71bab 100644 --- a/source/RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.cpp +++ b/source/RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.cpp @@ -1,5 +1,7 @@ #include "NLohmannJSONConverter.h" +#include <ArmarXCore/core/logging/Logging.h> + namespace armarx::aron::converter { nlohmann::json AronNlohmannJSONConverter::ConvertToNlohmannJSON(const data::VariantPtr& aron) diff --git a/source/RobotAPI/libraries/aron/core/Exception.h b/source/RobotAPI/libraries/aron/core/Exception.h index 5395c9eb65d2a61632ab56ad5ee1704a8679e6e1..fc080bafd09e2d7424bf0fc18538539f680329da 100644 --- a/source/RobotAPI/libraries/aron/core/Exception.h +++ b/source/RobotAPI/libraries/aron/core/Exception.h @@ -26,6 +26,7 @@ // STD/STL // ArmarX +#include <ArmarXCore/core/logging/Logging.h> #include <RobotAPI/interface/aron.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> #include <ArmarXCore/core/exceptions/Exception.h> diff --git a/source/RobotAPI/libraries/aron/core/aron_conversions.h b/source/RobotAPI/libraries/aron/core/aron_conversions.h index d0f88cab840be59b86bbeb22d7229afb9f9f0b48..d27d6415877d4c15f9ddf36310e656590f8efd7e 100644 --- a/source/RobotAPI/libraries/aron/core/aron_conversions.h +++ b/source/RobotAPI/libraries/aron/core/aron_conversions.h @@ -3,12 +3,29 @@ #include <map> #include <memory> #include <optional> +#include <type_traits> #include <vector> #include "Path.h" namespace armarx::aron { + +namespace detail +{ + + // Helper concept to avoid ambiguities + template<typename DtoT, typename BoT> + concept DtoAndBoAreSame = std::is_same<DtoT, BoT>::value; + + template <class ...> + struct is_optional : public std::false_type {}; + + template <class ...Ts> + struct is_optional<std::optional<Ts...>> : public std::true_type {}; + +} + /** * Framework for converting ARON DTOs (Data Transfer Objects) to C++ BOs * (Business Objects) and back. @@ -51,12 +68,6 @@ namespace armarx::aron * } * @endcode */ - - // Helper concept to avoid ambiguities - template<typename DtoT, typename BoT> - concept DtoAndBoAreSame = std::is_same<DtoT, BoT>::value; - - // Same type template <class T> void toAron(T& dto, const T& bo) @@ -139,6 +150,24 @@ namespace armarx::aron } } + + // One-sided optional + template <class DtoT, class BoT> + requires (not detail::is_optional<BoT>::value) + void toAron(std::optional<DtoT>& dto, const BoT& bo) + { + dto = DtoT{}; + toAron(*dto, bo); + } + template <class DtoT, class BoT> + requires (not detail::is_optional<DtoT>::value) + void fromAron(DtoT& dto, const std::optional<BoT>& bo) + { + bo = BoT{}; + fromAron(dto, *bo); + } + + // Flag-controlled optional template <class DtoT, class BoT> void toAron(DtoT& dto, bool& dtoValid, const BoT& bo, bool boValid) @@ -154,6 +183,7 @@ namespace armarx::aron } } + template <class DtoT, class BoT> void fromAron(const DtoT& dto, bool dtoValid, BoT& bo, bool& boValid) { @@ -222,7 +252,7 @@ namespace armarx::aron // std::map template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT> - requires (!(DtoAndBoAreSame<DtoKeyT, BoKeyT> and DtoAndBoAreSame<DtoValueT, BoValueT>)) + requires (!(detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and detail::DtoAndBoAreSame<DtoValueT, BoValueT>)) void toAron(std::map<DtoKeyT, DtoValueT>& dtoMap, const std::map<BoKeyT, BoValueT>& boMap) { @@ -236,7 +266,7 @@ namespace armarx::aron } } template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT> - requires (!(DtoAndBoAreSame<DtoKeyT, BoKeyT> and DtoAndBoAreSame<DtoValueT, BoValueT>)) + requires (!(detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and detail::DtoAndBoAreSame<DtoValueT, BoValueT>)) void fromAron(const std::map<DtoKeyT, DtoValueT>& dtoMap, std::map<BoKeyT, BoValueT>& boMap) { @@ -252,7 +282,7 @@ namespace armarx::aron template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT> - requires (!(DtoAndBoAreSame<DtoKeyT, BoKeyT> and DtoAndBoAreSame<DtoValueT, BoValueT>)) + requires (!(detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and detail::DtoAndBoAreSame<DtoValueT, BoValueT>)) std::map<DtoKeyT, DtoValueT> toAron(const std::map<BoKeyT, BoValueT>& boMap) { std::map<DtoKeyT, DtoValueT> dtoMap; @@ -343,20 +373,20 @@ namespace armarx // std::vector template <class DtoT, class BoT> - requires (!aron::DtoAndBoAreSame<DtoT, BoT>) + requires (!aron::detail::DtoAndBoAreSame<DtoT, BoT>) void toAron(std::vector<DtoT>& dtos, const std::vector<BoT>& bos) { armarx::aron::toAron(dtos, bos); } template <class DtoT, class BoT> - requires (!aron::DtoAndBoAreSame<DtoT, BoT>) + requires (!aron::detail::DtoAndBoAreSame<DtoT, BoT>) void fromAron(const std::vector<DtoT>& dtos, std::vector<BoT>& bos) { armarx::aron::fromAron(dtos, bos); } template <class DtoT, class BoT> - requires (!aron::DtoAndBoAreSame<DtoT, BoT>) + requires (!aron::detail::DtoAndBoAreSame<DtoT, BoT>) std::vector<DtoT> toAron(const std::vector<BoT>& bos) { return armarx::aron::toAron<DtoT, BoT>(bos); @@ -365,13 +395,13 @@ namespace armarx // std::map template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT> - requires (!(aron::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::DtoAndBoAreSame<DtoValueT, BoValueT>)) + requires (!(aron::detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::detail::DtoAndBoAreSame<DtoValueT, BoValueT>)) void toAron(std::map<DtoKeyT, DtoValueT>& dtoMap, const std::map<BoKeyT, BoValueT>& boMap) { armarx::aron::toAron(dtoMap, boMap); } template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT> - requires (!(aron::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::DtoAndBoAreSame<DtoValueT, BoValueT>)) + requires (!(aron::detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::detail::DtoAndBoAreSame<DtoValueT, BoValueT>)) void fromAron(const std::map<DtoKeyT, DtoValueT>& dtoMap, std::map<BoKeyT, BoValueT>& boMap) { armarx::aron::fromAron(dtoMap, boMap); @@ -379,7 +409,7 @@ namespace armarx template <class DtoKeyT, class DtoValueT, class BoKeyT, class BoValueT> - requires (!(aron::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::DtoAndBoAreSame<DtoValueT, BoValueT>)) + requires (!(aron::detail::DtoAndBoAreSame<DtoKeyT, BoKeyT> and aron::detail::DtoAndBoAreSame<DtoValueT, BoValueT>)) std::map<DtoKeyT, DtoValueT> toAron(const std::map<BoKeyT, BoValueT>& boMap) { armarx::aron::toAron<DtoKeyT, DtoValueT, BoKeyT, BoValueT>(boMap); diff --git a/source/RobotAPI/libraries/aron/core/data/rw/reader/nlohmannJSON/NlohmannJSONReader.cpp b/source/RobotAPI/libraries/aron/core/data/rw/reader/nlohmannJSON/NlohmannJSONReader.cpp index 21fdfc82b0fdec76910890100721d6f5ee19654c..e6beb0e9aab36bc5aa245155b7a42b3d0acb82ab 100644 --- a/source/RobotAPI/libraries/aron/core/data/rw/reader/nlohmannJSON/NlohmannJSONReader.cpp +++ b/source/RobotAPI/libraries/aron/core/data/rw/reader/nlohmannJSON/NlohmannJSONReader.cpp @@ -52,7 +52,8 @@ namespace armarx::aron::data::reader data::Descriptor NlohmannJSONReader::getDescriptor(InputType& input) { - return ConstNlohmannJSONVisitor::GetDescriptor(input); + auto ret = ConstNlohmannJSONVisitor::GetDescriptor(input); + return ret; } void NlohmannJSONReader::readList(const nlohmann::json& input, std::vector<nlohmann::json>& elements, Path& p) diff --git a/source/RobotAPI/libraries/aron/core/data/variant/complex/NDArray.cpp b/source/RobotAPI/libraries/aron/core/data/variant/complex/NDArray.cpp index 111068b393c86b681179544c4d60fd02953f3f36..483088aa7ffaf706271072d5e13d55f26b8e4ec4 100644 --- a/source/RobotAPI/libraries/aron/core/data/variant/complex/NDArray.cpp +++ b/source/RobotAPI/libraries/aron/core/data/variant/complex/NDArray.cpp @@ -142,6 +142,7 @@ namespace armarx::aron::data { if (t.empty()) { + ARMARX_TRACE; throw error::AronException(__PRETTY_FUNCTION__, "The type cannot be empty", getPath()); } @@ -166,6 +167,7 @@ namespace armarx::aron::data type::VariantPtr NDArray::recalculateType() const { + ARMARX_TRACE; throw error::NotImplementedYetException(__PRETTY_FUNCTION__); } @@ -179,29 +181,35 @@ namespace armarx::aron::data case type::Descriptor::MATRIX: { auto casted = type::Matrix::DynamicCastAndCheck(type); + ARMARX_TRACE; return (aron->shape.size() == 3 && aron->shape[0] == casted->getRows() && aron->shape[1] == casted->getCols()); } case type::Descriptor::QUATERNION: { auto casted = type::Quaternion::DynamicCastAndCheck(type); + ARMARX_TRACE; return (aron->shape.size() == 3 && aron->shape[0] == 1 && aron->shape[1] == 4); } case type::Descriptor::POINTCLOUD: { auto casted = type::PointCloud::DynamicCastAndCheck(type); + ARMARX_TRACE; return (aron->shape.size() == 3); } case type::Descriptor::IMAGE: { auto casted = type::Image::DynamicCastAndCheck(type); + ARMARX_TRACE; return (aron->shape.size() == 3); } case type::Descriptor::NDARRAY: { auto casted = type::NDArray::DynamicCastAndCheck(type); + ARMARX_TRACE; return (aron->shape.size() == (unsigned int) casted->getNumberDimensions()); } default: + ARMARX_TRACE; return false; } } diff --git a/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp b/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp index 09cab7521090642ff509a0aa0fd9bdb17c99544c..9724ae6279a2b2a2140d5964d7d101f6e9fbabc8 100644 --- a/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp +++ b/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp @@ -137,6 +137,7 @@ namespace armarx::aron::data { if (hasElement(key)) { + ARMARX_TRACE; throw error::AronException(__PRETTY_FUNCTION__, "The key '"+key+"' already exists in a aron dict."); } setElement(key, data); @@ -152,6 +153,7 @@ namespace armarx::aron::data auto it = childrenNavigators.find(key); if (it == childrenNavigators.end()) { + ARMARX_TRACE; throw error::AronException(__PRETTY_FUNCTION__, "Could not find key '" + key + "'. But I found the following keys: [" + simox::alg::join(this->getAllKeys(), ", ") + "]", getPath()); } return it->second; @@ -203,8 +205,10 @@ namespace armarx::aron::data return "armarx::aron::data::Dict"; } + // TODO type::VariantPtr Dict::recalculateType() const { + ARMARX_TRACE; throw error::NotImplementedYetException(__PRETTY_FUNCTION__); } @@ -227,29 +231,26 @@ namespace armarx::aron::data ARMARX_TRACE; return false; } - if (!objectTypeNav->getMemberType(key)) - { - ARMARX_TRACE; - return false; - } + auto childTypeNav = objectTypeNav->getMemberType(key); if (!nav) { ARMARX_TRACE; - auto childTypeNav = objectTypeNav->getMemberType(key); - if (childTypeNav->getMaybe() == type::Maybe::NONE) + if (childTypeNav && childTypeNav->getMaybe() == type::Maybe::NONE) { ARMARX_TRACE; return false; } + ARMARX_TRACE; return true; } - if (!nav->fullfillsType(objectTypeNav->getMemberType(key))) + if (!nav->fullfillsType(childTypeNav)) { ARMARX_TRACE; return false; } } + ARMARX_TRACE; return true; } case type::Descriptor::DICT: @@ -259,20 +260,29 @@ namespace armarx::aron::data for (const auto& [key, nav] : childrenNavigators) { (void) key; - if (!nav || !dictTypeNav->getAcceptedType()) + auto childTypeNav = dictTypeNav->getAcceptedType(); + if (!nav) { ARMARX_TRACE; - return false; + if (childTypeNav && childTypeNav->getMaybe() == type::Maybe::NONE) + { + ARMARX_TRACE; + return false; + } + ARMARX_TRACE; + return true; } - if (!nav->fullfillsType(dictTypeNav->getAcceptedType())) + if (!nav->fullfillsType(childTypeNav)) { ARMARX_TRACE; return false; } } + ARMARX_TRACE; return true; } default: + ARMARX_TRACE; return false; } } @@ -296,11 +306,13 @@ namespace armarx::aron::data { if (!path.hasElement()) { + ARMARX_TRACE; throw error::AronException(__PRETTY_FUNCTION__, "Could not navigate without a valid path", path); } std::string el = path.getFirstElement(); if (!hasElement(el)) { + ARMARX_TRACE; throw error::ValueNotValidException(__PRETTY_FUNCTION__, "Could not find an element of a path.", el, path); } @@ -313,6 +325,7 @@ namespace armarx::aron::data Path next = path.withDetachedFirstElement(); if (!childrenNavigators.at(el)) { + ARMARX_TRACE; throw error::AronException(__PRETTY_FUNCTION__, "Could not navigate into a NULL member. Seems like the member is optional and not set.", next); } return childrenNavigators.at(el)->navigateAbsolute(next); diff --git a/source/RobotAPI/libraries/aron/core/data/variant/container/List.cpp b/source/RobotAPI/libraries/aron/core/data/variant/container/List.cpp index db80996a17bc20796dbca992bfd765ef31aad93d..c53b51ee1b04c3e903b4ddd718b9793d75303412 100644 --- a/source/RobotAPI/libraries/aron/core/data/variant/container/List.cpp +++ b/source/RobotAPI/libraries/aron/core/data/variant/container/List.cpp @@ -127,7 +127,8 @@ namespace armarx::aron::data { if (i > aron->elements.size()) { - error::AronException(__PRETTY_FUNCTION__, "Cannot set a listelement at index " + std::to_string(i) + " because this list has size " + std::to_string(aron->elements.size())); + ARMARX_TRACE; + throw error::AronException(__PRETTY_FUNCTION__, "Cannot set a listelement at index " + std::to_string(i) + " because this list has size " + std::to_string(aron->elements.size())); } if (i == aron->elements.size()) @@ -165,6 +166,7 @@ namespace armarx::aron::data { if (i >= childrenNavigators.size()) { + ARMARX_TRACE; throw error::ValueNotValidException(__PRETTY_FUNCTION__, "The index is out of bounds (size = " + std::to_string(childrenNavigators.size()) + ")", std::to_string(i), getPath()); } return childrenNavigators[i]; @@ -208,6 +210,7 @@ namespace armarx::aron::data // TODO type::VariantPtr List::recalculateType() const { + ARMARX_TRACE; throw error::NotImplementedYetException(__PRETTY_FUNCTION__); } @@ -224,17 +227,24 @@ namespace armarx::aron::data auto listTypeNav = type::List::DynamicCastAndCheck(type); for (const auto& nav : childrenNavigators) { - if (!nav && !listTypeNav->getAcceptedType()) + auto childTypeNav = listTypeNav->getAcceptedType(); + if (!nav) { + if (childTypeNav && childTypeNav->getMaybe() == type::Maybe::NONE) + { + ARMARX_TRACE; + return false; + } ARMARX_TRACE; - return false; + return true; } - if (!nav->fullfillsType(listTypeNav->getAcceptedType())) + if (!nav->fullfillsType(childTypeNav)) { ARMARX_TRACE; return false; } } + ARMARX_TRACE; return true; } case type::Descriptor::TUPLE: @@ -243,15 +253,30 @@ namespace armarx::aron::data unsigned int i = 0; for (const auto& nav : childrenNavigators) { - if (!nav && !tupleTypeNav->getAcceptedType(i)) + if (!tupleTypeNav->hasAcceptedType(i)) { + ARMARX_TRACE; + return false; + } + + auto childTypeNav = tupleTypeNav->getAcceptedType(i); + if (!nav) + { + if (childTypeNav && childTypeNav->getMaybe() == type::Maybe::NONE) + { + ARMARX_TRACE; + return false; + } + ARMARX_TRACE; return false; } if (!nav->fullfillsType(tupleTypeNav->getAcceptedType(i))) { + ARMARX_TRACE; return false; } } + ARMARX_TRACE; return true; } case type::Descriptor::PAIR: @@ -259,19 +284,36 @@ namespace armarx::aron::data auto pairTypeNav = type::Pair::DynamicCastAndCheck(type); if (childrenSize() != 2) { + ARMARX_TRACE; return false; } - if (!childrenNavigators[0] && !pairTypeNav->getFirstAcceptedType()) + auto firstChildTypeNav = pairTypeNav->getFirstAcceptedType(); + if (!childrenNavigators[0]) { + if (firstChildTypeNav && firstChildTypeNav->getMaybe() == type::Maybe::NONE) + { + ARMARX_TRACE; + return false; + } + ARMARX_TRACE; return false; } - if (!childrenNavigators[1] && !pairTypeNav->getSecondAcceptedType()) + auto secondChildTypeNav = pairTypeNav->getSecondAcceptedType(); + if (!childrenNavigators[1]) { + if (secondChildTypeNav && secondChildTypeNav->getMaybe() == type::Maybe::NONE) + { + ARMARX_TRACE; + return false; + } + ARMARX_TRACE; return false; } - return childrenNavigators[0]->fullfillsType(pairTypeNav->getFirstAcceptedType()) && childrenNavigators[1]->fullfillsType(pairTypeNav->getSecondAcceptedType()); + ARMARX_TRACE; + return childrenNavigators[0]->fullfillsType(firstChildTypeNav) && childrenNavigators[1]->fullfillsType(secondChildTypeNav); } default: + ARMARX_TRACE; return false; } } @@ -295,6 +337,7 @@ namespace armarx::aron::data unsigned int i = std::stoi(path.getFirstElement()); if (!hasElement(i)) { + ARMARX_TRACE; throw error::ValueNotValidException(__PRETTY_FUNCTION__, "Could not find an element of a path.", std::to_string(i), std::to_string(childrenSize())); } @@ -307,6 +350,7 @@ namespace armarx::aron::data Path next = path.withDetachedFirstElement(); if (!childrenNavigators.at(i)) { + ARMARX_TRACE; throw error::AronException(__PRETTY_FUNCTION__, "Could not navigate into a NULL member. Seems like the member is optional and not set.", next); } return childrenNavigators.at(i)->navigateAbsolute(next); diff --git a/source/RobotAPI/libraries/aron/core/data/variant/primitive/Bool.cpp b/source/RobotAPI/libraries/aron/core/data/variant/primitive/Bool.cpp index 0e68bbc6dc16c373dd63c4626a45f5b1377afad4..2f7fe6fc8e486c43c32875c1cf072e721146c402 100644 --- a/source/RobotAPI/libraries/aron/core/data/variant/primitive/Bool.cpp +++ b/source/RobotAPI/libraries/aron/core/data/variant/primitive/Bool.cpp @@ -95,6 +95,7 @@ namespace armarx::aron::data } else { + ARMARX_TRACE; throw error::AronException(__PRETTY_FUNCTION__, "Could not set from string. Got: '" + setter + "'"); } } diff --git a/source/RobotAPI/libraries/aron/core/data/visitor/nlohmannJSON/NlohmannJSONVisitor.cpp b/source/RobotAPI/libraries/aron/core/data/visitor/nlohmannJSON/NlohmannJSONVisitor.cpp index 84adf5c1ea7643ece74e2bc3e224e5df075f7a12..e80e7d37e071585f8b6f3ae0e7d0f81d280b49e4 100644 --- a/source/RobotAPI/libraries/aron/core/data/visitor/nlohmannJSON/NlohmannJSONVisitor.cpp +++ b/source/RobotAPI/libraries/aron/core/data/visitor/nlohmannJSON/NlohmannJSONVisitor.cpp @@ -33,6 +33,7 @@ namespace armarx::aron::data return data::Descriptor::UNKNOWN; } std::string t = n[armarx::aron::data::rw::json::constantes::TYPE_SLUG]; + return armarx::aron::data::rw::json::conversion::String2Descriptor.at(t); } diff --git a/source/RobotAPI/libraries/aron/core/rw.h b/source/RobotAPI/libraries/aron/core/rw.h index 6257f2422687591b0991afed8a0577ee127207ef..95b6aac606f47d3c46de34ac5ec077ded28c41a4 100644 --- a/source/RobotAPI/libraries/aron/core/rw.h +++ b/source/RobotAPI/libraries/aron/core/rw.h @@ -26,7 +26,7 @@ namespace armarx::aron } template<class ReaderT, class DtoT, class BoT> - requires (data::isReader<ReaderT> && !DtoAndBoAreSame<DtoT, BoT>) + requires (data::isReader<ReaderT> && !detail::DtoAndBoAreSame<DtoT, BoT>) inline void read(ReaderT& aron_r, typename ReaderT::InputType& input, BoT& ret) { DtoT aron; @@ -36,7 +36,7 @@ namespace armarx::aron } template<class WriterT, class DtoT, class BoT> - requires (data::isWriter<WriterT> && !DtoAndBoAreSame<DtoT, BoT>) + requires (data::isWriter<WriterT> && !detail::DtoAndBoAreSame<DtoT, BoT>) inline void write(WriterT& aron_w, const BoT& input, typename WriterT::ReturnType& ret, const armarx::aron::Path& aron_p = armarx::aron::Path()) { DtoT aron; diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp index 0879de17b8e9258a211646e2b7c8d7c4bdc37ace..51d45e3975bb162460fd06893e91f388ac52b9f1 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp +++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp @@ -64,6 +64,11 @@ namespace armarx::aron::type return acceptedTypes; } + bool Tuple::hasAcceptedType(unsigned int i) const + { + return i < acceptedTypes.size(); + } + VariantPtr Tuple::getAcceptedType(unsigned int i) const { return acceptedTypes[i]; diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.h b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.h index d464f83269d5074e1ec6e759119b433c76de0f7d..3281584c15d6b4bb3e50c83ce598634a2bbec324 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.h +++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.h @@ -46,6 +46,7 @@ namespace armarx::aron::type // public member functions std::vector<VariantPtr> getAcceptedTypes() const; + bool hasAcceptedType(unsigned int i) const; VariantPtr getAcceptedType(unsigned int i) const; void addAcceptedType(const VariantPtr&); diff --git a/source/RobotAPI/libraries/aron/test/AronConversionTester.cpp b/source/RobotAPI/libraries/aron/test/AronConversionTester.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aac543a04b6ba1696dedc7a21c7d4ea125896e4e --- /dev/null +++ b/source/RobotAPI/libraries/aron/test/AronConversionTester.cpp @@ -0,0 +1,38 @@ +/** + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::ArmarXObjects::aron_cpp_to_python_conv_test + * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu ) + * @date 2023 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + + +#include "AronConversionTester.h" + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + + +namespace armarx::aron::test +{ + + AronConversionTester::AronConversionTester(dti::AronConversionTestInterfacePrx python) : interface(python) + { + ARMARX_CHECK(python); + } + + +} // namespace armarx::aron::test diff --git a/source/RobotAPI/libraries/aron/test/AronConversionTester.h b/source/RobotAPI/libraries/aron/test/AronConversionTester.h new file mode 100644 index 0000000000000000000000000000000000000000..b7ad4b8dfdcf55a37f8efc3116c27440d925d428 --- /dev/null +++ b/source/RobotAPI/libraries/aron/test/AronConversionTester.h @@ -0,0 +1,111 @@ +/** + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::ArmarXObjects::aron_cpp_to_python_conv_test + * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu ) + * @date 2023 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + + +#pragma once + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <ArmarXCore/core/logging/Logging.h> + +#include <RobotAPI/interface/aron/test/AronConversionTestInterface.h> + + +namespace armarx::aron::test +{ + + /** + * @brief Helper class for implementing distributed ARON conversion tests + * based on the `dti::AronConversionTestInterfacePrx`. + * + * Example usage: + * + * @code + * + * armarx::aron::test::dti::AronConversionTestInterfacePrx pythonComponent = ...; + * + * auto myAronClassProbeFn = []() + * { + * my::arondto::MyAronClass probe; + * probe.data = "42"; + * return probe, + * }; + * + * armarx::aron::test::AronConversionTester tester(pythonComponent); + * + * tester.test<my::arondto::MyAronClass>(myAronClassProbeFn, "MyAronClass"); + * + * @endcode + * + * Note that the `pythonComponent` must point to a corresponding + * implementation of the `AronConversionTestInterfacePrx`. + */ + class AronConversionTester + { + public: + template <class AronClassT> + using ProbeFn = std::function<AronClassT()>; + + + public: + AronConversionTester(dti::AronConversionTestInterfacePrx interface); + + /** + * @brief Test the conversion of a specific ARON class. + * + * @param probeFn A factory function creating a test instance of the + * ARON class. + * @param aronClassName The name of the ARON class. Can be used by the + * other component to decide which class to convert to. + */ + template <class AronClassT> + void + test(ProbeFn<AronClassT> probeFn, const std::string& aronClassName) + { + std::stringstream ss; + ss << "Test for ARON class '" << aronClassName << "': "; + + const AronClassT probe = probeFn(); + + dto::TestAronConversionRequest req; + req.aronClassName = aronClassName; + req.probe = probe.toAronDTO(); + + dto::TestAronConversionResponse res = interface->testAronConversion(req); + + if (res.success) + { + const AronClassT probeOut = AronClassT::FromAron(res.probe); + ARMARX_CHECK(probeOut == probe); + + ARMARX_IMPORTANT << ss.str() << "Success"; + } + else + { + ARMARX_WARNING << ss.str() << "Conversion in Python component failed: \n" << res.errorMessage; + } + } + + public: + dti::AronConversionTestInterfacePrx interface; + }; + +} // namespace armarx::aron::test diff --git a/source/RobotAPI/libraries/aron/test/CMakeLists.txt b/source/RobotAPI/libraries/aron/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a199acf0f19c13f6253e66947e540bfe3950efd --- /dev/null +++ b/source/RobotAPI/libraries/aron/test/CMakeLists.txt @@ -0,0 +1,25 @@ +set(LIB_NAME arontest) + +armarx_component_set_name("${LIB_NAME}") +armarx_set_target("Library: ${LIB_NAME}") + + +armarx_add_library( + LIBS + # ArmarXCore + ArmarXCore + # RobotAPI + RobotAPICore + RobotAPIInterfaces + aron + + HEADERS + AronConversionTester.h + + SOURCES + AronConversionTester.cpp +) + + +add_library(aron::test ALIAS arontest) +add_library(${PROJECT_NAME}::Aron::test ALIAS arontest) diff --git a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp index 23a708aceace48317d04884a8579fd21001b92c3..60a38b465ddb8bd9d6cbdac5ec4952606624880c 100644 --- a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp +++ b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp @@ -33,7 +33,9 @@ namespace armarx } else { - ARMARX_INFO << "Trying to add a provider with name '" << info.providerName << "' but the provider already exists."; + ARMARX_INFO << "Trying to add a provider with name '" << info.providerName << "' but the provider already exists. " + << "Overwriting the old provider info."; + skillProviderMap[info.providerName] = info.provider; } } @@ -47,7 +49,7 @@ namespace armarx } else { - ARMARX_INFO << "Trying to remove a provider with name '" << providerName << "' but it couldn't found."; + ARMARX_INFO << "Trying to remove a provider with name '" << providerName << "' but it couldn't be found."; } } @@ -79,31 +81,64 @@ namespace armarx providerName = info.skillId.providerName; } + bool remove = false; if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) { - skills::callback::dti::SkillProviderCallbackInterfacePrx myPrx; - getProxy(myPrx, -1); + const auto& n = it->first; + const auto& s = it->second; - skills::provider::dto::SkillExecutionRequest exInfo; - exInfo.skillName = info.skillId.skillName; - exInfo.executorName = info.executorName; - exInfo.callbackInterface = myPrx; - exInfo.params = info.params; + if (s) + { + skills::callback::dti::SkillProviderCallbackInterfacePrx myPrx; + getProxy(myPrx, -1); + + skills::provider::dto::SkillExecutionRequest exInfo; + exInfo.skillName = info.skillId.skillName; + exInfo.executorName = info.executorName; + exInfo.callbackInterface = myPrx; + exInfo.params = info.params; + + return s->executeSkill(exInfo); + } + else + { + remove = true; + } - return it->second->executeSkill(exInfo); + if (remove) + { + std::scoped_lock l(skillProviderMapMutex); + if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "' during execution. Removing it from skills."; + it = skillProviderMap.erase(it); + } + } } else { ARMARX_ERROR << "Could not execute a skill of provider '" + providerName + "' because the provider does not exist."; throw skills::error::SkillException(__PRETTY_FUNCTION__, "Skill execution failed. Could not execute a skill of provider '" + providerName + "' because the provider does not exist."); } + return {}; // Never happens } void SkillManagerComponentPluginUser::abortSkill(const std::string& providerName, const std::string& skillName, const Ice::Current ¤t) { + std::scoped_lock l(skillProviderMapMutex); if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) { - it->second->abortSkill(skillName); + const auto& n = it->first; + const auto& s = it->second; + if (s) + { + s->abortSkill(skillName); + } + else + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "'. Removing it from skills."; + it = skillProviderMap.erase(it); + } } } @@ -116,10 +151,23 @@ namespace armarx skills::manager::dto::SkillDescriptionMapMap SkillManagerComponentPluginUser::getSkillDescriptions(const Ice::Current ¤t) { skills::manager::dto::SkillDescriptionMapMap ret; - for (const auto& [n, s] : skillProviderMap) + + std::scoped_lock l(skillProviderMapMutex); + for (auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();) { - skills::provider::dto::SkillDescriptionMap m = s->getSkillDescriptions(); - ret.insert({n, m}); + const auto& n = it->first; + const auto& s = it->second; + if (s) + { + skills::provider::dto::SkillDescriptionMap m = s->getSkillDescriptions(); + ret.insert({n, m}); + ++it; + } + else + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "'. Removing it from skills."; + it = skillProviderMap.erase(it); + } } return ret; } @@ -127,10 +175,23 @@ namespace armarx skills::manager::dto::SkillStatusUpdateMapMap SkillManagerComponentPluginUser::getSkillExecutionStatuses(const Ice::Current ¤t) { skills::manager::dto::SkillStatusUpdateMapMap ret; - for (const auto& [n, s] : skillProviderMap) + + std::scoped_lock l(skillProviderMapMutex); + for (auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();) { - skills::provider::dto::SkillStatusUpdateMap m = s->getSkillExecutionStatuses(); - ret.insert({n, m}); + const auto& n = it->first; + const auto& s = it->second; + if (s) + { + skills::provider::dto::SkillStatusUpdateMap m = s->getSkillExecutionStatuses(); + ret.insert({n, m}); + it++; + } + else + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "'. Removing it from skills."; + it = skillProviderMap.erase(it); + } } return ret; } diff --git a/source/RobotAPI/libraries/skills/provider/SpecializedSkill.h b/source/RobotAPI/libraries/skills/provider/SpecializedSkill.h index 9f554e11e5c878bdd77cd7c866bef6871b3c6584..3f2b9371e2b087b4a5da77fb06e898bca525c320 100644 --- a/source/RobotAPI/libraries/skills/provider/SpecializedSkill.h +++ b/source/RobotAPI/libraries/skills/provider/SpecializedSkill.h @@ -76,6 +76,7 @@ namespace armarx } private: + /// Override this method if you want to disable a skill based on certain conditions virtual bool isAvailable(const SpecializedInitInput&) const { return true; diff --git a/source/RobotAPI/libraries/skills/provider/mixins/RobotWritingSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/RobotWritingSkillMixin.h new file mode 100644 index 0000000000000000000000000000000000000000..34856452c4b8bd3b4e61dd69ee03eb122d409566 --- /dev/null +++ b/source/RobotAPI/libraries/skills/provider/mixins/RobotWritingSkillMixin.h @@ -0,0 +1,28 @@ +#pragma once + + +// Others +#include <RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotWriter.h> + +namespace armarx::skills::mixin +{ + struct RobotWritingSkillMixin + { + armem::robot_state::VirtualRobotWriter robotWriter; + + RobotWritingSkillMixin(armem::client::MemoryNameSystem& mns) : + robotWriter(mns) + {} + }; + + struct SpecificRobotWritingSkillMixin + { + std::string robotName; + armem::robot_state::VirtualRobotWriter robotWriter; + + SpecificRobotWritingSkillMixin(const std::string& rn, armem::client::MemoryNameSystem& mns) : + robotName(rn), + robotWriter(mns) + {} + }; +}