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 <chennes@pioneerlibrarysystem.org>
This commit is contained in:
Pieter Hijma
2026-01-12 08:02:11 +01:00
committed by GitHub
parent a628391406
commit b173365653
2 changed files with 129 additions and 47 deletions

View File

@@ -36,6 +36,7 @@
#include <App/PropertyUnits.h>
#include <App/PropertyFile.h>
#include <App/PropertyGeo.h>
#include <App/PropertyPythonObject.h>
#include <Base/Tools.h>
#include "Dialogs/DlgAddProperty.h"
@@ -275,25 +276,42 @@ void DlgAddProperty::initializeGroup()
);
}
std::vector<Base::Type> DlgAddProperty::getSupportedTypes()
DlgAddProperty::SupportedTypes DlgAddProperty::getSupportedTypes()
{
std::vector<Base::Type> supportedTypes;
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);
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<Base::Type> 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<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("──────────────────────");
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<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 = {
// These types and their subtypes have editors.
@@ -414,19 +477,22 @@ bool DlgAddProperty::isTypeWithEditor(const Base::Type& type)
static const std::initializer_list<Base::Type> 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<const char*, 4> 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()) {

View File

@@ -30,6 +30,7 @@
#include <QDialog>
#include <QComboBox>
#include <QFormLayout>
#include <QStandardItemModel>
#include <FCGlobal.h>
@@ -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<Base::Type> commonTypes;
std::vector<Base::Type> otherTypes;
};
DlgAddProperty(QWidget* parent, App::PropertyContainer* container, ViewProviderVarSet* viewProvider);
void setupMacroRedirector();
void initializeGroup();
std::vector<Base::Type> 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();