diff --git a/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.cpp b/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.cpp index 878b44b6d08f22f6a7ad17f2adb22c4fb75a6b0f..5c25312a56f2cf17b31c5641bb09f7efaa8170a5 100644 --- a/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.cpp +++ b/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.cpp @@ -76,6 +76,10 @@ namespace armarx::skills::gui void SkillMemoryGUI::connectSignals() { + connect(skillGroupBox, + &SkillGroupBox::updateSkillDetails, + skillDetailGroupBox, + &SkillDetailGroupBox::updateSkillDetails); /* // connect update widget to memory update connect(this->updateWidget, diff --git a/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.h b/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.h index 07ec971daaaa2eb94de2dff82f2cf434f1d1e5aa..db87ee40bd958256cb35b16dee8d727197cdfa31 100644 --- a/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.h +++ b/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.h @@ -20,7 +20,6 @@ namespace armarx::skills::gui class SkillMemoryGUI : public QObject, public armarx::Logging { Q_OBJECT - using This = SkillMemoryGUI; public: SkillMemoryGUI(QTreeWidget* _skillExecutionTreeWidget, diff --git a/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.cpp b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.cpp index 53cf0c86805ab7fa3a38798fc22137b9c44a776d..db960fca7e97882af0170a9d4677e1c279d45915 100644 --- a/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.cpp +++ b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.cpp @@ -75,6 +75,14 @@ namespace armarx::skills::gui SkillExecutionTreeWidget::setupUi() { this->setColumnCount(4); + + this->setContextMenuPolicy(Qt::CustomContextMenu); + + QTreeWidgetItem* ___qtreewidgetitem = this->headerItem(); + ___qtreewidgetitem->setText(3, "Status"); + ___qtreewidgetitem->setText(2, "SkillID"); + ___qtreewidgetitem->setText(1, "Executor"); + ___qtreewidgetitem->setText(0, "Timestamp"); } inline bool diff --git a/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.cpp b/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.cpp index ec99668e6678fec4877898d7be9a637688cf6e67..85bfdc8c0a0db1831f9582c36cf97806d4ebfdf8 100644 --- a/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.cpp +++ b/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.cpp @@ -130,6 +130,30 @@ namespace armarx::skills::gui return snapshot; } + const std::optional<ProviderID> + SkillManagerWrapper::Snapshot::findFirstProvider(SkillID& skillId) + { + // check if id already contains a provider. If so, this function should not have been called! + if (skillId.isProviderSpecified()) + { + ARMARX_WARNING << "The memory snapshot was searched for any provider, when a provider " + "was specified."; + // we continue, but this might result in unexpected behaviour... + } + + for (auto& [prov, skillMap] : skills) + { + for (auto& [skill, desc] : skillMap) + { + if (skill == skillId) + { + return prov; + } + } + } + return std::nullopt; + } + void SkillManagerWrapper::stopExecution(skills::SkillExecutionID const& executionId, unsigned int max_retries) diff --git a/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.h b/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.h index 7b1a2cb92a1f4a61156ba63325eff91dc3930aba..68060e730f4607441e26a3d834614b42c0a574b4 100644 --- a/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.h +++ b/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.h @@ -46,6 +46,13 @@ namespace armarx::skills::gui Snapshot() : statuses({}), skills({}) { } + + /** + * @brief Finds the first provider which provides the given skill id in the snapshot. The skill id should not contains a provider. + * @param skillId the incomplete skill id. + * @return the first provider to match. Nullopt if none was found. + */ + const std::optional<ProviderID> findFirstProvider(skills::SkillID& skillId); }; // Basic functions to work with. These will produce Ice calls! diff --git a/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.h b/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.h index 26f6a490a0007ebb4ebce3a533d406e5146f4f3f..2041c2e9fc72e1b0a0e340e085ae3940b73cb57a 100644 --- a/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.h +++ b/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.h @@ -18,6 +18,12 @@ namespace armarx::skills::gui static const constexpr char* RESET_ARGS_BUTTON_TEXT = "Reset Args to Profile"; static const constexpr char* DEFAULT_PROFILE_TEXT = "<No Profile selected. Using root>"; + // contents are public, as this class is just a convenience wrapper + QPushButton* setArgsFromClipboard = nullptr; + QPushButton* copyArgsToClipboard = nullptr; + QPushButton* resetArgsToProfile = nullptr; + QComboBox* profileSelector = nullptr; + ProfileMenuWidget(std::shared_ptr<SkillManagerWrapper> _memory, QWidget* parent = nullptr) : QWidget(parent), MemoryCommunicatorBase(_memory) { @@ -26,11 +32,6 @@ namespace armarx::skills::gui private: void setupUi(); - - QPushButton* setArgsFromClipboard = nullptr; - QPushButton* copyArgsToClipboard = nullptr; - QPushButton* resetArgsToProfile = nullptr; - QComboBox* profileSelector = nullptr; }; } // namespace armarx::skills::gui diff --git a/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.cpp b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.cpp index 733be87143cb26768378fdb314e3eb70d4b6e2ae..e64e3f78d5439354c94393e024354331d1686389 100644 --- a/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.cpp +++ b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.cpp @@ -4,11 +4,131 @@ namespace armarx::skills::gui { + void + SkillDetailGroupBox::lock() + { + this->executeSkillButton->setDisabled(true); + this->skillDetailsTreeWidget->setDisabled(true); + this->descriptionWidget->setDisabled(true); + this->profileMenuWidget->setDisabled(true); + } + + void + SkillDetailGroupBox::unlock() + { + this->executeSkillButton->setDisabled(false); + this->skillDetailsTreeWidget->setDisabled(false); + this->descriptionWidget->setDisabled(false); + this->profileMenuWidget->setDisabled(false); + } + + void + SkillDetailGroupBox::updateSkillDetails(SkillID& _skillId) + { + if (_skillId.skillName == SkillID::UNKNOWN) + return; + + SkillManagerWrapper::Snapshot snapshot = memory->getLatestUpdate(); + + std::optional<skills::ProviderID> provider_opt; + // check skillId + if (_skillId.isProviderSpecified()) + { + provider_opt = _skillId.providerId; + } + else + { + // find first provider to provide the skill + provider_opt = snapshot.findFirstProvider(_skillId); + } + + if (provider_opt == std::nullopt) + { + // skill was not found in snapshot. Abort... + return; + } + + // construct skill id (with guaranteed valid provider) + skills::SkillID skillId = {provider_opt, _skillId.skillName}; + + // We assert that the skill exists + ARMARX_CHECK(snapshot.skills.count(skillId.providerId.value()) > 0); + ARMARX_CHECK(snapshot.skills.at(skillId.providerId.value()).count(skillId) > 0); + + // get skill description + skills::SkillDescription descr = snapshot.skills[skillId.providerId.value()][skillId]; + + // ------------ update widgets ------------ + + this->lock(); + + // setup groupBox + this->setTitle(QString::fromStdString(skillId.toString())); + + // setup table view + this->skillDetailsTreeWidget->clear(); + aronTreeWidgetController = nullptr; + skillsArgumentsTreeWidgetItem = nullptr; + + + { + auto it = new QTreeWidgetItem( + skillDetailsTreeWidget, + {QString::fromStdString("Name"), QString::fromStdString(skillId.skillName)}); + skillDetailsTreeWidget->addTopLevelItem(it); + } + + { + auto it = new QTreeWidgetItem( + skillDetailsTreeWidget, + {QString::fromStdString("Description"), QString::fromStdString(descr.description)}); + skillDetailsTreeWidget->addTopLevelItem(it); + } + + { + auto it = new QTreeWidgetItem( + skillDetailsTreeWidget, + {QString::fromStdString("Timeout"), + QString::fromStdString(std::to_string(descr.timeout.toMilliSeconds())) + " ms"}); + skillDetailsTreeWidget->addTopLevelItem(it); + } + + // select root profile + profileMenuWidget->profileSelector->setCurrentIndex(0); + + // remove any profile + while (profileMenuWidget->profileSelector->count() > 1) + { + profileMenuWidget->profileSelector->removeItem(1); + } + + // add new profiles for this skill + // TODO: Where stored? + + skillsArgumentsTreeWidgetItem = + new QTreeWidgetItem(skillDetailsTreeWidget, {QString::fromStdString("Arguments")}); + auto aron_args = descr.parametersType; + auto default_args_of_profile = descr.rootProfileDefaults; + + aronTreeWidgetController = + std::make_shared<AronTreeWidgetController>(skillDetailsTreeWidget, + skillsArgumentsTreeWidgetItem, + aron_args, + default_args_of_profile); + + // automatically expand args + skillsArgumentsTreeWidgetItem->setExpanded(true); + + this->unlock(); + } + void SkillDetailGroupBox::setupUi() { this->setTitle(QString::fromStdString(GROUP_BOX_TITLE)); + this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + // construct all sub widgets this->executeSkillButton = new QPushButton(); this->profileMenuWidget = new ProfileMenuWidget(this->memory, this); diff --git a/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.h b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.h index ef258f32b9816c3ec4858c4fce4f863183f29cf2..0d599bf86e304ee303aa766fe9a692674d41925c 100644 --- a/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.h +++ b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.h @@ -5,6 +5,7 @@ #include <QPushButton> #include <QVBoxLayout> +#include "RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetController.h" #include "RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/SkillDescriptionWidget.h" #include "../memory/MemoryCommunicatorBase.h" @@ -26,12 +27,31 @@ namespace armarx::skills::gui setupUi(); } + public slots: + /** + * @brief Update subwidgets of an updated skill selection. + * @param skillId + */ + void updateSkillDetails(skills::SkillID& skillId); + private: void setupUi(); + /** + * @brief locks this widget. + */ + void lock(); + /** + * @brief unlocks this widget. + */ + void unlock(); QVBoxLayout* layout = nullptr; QPushButton* executeSkillButton = nullptr; SkillDetailsTreeWidget* skillDetailsTreeWidget = nullptr; SkillDescriptionWidget* descriptionWidget = nullptr; + + // Helper to get the treeWidgetItem easily + QTreeWidgetItem* skillsArgumentsTreeWidgetItem = nullptr; + AronTreeWidgetControllerPtr aronTreeWidgetController = nullptr; ProfileMenuWidget* profileMenuWidget = nullptr; }; } // namespace armarx::skills::gui diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.cpp b/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.cpp index c53d3ed28f14da26b35963673a4d89aa8126f124..0f17f047d13af3f8aae8e797c4fec61e303743a8 100644 --- a/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.cpp +++ b/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.cpp @@ -15,6 +15,11 @@ namespace armarx::skills::gui void SkillGroupBox::setupUi() { + this->setTitle(QString::fromStdString(GROUP_BOX_TITLE)); + + this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + + // construct widgets this->searchBar = new QLineEdit(); this->acceptSearchButton = new QPushButton(); @@ -40,7 +45,6 @@ namespace armarx::skills::gui void SkillGroupBox::connectSignals() { - /* connect( this->acceptSearchButton, &QPushButton::clicked, this, &SkillGroupBox::handleSearch); connect(this->searchBar, &QLineEdit::editingFinished, this, &SkillGroupBox::handleSearch); @@ -48,6 +52,10 @@ namespace armarx::skills::gui &SkillGroupBox::searchRequest, this->memory.get(), &SkillManagerWrapper::acceptSearchRequest); -*/ + + connect(skillTreeWidget, + &SkillTreeWidget::updateSkillDetails, + this, + &SkillGroupBox::updateSkillDetails); } } // namespace armarx::skills::gui diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.h b/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.h index 3fd83e8833775db41b77845cadce0d0fc673075a..2cad20ecbb3a84776922eabe3ac5e12506c89905 100644 --- a/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.h +++ b/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.h @@ -14,6 +14,8 @@ namespace armarx::skills::gui { Q_OBJECT public: + static const constexpr char* GROUP_BOX_TITLE = "Skills"; + SkillGroupBox(std::shared_ptr<SkillManagerWrapper> _memory, QWidget* parent = nullptr) : QGroupBox(parent), MemoryCommunicatorBase(_memory) { @@ -22,9 +24,15 @@ namespace armarx::skills::gui signals: /** - * Output signal to controller. + * @brief Output signal to controller. */ void searchRequest(std::string search); + + /** + * @brief Notify the skill description widget of an updated selection. + * @param skillId + */ + void updateSkillDetails(skills::SkillID& skillId); private slots: /** * Takes string from line edit and emits the search request. diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.cpp b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.cpp index 029ada8af353dc5dfd5ce4485d9aa5f1e2d30945..b5a8fe1f1dcfa9024c19d46524c7e97c2bf9f18e 100644 --- a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.cpp +++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.cpp @@ -1,13 +1,58 @@ #include "SkillTreeWidget.h" +#include "RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.h" + namespace armarx::skills::gui { + void + SkillTreeWidget::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) + { + if (!current) + { + // gui has died? + return; + } + + auto c = dynamic_cast<SkillTreeWidgetItem*>(current); + if (!c) + { + // we don't know what to do with the item. Abort... + return; + } + + if (selectedSkill.skillId == c->skillId) + { + // no change + return; + } + + selectedSkill.skillId = c->skillId; + + emit updateSkillDetails(c->skillId); + } + + void + SkillTreeWidget::updateSkills() + { + } + void SkillTreeWidget::setupUi() { + this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QTreeWidgetItem* ___qtreewidgetitem1 = this->headerItem(); ___qtreewidgetitem1->setText(2, "HasOutputType"); ___qtreewidgetitem1->setText(1, "HasInputType"); ___qtreewidgetitem1->setText(0, "Skill"); + + connectSignals(); + } + + void + SkillTreeWidget::connectSignals() + { } + + } // namespace armarx::skills::gui diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.h b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.h index 7b37646775218fca63eb677941966db2fc617768..ea70846da279d55d43933bce4344fd88f4c1029d 100644 --- a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.h +++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.h @@ -11,6 +11,7 @@ namespace armarx::skills::gui { class SkillTreeWidget : public QTreeWidget, public MemoryCommunicatorBase { + Q_OBJECT public: SkillTreeWidget(std::shared_ptr<SkillManagerWrapper> _memory, QWidget* parent = nullptr) : QTreeWidget(parent), MemoryCommunicatorBase(_memory) @@ -31,6 +32,13 @@ namespace armarx::skills::gui SelectedSkill& getSelectedSkill(); + signals: + /** + * @brief Notify the skill description widget of an updated selection. + * @param skillId + */ + void updateSkillDetails(skills::SkillID& skillId); + private slots: void skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); void updateSkills(); @@ -39,6 +47,7 @@ namespace armarx::skills::gui SelectedSkill selectedSkill; void setupUi(); + void connectSignals(); }; } // namespace armarx::skills::gui diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.cpp b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.cpp index 235461cfc09404bbffd2ef035fc228689a5e16c7..e4845c11d5bc6264a0f4200d412eb6eb28198b19 100644 --- a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.cpp +++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.cpp @@ -1,6 +1,6 @@ #include "SkillTreeWidgetItem.h" -SkillTreeWidgetItem::SkillTreeWidgetItem() +namespace armarx::skills::gui { -} +} // namespace armarx::skills::gui diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.h b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.h index d56c906bbcf26cfcc284d7c82d19e2009627df91..2a2ae418e4f546027753a4faf62daf7693ee0f7a 100644 --- a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.h +++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.h @@ -1,10 +1,26 @@ #pragma once #include <QTreeWidgetItem> +#include "RobotAPI/libraries/skills/core/SkillID.h" -class SkillTreeWidgetItem : public QTreeWidgetItem + + +namespace armarx::skills::gui { -public: - SkillTreeWidgetItem(); -}; + class SkillTreeWidgetItem : public QTreeWidgetItem + { + public: + SkillTreeWidgetItem(const skills::SkillID& desc, QTreeWidgetItem* parent) : + QTreeWidgetItem(parent), skillId(desc) + { + } + + SkillTreeWidgetItem(const skills::SkillID& desc, QTreeWidget* parent) : + QTreeWidgetItem(parent), skillId(desc) + { + } + + skills::SkillID skillId; + }; +}