diff --git a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp index 10b31920d68599552ab3dc0713a41bf8ab56033f..db3fb7ee4c04b359d97ca606e54fe2961750043c 100644 --- a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp +++ b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp @@ -174,6 +174,10 @@ namespace armarx { //commitExampleImages(); } + if (true) + { + commitExamplesWithUntypedData(); + } CycleUtil c(static_cast<int>(1000 / p.commitFrequency)); while (!task->isStopped()) @@ -602,6 +606,37 @@ namespace armarx } } + void ExampleMemoryClient::commitExamplesWithUntypedData() + { + const armem::Time time = armem::Time::now(); + + armem::Commit commit; + { + armem::EntityUpdate& update = commit.add(); + update.entityID = exampleDataProviderID.withEntityName("unexpected_data"); + update.timeCreated = time; + + armem::example::ExampleData data; + toAron(data.memoryLink, armem::MemoryID()); // ////1/1 + + aron::data::DictPtr aron = data.toAron(); + aron->addElement("unexpectedString", std::make_shared<aron::data::String>("unexpected value")); + aron->addElement("unexpectedDict", std::make_shared<aron::data::Dict>( + std::map<std::string, aron::data::VariantPtr>{ + { "key43", std::make_shared<aron::data::Int>(43) }, + { "keyABC", std::make_shared<aron::data::String>("ABC") }, + } + )); + update.instancesData = { aron }; + } + + armem::CommitResult commitResult = memoryWriter.commit(commit); + if (!commitResult.allSuccess()) + { + ARMARX_WARNING << commitResult.allErrorMessages(); + } + } + void ExampleMemoryClient::processExampleEntityUpdate( const armem::MemoryID& subscriptionID, const std::vector<armem::MemoryID>& snapshotIDs) diff --git a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h index 0adda091a10f7c07585fe1a34d00ee3d7cae0737..930abfea7618c4ece3f7298c97376a54b201bac6 100644 --- a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h +++ b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h @@ -102,6 +102,8 @@ namespace armarx void commitExampleImages(); + void commitExamplesWithUntypedData(); + private: diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp index eae4cb934e7c878c2c2f7787f0ef0cd96a2f9775..e2537e0c5f94b382ea00920eb79f168e50b73331 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp +++ b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp @@ -12,6 +12,7 @@ #include <RobotAPI/libraries/armem_gui/instance/sanitize_typename.h> #include <RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.h> #include <RobotAPI/libraries/armem_gui/instance/MemoryIDTreeWidgetItem.h> +#include <RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.h> namespace armarx::armem::gui::instance @@ -28,21 +29,18 @@ namespace armarx::armem::gui::instance const aron::data::Dict& data) { auto childType = type.getAcceptedType(); - if (childType) + DictBuilder builder = getDictBuilder(); + builder.setUpdateItemFn([this, &childType, &data](const std::string & key, QTreeWidgetItem * item) { - DictBuilder builder = getDictBuilder(); - builder.setUpdateItemFn([this, &childType, &data](const std::string & key, QTreeWidgetItem * item) + auto childData = data.getElement(key); + if (childData) { - auto childData = data.getElement(key); - if (childData) - { - this->update(item, key, childType, childData); - } - return true; - }); - - builder.updateTreeWithContainer(parent, data.getAllKeys()); - } + this->updateDispatch(item, key, childType, childData); + } + return true; + }); + + builder.updateTreeWithContainer(parent, data.getAllKeys()); } @@ -54,7 +52,8 @@ namespace armarx::armem::gui::instance DictBuilder builder = getDictBuilder(); builder.setMakeItemFn([this, &type](const std::string & key) -> QTreeWidgetItem* { - if (type.getMemberType(key)->getFullName() == instance::rawMemoryIDTypeName) + if (type.hasMemberType(key) + && type.getMemberType(key)->getFullName() == instance::rawMemoryIDTypeName) { MemoryIDTreeWidgetItem* item = new MemoryIDTreeWidgetItem({QString::fromStdString(key)}); item->addKeyChildren(); @@ -67,17 +66,22 @@ namespace armarx::armem::gui::instance }); builder.setUpdateItemFn([this, &type, &data](const std::string & key, QTreeWidgetItem * item) { - auto childType = type.getMemberType(key); auto childData = data.getElement(key); - if (childType) + // We need this check here because getMemberType(key) throws + // instead of returning nullptr if the type doesn't have the key. + if (type.hasMemberType(key)) { - this->update(item, key, childType, childData); + this->updateDispatch(item, key, type.getMemberType(key), childData); + } + else + { + this->updateDispatch(item, key, nullptr, childData); } return true; }); - builder.updateTreeWithContainer(parent, type.getAllKeys()); + builder.updateTreeWithContainer(parent, data.getAllKeys()); } @@ -86,22 +90,19 @@ namespace armarx::armem::gui::instance const aron::data::List& data) { auto childType = type.getAcceptedType(); - if (childType) - { - auto children = data.getChildren(); + auto children = data.getChildren(); - ListBuilder builder = getListBuilder(); - builder.setUpdateItemFn([this, &children, &childType](size_t key, QTreeWidgetItem * item) + ListBuilder builder = getListBuilder(); + builder.setUpdateItemFn([this, &children, &childType](size_t key, QTreeWidgetItem * item) + { + if (auto childData = children.at(key)) { - if (auto childData = children.at(key)) - { - this->update(item, std::to_string(key), childType, childData); - } - return true; - }); - - builder.updateTreeWithContainer(parent, getIndex(children.size())); - } + this->updateDispatch(item, std::to_string(key), childType, childData); + } + return true; + }); + + builder.updateTreeWithContainer(parent, getIndex(children.size())); } @@ -119,10 +120,7 @@ namespace armarx::armem::gui::instance auto childType = i == 0 ? childTypes.first : childTypes.second; auto childData = data.getElement(static_cast<unsigned int>(i)); - if (childType) - { - this->update(item, std::to_string(i), childType, childData); - } + this->updateDispatch(item, std::to_string(i), childType, childData); return true; }); @@ -135,22 +133,43 @@ namespace armarx::armem::gui::instance const aron::type::Tuple& type, const aron::data::List& data) { + // Allows tuples where the data list is longer than the type tuple - + // is that desired behavior? + auto childTypes = type.getAcceptedTypes(); ListBuilder builder = getListBuilder(); builder.setUpdateItemFn([this, &data, &childTypes](size_t i, QTreeWidgetItem * item) { - auto childType = childTypes.at(i); + auto childType = (i < childTypes.size()) ? childTypes.at(i) : nullptr; auto childData = data.getElement(static_cast<unsigned int>(i)); - if (childType) - { - this->update(item, std::to_string(i), childType, childData); - } + this->updateDispatch(item, std::to_string(i), childType, childData); return true; }); - builder.updateTreeWithContainer(parent, getIndex(type.getAcceptedTypes().size())); + builder.updateTreeWithContainer(parent, getIndex(data.childrenSize())); + } + + + /*! Used so that elements in the data that don't appear in the type + * can still be shown in the GUI if type information is enabled + * (otherwise, they would be hidden). + */ + void TypedDataTreeBuilder::updateDispatch( + QTreeWidgetItem* item, + const std::string& key, + const aron::type::VariantPtr& type, + const aron::data::VariantPtr& data) + { + if (type) + { + this->update(item, key, type, data); + } + else + { + this->update(item, key, data); + } } @@ -217,6 +236,33 @@ namespace armarx::armem::gui::instance _updateTree(item, *t, *d); } // else??? + // phesch: else we stop here, since there's no container to recurse into. + } + } + + + void TypedDataTreeBuilder::update(QTreeWidgetItem* item, + const std::string& key, + const aron::data::VariantPtr& data) + { + if (data) + { + this->setRowTexts(item, key, data); + + if (auto cast = aron::data::Dict::DynamicCast(data)) + { + DataTreeBuilder builder; + builder.updateTree(item, cast); + } + else if (auto cast = aron::data::List::DynamicCast(data)) + { + DataTreeBuilder builder; + builder.updateTree(item, cast); + } + } + else + { + this->setRowTexts(item, key, "(none)"); } } diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.h b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.h index b4e6dc91bc963ac799e5230f95f5e46c7fb79ebb..b8aacc686df4dbf2119d963f5fc163aabe0c52bf 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.h +++ b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.h @@ -49,11 +49,20 @@ namespace armarx::armem::gui::instance protected: + void updateDispatch(QTreeWidgetItem* item, + const std::string& key, + const aron::type::VariantPtr& type, + const aron::data::VariantPtr& data); + void update(QTreeWidgetItem* item, const std::string& key, const aron::type::VariantPtr& type, const aron::data::VariantPtr& data); + void update(QTreeWidgetItem* item, + const std::string& key, + const aron::data::VariantPtr& data); + template <class DataT, class TypeT> void _updateTree(QTreeWidgetItem* item, TypeT& type, DataT& data); diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp index 56dd6f22a526a60c65bcd992b48ae214b7af2241..eb27eedcdb74c99f04003f0b0d143add11527bc7 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp +++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp @@ -105,7 +105,7 @@ namespace armarx::aron::type VariantPtr Object::getMemberType(const std::string& s) const { - if (memberTypes.find(s) == memberTypes.end() and !extends->hasMemberType(s)) + if (memberTypes.find(s) == memberTypes.end() and not (extends and extends->hasMemberType(s))) { throw error::ValueNotValidException("ObjectNavigator", "getMemberType", "Member not set. The list of all members is: " + simox::alg::to_string(simox::alg::get_keys(memberTypes)), s); }