From 80b3568581008d454188952477250735dcc7d9ed Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@kit.edu>
Date: Thu, 8 Oct 2020 17:49:11 +0200
Subject: [PATCH] Refactor ObjectPoseGui request tab

---
 .../ObjectPoseGui/ObjectPoseGuiWidget.ui      | 101 ++++++++++++++-
 .../ObjectPoseGuiWidgetController.cpp         | 118 +++++++++++-------
 2 files changed, 175 insertions(+), 44 deletions(-)

diff --git a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidget.ui b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidget.ui
index de8496435..0a8bbb2f9 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 e4373f379..ae76b958a 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.";
         }
     }
 
-- 
GitLab