| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <QMessageBox> |
| | #include <QString> |
| | #include <QCompleter> |
| | #include <algorithm> |
| | #include <memory> |
| | #include <array> |
| |
|
| | #include <App/Application.h> |
| | #include <App/Document.h> |
| | #include <App/DocumentObject.h> |
| | #include <App/ExpressionParser.h> |
| | #include <App/PropertyUnits.h> |
| | #include <App/PropertyFile.h> |
| | #include <App/PropertyGeo.h> |
| | #include <App/PropertyPythonObject.h> |
| | #include <Base/Tools.h> |
| |
|
| | #include "Dialogs/DlgAddProperty.h" |
| | #include "Application.h" |
| | #include "Macro.h" |
| | #include "ui_DlgAddProperty.h" |
| | #include "ViewProviderVarSet.h" |
| | #include "propertyeditor/PropertyItem.h" |
| |
|
| | FC_LOG_LEVEL_INIT("DlgAddProperty", true, true) |
| |
|
| | using namespace Gui; |
| | using namespace Gui::Dialog; |
| | using namespace Gui::PropertyEditor; |
| |
|
| | const std::string DlgAddProperty::GroupBase = "Base"; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | DlgAddProperty::DlgAddProperty(QWidget* parent, App::PropertyContainer* container) |
| | : DlgAddProperty(parent, container, nullptr) |
| | {} |
| |
|
| |
|
| | DlgAddProperty::DlgAddProperty(QWidget* parent, ViewProviderVarSet* viewProvider) |
| | : DlgAddProperty( |
| | parent, |
| | viewProvider ? viewProvider->getObject<App::PropertyContainer>() : nullptr, |
| | viewProvider |
| | ) |
| | {} |
| |
|
| | DlgAddProperty::DlgAddProperty( |
| | QWidget* parent, |
| | App::PropertyContainer* container, |
| | ViewProviderVarSet* viewProvider |
| | ) |
| | : QDialog(parent) |
| | , container(container) |
| | , ui(new Ui_DlgAddProperty) |
| | , comboBoxGroup(this) |
| | , completerType(this) |
| | , editor(nullptr) |
| | , transactionID(0) |
| | { |
| | ui->setupUi(this); |
| | setupMacroRedirector(); |
| | initializeWidgets(viewProvider); |
| | } |
| |
|
| | DlgAddProperty::~DlgAddProperty() = default; |
| |
|
| | void DlgAddProperty::setupMacroRedirector() |
| | { |
| | setValueRedirector = std::make_unique<MacroManager::MacroRedirector>( |
| | [this](MacroManager::LineType , const char* line) { this->setValueCommand = line; } |
| | ); |
| | } |
| |
|
| | int DlgAddProperty::findLabelRow(const char* labelName, QFormLayout* layout) |
| | { |
| | for (int row = 0; row < layout->rowCount(); ++row) { |
| | QLayoutItem* labelItem = layout->itemAt(row, QFormLayout::LabelRole); |
| | if (labelItem == nullptr) { |
| | continue; |
| | } |
| |
|
| | if (auto label = qobject_cast<QLabel*>(labelItem->widget())) { |
| | if (label->objectName() == QString::fromLatin1(labelName)) { |
| | return row; |
| | } |
| | } |
| | } |
| | return -1; |
| | } |
| |
|
| | void DlgAddProperty::removeExistingWidget(QFormLayout* formLayout, int labelRow) |
| | { |
| | if (QLayoutItem* existingItem = formLayout->itemAt(labelRow, QFormLayout::FieldRole)) { |
| | if (QWidget* existingWidget = existingItem->widget()) { |
| | formLayout->removeWidget(existingWidget); |
| | existingWidget->deleteLater(); |
| | } |
| | } |
| | } |
| |
|
| |
|
| | void DlgAddProperty::setWidgetForLabel(const char* labelName, QWidget* widget, QLayout* layout) |
| | { |
| | auto formLayout = qobject_cast<QFormLayout*>(layout); |
| | if (formLayout == nullptr) { |
| | FC_ERR("Form layout not found"); |
| | return; |
| | } |
| |
|
| | int labelRow = findLabelRow(labelName, formLayout); |
| | if (labelRow < 0) { |
| | FC_ERR("Could not find row for '" << labelName << "'"); |
| | return; |
| | } |
| |
|
| | removeExistingWidget(formLayout, labelRow); |
| | formLayout->setWidget(labelRow, QFormLayout::FieldRole, widget); |
| | } |
| |
|
| | void DlgAddProperty::populateGroup(EditFinishedComboBox& comboBox, const App::PropertyContainer* container) |
| | { |
| | auto paramGroup = App::GetApplication().GetParameterGroupByPath( |
| | "User parameter:BaseApp/Preferences/PropertyView" |
| | ); |
| | std::string lastGroup = paramGroup->GetASCII("NewPropertyGroup"); |
| |
|
| | std::vector<App::Property*> properties; |
| | container->getPropertyList(properties); |
| |
|
| | std::unordered_set<std::string> groupNames; |
| | for (const auto* prop : properties) { |
| | const char* groupName = container->getPropertyGroup(prop); |
| | groupNames.insert(groupName ? groupName : GroupBase); |
| | } |
| |
|
| | std::vector<std::string> groupNamesSorted(groupNames.begin(), groupNames.end()); |
| | std::ranges::sort(groupNamesSorted, [](const std::string& a, const std::string& b) { |
| | |
| | if (a == GroupBase) { |
| | return false; |
| | } |
| | if (b == GroupBase) { |
| | return true; |
| | } |
| | return a < b; |
| | }); |
| |
|
| | for (const auto& groupName : groupNamesSorted) { |
| | comboBox.addItem(QString::fromStdString(groupName)); |
| | } |
| |
|
| | if (!lastGroup.empty() && std::ranges::find(groupNames, lastGroup) != groupNames.end()) { |
| | comboBox.setEditText(QString::fromStdString(lastGroup)); |
| | } |
| | else { |
| | comboBox.setEditText(QString::fromStdString(groupNamesSorted[0])); |
| | } |
| | } |
| |
|
| | void DlgAddProperty::initializeGroup() |
| | { |
| | comboBoxGroup.setObjectName(QStringLiteral("comboBoxGroup")); |
| | comboBoxGroup.setInsertPolicy(QComboBox::InsertAtTop); |
| | comboBoxGroup.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); |
| |
|
| | setWidgetForLabel("labelGroup", &comboBoxGroup, layout()); |
| | populateGroup(comboBoxGroup, container); |
| |
|
| | connComboBoxGroup = connect( |
| | &comboBoxGroup, |
| | &EditFinishedComboBox::editFinished, |
| | this, |
| | &DlgAddProperty::onGroupFinished |
| | ); |
| | } |
| |
|
| | DlgAddProperty::SupportedTypes DlgAddProperty::getSupportedTypes() |
| | { |
| | std::vector<Base::Type> commonTypes = { |
| | App::PropertyLength::getClassTypeId(), |
| | App::PropertyAngle::getClassTypeId(), |
| | App::PropertyFloat::getClassTypeId(), |
| | App::PropertyInteger::getClassTypeId(), |
| | App::PropertyBool::getClassTypeId(), |
| | App::PropertyString::getClassTypeId(), |
| | App::PropertyEnumeration::getClassTypeId(), |
| | }; |
| |
|
| | std::vector<Base::Type> otherTypes; |
| | std::vector<Base::Type> allTypes; |
| | Base::Type::getAllDerivedFrom(Base::Type::fromName("App::Property"), allTypes); |
| |
|
| | const auto isCommonType = [&commonTypes](const Base::Type& type) { |
| | return std::ranges::find(commonTypes, type) != commonTypes.end(); |
| | }; |
| |
|
| | std::ranges::copy_if(allTypes, std::back_inserter(otherTypes), [&](const Base::Type& type) { |
| | return type.canInstantiate() && !isExcluded(type) && !isCommonType(type); |
| | }); |
| |
|
| | std::ranges::sort(otherTypes, [](Base::Type a, Base::Type b) { |
| | return strcmp(a.getName(), b.getName()) < 0; |
| | }); |
| |
|
| | return {.commonTypes = std::move(commonTypes), .otherTypes = std::move(otherTypes)}; |
| | } |
| |
|
| | void DlgAddProperty::initializeTypes() |
| | { |
| | auto* model = new TypeItemModel(this); |
| | ui->comboBoxType->setModel(model); |
| |
|
| | auto paramGroup = App::GetApplication().GetParameterGroupByPath( |
| | "User parameter:BaseApp/Preferences/PropertyView" |
| | ); |
| | auto lastType = Base::Type::fromName( |
| | paramGroup->GetASCII("NewPropertyType", "App::PropertyLength").c_str() |
| | ); |
| | if (lastType.isBad()) { |
| | lastType = App::PropertyLength::getClassTypeId(); |
| | } |
| |
|
| | const auto [commonTypes, otherTypes] = getSupportedTypes(); |
| |
|
| | const auto addTypes = [this, &lastType](const std::vector<Base::Type>& types) { |
| | for (const auto& type : types) { |
| | ui->comboBoxType->addItem(QString::fromLatin1(type.getName())); |
| | if (type == lastType) { |
| | ui->comboBoxType->setCurrentIndex(ui->comboBoxType->count() - 1); |
| | } |
| | } |
| | }; |
| |
|
| |
|
| | const auto addSeparator = [this]() { |
| | ui->comboBoxType->addItem(QStringLiteral("──────────────────────")); |
| | const int idx = ui->comboBoxType->count() - 1; |
| | ui->comboBoxType->setItemData(idx, true, TypeItemModel::SeparatorRole); |
| | }; |
| |
|
| | addTypes(commonTypes); |
| | addSeparator(); |
| | addTypes(otherTypes); |
| |
|
| | completerType.setModel(ui->comboBoxType->model()); |
| | completerType.setCaseSensitivity(Qt::CaseInsensitive); |
| | completerType.setFilterMode(Qt::MatchContains); |
| | ui->comboBoxType->setCompleter(&completerType); |
| | ui->comboBoxType->setInsertPolicy(QComboBox::NoInsert); |
| |
|
| | connComboBoxType = connect( |
| | ui->comboBoxType, |
| | &QComboBox::currentTextChanged, |
| | this, |
| | &DlgAddProperty::onTypeChanged |
| | ); |
| | } |
| |
|
| | void DlgAddProperty::removeSelectionEditor() |
| | { |
| | |
| | |
| | |
| | |
| | if (auto lineEdit = editor->findChild<QLineEdit*>()) { |
| | lineEdit->deselect(); |
| | } |
| | } |
| |
|
| | void DlgAddProperty::addEnumEditor(PropertyItem* propertyItem) |
| | { |
| | auto* values = static_cast<PropertyStringListItem*>(PropertyStringListItem::create()); |
| | values->setParent(propertyItem); |
| | values->setPropertyName(QLatin1String(QT_TRANSLATE_NOOP("App::Property", "Enum"))); |
| | if (propertyItem->childCount() > 0) { |
| | auto* child = propertyItem->takeChild(0); |
| | delete child; |
| | } |
| | propertyItem->appendChild(values); |
| | editor.reset( |
| | values->createEditor(this, [this]() { this->valueChangedEnum(); }, FrameOption::WithFrame) |
| | ); |
| | } |
| |
|
| | void DlgAddProperty::addNormalEditor(PropertyItem* propertyItem) |
| | { |
| | editor.reset( |
| | propertyItem->createEditor(this, [this]() { this->valueChanged(); }, FrameOption::WithFrame) |
| | ); |
| | } |
| |
|
| | void DlgAddProperty::addEditor(PropertyItem* propertyItem) |
| | { |
| | if (!isTypeWithEditor(propertyItem)) { |
| | return; |
| | } |
| |
|
| | if (isEnumPropertyItem()) { |
| | addEnumEditor(propertyItem); |
| | } |
| | else { |
| | addNormalEditor(propertyItem); |
| | } |
| | if (editor == nullptr) { |
| | return; |
| | } |
| |
|
| | |
| | |
| | editor->setMinimumHeight(comboBoxGroup.height()); |
| |
|
| | QSignalBlocker blockSignals(editor.get()); |
| |
|
| | |
| | |
| | |
| | setEditorData(propertyItem->data(PropertyItem::ValueColumn, Qt::EditRole)); |
| | editor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); |
| | editor->setObjectName(QStringLiteral("editor")); |
| |
|
| | setWidgetForLabel("labelValue", editor.get(), layout()); |
| |
|
| | QWidget::setTabOrder(ui->lineEditName, editor.get()); |
| | QWidget::setTabOrder(editor.get(), ui->lineEditToolTip); |
| |
|
| | removeSelectionEditor(); |
| | } |
| |
|
| | bool DlgAddProperty::isExcluded(const Base::Type& type) const |
| | { |
| | |
| | |
| | static const std::initializer_list<Base::Type> excludedTypes = { |
| | App::PropertyBoolList::getClassTypeId(), |
| | App::PropertyColorList::getClassTypeId(), |
| | App::PropertyExpressionEngine::getClassTypeId(), |
| | App::PropertyIntegerSet::getClassTypeId(), |
| | App::PropertyMap::getClassTypeId(), |
| | App::PropertyMaterial::getClassTypeId(), |
| | App::PropertyPlacementList::getClassTypeId(), |
| | App::PropertyPythonObject::getClassTypeId(), |
| | App::PropertyUUID::getClassTypeId() |
| | }; |
| |
|
| | std::string_view name(type.getName()); |
| | return !name.starts_with("App::Property") |
| | || std::ranges::find(excludedTypes, type) != excludedTypes.end(); |
| | } |
| |
|
| | bool DlgAddProperty::isTypeWithEditor(PropertyItem* propertyItem) const |
| | { |
| | if (propertyItem == nullptr) { |
| | return false; |
| | } |
| |
|
| | App::Property* prop = propertyItem->getFirstProperty(); |
| | if (prop == nullptr) { |
| | return false; |
| | } |
| |
|
| | const Base::Type type = prop->getTypeId(); |
| | return isTypeWithEditor(type); |
| | } |
| |
|
| | bool DlgAddProperty::isTypeWithEditor(const Base::Type& type) const |
| | { |
| | static const std::initializer_list<Base::Type> subTypesWithEditor = { |
| | |
| | App::PropertyBool::getClassTypeId(), |
| | App::PropertyColor::getClassTypeId(), |
| | App::PropertyFileIncluded::getClassTypeId(), |
| | App::PropertyFloat::getClassTypeId(), |
| | App::PropertyInteger::getClassTypeId() |
| | }; |
| |
|
| | static const std::initializer_list<Base::Type> typesWithEditor = { |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | App::PropertyEnumeration::getClassTypeId(), |
| | App::PropertyFile::getClassTypeId(), |
| | App::PropertyFloatList::getClassTypeId(), |
| | App::PropertyFont::getClassTypeId(), |
| | App::PropertyIntegerList::getClassTypeId(), |
| | App::PropertyLink::getClassTypeId(), |
| | App::PropertyLinkList::getClassTypeId(), |
| | App::PropertyXLink::getClassTypeId(), |
| | App::PropertyXLinkList::getClassTypeId(), |
| | App::PropertyMaterialList::getClassTypeId(), |
| | App::PropertyPath::getClassTypeId(), |
| | App::PropertyString::getClassTypeId(), |
| | App::PropertyStringList::getClassTypeId(), |
| | App::PropertyVectorList::getClassTypeId() |
| | }; |
| |
|
| | const auto isDerivedFromType = [&type](const Base::Type& t) { |
| | return type.isDerivedFrom(t); |
| | }; |
| |
|
| | return std::ranges::find(typesWithEditor, type) != typesWithEditor.end() |
| | || std::ranges::any_of(subTypesWithEditor, isDerivedFromType); |
| | } |
| |
|
| | bool DlgAddProperty::isTypeWithEditor(const std::string& type) const |
| | { |
| | Base::Type propType |
| | = Base::Type::getTypeIfDerivedFrom(type.c_str(), App::Property::getClassTypeId(), true); |
| | return isTypeWithEditor(propType); |
| | } |
| |
|
| | static PropertyItem* createPropertyItem(App::Property* prop) |
| | { |
| | const char* editor = prop->getEditorName(); |
| | if (Base::Tools::isNullOrEmpty(editor)) { |
| | return nullptr; |
| | } |
| | return PropertyItemFactory::instance().createPropertyItem(editor); |
| | } |
| |
|
| | void DlgAddProperty::createSupportDataForType(const Base::Type& type) |
| | { |
| | |
| | |
| | |
| | void* propInstance = type.createInstance(); |
| | if (!propInstance) { |
| | FC_THROWM(Base::RuntimeError, "Failed to create a property of type " << type.getName()); |
| | } |
| |
|
| | |
| | |
| | |
| | std::unique_ptr<App::Property, void (*)(App::Property*)> prop( |
| | static_cast<App::Property*>(propInstance), |
| | [](App::Property* p) { delete p; } |
| | ); |
| | prop->setContainer(container); |
| |
|
| | propertyItem.reset(createPropertyItem(prop.get())); |
| |
|
| | if (propertyItem && isTypeWithEditor(type)) { |
| | propertyItem->setPropertyData({prop.get()}); |
| | addEditor(propertyItem.get()); |
| | propertyItem->removeProperty(prop.get()); |
| | } |
| | } |
| |
|
| | void DlgAddProperty::initializeValue() |
| | { |
| | std::string type = ui->comboBoxType->currentText().toStdString(); |
| |
|
| | Base::Type propType |
| | = Base::Type::getTypeIfDerivedFrom(type.c_str(), App::Property::getClassTypeId(), true); |
| | if (propType.isBad()) { |
| | return; |
| | } |
| |
|
| | createSupportDataForType(propType); |
| | if (!isTypeWithEditor(propType)) { |
| | |
| | removeEditor(); |
| | } |
| | } |
| |
|
| | void DlgAddProperty::setTitle() |
| | { |
| | setWindowTitle(tr("Add Property")); |
| | } |
| |
|
| | void DlgAddProperty::setAddEnabled(bool enabled) |
| | { |
| | QPushButton* addButton = ui->buttonBox->button(QDialogButtonBox::Ok); |
| | QPushButton* closeButton = ui->buttonBox->button(QDialogButtonBox::Close); |
| | closeButton->setDefault(!enabled); |
| | addButton->setDefault(enabled); |
| | addButton->setEnabled(enabled); |
| | } |
| |
|
| | void DlgAddProperty::initializeWidgets(ViewProviderVarSet* viewProvider) |
| | { |
| | initializeGroup(); |
| | initializeTypes(); |
| | initializeValue(); |
| |
|
| | if (viewProvider) { |
| | connect(this, &QDialog::finished, this, [viewProvider](int result) { |
| | viewProvider->onFinished(result); |
| | }); |
| | } |
| | connLineEditNameTextChanged |
| | = connect(ui->lineEditName, &QLineEdit::textChanged, this, &DlgAddProperty::onNameChanged); |
| |
|
| | setTitle(); |
| | QPushButton* addButton = ui->buttonBox->button(QDialogButtonBox::Ok); |
| | addButton->setText(tr("Add")); |
| | setAddEnabled(false); |
| |
|
| | comboBoxGroup.setFocus(); |
| |
|
| | QWidget::setTabOrder(&comboBoxGroup, ui->comboBoxType); |
| | QWidget::setTabOrder(ui->comboBoxType, ui->lineEditName); |
| | QWidget::setTabOrder(ui->lineEditName, editor.get()); |
| | QWidget::setTabOrder(editor.get(), ui->lineEditToolTip); |
| |
|
| | adjustSize(); |
| | } |
| |
|
| | bool DlgAddProperty::propertyExists(const std::string& name) |
| | { |
| | App::Property* prop = container->getPropertyByName(name.c_str()); |
| | return prop && prop->getContainer() == container |
| | && !(propertyItem && propertyItem->getFirstProperty() == prop); |
| | } |
| |
|
| | bool DlgAddProperty::isNameValid() |
| | { |
| | std::string name = ui->lineEditName->text().toStdString(); |
| |
|
| | return !name.empty() && name == Base::Tools::getIdentifier(name) |
| | && !App::ExpressionParser::isTokenAConstant(name) |
| | && !App::ExpressionParser::isTokenAUnit(name) && !propertyExists(name); |
| | } |
| |
|
| | bool DlgAddProperty::isGroupValid() |
| | { |
| | std::string group = comboBoxGroup.currentText().toStdString(); |
| | return !group.empty() && group == Base::Tools::getIdentifier(group); |
| | } |
| |
|
| | bool DlgAddProperty::isTypeValid() |
| | { |
| | std::string type = ui->comboBoxType->currentText().toStdString(); |
| | return Base::Type::fromName(type.c_str()).isDerivedFrom(App::Property::getClassTypeId()) |
| | && type != "App::Property"; |
| | } |
| |
|
| | bool DlgAddProperty::isDocument() const |
| | { |
| | return container->isDerivedFrom<App::Document>(); |
| | } |
| |
|
| | bool DlgAddProperty::isDocumentObject() const |
| | { |
| | return container->isDerivedFrom<App::DocumentObject>(); |
| | } |
| |
|
| | bool DlgAddProperty::areFieldsValid() |
| | { |
| | return isNameValid() && isGroupValid() && isTypeValid(); |
| | } |
| |
|
| | void DlgAddProperty::showStatusMessage() |
| | { |
| | QString error; |
| | QString text = ui->lineEditName->text(); |
| | std::string name = text.toStdString(); |
| |
|
| | if (!isGroupValid()) { |
| | error = tr("Invalid group name"); |
| | } |
| | else if (!isTypeValid()) { |
| | error = tr("Invalid type name"); |
| | } |
| | else if (name.empty()) { |
| | error.clear(); |
| | } |
| | else if (name != Base::Tools::getIdentifier(name)) { |
| | error = tr("Invalid property name '%1'").arg(text); |
| | } |
| | else if (propertyExists(name)) { |
| | error = tr("Property '%1' already exists").arg(text); |
| | } |
| | else if (App::ExpressionParser::isTokenAConstant(name)) { |
| | error = tr("'%1' is a constant").arg(text); |
| | } |
| | else if (App::ExpressionParser::isTokenAUnit(name)) { |
| | error = tr("'%1' is a unit").arg(text); |
| | } |
| |
|
| | ui->labelError->setText(error); |
| | } |
| |
|
| | void DlgAddProperty::removeEditor() |
| | { |
| | if (editor == nullptr) { |
| | return; |
| | } |
| |
|
| | |
| | auto* placeholder = new QWidget(this); |
| | placeholder->setObjectName(QStringLiteral("placeholder")); |
| | placeholder->setMinimumHeight(comboBoxGroup.height()); |
| | setWidgetForLabel("labelValue", placeholder, layout()); |
| |
|
| | QWidget::setTabOrder(ui->lineEditName, ui->lineEditToolTip); |
| | editor = nullptr; |
| | } |
| |
|
| | bool DlgAddProperty::isEnumPropertyItem() const |
| | { |
| | return ui->comboBoxType->currentText() |
| | == QString::fromLatin1(App::PropertyEnumeration::getClassTypeId().getName()); |
| | } |
| |
|
| | QVariant DlgAddProperty::getEditorData() const |
| | { |
| | if (isEnumPropertyItem()) { |
| | PropertyItem* child = propertyItem->child(0); |
| | if (child == nullptr) { |
| | return {}; |
| | } |
| | return child->editorData(editor.get()); |
| | } |
| |
|
| | return propertyItem->editorData(editor.get()); |
| | } |
| |
|
| | void DlgAddProperty::setEditorData(const QVariant& data) |
| | { |
| | if (isEnumPropertyItem()) { |
| | PropertyItem* child = propertyItem->child(0); |
| | if (child == nullptr) { |
| | return; |
| | } |
| | child->setEditorData(editor.get(), data); |
| | } |
| | else { |
| | propertyItem->setEditorData(editor.get(), data); |
| | } |
| | } |
| |
|
| | void DlgAddProperty::setEditor(bool valueNeedsReset) |
| | { |
| | if (editor && !valueNeedsReset) { |
| | QVariant data = getEditorData(); |
| | addEditor(propertyItem.get()); |
| | if (editor == nullptr) { |
| | return; |
| | } |
| | setEditorData(data); |
| | removeSelectionEditor(); |
| | } |
| | else if (propertyItem) { |
| | addEditor(propertyItem.get()); |
| | } |
| | else { |
| | initializeValue(); |
| | } |
| |
|
| | if (editor) { |
| | QVariant data = propertyItem->editorData(editor.get()); |
| | propertyItem->setData(data); |
| | } |
| | } |
| |
|
| | void DlgAddProperty::setPropertyItem(App::Property* prop, bool supportsExpressions) |
| | { |
| | if (prop == nullptr) { |
| | return; |
| | } |
| |
|
| | if (propertyItem == nullptr) { |
| | propertyItem.reset(createPropertyItem(prop)); |
| | } |
| |
|
| | if (propertyItem == nullptr) { |
| | return; |
| | } |
| |
|
| | propertyItem->setAutoApply(true); |
| | propertyItem->setPropertyData({prop}); |
| | if (supportsExpressions) { |
| | objectIdentifier = std::make_unique<App::ObjectIdentifier>(*prop); |
| | propertyItem->bind(*objectIdentifier); |
| | } |
| | } |
| |
|
| | void DlgAddProperty::buildForUnbound(bool valueNeedsReset) |
| | { |
| | setEditor(valueNeedsReset); |
| | } |
| |
|
| | void DlgAddProperty::buildForBound(bool valueNeedsReset, bool supportsExpressions) |
| | { |
| | openTransaction(); |
| | App::Property* prop = createProperty(); |
| | setPropertyItem(prop, supportsExpressions); |
| | setEditor(valueNeedsReset); |
| | } |
| |
|
| | bool DlgAddProperty::clearBoundProperty() |
| | { |
| | |
| | |
| | bool isPropertyLinkItem = qobject_cast<PropertyLinkItem*>(propertyItem.get()) != nullptr; |
| | bool valueNeedsReset = isPropertyLinkItem || propertyItem->hasExpression(); |
| |
|
| | if (App::Property* prop = propertyItem->getFirstProperty()) { |
| | propertyItem->unbind(); |
| | propertyItem->removeProperty(prop); |
| | container->removeDynamicProperty(prop->getName()); |
| | closeTransaction(TransactionOption::Abort); |
| | } |
| | return valueNeedsReset; |
| | } |
| |
|
| | bool DlgAddProperty::clear(FieldChange fieldChange) |
| | { |
| | if (propertyItem == nullptr) { |
| | return true; |
| | } |
| |
|
| | bool valueNeedsReset = clearBoundProperty(); |
| |
|
| | if (fieldChange == FieldChange::Type) { |
| | valueNeedsReset = true; |
| | removeEditor(); |
| | propertyItem = nullptr; |
| | } |
| | return valueNeedsReset; |
| | } |
| |
|
| | void DlgAddProperty::onNameChanged([[maybe_unused]] const QString& text) |
| | { |
| | bool valueNeedsReset = clear(FieldChange::Name); |
| | if (isNameValid() && isTypeValid()) { |
| | buildForBound(valueNeedsReset, isDocumentObject()); |
| | } |
| | else if (isTypeValid()) { |
| | buildForUnbound(valueNeedsReset); |
| | } |
| | else { |
| | removeEditor(); |
| | propertyItem = nullptr; |
| | } |
| |
|
| | setAddEnabled(areFieldsValid()); |
| | showStatusMessage(); |
| | } |
| |
|
| | void DlgAddProperty::onGroupFinished() |
| | { |
| | if (isGroupValid() && propertyItem) { |
| | std::string group = comboBoxGroup.currentText().toStdString(); |
| | std::string doc = ui->lineEditToolTip->text().toStdString(); |
| | if (App::Property* prop = propertyItem->getFirstProperty(); |
| | prop && prop->getGroup() != group) { |
| | container->changeDynamicProperty(prop, group.c_str(), doc.c_str()); |
| | } |
| | } |
| |
|
| | setAddEnabled(areFieldsValid()); |
| | showStatusMessage(); |
| | } |
| |
|
| | void DlgAddProperty::onTypeChanged([[maybe_unused]] const QString& text) |
| | { |
| | bool valueNeedsReset = clear(FieldChange::Type); |
| | if (isNameValid() && isTypeValid()) { |
| | buildForBound(valueNeedsReset, isDocumentObject()); |
| | } |
| | else if (isTypeValid()) { |
| | buildForUnbound(valueNeedsReset); |
| | } |
| | |
| |
|
| | setAddEnabled(areFieldsValid()); |
| | showStatusMessage(); |
| | } |
| |
|
| | void DlgAddProperty::changeEvent(QEvent* e) |
| | { |
| | if (e->type() == QEvent::LanguageChange) { |
| | ui->retranslateUi(this); |
| | setTitle(); |
| | } |
| | QDialog::changeEvent(e); |
| | } |
| |
|
| | void DlgAddProperty::valueChangedEnum() |
| | { |
| | auto* propEnum = static_cast<App::PropertyEnumeration*>(propertyItem->getFirstProperty()); |
| | if (propEnum == nullptr || propertyItem->childCount() == 0) { |
| | return; |
| | } |
| |
|
| | auto* values = static_cast<PropertyStringListItem*>(propertyItem->child(0)); |
| | QVariant data = values->editorData(editor.get()); |
| | QStringList enumValues = data.toStringList(); |
| | |
| | std::vector<std::string> enumValuesVec; |
| | std::ranges::transform(enumValues, std::back_inserter(enumValuesVec), [](const QString& value) { |
| | return value.toStdString(); |
| | }); |
| | propEnum->setEnums(enumValuesVec); |
| | } |
| |
|
| | void DlgAddProperty::valueChanged() |
| | { |
| | QVariant data = propertyItem->editorData(editor.get()); |
| | propertyItem->setData(data); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void DlgAddProperty::openTransaction() |
| | { |
| | transactionID = App::GetApplication().setActiveTransaction("Add property"); |
| | } |
| |
|
| | void DlgAddProperty::critical(const QString& title, const QString& text) |
| | { |
| | static bool criticalDialogShown = false; |
| | if (!criticalDialogShown) { |
| | Base::StateLocker locker(criticalDialogShown); |
| | QMessageBox::critical(this, title, text); |
| | } |
| | } |
| |
|
| | void DlgAddProperty::recordMacroAdd( |
| | const App::PropertyContainer* container, |
| | const std::string& type, |
| | const std::string& name, |
| | const std::string& group, |
| | const std::string& doc |
| | ) const |
| | { |
| | std::ostringstream command; |
| | command << "App.getDocument('"; |
| | const App::Document* document = freecad_cast<App::Document*>(container); |
| | const App::DocumentObject* object = freecad_cast<App::DocumentObject*>(container); |
| | if (document) { |
| | command << document->getName() << "')"; |
| | } |
| | else if (object) { |
| | command << object->getDocument()->getName() << "')." << object->getNameInDocument(); |
| | } |
| | else { |
| | FC_ERR("Cannot record macro for container of type " << container->getTypeId().getName()); |
| | return; |
| | } |
| | command << ".addProperty('" << type << "', '" << name << "', '" << group << "', '" << doc + "')"; |
| | Application::Instance->macroManager()->addLine(Gui::MacroManager::App, command.str().c_str()); |
| | } |
| |
|
| | App::Property* DlgAddProperty::createProperty() |
| | { |
| | std::string name = ui->lineEditName->text().toStdString(); |
| | std::string group = comboBoxGroup.currentText().toStdString(); |
| | std::string type = ui->comboBoxType->currentText().toStdString(); |
| | std::string doc = ui->lineEditToolTip->text().toStdString(); |
| |
|
| | auto recordAddCommand = [this](MacroManager::LineType, const char* line) { |
| | this->addCommand = line; |
| | }; |
| |
|
| | try { |
| | App::Property* prop |
| | = container->addDynamicProperty(type.c_str(), name.c_str(), group.c_str(), doc.c_str()); |
| | MacroManager::MacroRedirector redirector(recordAddCommand); |
| | recordMacroAdd(container, type, name, group, doc); |
| | return prop; |
| | } |
| | catch (Base::Exception& e) { |
| | e.reportException(); |
| | critical( |
| | QObject::tr("Add property"), |
| | QObject::tr("Failed to add property to '%1': %2") |
| | .arg(QString::fromLatin1(container->getFullName().c_str()), QString::fromUtf8(e.what())) |
| | ); |
| | return nullptr; |
| | } |
| | } |
| |
|
| | void DlgAddProperty::closeTransaction(TransactionOption option) |
| | { |
| | if (transactionID == 0) { |
| | return; |
| | } |
| |
|
| | App::GetApplication().closeActiveTransaction(static_cast<bool>(option), transactionID); |
| | transactionID = 0; |
| | } |
| |
|
| | void DlgAddProperty::clearFields() |
| | { |
| | { |
| | QSignalBlocker blocker(ui->lineEditName); |
| | ui->lineEditName->clear(); |
| | } |
| | ui->lineEditToolTip->clear(); |
| | initializeValue(); |
| | setAddEnabled(false); |
| | } |
| |
|
| | void DlgAddProperty::addDocumentation() |
| | { |
| | |
| | |
| | |
| | |
| | |
| |
|
| | std::string group = comboBoxGroup.currentText().toStdString(); |
| | std::string doc = ui->lineEditToolTip->text().toStdString(); |
| |
|
| | if (propertyItem == nullptr) { |
| | |
| | return; |
| | } |
| |
|
| | App::Property* prop = propertyItem->getFirstProperty(); |
| | if (prop == nullptr) { |
| | return; |
| | } |
| |
|
| | container->changeDynamicProperty(prop, group.c_str(), doc.c_str()); |
| | } |
| |
|
| | void DlgAddProperty::accept() |
| | { |
| | addDocumentation(); |
| | auto* object = freecad_cast<App::DocumentObject*>(container); |
| | if (object) { |
| | object->ExpressionEngine.execute(); |
| | } |
| | closeTransaction(TransactionOption::Commit); |
| |
|
| | setValueRedirector = nullptr; |
| | Application::Instance->macroManager()->addLine(MacroManager::LineType::App, addCommand.c_str()); |
| | Application::Instance->macroManager()->addLine(MacroManager::LineType::App, setValueCommand.c_str()); |
| | setupMacroRedirector(); |
| |
|
| | 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()); |
| | paramGroup->SetASCII("NewPropertyGroup", group.c_str()); |
| |
|
| | clearFields(); |
| | ui->lineEditName->setFocus(); |
| |
|
| | |
| | |
| | } |
| |
|
| | void DlgAddProperty::reject() |
| | { |
| | if (propertyItem) { |
| | if (App::Property* prop = propertyItem->getFirstProperty()) { |
| | App::PropertyContainer* container = prop->getContainer(); |
| | container->removeDynamicProperty(prop->getName()); |
| | closeTransaction(TransactionOption::Abort); |
| | } |
| | } |
| | disconnect(connComboBoxGroup); |
| | disconnect(connComboBoxType); |
| | disconnect(connLineEditNameTextChanged); |
| |
|
| | QDialog::reject(); |
| | } |
| |
|
| | #include "moc_DlgAddProperty.cpp" |
| |
|