From 39c04e487779adcbb2db76be61ab535826b2a81c Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Fri, 3 Jan 2020 20:51:35 +0800 Subject: [PATCH] PartDesign: support CopyOnChange in SubShapeBinder --- src/Mod/PartDesign/App/ShapeBinder.cpp | 151 +++++++++++++++++- src/Mod/PartDesign/App/ShapeBinder.h | 16 +- .../Gui/ViewProviderShapeBinder.cpp | 60 +++++-- .../PartDesign/Gui/ViewProviderShapeBinder.h | 3 + 4 files changed, 214 insertions(+), 16 deletions(-) diff --git a/src/Mod/PartDesign/App/ShapeBinder.cpp b/src/Mod/PartDesign/App/ShapeBinder.cpp index 6153626f66..ab6d4cf866 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.cpp +++ b/src/Mod/PartDesign/App/ShapeBinder.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include FC_LOG_LEVEL_INIT("PartDesign",true,true) @@ -325,10 +326,30 @@ SubShapeBinder::SubShapeBinder() ADD_PROPERTY_TYPE(Context, (0), "Base", App::Prop_Hidden, "Stores the context of this binder. It is used for monitoring and auto updating\n" "the relative placement of the bound shape"); + + static const char *BindCopyOnChangeEnum[] = {"Disabled", "Enabled", "Mutated", 0}; + BindCopyOnChange.setEnums(BindCopyOnChangeEnum); + ADD_PROPERTY_TYPE(BindCopyOnChange, ((long)0), "Base", App::Prop_None, + "Disabled: disable copy on change.\n" + "Enabled: duplicate properties from binding object that are marked with 'CopyOnChange'.\n" + " Make internal copy of the object with any changed properties to obtain the\n" + " shape of an alternative configuration\n" + "Mutated: indicate the binder has already mutated by changing any properties marked with\n" + " 'CopyOnChange'. Those properties will not longer be kept in sync between the\n" + " binder and the binding object"); + Context.setScope(App::LinkScope::Hidden); ADD_PROPERTY_TYPE(_Version,(0),"Base",(App::PropertyType)( App::Prop_Hidden|App::Prop_ReadOnly), ""); + + _CopiedLink.setScope(App::LinkScope::Hidden); + ADD_PROPERTY_TYPE(_CopiedLink,(0),"Base",(App::PropertyType)( + App::Prop_Hidden|App::Prop_ReadOnly|App::Prop_NoPersist), ""); +} + +SubShapeBinder::~SubShapeBinder() { + clearCopiedObjects(); } void SubShapeBinder::setupObject() { @@ -374,6 +395,60 @@ App::DocumentObject *SubShapeBinder::getSubObject(const char *subname, PyObject return nullptr; } +void SubShapeBinder::setupCopyOnChange() { + copyOnChangeConns.clear(); + + const auto &support = Support.getSubListValues(); + if(BindCopyOnChange.getValue()==0 || support.size()!=1) { + if(hasCopyOnChange) { + hasCopyOnChange = false; + std::vector props; + getPropertyList(props); + for(auto prop : props) { + if(App::LinkBaseExtension::isCopyOnChangeProperty(this,*prop)) { + try { + removeDynamicProperty(prop->getName()); + } catch (Base::Exception &e) { + e.ReportException(); + } catch (...) { + } + } + } + } + return; + } + + auto linked = support.front().getValue(); + hasCopyOnChange = App::LinkBaseExtension::setupCopyOnChange(this,linked, + BindCopyOnChange.getValue()==1?©OnChangeConns:nullptr,hasCopyOnChange); + if(hasCopyOnChange) { + copyOnChangeConns.push_back(linked->signalChanged.connect( + [this](const App::DocumentObject &, const App::Property &prop) { + if(!prop.testStatus(App::Property::Output) + && !prop.testStatus(App::Property::PropOutput)) + { + if(this->_CopiedObjs.size()) { + FC_LOG("Clear binder " << getFullName() << " cache on change of " + << prop.getFullName()); + this->clearCopiedObjects(); + } + } + } + )); + } +} + +void SubShapeBinder::clearCopiedObjects() { + std::vector objs; + objs.swap(_CopiedObjs); + for(auto &o : objs) { + auto obj = o.getObject(); + if(obj) + obj->getDocument()->removeObject(obj->getNameInDocument()); + } + _CopiedLink.setValue(0); +} + void SubShapeBinder::update(SubShapeBinder::UpdateOption options) { Part::TopoShape result; std::vector shapes; @@ -406,6 +481,7 @@ void SubShapeBinder::update(SubShapeBinder::UpdateOption options) { if(parent && (parent!=Context.getValue() || parentSub!=Context.getSubName(false))) Context.setValue(parent,parentSub.c_str()); } + bool first = false; std::unordered_map mats; for(auto &l : Support.getSubListValues()) { @@ -454,7 +530,52 @@ void SubShapeBinder::update(SubShapeBinder::UpdateOption options) { if(init) continue; - const auto &subvals = l.getSubValues(); + App::DocumentObject *copied = 0; + + if(BindCopyOnChange.getValue() == 2 && Support.getSubListValues().size()==1) { + if(_CopiedObjs.size()) + copied = _CopiedObjs.front().getObject(); + + bool recomputeCopy = false; + + if(!copied) { + recomputeCopy = true; + clearCopiedObjects(); + + auto tmpDoc = App::GetApplication().newDocument( + "_tmp_binder", 0, false, true); + auto objs = tmpDoc->copyObject({obj},true,true); + if(objs.size()) { + for(auto it=objs.rbegin(); it!=objs.rend(); ++it) + _CopiedObjs.emplace_back(*it); + copied = objs.back(); + } + } + + if(copied) { + std::vector props; + getPropertyList(props); + for(auto prop : props) { + if(!App::LinkBaseExtension::isCopyOnChangeProperty(this,*prop)) + continue; + auto p = copied->getPropertyByName(prop->getName()); + if(p && p->getContainer()==copied + && p->getTypeId()==prop->getTypeId() + && !p->isSame(*prop)) + { + recomputeCopy = true; + std::unique_ptr pcopy(prop->Copy()); + p->Paste(*pcopy); + } + } + if(recomputeCopy) + copied->recomputeFeature(true); + obj = copied; + _CopiedLink.setValue(copied,l.getSubValues(false)); + } + } + + const auto &subvals = copied?_CopiedLink.getSubValues():l.getSubValues(); std::set subs(subvals.begin(),subvals.end()); static std::string none(""); if(subs.empty()) @@ -616,9 +737,15 @@ void SubShapeBinder::slotRecomputedObject(const App::DocumentObject& Obj) { } } +static const char _GroupPrefix[] = "Configuration ("; + App::DocumentObjectExecReturn* SubShapeBinder::execute(void) { + + setupCopyOnChange(); + if(BindMode.getValue()==0) update(UpdateForced); + return inherited::execute(); } @@ -641,11 +768,15 @@ void SubShapeBinder::onChanged(const App::Property *prop) { } }else if(!isRestoring()) { if(prop == &Support) { + clearCopiedObjects(); + setupCopyOnChange(); if(Support.getSubListValues().size()) { update(); if(BindMode.getValue() == 2) Support.setValue(0); } + }else if(prop == &BindCopyOnChange) { + setupCopyOnChange(); }else if(prop == &BindMode) { if(BindMode.getValue() == 2) Support.setValue(0); @@ -654,11 +785,27 @@ void SubShapeBinder::onChanged(const App::Property *prop) { checkPropertyStatus(); }else if(prop == &PartialLoad) { checkPropertyStatus(); - } + }else if(prop && !prop->testStatus(App::Property::User3)) + checkCopyOnChange(*prop); } inherited::onChanged(prop); } +void SubShapeBinder::checkCopyOnChange(const App::Property &prop) { + if(BindCopyOnChange.getValue()!=1 + || getDocument()->isPerformingTransaction() + || !App::LinkBaseExtension::isCopyOnChangeProperty(this,prop) + || Support.getSubListValues().size()!=1) + return; + + auto linked = Support.getSubListValues().front().getValue(); + if(!linked) + return; + auto linkedProp = linked->getPropertyByName(prop.getName()); + if(linkedProp && linkedProp->getTypeId()==prop.getTypeId() && !linkedProp->isSame(prop)) + BindCopyOnChange.setValue(2); +} + void SubShapeBinder::checkPropertyStatus() { Support.setAllowPartial(PartialLoad.getValue()); diff --git a/src/Mod/PartDesign/App/ShapeBinder.h b/src/Mod/PartDesign/App/ShapeBinder.h index 01500701fe..5cac63bc6b 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.h +++ b/src/Mod/PartDesign/App/ShapeBinder.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,8 @@ public: typedef Part::Feature inherited; SubShapeBinder(); + ~SubShapeBinder(); + const char* getViewProviderName(void) const override { return "PartDesignGui::ViewProviderSubShapeBinder"; } @@ -96,6 +99,7 @@ public: App::PropertyBool PartialLoad; App::PropertyXLink Context; App::PropertyInteger _Version; + App::PropertyEnumeration BindCopyOnChange; enum UpdateOption { UpdateNone = 0, @@ -123,13 +127,23 @@ protected: virtual void onDocumentRestored() override; virtual void setupObject() override; + void setupCopyOnChange(); + void checkCopyOnChange(const App::Property &prop); + void clearCopiedObjects(); + void checkPropertyStatus(); void slotRecomputedObject(const App::DocumentObject& Obj); typedef boost::signals2::scoped_connection Connection; Connection connRecomputedObj; - App::Document *contextDoc=0; + App::Document *contextDoc = 0; + + std::vector copyOnChangeConns; + bool hasCopyOnChange = true; + + App::PropertyXLinkSub _CopiedLink; + std::vector _CopiedObjs; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp index 116b4fc8b0..07df8ed040 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp @@ -32,12 +32,14 @@ # include #endif +#include #include #include #include #include #include #include +#include #include @@ -216,18 +218,46 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderSubShapeBinder,PartGui::ViewProviderP ViewProviderSubShapeBinder::ViewProviderSubShapeBinder() { sPixmap = "PartDesign_SubShapeBinder.svg"; - //get the datum coloring scheme - // set default color for datums (golden yellow with 60% transparency) - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath ( - "User parameter:BaseApp/Preferences/Mod/PartDesign"); - unsigned long shcol = hGrp->GetUnsigned ( "DefaultDatumColor", 0xFFD70099 ); - App::Color col ( (uint32_t) shcol ); - - ShapeColor.setValue(col); - LineColor.setValue(col); - PointColor.setValue(col); - Transparency.setValue(60); - LineWidth.setValue(1); + ADD_PROPERTY_TYPE(UseBinderStyle, (false), "",(App::PropertyType)(App::Prop_None), ""); +} + +void ViewProviderSubShapeBinder::attach(App::DocumentObject *obj) { + + UseBinderStyle.setValue(boost::istarts_with(obj->getNameInDocument(),"binder")); + ViewProviderPart::attach(obj); +} + +void ViewProviderSubShapeBinder::onChanged(const App::Property *prop) { + if(prop == &UseBinderStyle + && (!getObject() || !getObject()->isRestoring())) + { + App::Color shapeColor,lineColor,pointColor; + int transparency, linewidth; + if(UseBinderStyle.getValue()) { + //get the datum coloring scheme + // set default color for datums (golden yellow with 60% transparency) + static ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath ( + "User parameter:BaseApp/Preferences/Mod/PartDesign"); + shapeColor.setPackedValue(hGrp->GetUnsigned ( "DefaultDatumColor", 0xFFD70099 )); + lineColor = shapeColor; + pointColor = shapeColor; + transparency = 60; + linewidth = 1; + } else { + shapeColor.setPackedValue(Gui::ViewParams::instance()->getDefaultShapeColor()); + lineColor.setPackedValue(Gui::ViewParams::instance()->getDefaultShapeLineColor()); + pointColor = lineColor; + transparency = 0; + linewidth = Gui::ViewParams::instance()->getDefaultShapeLineWidth(); + } + ShapeColor.setValue(shapeColor); + LineColor.setValue(lineColor); + PointColor.setValue(pointColor); + Transparency.setValue(transparency); + LineWidth.setValue(linewidth); + } + + ViewProviderPart::onChanged(prop); } bool ViewProviderSubShapeBinder::canDropObjectEx(App::DocumentObject *, @@ -276,6 +306,7 @@ void ViewProviderSubShapeBinder::setupContextMenu(QMenu* menu, QObject* receiver act->setData(QVariant((int)Synchronize)); act = menu->addAction(QObject::tr("Select bound object"), receiver, member); act->setData(QVariant((int)SelectObject)); + ViewProviderPart::setupContextMenu(menu,receiver,member); } bool ViewProviderSubShapeBinder::setEdit(int ModNum) { @@ -305,7 +336,10 @@ bool ViewProviderSubShapeBinder::setEdit(int ModNum) { } Gui::Selection().selStackPush(); break; - }} + } + default: + return ViewProviderPart::setEdit(ModNum); + } return false; } diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h index 7621d41625..4165f8e39d 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h @@ -57,6 +57,7 @@ class PartDesignGuiExport ViewProviderSubShapeBinder : public PartGui::ViewProvi PROPERTY_HEADER_WITH_OVERRIDE(PartDesignGui::ViewProviderShapeBinder); public: + App::PropertyBool UseBinderStyle; /// Constructor ViewProviderSubShapeBinder(); @@ -72,6 +73,8 @@ public: virtual bool doubleClicked() override; virtual void setupContextMenu(QMenu* menu, QObject* receiver, const char* member) override; virtual bool setEdit(int ModNum) override; + virtual void attach(App::DocumentObject *obj) override; + virtual void onChanged(const App::Property *prop) override; private: enum {