diff --git a/scenarios/AronComponentConfigExample/AronComponentConfigExample.scx b/scenarios/AronComponentConfigExample/AronComponentConfigExample.scx new file mode 100644 index 0000000000000000000000000000000000000000..250a99e0a034d4addcef5a6039bf3b4f61e9bd24 --- /dev/null +++ b/scenarios/AronComponentConfigExample/AronComponentConfigExample.scx @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<scenario name="AronComponentConfigExample" creation="2022-11-02.11:11:59 AM" globalConfigName="./config/global.cfg" package="RobotAPI" deploymentType="local" nodeName="NodeMain"> + <application name="AronComponentConfigExample" instance="" package="RobotAPI" nodeName="" enabled="true" iceAutoRestart="false"/> + <application name="RemoteGuiProviderApp" instance="" package="ArmarXGui" nodeName="" enabled="true" iceAutoRestart="false"/> +</scenario> + diff --git a/scenarios/AronComponentConfigExample/config/AronComponentConfigExample.cfg b/scenarios/AronComponentConfigExample/config/AronComponentConfigExample.cfg new file mode 100644 index 0000000000000000000000000000000000000000..dcf2233099e0acef6a620567979cc71e1da2cc29 --- /dev/null +++ b/scenarios/AronComponentConfigExample/config/AronComponentConfigExample.cfg @@ -0,0 +1,344 @@ +# ================================================================== +# AronComponentConfigExample properties +# ================================================================== + +# ArmarX.AdditionalPackages: List of additional ArmarX packages which should be in the list of default packages. If you have custom packages, which should be found by the gui or other apps, specify them here. Comma separated List. +# Attributes: +# - Default: Default value not mapped. +# - Case sensitivity: yes +# - Required: no +# ArmarX.AdditionalPackages = Default value not mapped. + + +# ArmarX.ApplicationName: Application name +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.ApplicationName = "" + + +# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_CONFIG_DIR is set, the cache path will be made relative to ARMARX_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${ARMARX_WORKSPACE}/armarx_config) +# Attributes: +# - Default: mongo/.cache +# - Case sensitivity: yes +# - Required: no +# ArmarX.CachePath = mongo/.cache + + +# ArmarX.ComponentConfigTest.EnableProfiling: enable profiler which is used for logging performance events +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.ComponentConfigTest.EnableProfiling = false + + +# ArmarX.ComponentConfigTest.MinimumLoggingLevel: Local logging level only for this component +# Attributes: +# - Default: Undefined +# - Case sensitivity: yes +# - Required: no +# - Possible values: {Debug, Error, Fatal, Important, Info, Undefined, Verbose, Warning} +# ArmarX.ComponentConfigTest.MinimumLoggingLevel = Undefined + + +# ArmarX.ComponentConfigTest.ObjectName: Name of IceGrid well-known object +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.ObjectName = "" + + +# ArmarX.ComponentConfigTest.RemoteGuiName: Name of the remote gui provider +# Attributes: +# - Default: RemoteGuiProvider +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.RemoteGuiName = RemoteGuiProvider + + +# ArmarX.ComponentConfigTest.boolMember: +# Attributes: +# - Default: true +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.ComponentConfigTest.boolMember = true + + +# ArmarX.ComponentConfigTest.floatMember: +# Attributes: +# - Default: 100 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.floatMember = 100 + + +# ArmarX.ComponentConfigTest.intMember: +# Attributes: +# - Default: 1000 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.intMember = 1000 + + +# ArmarX.ComponentConfigTest.stringMember: +# Attributes: +# - Default: initial +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.stringMember = initial + + +# ArmarX.ComponentConfigTest.subMember.boolMember: +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.ComponentConfigTest.subMember.boolMember = false + + +# ArmarX.ComponentConfigTest.subMember.doubleMember: +# Attributes: +# - Default: 0 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.doubleMember = 0 + + +# ArmarX.ComponentConfigTest.subMember.floatMember: +# Attributes: +# - Default: 0 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.floatMember = 0 + + +# ArmarX.ComponentConfigTest.subMember.intMember: +# Attributes: +# - Default: 0 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.intMember = 0 + + +# ArmarX.ComponentConfigTest.subMember.stringMember: +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.stringMember = "" + + +# ArmarX.ComponentConfigTest.subMember.subsubMember.boolMember: +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.ComponentConfigTest.subMember.subsubMember.boolMember = false + + +# ArmarX.ComponentConfigTest.subMember.subsubMember.enumMember: +# Attributes: +# - Default: 1 +# - Case sensitivity: yes +# - Required: no +# - Possible values: {Bar, Baz, Foo, Qux} +# ArmarX.ComponentConfigTest.subMember.subsubMember.enumMember = 1 + + +# ArmarX.ComponentConfigTest.subMember.subsubMember.floatMember: +# Attributes: +# - Default: 0 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.subsubMember.floatMember = 0 + + +# ArmarX.ComponentConfigTest.subMember.subsubMember.intDictMember: +# Attributes: +# - Default: int1:1,int2:2 +# - Case sensitivity: yes +# - Required: no +ArmarX.ComponentConfigTest.subMember.subsubMember.intDictMember = int1:1,int2:2,int3:3,int5:4 + + +# ArmarX.ComponentConfigTest.subMember.subsubMember.intListMember: +# Attributes: +# - Default: 1, 2, 3, 4, 5, 6 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.subsubMember.intListMember = 1, 2, 3, 4, 5, 6 + + +# ArmarX.ComponentConfigTest.subMember.subsubMember.intMember: +# Attributes: +# - Default: 0 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.subsubMember.intMember = 0 + + +# ArmarX.ComponentConfigTest.subMember.subsubMember.stringDictMember: +# Attributes: +# - Default: string1:blub,string2:duh +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.subsubMember.stringDictMember = string1:blub,string2:duh + + +# ArmarX.ComponentConfigTest.subMember.subsubMember.stringListMember: +# Attributes: +# - Default: a, b, c, d, e +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.subsubMember.stringListMember = a, b, c, d, e + + +# ArmarX.ComponentConfigTest.subMember.subsubMember.stringMember: +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.ComponentConfigTest.subMember.subsubMember.stringMember = "" + + +# ArmarX.Config: Comma-separated list of configuration files +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.Config = "" + + +# ArmarX.DataPath: Semicolon-separated search list for data files +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.DataPath = "" + + +# ArmarX.DefaultPackages: List of ArmarX packages which are accessible by default. Comma separated List. If you want to add your own packages and use all default ArmarX packages, use the property 'AdditionalPackages'. +# Attributes: +# - Default: Default value not mapped. +# - Case sensitivity: yes +# - Required: no +# ArmarX.DefaultPackages = Default value not mapped. + + +# ArmarX.DependenciesConfig: Path to the (usually generated) config file containing all data paths of all dependent projects. This property usually does not need to be edited. +# Attributes: +# - Default: ./config/dependencies.cfg +# - Case sensitivity: yes +# - Required: no +# ArmarX.DependenciesConfig = ./config/dependencies.cfg + + +# ArmarX.DisableLogging: Turn logging off in whole application +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.DisableLogging = false + + +# ArmarX.EnableProfiling: Enable profiling of CPU load produced by this application +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.EnableProfiling = false + + +# ArmarX.LoadLibraries: Libraries to load at start up of the application. Must be enabled by the Application with enableLibLoading(). Format: PackageName:LibraryName;... or /absolute/path/to/library;... +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.LoadLibraries = "" + + +# ArmarX.LoggingGroup: The logging group is transmitted with every ArmarX log message over Ice in order to group the message in the GUI. +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.LoggingGroup = "" + + +# ArmarX.RedirectStdout: Redirect std::cout and std::cerr to ArmarXLog +# Attributes: +# - Default: true +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.RedirectStdout = true + + +# ArmarX.RemoteHandlesDeletionTimeout: The timeout (in ms) before a remote handle deletes the managed object after the use count reached 0. This time can be used by a client to increment the count again (may be required when transmitting remote handles) +# Attributes: +# - Default: 3000 +# - Case sensitivity: yes +# - Required: no +# ArmarX.RemoteHandlesDeletionTimeout = 3000 + + +# ArmarX.SecondsStartupDelay: The startup will be delayed by this number of seconds (useful for debugging) +# Attributes: +# - Default: 0 +# - Case sensitivity: yes +# - Required: no +# ArmarX.SecondsStartupDelay = 0 + + +# ArmarX.StartDebuggerOnCrash: If this application crashes (segmentation fault) qtcreator will attach to this process and start the debugger. +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.StartDebuggerOnCrash = false + + +# ArmarX.ThreadPoolSize: Size of the ArmarX ThreadPool that is always running. +# Attributes: +# - Default: 1 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ThreadPoolSize = 1 + + +# ArmarX.TopicSuffix: Suffix appended to all topic names for outgoing topics. This is mainly used to direct all topics to another name for TopicReplaying purposes. +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.TopicSuffix = "" + + +# ArmarX.UseTimeServer: Enable using a global Timeserver (e.g. from ArmarXSimulator) +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.UseTimeServer = false + + +# ArmarX.Verbosity: Global logging level for whole application +# Attributes: +# - Default: Info +# - Case sensitivity: yes +# - Required: no +# - Possible values: {Debug, Error, Fatal, Important, Info, Undefined, Verbose, Warning} +# ArmarX.Verbosity = Info + + diff --git a/scenarios/AronComponentConfigExample/config/RemoteGuiProviderApp.cfg b/scenarios/AronComponentConfigExample/config/RemoteGuiProviderApp.cfg new file mode 100644 index 0000000000000000000000000000000000000000..4b6abea40d72afd7d313ee47a9b191f3b26de30d --- /dev/null +++ b/scenarios/AronComponentConfigExample/config/RemoteGuiProviderApp.cfg @@ -0,0 +1,196 @@ +# ================================================================== +# RemoteGuiProviderApp properties +# ================================================================== + +# ArmarX.AdditionalPackages: List of additional ArmarX packages which should be in the list of default packages. If you have custom packages, which should be found by the gui or other apps, specify them here. Comma separated List. +# Attributes: +# - Default: Default value not mapped. +# - Case sensitivity: yes +# - Required: no +# ArmarX.AdditionalPackages = Default value not mapped. + + +# ArmarX.ApplicationName: Application name +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.ApplicationName = "" + + +# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_CONFIG_DIR is set, the cache path will be made relative to ARMARX_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${ARMARX_WORKSPACE}/armarx_config) +# Attributes: +# - Default: mongo/.cache +# - Case sensitivity: yes +# - Required: no +# ArmarX.CachePath = mongo/.cache + + +# ArmarX.Config: Comma-separated list of configuration files +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.Config = "" + + +# ArmarX.DataPath: Semicolon-separated search list for data files +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.DataPath = "" + + +# ArmarX.DefaultPackages: List of ArmarX packages which are accessible by default. Comma separated List. If you want to add your own packages and use all default ArmarX packages, use the property 'AdditionalPackages'. +# Attributes: +# - Default: Default value not mapped. +# - Case sensitivity: yes +# - Required: no +# ArmarX.DefaultPackages = Default value not mapped. + + +# ArmarX.DependenciesConfig: Path to the (usually generated) config file containing all data paths of all dependent projects. This property usually does not need to be edited. +# Attributes: +# - Default: ./config/dependencies.cfg +# - Case sensitivity: yes +# - Required: no +# ArmarX.DependenciesConfig = ./config/dependencies.cfg + + +# ArmarX.DisableLogging: Turn logging off in whole application +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.DisableLogging = false + + +# ArmarX.EnableProfiling: Enable profiling of CPU load produced by this application +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.EnableProfiling = false + + +# ArmarX.LoadLibraries: Libraries to load at start up of the application. Must be enabled by the Application with enableLibLoading(). Format: PackageName:LibraryName;... or /absolute/path/to/library;... +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.LoadLibraries = "" + + +# ArmarX.LoggingGroup: The logging group is transmitted with every ArmarX log message over Ice in order to group the message in the GUI. +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.LoggingGroup = "" + + +# ArmarX.RedirectStdout: Redirect std::cout and std::cerr to ArmarXLog +# Attributes: +# - Default: true +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.RedirectStdout = true + + +# ArmarX.RemoteGuiProvider.EnableProfiling: enable profiler which is used for logging performance events +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.RemoteGuiProvider.EnableProfiling = false + + +# ArmarX.RemoteGuiProvider.MinimumLoggingLevel: Local logging level only for this component +# Attributes: +# - Default: Undefined +# - Case sensitivity: yes +# - Required: no +# - Possible values: {Debug, Error, Fatal, Important, Info, Undefined, Verbose, Warning} +# ArmarX.RemoteGuiProvider.MinimumLoggingLevel = Undefined + + +# ArmarX.RemoteGuiProvider.ObjectName: Name of IceGrid well-known object +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.RemoteGuiProvider.ObjectName = "" + + +# ArmarX.RemoteGuiProvider.TopicName: Name of the topic on which updates to the remote state are reported. +# Attributes: +# - Default: RemoteGuiTopic +# - Case sensitivity: yes +# - Required: no +# ArmarX.RemoteGuiProvider.TopicName = RemoteGuiTopic + + +# ArmarX.RemoteHandlesDeletionTimeout: The timeout (in ms) before a remote handle deletes the managed object after the use count reached 0. This time can be used by a client to increment the count again (may be required when transmitting remote handles) +# Attributes: +# - Default: 3000 +# - Case sensitivity: yes +# - Required: no +# ArmarX.RemoteHandlesDeletionTimeout = 3000 + + +# ArmarX.SecondsStartupDelay: The startup will be delayed by this number of seconds (useful for debugging) +# Attributes: +# - Default: 0 +# - Case sensitivity: yes +# - Required: no +# ArmarX.SecondsStartupDelay = 0 + + +# ArmarX.StartDebuggerOnCrash: If this application crashes (segmentation fault) qtcreator will attach to this process and start the debugger. +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.StartDebuggerOnCrash = false + + +# ArmarX.ThreadPoolSize: Size of the ArmarX ThreadPool that is always running. +# Attributes: +# - Default: 1 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ThreadPoolSize = 1 + + +# ArmarX.TopicSuffix: Suffix appended to all topic names for outgoing topics. This is mainly used to direct all topics to another name for TopicReplaying purposes. +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.TopicSuffix = "" + + +# ArmarX.UseTimeServer: Enable using a global Timeserver (e.g. from ArmarXSimulator) +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.UseTimeServer = false + + +# ArmarX.Verbosity: Global logging level for whole application +# Attributes: +# - Default: Info +# - Case sensitivity: yes +# - Required: no +# - Possible values: {Debug, Error, Fatal, Important, Info, Undefined, Verbose, Warning} +# ArmarX.Verbosity = Info + + diff --git a/scenarios/AronComponentConfigExample/config/global.cfg b/scenarios/AronComponentConfigExample/config/global.cfg new file mode 100644 index 0000000000000000000000000000000000000000..44dde159548b3d54011a075a37f6ac0d7fc41f14 --- /dev/null +++ b/scenarios/AronComponentConfigExample/config/global.cfg @@ -0,0 +1,4 @@ +# ================================================================== +# Global Config from Scenario AronComponentConfigExample +# ================================================================== + diff --git a/source/RobotAPI/components/AronComponentConfigExample/AronComponentConfigExample.cpp b/source/RobotAPI/components/AronComponentConfigExample/AronComponentConfigExample.cpp index 2f5095b5beee6b1732b8bba2d2ad3ee4d71a0cef..683fcef10a9793f2e54ff7432b377ccdcf7635e0 100644 --- a/source/RobotAPI/components/AronComponentConfigExample/AronComponentConfigExample.cpp +++ b/source/RobotAPI/components/AronComponentConfigExample/AronComponentConfigExample.cpp @@ -57,6 +57,10 @@ namespace armarx ARMARX_TRACE; auto& config = aron_component_config_plugin_->config_.getWriteBuffer(); + for (const auto& [key, value] : config.subMember.subsubMember.intDictMember) + { + ARMARX_INFO << key << value; + } config.intMember--; aron_component_config_plugin_->config_.commitWrite(); }, 1000); diff --git a/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt b/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt index f9e545e5c4caceed94f27109f824468e111c742e..2529d9e77da2d02cadad9be1da028aae078c23fe 100644 --- a/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt +++ b/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt @@ -29,6 +29,7 @@ set(LIBS set(LIB_FILES PropertyDefinitionVisitors.cpp RemoteGuiVisitors.cpp + VariantHelperFactory.cpp ) set(LIB_HEADERS @@ -37,6 +38,7 @@ set(LIB_HEADERS RemoteGuiVisitors.h Util.h ComponentPlugin.h + VariantHelperFactory.h ) diff --git a/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp b/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp index bf606b399fd57cfd88d8c36745d1e611ce128624..c8a21c747d81c4465a1c85281da518f4905001e6 100644 --- a/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp +++ b/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp @@ -26,6 +26,7 @@ #include <ArmarXCore/core/application/properties/PropertyDefinition.h> #include <ArmarXCore/core/application/properties/PropertyUser.h> #include <RobotAPI/libraries/aron/core/data/variant/All.h> +#include <RobotAPI/libraries/aron_component_config/VariantHelperFactory.h> #include "Util.h" @@ -43,7 +44,6 @@ namespace armarx::aron::component_config auto value = data::Int::DynamicCastAndCheck(i); auto name = pathToName(i); property_user_->getProperty(value->getValue(), name); - i = value; } void @@ -53,7 +53,6 @@ namespace armarx::aron::component_config auto value = data::Float::DynamicCastAndCheck(f); auto name = pathToName(f); property_user_->getProperty(value->getValue(), name); - f = value; } void @@ -63,7 +62,6 @@ namespace armarx::aron::component_config auto value = data::Double::DynamicCastAndCheck(d); auto name = pathToName(d); property_user_->getProperty(value->getValue(), name); - d = value; } void @@ -73,7 +71,6 @@ namespace armarx::aron::component_config auto value = data::Bool::DynamicCastAndCheck(b); auto name = pathToName(b); property_user_->getProperty(value->getValue(), name); - b = value; } void @@ -82,15 +79,26 @@ namespace armarx::aron::component_config INPUT_GUARD(string); auto value = data::String::DynamicCastAndCheck(string); auto name = pathToName(string); - property_user_->getProperty(value->getValue(), name); - string = value; + auto property = property_user_->getProperty<std::string>(name); + if (not property.getValue().empty()){ + value->getValue() = property.getValueAndReplaceAllVars(); + } else + { + value->getValue() = ""; + } } void PropertyDefinitionGetterVisitor::visitListOnEnter(DataInput& o, TypeInput& t) { + in_list_ = true; const auto& name = pathToName(o); - const auto& type = type::List::DynamicCast(t); + const auto& type = type::List::DynamicCast(t)->getAcceptedType()->getDescriptor(); + if (std::find(implementedListDescriptors.begin(), implementedListDescriptors.end(), type) == + implementedListDescriptors.end()) + { + return; + } auto old_list = data::List::DynamicCast(o); old_list->clear(); auto get_list = [this, & name]() -> std::vector<std::string> @@ -100,32 +108,15 @@ namespace armarx::aron::component_config return simox::alg::split(list, ","); }; int i = 0; - switch (type->getAcceptedType()->getDescriptor()) + std::vector<std::string> vector = get_list(); + std::for_each(vector.begin(), vector.end(), [&old_list, &i, &type](const auto& el) { - case type::Descriptor::INT: - { - std::vector<std::string> vector = get_list(); - std::for_each(vector.begin(), vector.end(), [&old_list, &i](const auto& el) - { - old_list->addElement(make_int(std::stoi(el), old_list->getPath().withIndex(i))); - i++; - }); - break; - } - case type::Descriptor::STRING: - { - std::vector<std::string> vector = get_list(); - std::for_each(vector.begin(), vector.end(), [&old_list, &i](const auto& el) - { - old_list->addElement(make_string(el, old_list->getPath().withIndex(i))); - i++; - }); - break; - } - default: - throw armarx::NotImplementedYetException(); - } - in_list_ = true; + old_list->addElement(factories::VariantHelper::make(type)->from_string(el, + old_list->getPath() + .withIndex(i))); + i++; + }); + } void @@ -140,7 +131,6 @@ namespace armarx::aron::component_config auto data = data::Int::DynamicCastAndCheck(enumData); auto name = pathToName(enumData); property_user_->getProperty(data->getValue(), name); - enumData = data; } void @@ -159,10 +149,16 @@ namespace armarx::aron::component_config PropertyDefinitionGetterVisitor::visitDictOnEnter(std::shared_ptr<data::Variant>& o, const std::shared_ptr<type::Variant>& t) { + in_list_ = true; const auto& name = pathToName(o); - const auto& type = type::Dict::DynamicCast(t); - auto old_list = data::Dict::DynamicCast(o); - old_list->clear(); + const auto& type = type::Dict::DynamicCast(t)->getAcceptedType()->getDescriptor(); + if (std::find(implementedListDescriptors.begin(), implementedListDescriptors.end(), type) == + implementedListDescriptors.end()) + { + return; + } + auto old_dict = data::Dict::DynamicCast(o); + old_dict->clear(); auto get_list = [this, & name]() -> std::vector<std::string> { std::string list; @@ -170,34 +166,14 @@ namespace armarx::aron::component_config return simox::alg::split(list, ","); }; std::vector<std::string> vector = get_list(); - switch (type->getAcceptedType()->getDescriptor()) + std::for_each(vector.begin(), vector.end(), [&old_dict, &type](const auto& el) { - case type::Descriptor::INT: - { - std::for_each(vector.begin(), vector.end(), [&old_list](const auto& el) - { - auto key_value = simox::alg::split(el, ":"); - old_list->addElement(key_value.front(), - make_int(std::stoi(key_value.back()), - old_list->getPath().withElement(key_value.front()))); - }); - break; - } - case type::Descriptor::STRING: - { - std::for_each(vector.begin(), vector.end(), [&old_list](const auto& el) - { - auto key_value = simox::alg::split(el, ":"); - old_list->addElement(key_value.front(), - make_string(key_value.back(), - old_list->getPath().withElement(key_value.front()))); - }); - break; - } - default: - throw armarx::NotImplementedYetException(); - } - in_list_ = true; + auto key_value = simox::alg::split(el, ":"); + old_dict->addElement(key_value.front(), + factories::VariantHelper::make(type)->from_string(key_value.back(), + old_dict->getPath() + .withElement(key_value.front()))); + }); } void @@ -302,35 +278,20 @@ namespace armarx::aron::component_config ARMARX_CHECK_NOT_NULL(l); in_list_ = true; const auto& name = pathToName(l); - const auto& t_desc = t->getAcceptedType()->getDescriptor(); + const auto& type = t->getAcceptedType()->getDescriptor(); + if (std::find(implementedListDescriptors.begin(), implementedListDescriptors.end(), type) == + implementedListDescriptors.end()) + { + return; + } const auto& input = l->getElements(); std::string str; - switch (t_desc) + std::vector<std::string> vector; + std::transform(input.begin(), input.end(), std::back_inserter(vector), [&type](const auto& el) { - case type::Descriptor::INT: - { - std::vector<int> vector; - std::transform(input.begin(), input.end(), std::back_inserter(vector), [](const auto& el) - { - return data::Int::DynamicCast(el)->getValue(); - }); - str = simox::alg::to_string(vector, ", "); - break; - } - case type::Descriptor::STRING: - { - std::vector<std::string> vector; - std::transform(input.begin(), input.end(), std::back_inserter(vector), [](const auto& el) - { - return data::String::DynamicCast(el)->getValue(); - }); - str = simox::alg::to_string(vector, ", "); - break; - } - // TODO: other basic types - default: - throw armarx::NotImplementedYetException(); - } + return factories::VariantHelper::make(type)->to_string(el); + }); + str = simox::alg::to_string(vector, ", "); property_definitions_->defineOptionalProperty<std::string>(name, str); } @@ -345,28 +306,18 @@ namespace armarx::aron::component_config { in_list_ = true; const auto& name = pathToName(d); - const auto& t_desc = t->getAcceptedType()->getDescriptor(); + const auto& type = t->getAcceptedType()->getDescriptor(); + if (std::find(implementedListDescriptors.begin(), implementedListDescriptors.end(), type) == + implementedListDescriptors.end()) + { + return; + } const auto& input = d->getElements(); std::stringstream ss; for (const auto& [key, el]: input) { ss << key << ":"; - switch (t_desc) - { - case type::Descriptor::INT: - { - ss << data::Int::DynamicCast(el)->getValue(); - break; - } - case type::Descriptor::STRING: - { - ss << data::String::DynamicCast(el)->getValue(); - break; - } - // TODO: other basic types - default: - throw armarx::NotImplementedYetException(); - } + ss << factories::VariantHelper::make(type)->to_string(el); ss << ","; } std::string value = ss.str(); diff --git a/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.cpp b/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.cpp index e3f10aa5d809f7f0c46f4c34f8eecf98ae77d7df..42c8124493d8273594e5056b70bb8f5a37c6141f 100644 --- a/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.cpp +++ b/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.cpp @@ -25,6 +25,7 @@ #include <ArmarXGui/libraries/RemoteGui/RemoteGui.h> #include <RobotAPI/libraries/aron/core/data/variant/All.h> #include <ArmarXCore/util/CPPUtility/Iterator.h> +#include <RobotAPI/libraries/aron_component_config/VariantHelperFactory.h> #include "Util.h" #define INPUT_GUARD(i) \ @@ -38,8 +39,7 @@ namespace armarx::aron::component_config void MakeConfigGuiVisitor::visitObjectOnEnter(DataInput& dict, TypeInput&) { - ARMARX_TRACE; - ARMARX_CHECK_NOT_NULL(dict); + INPUT_GUARD(dict); if (dict->getPath().hasElement()) { @@ -56,7 +56,7 @@ namespace armarx::aron::component_config void MakeConfigGuiVisitor::visitObjectOnExit(DataInput& dict, TypeInput&) { - ARMARX_TRACE; + INPUT_GUARD(dict); auto builder = *group_hierarchy_.back(); group_hierarchy_.pop_back(); if (!group_hierarchy_.empty()) @@ -70,10 +70,15 @@ namespace armarx::aron::component_config { INPUT_GUARD(i); auto value = data::Int::DynamicCastAndCheck(i); + const auto& name = pathToName(i); + auto group = RemoteGui::makeHBoxLayout(name + "_layout"); + group.addChild(RemoteGui::makeLabel(name + "_label").value(i->getPath().getLastElement())); + group.addHSpacer(); + group.addChild(RemoteGui::makeIntSpinBox(name).value(value->getValue()) + .min(-1000) + .max(1000).toolTip(name)); group_hierarchy_.back() - ->addChild(RemoteGui::makeIntSpinBox(pathToName(i)).value(value->getValue()) - .min(-1000) - .max(1000)); + ->addChild(group); } void @@ -81,10 +86,15 @@ namespace armarx::aron::component_config { INPUT_GUARD(f); auto value = data::Float::DynamicCastAndCheck(f); + const auto& name = pathToName(f); + auto group = RemoteGui::makeHBoxLayout(name + "_layout"); + group.addChild(RemoteGui::makeLabel(name + "_label").value(f->getPath().getLastElement())); + group.addHSpacer(); + group.addChild(RemoteGui::makeFloatSpinBox(name).value(value->getValue()) + .min(-1000) + .max(1000).toolTip(name)); group_hierarchy_.back() - ->addChild(RemoteGui::makeFloatSpinBox(pathToName(f)).value(value->getValue()) - .min(-1000) - .max(1000)); + ->addChild(group); } void @@ -92,10 +102,15 @@ namespace armarx::aron::component_config { INPUT_GUARD(d); auto value = data::Double::DynamicCastAndCheck(d); + const auto& name = pathToName(d); + auto group = RemoteGui::makeHBoxLayout(name + "_layout"); + group.addChild(RemoteGui::makeLabel(name + "_label").value(d->getPath().getLastElement())); + group.addHSpacer(); + group.addChild(RemoteGui::makeFloatSpinBox(name).value(value->getValue()) + .min(-1000) + .max(1000).toolTip(name)); group_hierarchy_.back() - ->addChild(RemoteGui::makeFloatSpinBox(pathToName(d)).value(value->getValue()) - .min(-1000) - .max(1000)); + ->addChild(group); } void @@ -113,7 +128,12 @@ namespace armarx::aron::component_config { INPUT_GUARD(string); auto value = data::String::DynamicCastAndCheck(string); - group_hierarchy_.back()->addChild(RemoteGui::makeLineEdit(pathToName(string)).value(value->getValue())); + const auto& name = pathToName(string); + auto group = RemoteGui::makeHBoxLayout(name + "_layout"); + group.addChild(RemoteGui::makeLabel(name + "_label").value(string->getPath().getLastElement())); + group.addHSpacer(); + group.addChild(RemoteGui::makeLineEdit(name).value(value->getValue()).toolTip(name)); + group_hierarchy_.back()->addChild(group); } MakeConfigGuiVisitor::MakeConfigGuiVisitor(const std::string& name) : @@ -130,24 +150,20 @@ namespace armarx::aron::component_config void MakeConfigGuiVisitor::visitListOnEnter(DataInput& o, TypeInput& t) { + in_list_ = true; auto group = RemoteGui::makeSimpleGridLayout(pathToName(o) + "_grid").cols(20); auto data = data::List::DynamicCastAndCheck(o); - auto type = type::List::DynamicCast(t); + auto type = type::List::DynamicCast(t)->getAcceptedType()->getDescriptor(); + ARMARX_INFO << pathToName(data); + if (std::find(implementedListDescriptors.begin(), implementedListDescriptors.end(), type) == + implementedListDescriptors.end()) + { + return; + } for (const auto& el: data->getElements()) { - switch (type->getAcceptedType()->getDescriptor()) - { - case type::Descriptor::STRING: - group.addChild(RemoteGui::makeLineEdit(pathToName(el)).value(data::String::DynamicCast(el)->getValue()), - 10); - break; - case type::Descriptor::INT: - group.addChild(RemoteGui::makeLineEdit(pathToName(el)).value(std::to_string(data::Int::DynamicCast( - el)->getValue())), 10); - break; - default: - throw armarx::NotImplementedYetException(); - } + group.addChild(RemoteGui::makeLineEdit(pathToName(el)).value(factories::VariantHelper::make(type)->to_string( + el)), 10); group.addHSpacer(8); group.addChild(RemoteGui::makeButton(pathToName(el) + "_button").label("-").toolTip("Remove List Element"), 2); @@ -161,7 +177,6 @@ namespace armarx::aron::component_config "_add").label("+") .toolTip( "Add new list entry."))); - in_list_ = true; } void @@ -176,35 +191,35 @@ namespace armarx::aron::component_config INPUT_GUARD(o); auto data = data::Int::DynamicCastAndCheck(o); auto type = type::IntEnum::DynamicCast(t); + const auto& name = pathToName(o); + auto group = RemoteGui::makeHBoxLayout(name + "_layout"); + group.addChild(RemoteGui::makeLabel(name + "_label").value(o->getPath().getLastElement())); + group.addHSpacer(); + group.addChild(RemoteGui::makeComboBox(name).options(type->getAcceptedValueNames()) + .value(type->getValueName(data->getValue())).toolTip(name)); group_hierarchy_.back() - ->addChild(RemoteGui::makeComboBox(pathToName(o)).options(type->getAcceptedValueNames()) - .value(type->getValueName(data->getValue()))); + ->addChild(group); } void MakeConfigGuiVisitor::visitDictOnEnter(const std::shared_ptr<data::Variant>& o, const std::shared_ptr<type::Variant>& t) { + in_list_ = true; auto group = RemoteGui::makeSimpleGridLayout(pathToName(o) + "_grid").cols(20); auto data = data::Dict::DynamicCastAndCheck(o); - auto type = type::Dict::DynamicCast(t); + auto type = type::Dict::DynamicCast(t)->getAcceptedType()->getDescriptor(); + if (std::find(implementedListDescriptors.begin(), implementedListDescriptors.end(), type) == + implementedListDescriptors.end()) + { + return; + } for (const auto& el: data->getElements()) { group.addChild(RemoteGui::makeLineEdit(pathToName(el.second) + "_lbl").value(el.first), 5); group.addHSpacer(2); - switch (type->getAcceptedType()->getDescriptor()) - { - case type::Descriptor::STRING: - group.addChild(RemoteGui::makeLineEdit(pathToName(el.second)).value(data::String::DynamicCast(el.second) - ->getValue()), 5); - break; - case type::Descriptor::INT: - group.addChild(RemoteGui::makeLineEdit(pathToName(el.second)).value(std::to_string(data::Int::DynamicCast( - el.second)->getValue())), 5); - break; - default: - throw armarx::NotImplementedYetException(); - } + group.addChild(RemoteGui::makeLineEdit(pathToName(el.second)).value(factories::VariantHelper::make(type)->to_string( + el.second)), 5); group.addHSpacer(6); group.addChild(RemoteGui::makeButton(pathToName(el.second) + "_button").label("-") .toolTip("Remove List Element"), 2); @@ -218,7 +233,6 @@ namespace armarx::aron::component_config "_add").label("+") .toolTip( "Add new dict entry."))); - in_list_ = true; } void @@ -395,8 +409,14 @@ namespace armarx::aron::component_config void GetValueFromMapVisitor::visitListOnEnter(DataInput& o, TypeInput& t) { + in_list_ = true; auto data = data::List::DynamicCastAndCheck(o); - auto type = type::List::DynamicCast(t); + auto type = type::List::DynamicCast(t)->getAcceptedType()->getDescriptor(); + if (std::find(implementedListDescriptors.begin(), implementedListDescriptors.end(), type) == + implementedListDescriptors.end()) + { + return; + } const auto& elements = data->getElements(); for (const auto& [idx, el]: armarx::MakeIndexedContainer(elements)) { @@ -405,41 +425,16 @@ namespace armarx::aron::component_config data->removeElement(idx); tab_rebuild_required_ = true; } - - switch (type->getAcceptedType()->getDescriptor()) - { - case type::Descriptor::STRING: - { - proxy_->getValue(data::String::DynamicCast(el)->getValue(), pathToName(el)); - break; - } - case type::Descriptor::INT: - { - std::string str; - proxy_->getValue(str, pathToName(el)); - data::Int::DynamicCast(el)->getValue() = std::stoi(str); - break; - } - default: - throw armarx::NotImplementedYetException(); - } + auto gui_value = proxy_->getValue<std::string>(pathToName(el)).get(); + factories::VariantHelper::make(type)->set_value_from_string(el, gui_value); } if (proxy_->getButtonClicked(pathToName(o) + "_add")) { - switch (type->getAcceptedType()->getDescriptor()) - { - case type::Descriptor::STRING: - data->addElement(make_string("", o->getPath().withIndex(data->childrenSize()))); - break; - case type::Descriptor::INT: - data->addElement(make_int(0, o->getPath().withIndex(data->childrenSize()))); - break; - default: - throw armarx::NotImplementedYetException(); - } + data->addElement(factories::VariantHelper::make(type)->from_string("", + o->getPath() + .withIndex(data->childrenSize()))); tab_rebuild_required_ = true; } - in_list_ = true; } void @@ -457,8 +452,14 @@ namespace armarx::aron::component_config void GetValueFromMapVisitor::visitDictOnEnter(std::shared_ptr<data::Variant>& o, const std::shared_ptr<type::Variant>& t) { + in_list_ = true; auto data = data::Dict::DynamicCastAndCheck(o); - auto type = type::Dict::DynamicCast(t); + auto type = type::Dict::DynamicCast(t)->getAcceptedType()->getDescriptor(); + if (std::find(implementedListDescriptors.begin(), implementedListDescriptors.end(), type) == + implementedListDescriptors.end()) + { + return; + } const auto& elements = data->getElements(); std::map<std::string, std::string> changed_labels; for (const auto& [idx, el]: elements) @@ -469,63 +470,28 @@ namespace armarx::aron::component_config data->removeElement(idx); tab_rebuild_required_ = true; } - - switch (type->getAcceptedType()->getDescriptor()) + auto gui_value = proxy_->getValue<std::string>(name).get(); + auto gui_key = proxy_->getValue<std::string>(name + "_lbl").get(); + auto config_value = factories::VariantHelper::make(type)->to_string(el); + if (gui_value != config_value) { - case type::Descriptor::STRING: + if (proxy_->hasValueChanged(name)) + { + factories::VariantHelper::make(type)->set_value_from_string(el, gui_value); + } else { - auto gui_value = proxy_->getValue<std::string>(name).get(); - auto gui_key = proxy_->getValue<std::string>(name + "_lbl").get(); - if (gui_value != data::String::DynamicCast(el)->getValue()) - { - if (proxy_->hasValueChanged(name)) - { - data::String::DynamicCast(el)->getValue() = gui_value; - } else - { - proxy_->setValue(data::String::DynamicCast(el)->getValue(), name); - } - } - if (gui_key != idx) - { - if (proxy_->hasValueChanged(name + "_lbl")) - { - changed_labels.emplace(idx, gui_key); - } else - { - proxy_->setValue(idx, name + "_lbl"); - } - } - break; + proxy_->setValue(config_value, name); } - case type::Descriptor::INT: + } + if (gui_key != idx) + { + if (proxy_->hasValueChanged(name + "_lbl")) + { + changed_labels.emplace(idx, gui_key); + } else { - auto gui_value = std::stoi(proxy_->getValue<std::string>(name).get()); - auto gui_key = proxy_->getValue<std::string>(name + "_lbl").get(); - if (gui_value != data::Int::DynamicCast(el)->getValue()) - { - if (proxy_->hasValueChanged(name)) - { - data::Int::DynamicCast(el)->getValue() = gui_value; - } else - { - proxy_->setValue(std::to_string(data::Int::DynamicCast(el)->getValue()), name); - } - } - if (gui_key != idx) - { - if (proxy_->hasValueChanged(name + "_lbl")) - { - changed_labels.emplace(idx, gui_key); - } else - { - proxy_->setValue(idx, name + "_lbl"); - } - } - break; + proxy_->setValue(idx, name + "_lbl"); } - default: - throw armarx::NotImplementedYetException(); } } // replace changed keys in map @@ -533,40 +499,22 @@ namespace armarx::aron::component_config { auto element = data->getElement(old_label); data->removeElement(old_label); - switch (type->getAcceptedType()->getDescriptor()) - { - case type::Descriptor::STRING: - data->addElement(new_label, - make_string(data::String::DynamicCast(element)->getValue(), - o->getPath().withDetachedLastElement().withElement(new_label))); - break; - case type::Descriptor::INT: - data->addElement(new_label, - make_int(data::Int::DynamicCast(element)->getValue(), - o->getPath().withDetachedLastElement().withElement(new_label))); - break; - default: - throw armarx::NotImplementedYetException(); - } + auto variantHelper = factories::VariantHelper::make(type); + data->addElement(new_label, + variantHelper->from_string(variantHelper->to_string(element), + o->getPath().withDetachedLastElement().withElement(new_label))); tab_rebuild_required_ = true; } if (proxy_->getButtonClicked(pathToName(o) + "_add")) { - switch (type->getAcceptedType()->getDescriptor()) - { - case type::Descriptor::STRING: - data->addElement("defaultKey", make_string("", o->getPath().withElement("defaultKey"))); - break; - case type::Descriptor::INT: - data->addElement("defaultKey", make_int(0, o->getPath().withElement("defaultKey"))); - break; - default: - throw armarx::NotImplementedYetException(); - } + data->addElement("defaultKey", + factories::VariantHelper::make(type)->from_string("", + o->getPath() + .withElement("defaultKey"))); tab_rebuild_required_ = true; } - in_list_ = true; + } void diff --git a/source/RobotAPI/libraries/aron_component_config/VariantHelperFactory.cpp b/source/RobotAPI/libraries/aron_component_config/VariantHelperFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a96073c1846e5cad2c736af6b638724e422a4c0 --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/VariantHelperFactory.cpp @@ -0,0 +1,207 @@ +/* + * 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 + * @author Christoph Pohl ( christoph dot pohl at kit dot edu ) + * @date 04.11.22 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#include <RobotAPI/libraries/aron/core/data/variant/All.h> +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> +#include <ArmarXCore/core/application/properties/Property.h> +#include "VariantHelperFactory.h" + +namespace armarx::aron::component_config::products +{ + template <> + std::string + VariantHelper<type::Descriptor::INT>::to_string(const data::VariantPtr& ptr) const + { + ARMARX_TRACE; + return simox::alg::to_string(data::Int::DynamicCast(ptr)->getValue()); + } + + template <> + std::string + VariantHelper<type::Descriptor::BOOL>::to_string(const data::VariantPtr& ptr) const + { + ARMARX_TRACE; + return simox::alg::to_string(data::Bool::DynamicCast(ptr)->getValue()); + } + + template <> + std::string + VariantHelper<type::Descriptor::STRING>::to_string(const data::VariantPtr& ptr) const + { + ARMARX_TRACE; + return data::String::DynamicCast(ptr)->getValue(); + } + + template <> + std::string + VariantHelper<type::Descriptor::FLOAT>::to_string(const data::VariantPtr& ptr) const + { + ARMARX_TRACE; + return simox::alg::to_string(data::Float::DynamicCast(ptr)->getValue()); + } + + template <> + std::string + VariantHelper<type::Descriptor::INT_ENUM>::to_string(const data::VariantPtr& ptr) const + { + ARMARX_TRACE; + // TODO: this is should use the name of the enum value + return simox::alg::to_string(data::Int::DynamicCast(ptr)->getValue()); + } + + template <> + std::string + VariantHelper<type::Descriptor::DOUBLE>::to_string(const data::VariantPtr& ptr) const + { + ARMARX_TRACE; + return simox::alg::to_string(data::Double::DynamicCast(ptr)->getValue()); + } + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::INT>::from_string(const std::string& string, + const armarx::aron::Path& path) const + { + ARMARX_TRACE; + return make_int(std::stoi(string), path); + } + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::FLOAT>::from_string(const std::string& string, + const armarx::aron::Path& path) const + { + ARMARX_TRACE; + return make_float(std::stof(string), path); + } + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::DOUBLE>::from_string(const std::string& string, + const armarx::aron::Path& path) const + { + ARMARX_TRACE; + return make_double(std::stod(string), path); + } + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::BOOL>::from_string(const std::string& string, + const armarx::aron::Path& path) const + { + ARMARX_TRACE; + if (string == "true") + { + return make_bool(true, path); + } else if (string == "false") + { + return make_bool(false, path); + } + throw armarx::InvalidArgumentException("Boolean string has to be either true or false"); + } + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::INT_ENUM>::from_string(const std::string& string, + const armarx::aron::Path& path) const + { + // TODO: this might not work + ARMARX_TRACE; + return make_int(std::stoi(string), path); + } + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::STRING>::from_string(const std::string& string, + const armarx::aron::Path& path) const + { + ARMARX_TRACE; + std::string formatted_string = ""; + if (not string.empty()) + { + formatted_string = armarx::FileSystemPathBuilder_ApplyFormattingAndResolveEnvAndCMakeVars(string); + } + return make_string(formatted_string, path); + } + + template <> + void + products::VariantHelper<type::Descriptor::INT>::set_value_from_string(const armarx::aron::data::VariantPtr& variant, + const std::string& string) const + { + ARMARX_TRACE; + data::Int::DynamicCast(variant)->getValue() = std::stoi(string); + } + + template <> + void + products::VariantHelper<type::Descriptor::FLOAT>::set_value_from_string(const armarx::aron::data::VariantPtr& variant, + const std::string& string) const + { + ARMARX_TRACE; + data::Float::DynamicCast(variant)->getValue() = std::stof(string); + } + + template <> + void + products::VariantHelper<type::Descriptor::DOUBLE>::set_value_from_string(const armarx::aron::data::VariantPtr& variant, + const std::string& string) const + { + ARMARX_TRACE; + data::Double::DynamicCast(variant)->getValue() = std::stod(string); + } + + template <> + void + products::VariantHelper<type::Descriptor::BOOL>::set_value_from_string(const armarx::aron::data::VariantPtr& variant, + const std::string& string) const + { + ARMARX_TRACE; + data::Bool::DynamicCast(variant)->getValue() = string == "true"; + } + + template <> + void + products::VariantHelper<type::Descriptor::STRING>::set_value_from_string(const armarx::aron::data::VariantPtr& variant, + const std::string& string) const + { + ARMARX_TRACE; + data::String::DynamicCast(variant)->getValue() = string; + } + + template <> + void + products::VariantHelper<type::Descriptor::INT_ENUM>::set_value_from_string(const armarx::aron::data::VariantPtr& variant, + const std::string& string) const + { + ARMARX_TRACE; + data::Int::DynamicCast(variant)->getValue() = std::stoi(string); + } + + + template struct products::VariantHelper<type::Descriptor::INT>; + template struct products::VariantHelper<type::Descriptor::STRING>; + template struct products::VariantHelper<type::Descriptor::BOOL>; + template struct products::VariantHelper<type::Descriptor::FLOAT>; + template struct products::VariantHelper<type::Descriptor::DOUBLE>; + template struct products::VariantHelper<type::Descriptor::INT_ENUM>; +} \ No newline at end of file diff --git a/source/RobotAPI/libraries/aron_component_config/VariantHelperFactory.h b/source/RobotAPI/libraries/aron_component_config/VariantHelperFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..d2dfb921a7f5cea9e55c6fd96258f258a965c9e3 --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/VariantHelperFactory.h @@ -0,0 +1,174 @@ +/* + * 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 + * @author Christoph Pohl ( christoph dot pohl at kit dot edu ) + * @date 04.11.22 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#pragma once + +#include <ArmarXCore/util/CPPUtility/SelfRegisteringFactory.h> +#include <ArmarXCore/core/application/properties/forward_declarations.h> +#include <RobotAPI/libraries/aron/core/Descriptor.h> +#include <RobotAPI/libraries/aron/core/data/variant/Variant.h> + +namespace armarx::aron::component_config +{ + namespace factories + { + struct VariantHelper : armarx::Factory<VariantHelper, type::Descriptor> + { + explicit VariantHelper(Key) + { + }; + + virtual ~VariantHelper() = default; + + virtual std::string to_string(const armarx::aron::data::VariantPtr&) const = 0; + + virtual void + set_value_from_string(const armarx::aron::data::VariantPtr&, const std::string& string) const = 0; + + virtual aron::data::VariantPtr from_string(const std::string&, const armarx::aron::Path& path) const = 0; + }; + } + namespace products + { + template <type::Descriptor DescT> + struct VariantHelper : factories::VariantHelper::Registrar<VariantHelper<DescT>> + { + using RegistrarT = factories::VariantHelper::Registrar<VariantHelper<DescT>>; + static constexpr type::Descriptor id = DescT; + + explicit VariantHelper() : RegistrarT(typename RegistrarT::Registration()) + { + }; + + [[nodiscard]] std::string to_string(const data::VariantPtr& ptr) const override; + + void set_value_from_string(const armarx::aron::data::VariantPtr& variant, + const std::string& string) const override; + + [[nodiscard]] aron::data::VariantPtr + from_string(const std::string&, const armarx::aron::Path& path) const override; + }; + + + } + + template <> + std::string + products::VariantHelper<type::Descriptor::INT>::to_string(const data::VariantPtr& ptr) const; + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::INT>::from_string(const std::string&, + const armarx::aron::Path& path) const; + + template <> + void + products::VariantHelper<type::Descriptor::INT>::set_value_from_string(const armarx::aron::data::VariantPtr&, + const std::string&) const; + + template <> + std::string + products::VariantHelper<type::Descriptor::FLOAT>::to_string(const data::VariantPtr& ptr) const; + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::FLOAT>::from_string(const std::string&, + const armarx::aron::Path& path) const; + + template <> + void + products::VariantHelper<type::Descriptor::FLOAT>::set_value_from_string(const armarx::aron::data::VariantPtr&, + const std::string&) const; + + template <> + std::string + products::VariantHelper<type::Descriptor::BOOL>::to_string(const data::VariantPtr& ptr) const; + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::BOOL>::from_string(const std::string&, + const armarx::aron::Path& path) const; + + template <> + void + products::VariantHelper<type::Descriptor::BOOL>::set_value_from_string(const armarx::aron::data::VariantPtr&, + const std::string&) const; + + template <> + std::string + products::VariantHelper<type::Descriptor::STRING>::to_string(const data::VariantPtr& ptr) const; + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::STRING>::from_string(const std::string&, + const armarx::aron::Path& path) const; + + template <> + void + products::VariantHelper<type::Descriptor::STRING>::set_value_from_string(const armarx::aron::data::VariantPtr&, + const std::string&) const; + + template <> + std::string + products::VariantHelper<type::Descriptor::DOUBLE>::to_string(const data::VariantPtr& ptr) const; + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::DOUBLE>::from_string(const std::string&, + const armarx::aron::Path& path) const; + + template <> + void + products::VariantHelper<type::Descriptor::DOUBLE>::set_value_from_string(const armarx::aron::data::VariantPtr&, + const std::string&) const; + + template <> + std::string + products::VariantHelper<type::Descriptor::INT_ENUM>::to_string(const data::VariantPtr& ptr) const; + + template <> + aron::data::VariantPtr + products::VariantHelper<type::Descriptor::INT_ENUM>::from_string(const std::string&, + const armarx::aron::Path& path) const; + + template <> + void + products::VariantHelper<type::Descriptor::INT_ENUM>::set_value_from_string(const armarx::aron::data::VariantPtr&, + const std::string&) const; + + + static inline const std::list<type::Descriptor> implementedListDescriptors = { + type::Descriptor::INT_ENUM, + type::Descriptor::INT, + type::Descriptor::STRING, + type::Descriptor::FLOAT, + type::Descriptor::DOUBLE, + type::Descriptor::BOOL, + }; + extern template struct products::VariantHelper<type::Descriptor::INT>; + extern template struct products::VariantHelper<type::Descriptor::FLOAT>; + extern template struct products::VariantHelper<type::Descriptor::DOUBLE>; + extern template struct products::VariantHelper<type::Descriptor::STRING>; + extern template struct products::VariantHelper<type::Descriptor::BOOL>; + extern template struct products::VariantHelper<type::Descriptor::INT_ENUM>; +} +