diff --git a/src/Gui/DlgAddPropertyVarSet.cpp b/src/Gui/DlgAddPropertyVarSet.cpp index 8f1576abd9..ad6cf93376 100644 --- a/src/Gui/DlgAddPropertyVarSet.cpp +++ b/src/Gui/DlgAddPropertyVarSet.cpp @@ -46,6 +46,8 @@ using namespace Gui::Dialog; const std::string DlgAddPropertyVarSet::GROUP_BASE = "Base"; +const bool CLEAR_NAME = true; + DlgAddPropertyVarSet::DlgAddPropertyVarSet(QWidget* parent, ViewProviderVarSet* viewProvider) : QDialog(parent), @@ -65,7 +67,7 @@ DlgAddPropertyVarSet::~DlgAddPropertyVarSet() = default; void DlgAddPropertyVarSet::initializeGroup() { connect(&comboBoxGroup, &EditFinishedComboBox::editFinished, - this, &DlgAddPropertyVarSet::onGroupDetermined); + this, &DlgAddPropertyVarSet::onEditFinished); comboBoxGroup.setObjectName(QString::fromUtf8("comboBoxGroup")); comboBoxGroup.setInsertPolicy(QComboBox::InsertAtTop); comboBoxGroup.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); @@ -138,8 +140,8 @@ void DlgAddPropertyVarSet::initializeTypes() ui->comboBoxType->setCompleter(&completerType); ui->comboBoxType->setInsertPolicy(QComboBox::NoInsert); - connect(ui->comboBoxType, qOverload(&QComboBox::currentIndexChanged), - this, &DlgAddPropertyVarSet::onTypePropertyDetermined); + connect(ui->comboBoxType, &QComboBox::currentTextChanged, + this, &DlgAddPropertyVarSet::onEditFinished); } /* @@ -149,12 +151,12 @@ static void printFocusChain(QWidget *widget) { QWidget* start = widget; int i = 0; do { - FC_ERR(" " << widget->objectName().toUtf8().constData()); + FC_ERR(" " << widget->objectName().toStdString(); widget = widget->nextInFocusChain(); i++; } while (widget != nullptr && i < 30 && start != widget); QWidget *currentWidget = QApplication::focusWidget(); - FC_ERR(" Current focus widget:" << (currentWidget ? currentWidget->objectName().toUtf8().constData() : "None") << std::endl << std::endl); + FC_ERR(" Current focus widget:" << (currentWidget ? currentWidget->objectName().toStdString() : "None") << std::endl << std::endl); } */ @@ -165,8 +167,10 @@ void DlgAddPropertyVarSet::initializeWidgets(ViewProviderVarSet* viewProvider) connect(this, &QDialog::finished, this, [viewProvider](int result) { viewProvider->onFinished(result); }); + connect(ui->lineEditName, &QLineEdit::editingFinished, + this, &DlgAddPropertyVarSet::onEditFinished); connect(ui->lineEditName, &QLineEdit::textChanged, - this, &DlgAddPropertyVarSet::onNamePropertyDetermined); + this, &DlgAddPropertyVarSet::onNamePropertyChanged); std::string title = "Add a property to " + varSet->getFullName(); setWindowTitle(QString::fromStdString(title)); @@ -188,11 +192,13 @@ void DlgAddPropertyVarSet::setOkEnabled(bool enabled) okButton->setEnabled(enabled); } -void DlgAddPropertyVarSet::clearEditors() +void DlgAddPropertyVarSet::clearEditors(bool clearName) { - bool beforeBlocked = ui->lineEditName->blockSignals(true); - ui->lineEditName->clear(); - ui->lineEditName->blockSignals(beforeBlocked); + if (clearName) { + bool beforeBlocked = ui->lineEditName->blockSignals(true); + ui->lineEditName->clear(); + ui->lineEditName->blockSignals(beforeBlocked); + } removeEditor(); setOkEnabled(false); namePropertyToAdd.clear(); @@ -249,9 +255,11 @@ bool DlgAddPropertyVarSet::isTypeWithEditor(const std::string& type) return typesWithoutEditor.find(type) == typesWithoutEditor.end(); } -void DlgAddPropertyVarSet::createProperty(std::string& name, std::string& group) +void DlgAddPropertyVarSet::createProperty() { - std::string type = ui->comboBoxType->currentText().toUtf8().constData(); + std::string name = ui->lineEditName->text().toStdString(); + std::string group = comboBoxGroup.currentText().toStdString(); + std::string type = ui->comboBoxType->currentText().toStdString(); App::Property* prop; try { @@ -285,60 +293,81 @@ void DlgAddPropertyVarSet::createProperty(std::string& name, std::string& group) setOkEnabled(true); } -void DlgAddPropertyVarSet::onNamePropertyDetermined(const QString& text) -{ - if (!namePropertyToAdd.empty()) { - // We were already adding a property with this name. We have to remove - // the property, the editor because it is associated with the property, - // and we have to abort the transaction. +void DlgAddPropertyVarSet::changePropertyToAdd() { + // we were already adding a new property, the only option to get here + // is a change of type or group. + + std::string name = ui->lineEditName->text().toStdString(); + assert(name == namePropertyToAdd); + + App::Property* prop = varSet->getPropertyByName(namePropertyToAdd.c_str()); + + std::string group = comboBoxGroup.currentText().toStdString(); + if (prop->getGroup() != group) { + varSet->changeDynamicProperty(prop, group.c_str(), nullptr); + } + + std::string type = ui->comboBoxType->currentText().toStdString(); + if (prop->getTypeId() != Base::Type::fromName(type.c_str())) { + // the property should have a different type varSet->removeDynamicProperty(namePropertyToAdd.c_str()); - removeEditor(); - App::Document* doc = varSet->getDocument(); - if (doc->hasPendingTransaction()) { - doc->abortTransaction(); - } - namePropertyToAdd.clear(); + createProperty(); } - if (text.isEmpty()) { - // We can not define a property, so we should not have an editor for the value. - clearEditors(); - return; - } - std::string name = text.toUtf8().constData(); - std::string group = comboBoxGroup.currentText().toUtf8().constData(); - if(name.empty() || group.empty() - || name != Base::Tools::getIdentifier(name) - || group != Base::Tools::getIdentifier(group)) { - QMessageBox::critical(getMainWindow(), - QObject::tr("Invalid name"), - QObject::tr("The property name or group name must only contain alpha numericals,\n" - "underscore, and must not start with a digit.")); - clearEditors(); - return; - } - - auto prop = varSet->getPropertyByName(name.c_str()); - if(prop && prop->getContainer() == varSet) { - QMessageBox::critical(this, - QObject::tr("Invalid name"), - QObject::tr("The property '%1' already exists in '%2'").arg( - QString::fromLatin1(name.c_str()), - QString::fromLatin1(varSet->getFullName().c_str()))); - clearEditors(); - return; - } - - App::Document* doc = varSet->getDocument(); - doc->openTransaction("Add property VarSet"); - createProperty(name, group); - - // FC_ERR("chain onNameDetermined"); - // printFocusChain(ui->lineEditName); } -void DlgAddPropertyVarSet::onGroupDetermined() + +void DlgAddPropertyVarSet::clearCurrentProperty() { - std::string group = comboBoxGroup.currentText().toUtf8().constData(); + removeEditor(); + varSet->removeDynamicProperty(namePropertyToAdd.c_str()); + App::Document* doc = varSet->getDocument(); + if (doc->hasPendingTransaction()) { + doc->abortTransaction(); + } + setOkEnabled(false); + namePropertyToAdd.clear(); +} + +class CreatePropertyException : public std::exception { +public: + explicit CreatePropertyException(const std::string& message) : msg(message) {} + + const char* what() const noexcept override { + return msg.c_str(); + } + +private: + std::string msg; +}; + +void DlgAddPropertyVarSet::checkName() { + std::string name = ui->lineEditName->text().toStdString(); + if(name.empty() || name != Base::Tools::getIdentifier(name)) { + QMessageBox::critical(getMainWindow(), + QObject::tr("Invalid name"), + QObject::tr("The property name must only contain alpha numericals,\n" + "underscore, and must not start with a digit.")); + clearEditors(!CLEAR_NAME); + throw CreatePropertyException("Invalid name"); + } + + if (namePropertyToAdd.empty()) { + // we are adding a new property, check whether it doesn't already exist + auto prop = varSet->getPropertyByName(name.c_str()); + if(prop && prop->getContainer() == varSet) { + QMessageBox::critical(this, + QObject::tr("Invalid name"), + QObject::tr("The property '%1' already exists in '%2'").arg( + QString::fromLatin1(name.c_str()), + QString::fromLatin1(varSet->getFullName().c_str()))); + clearEditors(!CLEAR_NAME); + throw CreatePropertyException("Invalid name"); + } + } +} + +void DlgAddPropertyVarSet::checkGroup() { + std::string group = comboBoxGroup.currentText().toStdString(); if (group.empty() || group != Base::Tools::getIdentifier(group)) { QMessageBox::critical(this, @@ -346,36 +375,58 @@ void DlgAddPropertyVarSet::onGroupDetermined() QObject::tr("The group name must only contain alpha numericals,\n" "underscore, and must not start with a digit.")); comboBoxGroup.setEditText(QString::fromUtf8("Base")); + throw CreatePropertyException("Invalid name"); + } +} + +void DlgAddPropertyVarSet::checkType() { + std::string type = ui->comboBoxType->currentText().toStdString(); + + if (Base::Type::fromName(type.c_str()) == Base::Type::badType()) { + throw CreatePropertyException("Invalid name"); + } +} + +void DlgAddPropertyVarSet::onEditFinished() { + /* The editor for the value is dynamically created if 1) the name has been + * determined and 2) if the type of the property has been determined. The + * group of the property is important too, but it is not essential, because + * we can change the group after the property has been created. + * + * In this function we check whether we can create a property and therefore + * an editor. + */ + + try { + checkName(); + checkGroup(); + checkType(); + } + catch (const CreatePropertyException& e) { + if (!namePropertyToAdd.empty()) { + clearCurrentProperty(); + } return; } - if (!namePropertyToAdd.empty()) { - // we were already adding a property - App::Property* prop = varSet->getPropertyByName(namePropertyToAdd.c_str()); - if (prop->getGroup() != group) { - varSet->changeDynamicProperty(prop, group.c_str(), nullptr); - } + if (namePropertyToAdd.empty()) { + // we are adding a new property + App::Document* doc = varSet->getDocument(); + doc->openTransaction("Add property VarSet"); + createProperty(); + } + else { + // we were already adding a new property that should now be changed + changePropertyToAdd(); } - - // FC_ERR("chain onGroupDetermined"); - // printFocusChain(&comboBoxGroup); - ui->comboBoxType->setFocus(); } -void DlgAddPropertyVarSet::onTypePropertyDetermined() +void DlgAddPropertyVarSet::onNamePropertyChanged(const QString& text) { - std::string type = ui->comboBoxType->currentText().toUtf8().constData(); - - if (!namePropertyToAdd.empty()) { - // we were already adding a name, so check this property - App::Property* prop = varSet->getPropertyByName(namePropertyToAdd.c_str()); - - if (prop->getTypeId() != Base::Type::fromName(type.c_str())) { - // the property should have a different type - std::string group = prop->getGroup(); - varSet->removeDynamicProperty(namePropertyToAdd.c_str()); - createProperty(namePropertyToAdd, group); - } + if (!namePropertyToAdd.empty() && text.toStdString() != namePropertyToAdd) { + // The user decided to change the name of the property. This + // invalidates the editor that is strictly associated with the property. + clearCurrentProperty(); } } @@ -398,8 +449,8 @@ void DlgAddPropertyVarSet::accept() return; } - std::string group = comboBoxGroup.currentText().toUtf8().constData(); - std::string type = ui->comboBoxType->currentText().toUtf8().constData(); + std::string group = comboBoxGroup.currentText().toStdString(); + std::string type = ui->comboBoxType->currentText().toStdString(); auto paramGroup = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/PropertyView"); paramGroup->SetASCII("NewPropertyType", type.c_str()); diff --git a/src/Gui/DlgAddPropertyVarSet.h b/src/Gui/DlgAddPropertyVarSet.h index 5db09b6b05..59059a6a37 100644 --- a/src/Gui/DlgAddPropertyVarSet.h +++ b/src/Gui/DlgAddPropertyVarSet.h @@ -79,17 +79,21 @@ private: void initializeWidgets(ViewProviderVarSet* viewProvider); void setOkEnabled(bool enabled); - void clearEditors(); + void clearEditors(bool clearName = true); + void clearCurrentProperty(); void removeEditor(); void addEditor(PropertyEditor::PropertyItem* propertyItem, std::string& type); bool isTypeWithEditor(const std::string& type); - void createProperty(std::string& name, std::string& group); + void createProperty(); + void changePropertyToAdd(); - void onNamePropertyDetermined(const QString& text); - void onGroupDetermined(); - void onTypePropertyDetermined(); + void checkName(); + void checkGroup(); + void checkType(); + void onEditFinished(); + void onNamePropertyChanged(const QString& text); void getSupportedTypes(std::vector& types);