diff --git a/src/Gui/Dialogs/DlgAddPropertyVarSet.cpp b/src/Gui/Dialogs/DlgAddPropertyVarSet.cpp index 3ec99ecec7..db221c360e 100644 --- a/src/Gui/Dialogs/DlgAddPropertyVarSet.cpp +++ b/src/Gui/Dialogs/DlgAddPropertyVarSet.cpp @@ -173,9 +173,11 @@ void DlgAddPropertyVarSet::removeExistingWidget(QFormLayout* formLayout, int lab } } } -void DlgAddPropertyVarSet::setWidgetForLabel(const char* labelName, QWidget* widget) + +void DlgAddPropertyVarSet::setWidgetForLabel(const char* labelName, QWidget* widget, + QLayout* layout) { - auto formLayout = qobject_cast(layout()); + auto formLayout = qobject_cast(layout); if (formLayout == nullptr) { FC_ERR("Form layout not found"); return; @@ -191,14 +193,9 @@ void DlgAddPropertyVarSet::setWidgetForLabel(const char* labelName, QWidget* wid formLayout->setWidget(labelRow, QFormLayout::FieldRole, widget); } -void DlgAddPropertyVarSet::initializeGroup() +void DlgAddPropertyVarSet::populateGroup(EditFinishedComboBox& comboBox, + const App::DocumentObject* varSet) { - comboBoxGroup.setObjectName(QStringLiteral("comboBoxGroup")); - comboBoxGroup.setInsertPolicy(QComboBox::InsertAtTop); - comboBoxGroup.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - - setWidgetForLabel("labelGroup", &comboBoxGroup); - std::vector properties; varSet->getPropertyList(properties); @@ -221,10 +218,21 @@ void DlgAddPropertyVarSet::initializeGroup() }); for (const auto& groupName : groupNamesSorted) { - comboBoxGroup.addItem(QString::fromStdString(groupName)); + comboBox.addItem(QString::fromStdString(groupName)); } - comboBoxGroup.setEditText(QString::fromStdString(groupNamesSorted[0])); + comboBox.setEditText(QString::fromStdString(groupNamesSorted[0])); +} + +void DlgAddPropertyVarSet::initializeGroup() +{ + comboBoxGroup.setObjectName(QStringLiteral("comboBoxGroup")); + comboBoxGroup.setInsertPolicy(QComboBox::InsertAtTop); + comboBoxGroup.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + setWidgetForLabel("labelGroup", &comboBoxGroup, layout()); + populateGroup(comboBoxGroup, varSet); + connComboBoxGroup = connect(&comboBoxGroup, &EditFinishedComboBox::editFinished, this, &DlgAddPropertyVarSet::onGroupFinished); } @@ -335,7 +343,7 @@ void DlgAddPropertyVarSet::addEditor(PropertyItem* propertyItem) editor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); editor->setObjectName(QStringLiteral("editor")); - setWidgetForLabel("labelValue", editor.get()); + setWidgetForLabel("labelValue", editor.get(), layout()); QWidget::setTabOrder(ui->comboBoxType, editor.get()); QWidget::setTabOrder(editor.get(), ui->checkBoxAdd); @@ -544,7 +552,7 @@ void DlgAddPropertyVarSet::removeEditor() auto* placeholder = new QWidget(this); placeholder->setObjectName(QStringLiteral("placeholder")); placeholder->setMinimumHeight(comboBoxGroup.height()); - setWidgetForLabel("labelValue", placeholder); + setWidgetForLabel("labelValue", placeholder, layout()); QWidget::setTabOrder(ui->comboBoxType, ui->checkBoxAdd); editor = nullptr; diff --git a/src/Gui/Dialogs/DlgAddPropertyVarSet.h b/src/Gui/Dialogs/DlgAddPropertyVarSet.h index 85c9efff0d..7978f5da77 100644 --- a/src/Gui/Dialogs/DlgAddPropertyVarSet.h +++ b/src/Gui/Dialogs/DlgAddPropertyVarSet.h @@ -86,6 +86,8 @@ public: void changeEvent(QEvent* e) override; void accept() override; void reject() override; + static void populateGroup(EditFinishedComboBox& comboBox, const App::DocumentObject* varSet); + static void setWidgetForLabel(const char* labelName, QWidget* widget, QLayout* layout); public Q_SLOTS: void valueChanged(); @@ -102,9 +104,6 @@ private: Type }; - int findLabelRow(const char* labelName, QFormLayout* layout); - void removeExistingWidget(QFormLayout* layout, int labelRow); - void setWidgetForLabel(const char* labelName, QWidget* widget); void initializeGroup(); std::vector getSupportedTypes(); @@ -153,6 +152,9 @@ private: void clearFields(); void addDocumentation(); + static void removeExistingWidget(QFormLayout* layout, int labelRow); + static int findLabelRow(const char* labelName, QFormLayout* layout); + private: App::VarSet* varSet; std::unique_ptr ui; diff --git a/src/Gui/Dialogs/DlgExpressionInput.cpp b/src/Gui/Dialogs/DlgExpressionInput.cpp index 1843920c02..3f9380597a 100644 --- a/src/Gui/Dialogs/DlgExpressionInput.cpp +++ b/src/Gui/Dialogs/DlgExpressionInput.cpp @@ -1,5 +1,6 @@ /*************************************************************************** * Copyright (c) 2015 Eivind Kvedalen * + * Copyright (c) 2025 Pieter Hijma * * * * This file is part of the FreeCAD CAx development system. * * * @@ -27,6 +28,7 @@ #include #include #include +#include #endif #include @@ -64,6 +66,7 @@ DlgExpressionInput::DlgExpressionInput(const App::ObjectIdentifier & _path, , impliedUnit(_impliedUnit) , minimumWidth(10) , varSetsVisible(false) + , comboBoxGroup(this) { assert(path.getDocumentObject()); @@ -135,7 +138,7 @@ DlgExpressionInput::~DlgExpressionInput() #endif disconnect(ui->comboBoxVarSet, qOverload(&QComboBox::currentIndexChanged), this, &DlgExpressionInput::onVarSetSelected); - disconnect(ui->lineEditGroup, &QLineEdit::textChanged, + disconnect(&comboBoxGroup, &EditFinishedComboBox::currentTextChanged, this, &DlgExpressionInput::onTextChangedGroup); disconnect(ui->lineEditPropNew, &QLineEdit::textChanged, this, &DlgExpressionInput::namePropChanged); @@ -215,11 +218,16 @@ void DlgExpressionInput::initializeVarSets() #endif connect(ui->comboBoxVarSet, qOverload(&QComboBox::currentIndexChanged), this, &DlgExpressionInput::onVarSetSelected); - connect(ui->lineEditGroup, &QLineEdit::textChanged, + connect(&comboBoxGroup, &EditFinishedComboBox::currentTextChanged, this, &DlgExpressionInput::onTextChangedGroup); connect(ui->lineEditPropNew, &QLineEdit::textChanged, this, &DlgExpressionInput::namePropChanged); + comboBoxGroup.setObjectName(QStringLiteral("comboBoxGroup")); + comboBoxGroup.setInsertPolicy(QComboBox::InsertAtTop); + comboBoxGroup.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + DlgAddPropertyVarSet::setWidgetForLabel("labelGroup", &comboBoxGroup, ui->formLayout); + std::vector varSets = getAllVarSets(); if (!varSets.empty() && typeOkForVarSet()) { ui->checkBoxVarSets->setVisible(true); @@ -277,59 +285,59 @@ QPoint DlgExpressionInput::expressionPosition() const void DlgExpressionInput::checkExpression(const QString& text) { - //now handle expression - std::shared_ptr expr(ExpressionParser::parse(path.getDocumentObject(), text.toUtf8().constData())); + //now handle expression + std::shared_ptr expr(ExpressionParser::parse(path.getDocumentObject(), text.toUtf8().constData())); - if (expr) { - std::string error = path.getDocumentObject()->ExpressionEngine.validateExpression(path, expr); + if (expr) { + std::string error = path.getDocumentObject()->ExpressionEngine.validateExpression(path, expr); - if (!error.empty()) - throw Base::RuntimeError(error.c_str()); + if (!error.empty()) + throw Base::RuntimeError(error.c_str()); - std::unique_ptr result(expr->eval()); + std::unique_ptr result(expr->eval()); - expression = expr; - okBtn->setEnabled(true); - ui->msg->clear(); + expression = expr; + okBtn->setEnabled(true); + ui->msg->clear(); - //set default palette as we may have read text right now - ui->msg->setPalette(okBtn->palette()); + //set default palette as we may have read text right now + ui->msg->setPalette(okBtn->palette()); - auto * n = freecad_cast(result.get()); - if (n) { - Base::Quantity value = n->getQuantity(); - if (!value.isValid()) { - throw Base::ValueError("Not a number"); - } - - auto msg = value.getUserString(); - if (impliedUnit != Base::Unit::One) { - if (!value.isDimensionless() && value.getUnit() != impliedUnit) - throw Base::UnitsMismatchError("Unit mismatch between result and required unit"); - - value.setUnit(impliedUnit); - - } - else if (!value.isDimensionless()) { - msg += " (Warning: unit discarded)"; - - QPalette p(ui->msg->palette()); - p.setColor(QPalette::WindowText, Qt::red); - ui->msg->setPalette(p); - } - - numberRange.throwIfOutOfRange(value); - - ui->msg->setText(QString::fromStdString(msg)); - } - else { - ui->msg->setText(QString::fromStdString(result->toString())); + auto * n = freecad_cast(result.get()); + if (n) { + Base::Quantity value = n->getQuantity(); + if (!value.isValid()) { + throw Base::ValueError("Not a number"); } + auto msg = value.getUserString(); + if (impliedUnit != Base::Unit::One) { + if (!value.isDimensionless() && value.getUnit() != impliedUnit) + throw Base::UnitsMismatchError("Unit mismatch between result and required unit"); + + value.setUnit(impliedUnit); + + } + else if (!value.isDimensionless()) { + msg += " (Warning: unit discarded)"; + + QPalette p(ui->msg->palette()); + p.setColor(QPalette::WindowText, Qt::red); + ui->msg->setPalette(p); + } + + numberRange.throwIfOutOfRange(value); + + ui->msg->setText(QString::fromStdString(msg)); } + else { + ui->msg->setText(QString::fromStdString(result->toString())); + } + + } } -static const bool NO_CHECK_EXPR = false; +static const bool NoCheckExpr = false; void DlgExpressionInput::textChanged(const QString &text) { @@ -358,7 +366,7 @@ void DlgExpressionInput::textChanged(const QString &text) // If varsets are visible, check whether the varset info also // agrees that the button should be enabled. // No need to check the expression in that function. - updateVarSetInfo(NO_CHECK_EXPR); + updateVarSetInfo(NoCheckExpr); } } catch (Base::Exception & e) { @@ -378,31 +386,34 @@ void DlgExpressionInput::setDiscarded() void DlgExpressionInput::setExpressionInputSize(int width, int height) { - if (ui->expression->minimumHeight() < height) + if (ui->expression->minimumHeight() < height) { ui->expression->setMinimumHeight(height); + } - if (ui->expression->minimumWidth() < width) + if (ui->expression->minimumWidth() < width) { ui->expression->setMinimumWidth(width); + } minimumWidth = width; } -void DlgExpressionInput::mouseReleaseEvent(QMouseEvent* ev) +void DlgExpressionInput::mouseReleaseEvent(QMouseEvent* event) { - Q_UNUSED(ev); + Q_UNUSED(event); } -void DlgExpressionInput::mousePressEvent(QMouseEvent* ev) +void DlgExpressionInput::mousePressEvent(QMouseEvent* event) { - Q_UNUSED(ev); + Q_UNUSED(event); // The 'FramelessWindowHint' is also set when the background is transparent. if (windowFlags() & Qt::FramelessWindowHint) { //we need to reject the dialog when clicked on the background. As the background is transparent //this is the expected behaviour for the user bool on = ui->expression->completerActive(); - if (!on) + if (!on) { this->reject(); + } } } @@ -459,29 +470,59 @@ static bool isNamePropOk(const QString& nameProp, App::DocumentObject* obj, return true; } -static const int ROLE_DOC = Qt::UserRole; -static const int ROLE_VARSET_NAME = Qt::UserRole + 1; -static const int ROLE_VARSET_LABEL = Qt::UserRole + 2; -static const int ROLE_GROUP = Qt::UserRole + 3; +static const int DocRole = Qt::UserRole; +static const int VarSetNameRole = Qt::UserRole + 1; +static const int VarSetLabelRole = Qt::UserRole + 2; +static const int LevelRole = Qt::UserRole + 3; -static QString getValue(QTreeWidgetItem* item, int role) +static QString getValue(QComboBox* comboBox, int role) { - QVariant variant = item->data(0, role); + QVariant variant = comboBox->currentData(role); return variant.toString(); } +static void storePreferences(const std::string& nameDoc, + const std::string& nameVarSet, + const std::string& nameGroup) +{ + auto paramExpressionEditor = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/ExpressionEditor"); + paramExpressionEditor->SetASCII("LastDocument", nameDoc); + paramExpressionEditor->SetASCII("LastVarSet", nameVarSet); + paramExpressionEditor->SetASCII("LastGroup", nameGroup); +} + +static const App::NumberExpression* toNumberExpr(const App::Expression* expr) +{ + return freecad_cast(expr); +} + +static const App::StringExpression* toStringExpr(const App::Expression* expr) +{ + return freecad_cast(expr); +} + +static const App::OperatorExpression* toUnitNumberExpr(const App::Expression* expr) +{ + auto* opExpr = freecad_cast(expr); + if (opExpr && opExpr->getOperator() == App::OperatorExpression::Operator::UNIT && + toNumberExpr(opExpr->getLeft())) { + return opExpr; + } + return nullptr; +} + void DlgExpressionInput::acceptWithVarSet() { // all checks have been performed in updateVarSetInfo and textChanged that // decide to enable the button // create a property in the VarSet - QTreeWidgetItem *selected = treeWidget->currentItem(); - QString nameVarSet = getValue(selected, ROLE_VARSET_NAME); - QString nameGroup = ui->lineEditGroup->text(); + QString nameVarSet = getValue(ui->comboBoxVarSet, VarSetNameRole); + QString nameGroup = comboBoxGroup.currentText(); QString nameProp = ui->lineEditPropNew->text(); - QString nameDoc = getValue(selected, ROLE_DOC); + QString nameDoc = getValue(ui->comboBoxVarSet, DocRole); App::Document* doc = App::GetApplication().getDocument(nameDoc.toUtf8()); App::DocumentObject* obj = doc->getObject(nameVarSet.toUtf8()); @@ -494,10 +535,8 @@ void DlgExpressionInput::acceptWithVarSet() // // The value of the property is going to be the value that was originally // meant to be the value for the property that this dialog is targeting. - Expression* exprSimplfied = expression->simplify(); - auto ne = freecad_cast(exprSimplfied); - auto se = freecad_cast(exprSimplfied); - if (ne) { + const Expression* expr = expression.get(); + if (const NumberExpression* ne = toNumberExpr(expr)) { // the value is a number: directly assign it to the property instead of // making it an expression in the variable set Gui::Command::doCommand(Gui::Command::Doc, "App.getDocument('%s').getObject('%s').%s = %f", @@ -505,15 +544,22 @@ void DlgExpressionInput::acceptWithVarSet() obj->getNameInDocument(), prop->getName(), ne->getValue()); } - else if (se) { + else if (const StringExpression* se = toStringExpr(expr)) { // the value is a string: directly assign it to the property. Gui::Command::doCommand(Gui::Command::Doc, "App.getDocument('%s').getObject('%s').%s = \"%s\"", obj->getDocument()->getName(), obj->getNameInDocument(), prop->getName(), se->getText().c_str()); } + else if (const OperatorExpression* une = toUnitNumberExpr(expr)) { + // the value is a unit number: directly assign it to the property. + Gui::Command::doCommand(Gui::Command::Doc, "App.getDocument('%s').getObject('%s').%s = \"%s\"", + obj->getDocument()->getName(), + obj->getNameInDocument(), + prop->getName(), une->toString().c_str()); + } else { - // the value is an epxression: make an expression binding in the variable set. + // the value is an expression: make an expression binding in the variable set. ObjectIdentifier objId(*prop); Binding binding; binding.bind(objId); @@ -525,6 +571,8 @@ void DlgExpressionInput::acceptWithVarSet() // for the original property that is the target of this dialog. expression.reset(ExpressionParser::parse(path.getDocumentObject(), prop->getFullName().c_str())); + + storePreferences(nameDoc.toStdString(), nameVarSet.toStdString(), group); } void DlgExpressionInput::accept() { @@ -534,93 +582,149 @@ void DlgExpressionInput::accept() { QDialog::accept(); } -static void addGroupsVarSetComboBox(App::VarSet* varSet, QTreeWidgetItem* varSetItem) +static App::Document* getPreselectedDocument() { - std::vector properties; - std::set namesGroup; - varSet->getPropertyList(properties); - for (auto prop : properties) { - const char* nameGroup = prop->getGroup(); - if (!nameGroup || strcmp(nameGroup, "") == 0) { - namesGroup.insert("Base"); - } - else { - namesGroup.insert(nameGroup); - } + auto paramExpressionEditor = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/ExpressionEditor"); + std::string lastDoc = paramExpressionEditor->GetASCII("LastDocument", ""); + + if (lastDoc.empty()) { + return App::GetApplication().getActiveDocument(); } - for (const auto& nameGroup : namesGroup) { - // the item will be automatically destroyed when the varSetItem will be destroyed - auto item = new QTreeWidgetItem(varSetItem); - item->setText(0, QString::fromStdString(nameGroup)); - item->setData(0, ROLE_GROUP, QString::fromStdString(nameGroup)); - item->setData(0, ROLE_VARSET_NAME, varSetItem->data(0, ROLE_VARSET_NAME)); - item->setData(0, ROLE_VARSET_LABEL, varSetItem->data(0, ROLE_VARSET_LABEL)); - item->setData(0, ROLE_DOC, varSetItem->data(0, ROLE_DOC)); + + App::Document* doc = App::GetApplication().getDocument(lastDoc.c_str()); + if (doc == nullptr) { + return App::GetApplication().getActiveDocument(); } + + return doc; } -static void addVarSetsVarSetComboBox(std::vector& varSets, QTreeWidgetItem* docItem) +int DlgExpressionInput::getVarSetIndex(const App::Document* doc) const { - for (auto varSet : varSets) { - auto vp = freecad_cast( + auto paramExpressionEditor = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/ExpressionEditor"); + std::string lastVarSet = paramExpressionEditor->GetASCII("LastVarSet", "VarSet"); + + auto* model = qobject_cast(ui->comboBoxVarSet->model()); + for (int i = 0; i < model->rowCount(); ++i) { + QStandardItem* item = model->item(i); + if (item->data(DocRole).toString() == QString::fromUtf8(doc->getName()) && + item->data(VarSetNameRole).toString() == QString::fromStdString(lastVarSet)) { + return i; + } + } + + // Select the first varset of the first document (the document is item 0) + return 1; +} + +void DlgExpressionInput::preselectVarSet() +{ + const App::Document* doc = getPreselectedDocument(); + if (doc == nullptr) { + FC_ERR("No active document found"); + } + ui->comboBoxVarSet->setCurrentIndex(getVarSetIndex(doc)); +} + +// Custom delegate to add indentation +class IndentedItemDelegate : public QStyledItemDelegate { +public: + explicit IndentedItemDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {} + + void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override { + QStyledItemDelegate::initStyleOption(option, index); + + if (index.data(LevelRole) == 1) { + int indentWidth = 20; + option->rect.adjust(indentWidth, 0, 0, 0); + } + } +}; + +static void addVarSetsVarSetComboBox(std::vector& varSets, + QStandardItem* docItem, QStandardItemModel* model) +{ + for (auto* varSet : varSets) { + auto* vp = freecad_cast( Gui::Application::Instance->getViewProvider(varSet)); - // the item will be automatically destroyed when the docItem will be destroyed - auto item = new QTreeWidgetItem(docItem); - item->setIcon(0, vp->getIcon()); - item->setText(0, QString::fromUtf8(varSet->Label.getValue())); - item->setData(0, ROLE_VARSET_LABEL, QString::fromUtf8(varSet->Label.getValue())); - item->setData(0, ROLE_VARSET_NAME, QString::fromUtf8(varSet->getNameInDocument())); - item->setData(0, ROLE_DOC, docItem->data(0, ROLE_DOC)); - addGroupsVarSetComboBox(varSet, item); - } -} - -static void addDocVarSetComboBox(App::Document* doc, QPixmap& docIcon, QTreeWidgetItem* rootItem) -{ - if (!doc->testStatus(App::Document::TempDoc)) { - std::vector varSets; - getVarSetsDocument(varSets, doc); - if (!varSets.empty()) { - // the item will be automatically destroyed when the rootItem will be destroyed - auto item = new QTreeWidgetItem(rootItem); - item->setIcon(0, docIcon); - item->setText(0, QString::fromUtf8(doc->Label.getValue())); - item->setData(0, ROLE_DOC, QByteArray(doc->getName())); - item->setFlags(Qt::ItemIsEnabled); - item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); - addVarSetsVarSetComboBox(varSets, item); + if (vp == nullptr) { + FC_ERR("No ViewProvider found for VarSet: " << varSet->getNameInDocument()); + continue; } + + // The item will be owned by the model, so no need to delete it manually. + auto item = new QStandardItem(); + item->setIcon(vp->getIcon()); + item->setText(QString::fromUtf8(varSet->Label.getValue())); + item->setData(QString::fromUtf8(varSet->Label.getValue()), VarSetLabelRole); + item->setData(QString::fromUtf8(varSet->getNameInDocument()), VarSetNameRole); + item->setData(docItem->data(DocRole), DocRole); + item->setData(1, LevelRole); + model->appendRow(item); } } -static QTreeWidget* createVarSetTreeWidget() +static void addDocVarSetComboBox(App::Document* doc, QPixmap& docIcon, + QStandardItemModel* model) { - // the caller of the function is responsible of managing the tree widget - auto treeWidget = new QTreeWidget(); - treeWidget->setColumnCount(1); - treeWidget->setHeaderHidden(true); - // the rootItem will be destroyed when the treeWidget will be destroyed - QTreeWidgetItem *rootItem = treeWidget->invisibleRootItem(); + if (doc->testStatus(App::Document::TempDoc)) { + // Do not add temporary documents to the VarSet combo box + return; + } + std::vector varSets; + getVarSetsDocument(varSets, doc); + if (varSets.empty()) { + return; + } + + // The item will be owned by the model, so no need to delete it manually. + auto* item = new QStandardItem(); + item->setIcon(docIcon); + item->setText(QString::fromUtf8(doc->Label.getValue())); + item->setData(QByteArray(doc->getName()), DocRole); + item->setFlags(Qt::ItemIsEnabled); // Make sure this item cannot be selected + item->setData(0, LevelRole); + model->appendRow(item); + + addVarSetsVarSetComboBox(varSets, item, model); +} + +QStandardItemModel* DlgExpressionInput::createVarSetModel() +{ + // Create the model + auto* model = new QStandardItemModel(ui->comboBoxVarSet); + model->setColumnCount(1); + + // Add items to the model QPixmap docIcon(Gui::BitmapFactory().pixmap("Document")); std::vector docs = App::GetApplication().getDocuments(); for (auto doc : docs) { - addDocVarSetComboBox(doc, docIcon, rootItem); + addDocVarSetComboBox(doc, docIcon, model); } - treeWidget->expandAll(); - return treeWidget; + return model; } void DlgExpressionInput::setupVarSets() { ui->comboBoxVarSet->clear(); - // createVarSetTreeWidget returns a dynamically allocated tree widget - // the memory is managed by means of the unique pointer treeWidget. - treeWidget.reset(createVarSetTreeWidget()); - ui->comboBoxVarSet->setModel(treeWidget->model()); - ui->comboBoxVarSet->setView(treeWidget.get()); + + QStandardItemModel* model = createVarSetModel(); + { + QSignalBlocker blocker(ui->comboBoxVarSet); + auto* listView = new QListView(this); + listView->setSelectionMode(QAbstractItemView::SingleSelection); + listView->setModel(model); + ui->comboBoxVarSet->setView(listView); + ui->comboBoxVarSet->setModel(model); + ui->comboBoxVarSet->setItemDelegate(new IndentedItemDelegate(ui->comboBoxVarSet)); + } + + preselectVarSet(); okBtn->setEnabled(false); } @@ -641,22 +745,45 @@ void DlgExpressionInput::onCheckVarSets(int state) { } } -void DlgExpressionInput::onVarSetSelected(int) +void DlgExpressionInput::preselectGroup() { - QTreeWidgetItem* selected = treeWidget->currentItem(); + auto paramExpressionEditor = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/ExpressionEditor"); + std::string lastGroup = paramExpressionEditor->GetASCII("LastGroup", ""); - if (selected) { - // if group is known, fill it in - QVariant variantGroup = selected->data(0, ROLE_GROUP); - if (variantGroup.isValid()) { - ui->lineEditGroup->setText(variantGroup.toString()); - } - else { - ui->lineEditGroup->clear(); - } + if (lastGroup.empty()) { + return; } + int index = comboBoxGroup.findText(QString::fromStdString(lastGroup)); + if (index == -1) { + return; + } + + comboBoxGroup.setCurrentIndex(index); +} + +void DlgExpressionInput::onVarSetSelected([[maybe_unused]] int index) +{ + QString docName = getValue(ui->comboBoxVarSet, DocRole); + QString varSetName = getValue(ui->comboBoxVarSet, VarSetNameRole); + if (docName.isEmpty() || varSetName.isEmpty()) { + FC_ERR("No document or variable set selected"); + return; + } + + App::DocumentObject* varSet = App::GetApplication().getDocument( + docName.toUtf8())->getObject( + varSetName.toUtf8()); + if (varSet == nullptr) { + FC_ERR("Variable set not found: " << varSetName.toStdString()); + return; + } + + DlgAddPropertyVarSet::populateGroup(comboBoxGroup, varSet); + preselectGroup(); updateVarSetInfo(); + ui->lineEditPropNew->setFocus(); } void DlgExpressionInput::onTextChangedGroup(const QString&) @@ -704,11 +831,11 @@ bool DlgExpressionInput::reportGroup(QString& nameGroup) return false; } -bool DlgExpressionInput::reportName(QTreeWidgetItem* item) +bool DlgExpressionInput::reportName() { QString nameProp = ui->lineEditPropNew->text(); - QString nameVarSet = getValue(item, ROLE_VARSET_NAME); - QString nameDoc = getValue(item, ROLE_DOC); + QString nameVarSet = getValue(ui->comboBoxVarSet, VarSetNameRole); + QString nameDoc = getValue(ui->comboBoxVarSet, DocRole); App::Document* doc = App::GetApplication().getDocument(nameDoc.toUtf8()); App::DocumentObject* obj = doc->getObject(nameVarSet.toUtf8()); std::stringstream message; @@ -722,47 +849,30 @@ bool DlgExpressionInput::reportName(QTreeWidgetItem* item) void DlgExpressionInput::updateVarSetInfo(bool checkExpr) { - QTreeWidgetItem* selected = treeWidget->currentItem(); - - if (selected) { - QString nameGroup = ui->lineEditGroup->text(); - if (reportGroup(nameGroup)) { - // needed to report something about the group, so disable the button - okBtn->setEnabled(false); - return; - } - - if (reportName(selected)) { - // needed to report something about the name, so disable the button - okBtn->setEnabled(false); - return; - } - - // QString nameProp = ui->lineEditPropNew->text(); - // QString labelVarSet = getValue(selected, ROLE_VARSET_LABEL); - // QString nameDoc = getValue(selected, ROLE_DOC); - // std::stringstream message; - // message << "Adding property " << nameProp.toStdString() << std::endl - // << "of type " << getType() << std::endl - // << "to variable set " << labelVarSet.toStdString() << std::endl - // << "in group " << nameGroup.toStdString() << std::endl - // << "in document " << nameDoc.toStdString() << "."; - - // reportVarSetInfo(message.str().c_str()); - if (checkExpr) { - // We have to check the text of the expression as well - try { - checkExpression(ui->expression->text()); - okBtn->setEnabled(true); - } - catch (Base::Exception&) { - okBtn->setDisabled(true); - } - } - } - else { + if (reportName()) { + // needed to report something about the name, so disable the button okBtn->setEnabled(false); + return; } + + QString nameGroup = comboBoxGroup.currentText(); + if (reportGroup(nameGroup)) { + // needed to report something about the group, so disable the button + okBtn->setEnabled(false); + return; + } + + if (checkExpr) { + // We have to check the text of the expression as well + try { + checkExpression(ui->expression->text()); + } + catch (Base::Exception&) { + okBtn->setEnabled(false); + } + } + + okBtn->setEnabled(true); } #include "moc_DlgExpressionInput.cpp" diff --git a/src/Gui/Dialogs/DlgExpressionInput.h b/src/Gui/Dialogs/DlgExpressionInput.h index ccb889f432..e50e9ba702 100644 --- a/src/Gui/Dialogs/DlgExpressionInput.h +++ b/src/Gui/Dialogs/DlgExpressionInput.h @@ -25,11 +25,14 @@ #include #include +#include #include #include #include #include +#include "Dialogs/DlgAddPropertyVarSet.h" + namespace Ui { class DlgExpressionInput; } @@ -44,9 +47,7 @@ class Expression; class DocumentObject; } -namespace Gui { - -namespace Dialog { +namespace Gui::Dialog { class GuiExport NumberRange { @@ -83,8 +84,8 @@ public Q_SLOTS: void accept() override; protected: - void mouseReleaseEvent(QMouseEvent*) override; - void mousePressEvent(QMouseEvent*) override; + void mouseReleaseEvent(QMouseEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; private: Base::Type getTypePath(); @@ -92,10 +93,14 @@ private: bool typeOkForVarSet(); void initializeVarSets(); void checkExpression(const QString& text); + int getVarSetIndex(const App::Document* doc) const; + void preselectGroup(); + void preselectVarSet(); + QStandardItemModel* createVarSetModel(); void setupVarSets(); std::string getType(); void reportVarSetInfo(const std::string& message); - bool reportName(QTreeWidgetItem* item); + bool reportName(); bool reportGroup(QString& nameGroup); void updateVarSetInfo(bool checkExpr = true); void acceptWithVarSet(); @@ -104,7 +109,7 @@ private Q_SLOTS: void textChanged(const QString & text); void setDiscarded(); void onCheckVarSets(int state); - void onVarSetSelected(int); + void onVarSetSelected(int index); void onTextChangedGroup(const QString&); void namePropChanged(const QString&); @@ -119,12 +124,13 @@ private: int minimumWidth; bool varSetsVisible; - std::unique_ptr treeWidget; QPushButton* okBtn = nullptr; QPushButton* discardBtn = nullptr; + + EditFinishedComboBox comboBoxGroup; }; } -} + #endif // GUI_DIALOG_EXPRESSIONINPUT_H diff --git a/src/Gui/Dialogs/DlgExpressionInput.ui b/src/Gui/Dialogs/DlgExpressionInput.ui index 04d261470f..a26d728d1d 100644 --- a/src/Gui/Dialogs/DlgExpressionInput.ui +++ b/src/Gui/Dialogs/DlgExpressionInput.ui @@ -195,17 +195,7 @@ - - - - - - 0 - 0 - - - - + @@ -213,13 +203,6 @@ - - - - Variable Set: - - - @@ -227,11 +210,25 @@ - - + + + + Variable Set: + + - - + + + + + 0 + 0 + + + + + +