From 739804b511a92e6afd40c46086589c744069ff72 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 1 Mar 2022 15:13:34 +0100 Subject: [PATCH] Mod: add string header to dxf.h --- src/App/FeaturePython.cpp | 22 +++++++ src/App/FeaturePython.h | 10 +++- src/App/Property.h | 1 + src/App/PropertyContainer.h | 2 + src/App/PropertyContainerPyImp.cpp | 1 + src/Gui/ViewProviderPythonFeature.cpp | 21 +++++++ src/Gui/ViewProviderPythonFeature.h | 8 +++ src/Gui/propertyeditor/PropertyItem.cpp | 57 ++++++++++++------- src/Gui/propertyeditor/PropertyItem.h | 37 ++++++++---- .../propertyeditor/PropertyItemDelegate.cpp | 25 +++++++- src/Gui/propertyeditor/PropertyItemDelegate.h | 3 + 11 files changed, 153 insertions(+), 34 deletions(-) diff --git a/src/App/FeaturePython.cpp b/src/App/FeaturePython.cpp index 79ea67ed30..d7c33c3ca4 100644 --- a/src/App/FeaturePython.cpp +++ b/src/App/FeaturePython.cpp @@ -553,6 +553,28 @@ FeaturePythonImp::redirectSubName(std::ostringstream &ss, } } +bool FeaturePythonImp::editProperty(const char *name) +{ + _FC_PY_CALL_CHECK(editProperty,return false); + Base::PyGILStateLocker lock; + try { + Py::Tuple args(1); + args.setItem(0, Py::String(name)); + Py::Object ret(Base::pyCall(py_editProperty.ptr(),args.ptr())); + return ret.isTrue(); + } + catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } + + Base::PyException e; // extract the Python error text + e.ReportException(); + } + return false; +} + // --------------------------------------------------------- namespace App { diff --git a/src/App/FeaturePython.h b/src/App/FeaturePython.h index 1a15f6ea87..da21ba4418 100644 --- a/src/App/FeaturePython.h +++ b/src/App/FeaturePython.h @@ -81,6 +81,8 @@ public: /// Set sub-element visibility int setElementVisible(const char *, bool); + bool editProperty(const char *propName); + private: App::DocumentObject* object; bool has__object__; @@ -102,7 +104,8 @@ private: FC_PY_ELEMENT(canLoadPartial)\ FC_PY_ELEMENT(hasChildElement)\ FC_PY_ELEMENT(isElementVisible)\ - FC_PY_ELEMENT(setElementVisible) + FC_PY_ELEMENT(setElementVisible)\ + FC_PY_ELEMENT(editProperty)\ #define FC_PY_ELEMENT_DEFINE(_name) \ Py::Object py_##_name; @@ -300,6 +303,11 @@ public: return FeatureT::canLoadPartial(); } + virtual void editProperty(const char *propName) override { + if (!imp->editProperty(propName)) + FeatureT::editProperty(propName); + } + PyObject *getPyObject(void) override { if (FeatureT::PythonObject.is(Py::_None())) { // ref counter is set to 1 diff --git a/src/App/Property.h b/src/App/Property.h index d6f3cc4614..c124205766 100644 --- a/src/App/Property.h +++ b/src/App/Property.h @@ -77,6 +77,7 @@ public: // expression on restore and touch the object on value change. Busy = 15, // internal use to avoid recursive signaling CopyOnChange = 16, // for Link to copy the linked object on change of the property with this flag + UserEdit = 17, // cause property editor to create button for user defined editing // The following bits are corresponding to PropertyType set when the // property added. These types are meant to be static, and cannot be diff --git a/src/App/PropertyContainer.h b/src/App/PropertyContainer.h index f7ebe291c2..68346244d0 100644 --- a/src/App/PropertyContainer.h +++ b/src/App/PropertyContainer.h @@ -221,6 +221,8 @@ public: virtual void Save (Base::Writer &writer) const; virtual void Restore(Base::XMLReader &reader); + virtual void editProperty(const char * /*propName*/) {} + const char *getPropertyPrefix() const { return _propertyPrefix.c_str(); } diff --git a/src/App/PropertyContainerPyImp.cpp b/src/App/PropertyContainerPyImp.cpp index af5380ef29..67b884d687 100644 --- a/src/App/PropertyContainerPyImp.cpp +++ b/src/App/PropertyContainerPyImp.cpp @@ -197,6 +197,7 @@ static const std::map &getStatusMap() { statusMap["PartialTrigger"] = Property::PartialTrigger; statusMap["NoRecompute"] = Property::NoRecompute; statusMap["CopyOnChange"] = Property::CopyOnChange; + statusMap["UserEdit"] = Property::UserEdit; } return statusMap; } diff --git a/src/Gui/ViewProviderPythonFeature.cpp b/src/Gui/ViewProviderPythonFeature.cpp index df7dc594fa..08e36019df 100644 --- a/src/Gui/ViewProviderPythonFeature.cpp +++ b/src/Gui/ViewProviderPythonFeature.cpp @@ -1418,6 +1418,27 @@ bool ViewProviderPythonFeatureImp::getLinkedViewProvider( return true; } +bool ViewProviderPythonFeatureImp::editProperty(const char *name) +{ + _FC_PY_CALL_CHECK(editProperty,return false); + Base::PyGILStateLocker lock; + try { + Py::Tuple args(1); + args.setItem(0, Py::String(name)); + Py::Object ret(Base::pyCall(py_editProperty.ptr(),args.ptr())); + return ret.isTrue(); + } + catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } + + Base::PyException e; // extract the Python error text + e.ReportException(); + } + return false; +} // --------------------------------------------------------- diff --git a/src/Gui/ViewProviderPythonFeature.h b/src/Gui/ViewProviderPythonFeature.h index bd522ed5c2..0a65eae772 100644 --- a/src/Gui/ViewProviderPythonFeature.h +++ b/src/Gui/ViewProviderPythonFeature.h @@ -125,6 +125,8 @@ public: bool getDropPrefix(std::string &prefix) const; + bool editProperty(const char *propName); + private: ViewProviderDocumentObject* object; App::PropertyPythonObject &Proxy; @@ -170,6 +172,7 @@ private: FC_PY_ELEMENT(getDropPrefix) \ FC_PY_ELEMENT(replaceObject) \ FC_PY_ELEMENT(getLinkedViewProvider) \ + FC_PY_ELEMENT(editProperty) \ #undef FC_PY_ELEMENT #define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_DEFINE(_name) @@ -575,6 +578,11 @@ protected: return res; } + virtual void editProperty(const char *propName) override { + if (!imp->editProperty(propName)) + ViewProviderT::editProperty(propName); + } + public: virtual void setupContextMenu(QMenu* menu, QObject* recipient, const char* member) override { diff --git a/src/Gui/propertyeditor/PropertyItem.cpp b/src/Gui/propertyeditor/PropertyItem.cpp index cc94b43b54..3aa6446bf7 100644 --- a/src/Gui/propertyeditor/PropertyItem.cpp +++ b/src/Gui/propertyeditor/PropertyItem.cpp @@ -1481,9 +1481,8 @@ void PropertyVectorItem::propertyBound() // --------------------------------------------------------------- -VectorListWidget::VectorListWidget (int decimals, QWidget * parent) +PropertyEditorWidget::PropertyEditorWidget (QWidget * parent) : QWidget(parent) - , decimals(decimals) { QHBoxLayout *layout = new QHBoxLayout(this); layout->setMargin(0); @@ -1499,20 +1498,53 @@ VectorListWidget::VectorListWidget (int decimals, QWidget * parent) #endif layout->addWidget(button); - connect(button, SIGNAL(clicked()), this, SLOT(buttonClicked())); - setFocusProxy(lineEdit); + connect(button, SIGNAL(clicked()), this, SIGNAL(buttonClick())); + + // QAbstractItemView will call selectAll() if a QLineEdit is the focus + // proxy. Since the QLineEdit here is read-only and not meant for editing, + // do not set it as focus proxy. Otherwise, the text won't even shown for + // most stylesheets (which contain a trick to hide the content of a selected + // read-only/disabled editor widgets). + // + // setFocusProxy(lineEdit); } -VectorListWidget::~VectorListWidget() +PropertyEditorWidget::~PropertyEditorWidget() { } -void VectorListWidget::resizeEvent(QResizeEvent* e) +void PropertyEditorWidget::resizeEvent(QResizeEvent* e) { button->setFixedWidth(e->size().height()); button->setFixedHeight(e->size().height()); } +void PropertyEditorWidget::showValue(const QVariant &d) +{ + lineEdit->setText(d.toString()); +} + + +QVariant PropertyEditorWidget::value() const +{ + return variant; +} + +void PropertyEditorWidget::setValue(const QVariant& val) +{ + variant = val; + showValue(variant); + valueChanged(variant); +} + +// --------------------------------------------------------------- + +VectorListWidget::VectorListWidget(int decimals, QWidget *parent) + :PropertyEditorWidget(parent), decimals(decimals) +{ + connect(button, SIGNAL(clicked()), this, SLOT(buttonClicked())); +} + void VectorListWidget::buttonClicked() { VectorListEditor dlg(decimals, Gui::getMainWindow()); @@ -1542,19 +1574,6 @@ void VectorListWidget::showValue(const QVariant& d) } lineEdit->setText(data); } - -QVariant VectorListWidget::value() const -{ - return variant; -} - -void VectorListWidget::setValue(const QVariant& val) -{ - variant = val; - showValue(variant); - valueChanged(variant); -} - // --------------------------------------------------------------- PROPERTYITEM_SOURCE(Gui::PropertyEditor::PropertyVectorListItem) diff --git a/src/Gui/propertyeditor/PropertyItem.h b/src/Gui/propertyeditor/PropertyItem.h index a5871ca694..5da33fb7a8 100644 --- a/src/Gui/propertyeditor/PropertyItem.h +++ b/src/Gui/propertyeditor/PropertyItem.h @@ -180,13 +180,14 @@ public: bool hasAnyExpression() const; + virtual QVariant toString(const QVariant&) const; + protected: PropertyItem(); virtual QVariant displayName() const; virtual QVariant decoration(const QVariant&) const; virtual QVariant toolTip(const App::Property*) const; - virtual QVariant toString(const QVariant&) const; virtual QVariant value(const App::Property*) const; virtual void setValue(const QVariant&); virtual void initialize(); @@ -481,13 +482,13 @@ private: PropertyFloatItem* m_z; }; -class VectorListWidget : public QWidget +class PropertyEditorWidget : public QWidget { Q_OBJECT public: - VectorListWidget (int decimals, QWidget * parent = nullptr); - virtual ~VectorListWidget(); + PropertyEditorWidget (QWidget * parent = nullptr); + virtual ~PropertyEditorWidget(); QVariant value() const; @@ -495,20 +496,34 @@ public Q_SLOTS: void setValue(const QVariant&); protected: - void showValue(const QVariant& data); + virtual void showValue(const QVariant& data); void resizeEvent(QResizeEvent*); +Q_SIGNALS: + void buttonClick(); + void valueChanged(const QVariant &); + +protected: + QVariant variant; + QLineEdit *lineEdit; + QPushButton *button; +}; + +class VectorListWidget : public PropertyEditorWidget +{ + Q_OBJECT + +public: + VectorListWidget (int decimals, QWidget * parent = nullptr); + +protected: + virtual void showValue(const QVariant& data) override; + private Q_SLOTS: void buttonClicked(); -Q_SIGNALS: - void valueChanged(const QVariant &); - private: int decimals; - QVariant variant; - QLineEdit *lineEdit; - QPushButton *button; }; /** diff --git a/src/Gui/propertyeditor/PropertyItemDelegate.cpp b/src/Gui/propertyeditor/PropertyItemDelegate.cpp index b46c2ad23c..43676168a1 100644 --- a/src/Gui/propertyeditor/PropertyItemDelegate.cpp +++ b/src/Gui/propertyeditor/PropertyItemDelegate.cpp @@ -181,10 +181,27 @@ QWidget * PropertyItemDelegate::createEditor (QWidget * parent, const QStyleOpti QWidget* editor; expressionEditor = 0; + userEditor = nullptr; if(parentEditor && parentEditor->isBinding()) expressionEditor = editor = childItem->createExpressionEditor(parent, this, SLOT(valueChanged())); - else - editor = childItem->createEditor(parent, this, SLOT(valueChanged())); + else { + const auto &props = childItem->getPropertyData(); + if (props.size() && props[0]->testStatus(App::Property::UserEdit)) { + editor = userEditor = new PropertyEditorWidget(parent); + QObject::connect(userEditor, &PropertyEditorWidget::buttonClick, childItem, + [childItem]() { + const auto &props = childItem->getPropertyData(); + if (props.size() + && props[0]->getName() + && props[0]->testStatus(App::Property::UserEdit) + && props[0]->getContainer()) + { + props[0]->getContainer()->editProperty(props[0]->getName()); + } + }); + } else + editor = childItem->createEditor(parent, this, SLOT(valueChanged())); + } if (editor) // Make sure the editor background is painted so the cell content doesn't show through editor->setAutoFillBackground(true); if (editor && childItem->isReadOnly()) @@ -231,6 +248,8 @@ void PropertyItemDelegate::setEditorData(QWidget *editor, const QModelIndex &ind editor->blockSignals(true); if(expressionEditor == editor) childItem->setExpressionEditorData(editor, data); + else if (userEditor == editor) + userEditor->setValue(childItem->toString(data)); else childItem->setEditorData(editor, data); editor->blockSignals(false); @@ -239,7 +258,7 @@ void PropertyItemDelegate::setEditorData(QWidget *editor, const QModelIndex &ind void PropertyItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { - if (!index.isValid() || !changed) + if (!index.isValid() || !changed || userEditor) return; PropertyItem *childItem = static_cast(index.internalPointer()); QVariant data; diff --git a/src/Gui/propertyeditor/PropertyItemDelegate.h b/src/Gui/propertyeditor/PropertyItemDelegate.h index 5cdc59f403..1b543902b7 100644 --- a/src/Gui/propertyeditor/PropertyItemDelegate.h +++ b/src/Gui/propertyeditor/PropertyItemDelegate.h @@ -29,6 +29,8 @@ namespace Gui { namespace PropertyEditor { +class PropertyEditorWidget; + class PropertyItemDelegate : public QItemDelegate { Q_OBJECT @@ -52,6 +54,7 @@ public Q_SLOTS: private: mutable QWidget *expressionEditor; + mutable PropertyEditorWidget *userEditor = nullptr; mutable bool pressed; bool changed; };