From 4e2ac806afff4ca3516614925b27f0e030a34778 Mon Sep 17 00:00:00 2001 From: Meixner <andre.meixner@kit.edu> Date: Tue, 3 Dec 2024 17:56:45 +0100 Subject: [PATCH] Fixed errors with ArViz profiles; Added setting default profile --- .../ArViz/ArVizWidgetController.cpp | 22 ++- .../ArViz/ArvizProfileManagerWidget.cpp | 125 ++++++++++++++---- .../ArViz/ArvizProfileManagerWidget.h | 46 ++++++- 3 files changed, 148 insertions(+), 45 deletions(-) diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp index b1933de86..fc014c5ad 100644 --- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp @@ -22,16 +22,14 @@ #include "ArVizWidgetController.h" -#include <ArmarXCore/observers/variant/Variant.h> -#include "RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.h" - #include <SimoxUtility/algorithm/string/string_tools.h> +#include <ArmarXCore/observers/variant/Variant.h> + #include <QLineEdit> #include <QMessageBox> #include <QTimer> #include <QFileDialog> -#include <qnamespace.h> namespace armarx @@ -94,14 +92,7 @@ namespace armarx connect(this, &This::connectGui, this, &This::onConnectGui, Qt::QueuedConnection); connect(this, &This::disconnectGui, this, &This::onDisconnectGui, Qt::QueuedConnection); - arvizeProfileLayerWidget = new ArvizProfileManagerWidget(); - widget.verticalLayout->addWidget(arvizeProfileLayerWidget); - connect(arvizeProfileLayerWidget, &ArvizProfileManagerWidget::publishUpdate, this, &This::updateLayersFromProfile); - connect(arvizeProfileLayerWidget, &ArvizProfileManagerWidget::fetchUpdate, this, &This::updateLayers); - - // Layer info tree. - connect(widget.layerTree, &QTreeWidget::currentItemChanged, this, &This::updateSelectedLayer); connect(widget.layerInfoTreeGroupBox, &QGroupBox::toggled, &layerInfoTree, &LayerInfoTree::setEnabled); @@ -120,6 +111,12 @@ namespace armarx layersChanged(layers); }; + // Arviz Profile tree. + arvizeProfileLayerWidget = new ArvizProfileManagerWidget(); + widget.verticalLayout->addWidget(arvizeProfileLayerWidget); + connect(arvizeProfileLayerWidget, &ArvizProfileManagerWidget::publishUpdate, this, &This::updateLayersFromProfile); + connect(arvizeProfileLayerWidget, &ArvizProfileManagerWidget::fetchUpdate, this, &This::updateLayers); + replayTimer->start(33); } @@ -304,9 +301,10 @@ namespace armarx if (iter == currentComponents.end()) { // Create a new item + QSignalBlocker blocker(tree); // otherwise added as unchecked and directly updated currentItem = new QTreeWidgetItem(tree); currentItem->setText(0, QString::fromStdString(component)); - currentItem->setCheckState(0, arvizeProfileLayerWidget->isHidden(entry) ? Qt::Unchecked : Qt::Checked); + currentItem->setCheckState(0, arvizeProfileLayerWidget->isHidden(component) ? Qt::Unchecked : Qt::Checked); componentWasNew = true; } diff --git a/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.cpp b/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.cpp index fc28f1901..4af5a0fd4 100644 --- a/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.cpp +++ b/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.cpp @@ -1,6 +1,6 @@ #include "ArvizProfileManagerWidget.h" -#include <string> +#include <string> #include <QVBoxLayout> #include <QMessageBox> @@ -9,9 +9,8 @@ #include <QFormLayout> #include <QDialogButtonBox> #include <QPushButton> -#include <qboxlayout.h> -#include <qchar.h> -#include <qradiobutton.h> +#include <QBoxLayout> +#include <QRadioButton> #include <ArmarXCore/core/system/ArmarXDataPath.h> #include <ArmarXCore/core/logging/Logging.h> @@ -19,10 +18,13 @@ namespace armarx { -ProfileDialog::ProfileDialog(QWidget *parent, const QString &name, bool additive, bool addDialog) +const QString ArvizProfileManagerWidget::SETTINGS_DEFAULT_PROFILE_KEY = "defaultProfileName"; + + +ProfileDialog::ProfileDialog(QWidget *parent, const QString &name, bool additive, bool addDialog, bool isDefault) : QDialog(parent) { - setWindowTitle(addDialog ? "Add Profile" : "Edit Profile"); + setWindowTitle(addDialog ? "Add ArViz Profile" : "Edit ArViz Profile"); // Set up UI components nameInput = new QLineEdit(this); @@ -33,10 +35,14 @@ ProfileDialog::ProfileDialog(QWidget *parent, const QString &name, bool additive substractiveRadioButton = new QRadioButton("Save removed layers", this); substractiveRadioButton->setChecked(not additive); + defaultCheckBox = new QCheckBox("Mark default", this); + defaultCheckBox->setChecked(isDefault); + // Save/Cancel buttons QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel, this); connect(buttonBox, &QDialogButtonBox::accepted, this, &ProfileDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &ProfileDialog::reject); + buttonBox->setCenterButtons(true); // Delete button deleteButton = new QPushButton("Delete", this); @@ -47,13 +53,13 @@ ProfileDialog::ProfileDialog(QWidget *parent, const QString &name, bool additive formLayout->addRow("Profile Name:", nameInput); formLayout->addRow(additiveRadioButton); formLayout->addRow(substractiveRadioButton); + formLayout->addRow(defaultCheckBox); + formLayout->addRow(buttonBox); + formLayout->addRow(deleteButton); - QHBoxLayout *mainLayout = new QHBoxLayout; - mainLayout->addLayout(formLayout); - mainLayout->addWidget(buttonBox); - mainLayout->addWidget(deleteButton); - - setLayout(mainLayout); + setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + setLayout(formLayout); + adjustSize(); } ProfileDialog::~ProfileDialog() @@ -70,6 +76,11 @@ bool ProfileDialog::isAdditive() const return additiveRadioButton->isChecked(); } +bool ProfileDialog::isDefaultProfile() const +{ + return defaultCheckBox->isChecked(); +} + void ProfileDialog::deleteProfile() { // Handle the profile deletion @@ -89,14 +100,14 @@ ArvizProfileManagerWidget::ArvizProfileManagerWidget(QWidget* parent) : // Setup UI elements layersComboBox = new QComboBox(this); - connect(layersComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), - this, &ArvizProfileManagerWidget::onLayersSelected); + connect(layersComboBox, QOverload<int>::of(&QComboBox::activated), + this, &ArvizProfileManagerWidget::onProfileSelected); addButton = new QPushButton("Add", this); editButton = new QPushButton("Edit", this); saveButton = new QPushButton("Save", this); - layout->addWidget(new QLabel("Arviz Profile: ")); + layout->addWidget(new QLabel("ArViz Profile: ")); layout->addWidget(layersComboBox); layout->addWidget(addButton); layout->addWidget(editButton); @@ -106,20 +117,35 @@ ArvizProfileManagerWidget::ArvizProfileManagerWidget(QWidget* parent) : connect(addButton, &QPushButton::clicked, this, &ArvizProfileManagerWidget::addProfile); connect(editButton, &QPushButton::clicked, this, &ArvizProfileManagerWidget::editProfile); - connect(saveButton, &QPushButton::clicked, this, &ArvizProfileManagerWidget::saveCurrentLayers); + connect(saveButton, &QPushButton::clicked, this, &ArvizProfileManagerWidget::saveCurrentProfile); loadLayerNames(); + + // Load default profile + const QString defaultProfileName + = settings.value(SETTINGS_DEFAULT_PROFILE_KEY).toString(); + if (int i = layersComboBox->findText(defaultProfileName); i >= 0) + { + layersComboBox->setCurrentText(defaultProfileName); + onProfileSelected(i); + } + else + { + // Not found. Load empty profile + layersComboBox->setCurrentIndex(-1); + } } -void ArvizProfileManagerWidget::onLayersSelected(int index) +void ArvizProfileManagerWidget::onProfileSelected(int index) { - const QString name = layersComboBox->currentText(); - - loadProfile(name); - emit publishUpdate(); + if (index >= 0 and index < layersComboBox->count()) + { + loadProfile(layersComboBox->itemText(index)); + emit publishUpdate(); + } } -void ArvizProfileManagerWidget::saveCurrentLayers() +void ArvizProfileManagerWidget::saveCurrentProfile() { const QString name = layersComboBox->currentText(); if (name.isEmpty()) @@ -138,7 +164,7 @@ void ArvizProfileManagerWidget::saveCurrentLayers() } } -void ArvizProfileManagerWidget::deleteCurrentLayersSave() +void ArvizProfileManagerWidget::deleteCurrentProfileSave() { const QString name = layersComboBox->currentText(); settings.remove(name); @@ -168,16 +194,28 @@ void ArvizProfileManagerWidget::addProfile() { name = defaultName + QString::fromStdString(std::to_string(counter++)); } - dialog = new ProfileDialog(this, name, defaultAdditive, true); + dialog = new ProfileDialog(this, name, defaultAdditive, true, + settings.value(SETTINGS_DEFAULT_PROFILE_KEY) == name); const int result = dialog->exec(); if (result == QDialog::Accepted) { + if (dialog->getName().isEmpty()) + { + ARMARX_WARNING << "Empty name for profile set."; + return; + } if (layersComboBox->findText(dialog->getName()) >= 0) { ARMARX_WARNING << "Profile with name " << dialog->getName().toStdString() << " already exists!"; return; } + + if (dialog->isDefaultProfile()) + { + settings.setValue(SETTINGS_DEFAULT_PROFILE_KEY, dialog->getName()); + } + currentProfile.layers = {}; currentProfile.additive = dialog->isAdditive(); emit fetchUpdate(); @@ -203,23 +241,52 @@ void ArvizProfileManagerWidget::editProfile() { if (dialog == nullptr || !dialog->isVisible()) { - dialog = new ProfileDialog(this, layersComboBox->currentText(), currentProfile.additive, false); - connect(dialog, &ProfileDialog::deleteProfileSignal, this, &ArvizProfileManagerWidget::deleteCurrentLayersSave); + const auto name = layersComboBox->currentText(); + dialog = new ProfileDialog(this, name, currentProfile.additive, + false, settings.value(SETTINGS_DEFAULT_PROFILE_KEY) == name); + connect(dialog, &ProfileDialog::deleteProfileSignal, this, &ArvizProfileManagerWidget::deleteCurrentProfileSave); const int result = dialog->exec(); if (result == QDialog::Accepted) { + const auto newName = dialog->getName(); + + if (newName.isEmpty()) + { + ARMARX_WARNING << "Empty name for profile set."; + return; + } + + if (newName != name) + { + // Rename + if (layersComboBox->findText(newName) >= 0) + { + ARMARX_WARNING << "Profile with name " << newName.toStdString() << " already exists!"; + return; + } + settings.remove(layersComboBox->currentText()); + } + if (dialog->isAdditive() != currentProfile.additive) { currentProfile.layers.clear(); currentProfile.additive = dialog->isAdditive(); emit fetchUpdate(); } + + if (dialog->isDefaultProfile()) + { + settings.setValue(SETTINGS_DEFAULT_PROFILE_KEY, newName); + } + else if (settings.value(SETTINGS_DEFAULT_PROFILE_KEY) == name) + { + settings.setValue(SETTINGS_DEFAULT_PROFILE_KEY, ""); + } - settings.remove(layersComboBox->currentText()); saveProfile(dialog->getName(), currentProfile); loadLayerNames(); - layersComboBox->setCurrentText(dialog->getName()); + layersComboBox->setCurrentText(newName); } else { @@ -254,6 +321,8 @@ void ArvizProfileManagerWidget::loadLayerNames() void ArvizProfileManagerWidget::loadProfile(const QString& name) { + ARMARX_INFO << "Loading ArViz profile " << name.toStdString(); + std::scoped_lock lock(mtx); currentProfile.layers.clear(); diff --git a/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.h b/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.h index 3f998ebd5..1f5a97151 100644 --- a/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.h +++ b/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.h @@ -1,3 +1,24 @@ +/* + * 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::gui-plugins::ArVizProfileManagerWidget + * @author Andre Meixner ( andre dot meixner at kit dot edu ) + * @date 2024 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ #pragma once #include <QWidget> @@ -8,9 +29,10 @@ #include <QSettings> #include <QString> #include <QCheckBox> -#include <qradiobutton.h> +#include <QRadioButton> #include <mutex> +#include <qcheckbox.h> #include <unordered_set> #include <string> #include <utility> @@ -44,11 +66,13 @@ namespace armarx Q_OBJECT public: - explicit ProfileDialog(QWidget *parent = nullptr, const QString &name = "", bool additive = false, bool addDialog = true); + explicit ProfileDialog(QWidget *parent = nullptr, const QString &name = "", + bool additive = false, bool addDialog = true, bool isDefault = false); ~ProfileDialog(); QString getName() const; bool isAdditive() const; + bool isDefaultProfile() const; signals: void deleteProfileSignal(); @@ -61,6 +85,7 @@ namespace armarx QRadioButton *additiveRadioButton; QRadioButton *substractiveRadioButton; QPushButton *deleteButton; + QCheckBox *defaultCheckBox; }; @@ -108,14 +133,23 @@ namespace armarx } } + inline bool isHidden(const std::string& componentName) const + { + std::scoped_lock lock(mtx); + + return currentProfile.additive == (currentProfile.layers.count({componentName, "*"}) == 0); + } + signals: void publishUpdate(); void fetchUpdate(); + public slots: + void onProfileSelected(int index); + private slots: - void onLayersSelected(int index); - void saveCurrentLayers(); - void deleteCurrentLayersSave(); + void saveCurrentProfile(); + void deleteCurrentProfileSave(); void addProfile(); void editProfile(); @@ -134,6 +168,8 @@ namespace armarx mutable std::mutex mtx; Profile currentProfile; + + static const QString SETTINGS_DEFAULT_PROFILE_KEY; }; } -- GitLab