diff --git a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidget.ui b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidget.ui index de8496435fea6ea6fb7dca4bce1833fffa0ee632..0a8bbb2f936f3ac863cbfb1dba62c0dcfc501591 100644 --- a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidget.ui +++ b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidget.ui @@ -68,14 +68,111 @@ <item> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QTableWidget" name="requestTable"/> + <widget class="QTreeWidget" name="requestTree"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="columnCount"> + <number>3</number> + </property> + <attribute name="headerCascadingSectionResizes"> + <bool>true</bool> + </attribute> + <attribute name="headerShowSortIndicator" stdset="0"> + <bool>true</bool> + </attribute> + <attribute name="headerStretchLastSection"> + <bool>true</bool> + </attribute> + <column> + <property name="text"> + <string>ID</string> + </property> + </column> + <column> + <property name="text"> + <string>Provider</string> + </property> + </column> + <column> + <property name="text"> + <string>Request</string> + </property> + </column> + <item> + <property name="text"> + <string>Dataset2</string> + </property> + <property name="text"> + <string/> + </property> + <property name="text"> + <string/> + </property> + <item> + <property name="text"> + <string>ClassName3</string> + </property> + <property name="text"> + <string>Provider1</string> + </property> + <property name="text"> + <string/> + </property> + </item> + <item> + <property name="text"> + <string>ClassName3</string> + </property> + <property name="text"> + <string>Provider2</string> + </property> + </item> + </item> + <item> + <property name="text"> + <string>Dataset1</string> + </property> + <property name="text"> + <string/> + </property> + <property name="text"> + <string/> + </property> + <item> + <property name="text"> + <string>ClassName2</string> + </property> + <property name="text"> + <string>Provider1</string> + </property> + <property name="text"> + <string/> + </property> + </item> + <item> + <property name="text"> + <string>ClassName1</string> + </property> + <property name="text"> + <string>Provider2</string> + </property> + <property name="text"> + <string/> + </property> + </item> + </item> + </widget> </item> </layout> </item> <item> <layout class="QVBoxLayout" name="verticalLayout_4"> <item> - <widget class="QLabel" name="label_2"> + <widget class="QLabel" name="labelTimeout"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> <horstretch>0</horstretch> diff --git a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp index e4373f379e851fbf053fa798be629db19510ec9a..ae76b958a2a21ea42459627413b7a81f5163567f 100644 --- a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp @@ -42,9 +42,8 @@ namespace armarx widget.objectsTable->setHorizontalHeaderLabels(header); - header = QStringList{"Dataset", "ClassName", "Type", "Provider", "Request"}; - widget.requestTable->setColumnCount(header.size()); - widget.requestTable->setHorizontalHeaderLabels(header); + widget.requestTree->clear(); + widget.requestTree->sortItems(0, Qt::SortOrder::AscendingOrder); using This = ObjectPoseGuiWidgetController; @@ -60,7 +59,6 @@ namespace armarx ObjectPoseGuiWidgetController::~ObjectPoseGuiWidgetController() { - } @@ -76,7 +74,7 @@ namespace armarx QString ObjectPoseGuiWidgetController::GetWidgetName() { - return "VisionX.ObjectPoseGui"; + return "MemoryX.ObjectPoseGui"; } static const std::string CONFIG_KEY_OBJECT_POSE_OBSERVER = "ObjectPoseObserver"; @@ -171,6 +169,14 @@ namespace armarx } + + struct ProviderInfo + { + std::string name; + objpose::ObjectPoseProviderPrx proxy; + objpose::ObjectTypeEnum objectType; + }; + void ObjectPoseGuiWidgetController::updateRequestTab() { if (!objectPoseObserver) @@ -181,43 +187,43 @@ namespace armarx IceUtil::Time start = IceUtil::Time::now(); objpose::ProviderInfoMap availableProvidersInfo = objectPoseObserver->getAvailableProvidersInfo(); - ARMARX_INFO << "Got infos of " << availableProvidersInfo.size() << " object poses. " + ARMARX_INFO << "Got infos of " << availableProvidersInfo.size() << " object pose providers. " << "(Took " << (IceUtil::Time::now() - start).toMilliSeconds() << " ms.)"; - start = IceUtil::Time::now(); - int row = 0; + + // Restructure data. + std::map<std::string, std::map<std::string, std::map<std::string, ProviderInfo>>> data; for (const auto& [providerName, info] : availableProvidersInfo) { for (const auto& id : info.supportedObjects) { - int col = 0; + ProviderInfo& dinfo = data[id.dataset][id.className][providerName]; + dinfo.name = providerName; + dinfo.proxy = info.proxy; + dinfo.objectType = info.objectType; + } + } + + QTreeWidget* tree = widget.requestTree; + tree->clear(); + + start = IceUtil::Time::now(); + for (const auto& [dataset, datasetData] : data) + { + QTreeWidgetItem* datasetItem = new QTreeWidgetItem({QString::fromStdString(dataset)}); + tree->addTopLevelItem(datasetItem); - // header = QStringList{"Dataset", "ClassName", "Type", "Provider", "Request"}; - /* - if (row < widget.requestTable->rowCount()) + for (const auto& [className, providerData] : datasetData) + { + for (const auto& [providerName, providerInfo] : providerData) { - widget.requestTable->item(row, col++)->setText(id.dataset.c_str()); - widget.requestTable->item(row, col++)->setText(id.className.c_str()); - widget.requestTable->item(row, col++)->setText(objpose::ObjectTypeEnumNames.to_name(info.objectType).c_str()); - widget.requestTable->item(row, col++)->setText(providerName.c_str()); - widget.requestTable->item(row, col++)->setText(id.dataset.c_str()); + QTreeWidgetItem* classItem = new QTreeWidgetItem( + { QString::fromStdString(className), QString::fromStdString(providerName)}); + datasetItem->addChild(classItem); + QCheckBox* requestCheckBox = new QCheckBox(); - widget.requestTable->setCellWidget(row, col++, requestCheckBox); + tree->setItemWidget(classItem, 2, requestCheckBox); } - else - */ - widget.requestTable->setItem( - row, col++, new QTableWidgetItem(id.dataset.c_str())); - widget.requestTable->setItem( - row, col++, new QTableWidgetItem(id.className.c_str())); - widget.requestTable->setItem( - row, col++, new QTableWidgetItem(objpose::ObjectTypeEnumNames.to_name(info.objectType).c_str())); - widget.requestTable->setItem( - row, col++, new QTableWidgetItem(providerName.c_str())); - QCheckBox* requestCheckBox = new QCheckBox(); - widget.requestTable->setCellWidget(row, col++, requestCheckBox); - - ++row; } } @@ -226,20 +232,48 @@ namespace armarx void ObjectPoseGuiWidgetController::requestSelectedObjects() { - objpose::RequestObjectsInput requests; + std::map<std::string, objpose::observer::RequestObjectsInput> requestsPerProvider; + + QTreeWidget* tree = widget.requestTree; + for (int i = 0; i < tree->topLevelItemCount(); ++i) + { + QTreeWidgetItem* datasetItem = tree->topLevelItem(i); + for (int j = 0; j < datasetItem->childCount(); ++j) + { + QTreeWidgetItem* classItem = datasetItem->child(j); + QCheckBox* selected = dynamic_cast<QCheckBox*>(tree->itemWidget(classItem, 2)); + ARMARX_CHECK_NOT_NULL(selected); + if (selected->isChecked()) + { + std::string providerName = classItem->text(1).toStdString(); + objpose::observer::RequestObjectsInput& requests = requestsPerProvider[providerName]; + objpose::ObjectID& id = requests.request.objectIDs.emplace_back(); + id.dataset = datasetItem->text(0).toStdString(); + id.className = classItem->text(0).toStdString(); + } + } + } + + long timeoutMS = -1; + if (!widget.requestInfiniteCheckBox->isChecked()) + { + timeoutMS = long(widget.requestTimeoutSpinBox->value() * 1000); + } - QTableWidget* table = widget.requestTable; - for (int row = 0; row < table->rowCount(); ++row) + for (auto& [providerName, request] : requestsPerProvider) { - QCheckBox* selected = dynamic_cast<QCheckBox*>(table->cellWidget(row, table->columnCount() - 1)); - ARMARX_CHECK_NOT_NULL(selected); - if (selected->isChecked()) + request.provider = providerName; + request.request.relativeTimeoutMS = timeoutMS; + + ARMARX_INFO << "Requesting " << request.request.objectIDs.size() << " objects for " + << request.request.relativeTimeoutMS << " ms."; + objpose::observer::RequestObjectsOutput output = objectPoseObserver->requestObjects(request); + int successful = 0; + for (const auto& [id, result] : output.results) { - objpose::ObjectID id; - id.dataset = table->item(row, 0)->text().toStdString(); - id.className = table->item(row, 1)->text().toStdString(); - requests.objectIDs.emplace_back(id); + successful += int(!result.providerName.empty() && result.result.success); } + ARMARX_INFO << successful << " of " << request.request.objectIDs.size() << " object request successful."; } }