From b173365653a8b515f1e264bc2dcda4364b519884 Mon Sep 17 00:00:00 2001 From: Pieter Hijma Date: Mon, 12 Jan 2026 08:02:11 +0100 Subject: [PATCH] Gui: Add common types to Add Property dialog (#26765) * Gui: Add common types to Add Property dialog Add a preselection of commonly used types in the Add Property dialog. The dialog supports now all properties that have an editor. This doesn't necessarily mean that the editor is shown in the Add Property dialog; some properties should not show their editor in the Add Property dialog, such as vector and placement. * Gui: Make Add Property dialog Qt 6 compatible This change stops using a Qt 6.10 feature and makes it compatible with all of Qt 6. * Update src/Gui/Dialogs/DlgAddProperty.cpp --------- Co-authored-by: Chris Hennes --- src/Gui/Dialogs/DlgAddProperty.cpp | 135 ++++++++++++++++++++--------- src/Gui/Dialogs/DlgAddProperty.h | 41 +++++++-- 2 files changed, 129 insertions(+), 47 deletions(-) diff --git a/src/Gui/Dialogs/DlgAddProperty.cpp b/src/Gui/Dialogs/DlgAddProperty.cpp index 5df97b1301..1859fe2d66 100644 --- a/src/Gui/Dialogs/DlgAddProperty.cpp +++ b/src/Gui/Dialogs/DlgAddProperty.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "Dialogs/DlgAddProperty.h" @@ -275,25 +276,42 @@ void DlgAddProperty::initializeGroup() ); } -std::vector DlgAddProperty::getSupportedTypes() +DlgAddProperty::SupportedTypes DlgAddProperty::getSupportedTypes() { - std::vector supportedTypes; + std::vector commonTypes = { + App::PropertyLength::getClassTypeId(), + App::PropertyAngle::getClassTypeId(), + App::PropertyFloat::getClassTypeId(), + App::PropertyInteger::getClassTypeId(), + App::PropertyBool::getClassTypeId(), + App::PropertyString::getClassTypeId(), + App::PropertyEnumeration::getClassTypeId(), + }; + + std::vector otherTypes; std::vector allTypes; Base::Type::getAllDerivedFrom(Base::Type::fromName("App::Property"), allTypes); - std::ranges::copy_if(allTypes, std::back_inserter(supportedTypes), [&](const Base::Type& type) { - return type.canInstantiate() && isTypeWithEditor(type); + 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(supportedTypes, [](Base::Type a, Base::Type b) { + std::ranges::sort(otherTypes, [](Base::Type a, Base::Type b) { return strcmp(a.getName(), b.getName()) < 0; }); - return supportedTypes; + 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" ); @@ -304,14 +322,27 @@ void DlgAddProperty::initializeTypes() lastType = App::PropertyLength::getClassTypeId(); } - std::vector types = getSupportedTypes(); + const auto [commonTypes, otherTypes] = getSupportedTypes(); - for (const auto& type : types) { - ui->comboBoxType->addItem(QString::fromLatin1(type.getName())); - if (type == lastType) { - ui->comboBoxType->setCurrentIndex(ui->comboBoxType->count() - 1); + const auto addTypes = [this, &lastType](const std::vector& 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("──────────────────────"); + 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); @@ -362,11 +393,7 @@ void DlgAddProperty::addNormalEditor(PropertyItem* propertyItem) void DlgAddProperty::addEditor(PropertyItem* propertyItem) { - if (isSubLinkPropertyItem()) { - // Since sublinks need the 3D view to select an object and the dialog - // is modal, we do not provide an editor for sublinks. It is possible - // to create a property of this type though and the property can be set - // in the property view later which does give access to the 3D view. + if (!isTypeWithEditor(propertyItem)) { return; } @@ -401,7 +428,43 @@ void DlgAddProperty::addEditor(PropertyItem* propertyItem) removeSelectionEditor(); } -bool DlgAddProperty::isTypeWithEditor(const Base::Type& type) +bool DlgAddProperty::isExcluded(const Base::Type& type) const +{ + // These properties are excluded because you cannot give them a value in + // the property view. + static const std::initializer_list 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 subTypesWithEditor = { // These types and their subtypes have editors. @@ -414,19 +477,22 @@ bool DlgAddProperty::isTypeWithEditor(const Base::Type& type) static const std::initializer_list typesWithEditor = { // These types have editors but not necessarily their subtypes. + + // Although sublink properties have editors, they need the 3D view to + // select an object. Because the dialog is modal, it is not possible + // to make use of the 3D view, hence we do not provide an editor for + // sublinks and their lists. It is possible to create a property of + // this type though and the property can be set in the property view + // later which does give access to the 3D view. App::PropertyEnumeration::getClassTypeId(), App::PropertyFile::getClassTypeId(), App::PropertyFloatList::getClassTypeId(), App::PropertyFont::getClassTypeId(), App::PropertyIntegerList::getClassTypeId(), App::PropertyLink::getClassTypeId(), - App::PropertyLinkSub::getClassTypeId(), App::PropertyLinkList::getClassTypeId(), - App::PropertyLinkSubList::getClassTypeId(), App::PropertyXLink::getClassTypeId(), - App::PropertyXLinkSub::getClassTypeId(), App::PropertyXLinkList::getClassTypeId(), - App::PropertyXLinkSubList::getClassTypeId(), App::PropertyMaterialList::getClassTypeId(), App::PropertyPath::getClassTypeId(), App::PropertyString::getClassTypeId(), @@ -442,7 +508,7 @@ bool DlgAddProperty::isTypeWithEditor(const Base::Type& type) || std::ranges::any_of(subTypesWithEditor, isDerivedFromType); } -bool DlgAddProperty::isTypeWithEditor(const std::string& type) +bool DlgAddProperty::isTypeWithEditor(const std::string& type) const { Base::Type propType = Base::Type::getTypeIfDerivedFrom(type.c_str(), App::Property::getClassTypeId(), true); @@ -458,7 +524,7 @@ static PropertyItem* createPropertyItem(App::Property* prop) return PropertyItemFactory::instance().createPropertyItem(editor); } -void DlgAddProperty::createEditorForType(const Base::Type& type) +void DlgAddProperty::createSupportDataForType(const Base::Type& type) { // Temporarily create a property for two reasons: // - to acquire the editor name from the instance, and @@ -496,10 +562,9 @@ void DlgAddProperty::initializeValue() return; } - if (isTypeWithEditor(propType)) { - createEditorForType(propType); - } - else { + createSupportDataForType(propType); + if (!isTypeWithEditor(propType)) { + // remove the editor from a previous add removeEditor(); } } @@ -644,20 +709,6 @@ bool DlgAddProperty::isEnumPropertyItem() const == QString::fromLatin1(App::PropertyEnumeration::getClassTypeId().getName()); } -bool DlgAddProperty::isSubLinkPropertyItem() const -{ - const QString type = ui->comboBoxType->currentText(); - static const std::array sublinkTypes = { - App::PropertyLinkSub::getClassTypeId().getName(), - App::PropertyLinkSubList::getClassTypeId().getName(), - App::PropertyXLinkSub::getClassTypeId().getName(), - App::PropertyXLinkSubList::getClassTypeId().getName() - }; - return std::ranges::any_of(sublinkTypes, [&type](const char* subLinkType) { - return type == QString::fromLatin1(subLinkType); - }); -} - QVariant DlgAddProperty::getEditorData() const { if (isEnumPropertyItem()) { diff --git a/src/Gui/Dialogs/DlgAddProperty.h b/src/Gui/Dialogs/DlgAddProperty.h index 717eb74a72..e2156b1244 100644 --- a/src/Gui/Dialogs/DlgAddProperty.h +++ b/src/Gui/Dialogs/DlgAddProperty.h @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -85,6 +86,29 @@ private: class Ui_DlgAddProperty; +class TypeItemModel: public QStandardItemModel +{ + Q_OBJECT +public: + static constexpr int SeparatorRole = Qt::UserRole + 1; + + explicit TypeItemModel(QObject* parent = nullptr) + : QStandardItemModel(parent) + {} + + Qt::ItemFlags flags(const QModelIndex& index) const override + { + Qt::ItemFlags flags = QStandardItemModel::flags(index); + if (index.isValid()) { + QVariant isSeparator = index.data(SeparatorRole); + if (isSeparator.isValid() && isSeparator.toBool()) { + return flags & ~(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + } + } + return flags; + } +}; + class GuiExport DlgAddProperty: public QDialog { Q_OBJECT @@ -126,26 +150,33 @@ private: Type }; + struct SupportedTypes + { + std::vector commonTypes; + std::vector otherTypes; + }; + DlgAddProperty(QWidget* parent, App::PropertyContainer* container, ViewProviderVarSet* viewProvider); void setupMacroRedirector(); void initializeGroup(); - std::vector getSupportedTypes(); + SupportedTypes getSupportedTypes(); void initializeTypes(); void removeSelectionEditor(); QVariant getEditorData() const; void setEditorData(const QVariant& data); - bool isSubLinkPropertyItem() const; bool isEnumPropertyItem() const; void addEnumEditor(PropertyEditor::PropertyItem* propertyItem); void addNormalEditor(PropertyEditor::PropertyItem* propertyItem); void addEditor(PropertyEditor::PropertyItem* propertyItem); - bool isTypeWithEditor(const Base::Type& type); - bool isTypeWithEditor(const std::string& type); - void createEditorForType(const Base::Type& type); + bool isExcluded(const Base::Type& type) const; + bool isTypeWithEditor(PropertyEditor::PropertyItem* propertyItem) const; + bool isTypeWithEditor(const Base::Type& type) const; + bool isTypeWithEditor(const std::string& type) const; + void createSupportDataForType(const Base::Type& type); void initializeValue(); void setTitle();