diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index 91963ecf83..26abc6f76b 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -117,6 +117,7 @@ PyMOD_INIT_FUNC(_PartDesign) PartDesign::AdditiveLoft ::init(); PartDesign::SubtractiveLoft ::init(); PartDesign::ShapeBinder ::init(); + PartDesign::SubShapeBinder ::init(); PartDesign::Plane ::init(); PartDesign::Line ::init(); PartDesign::Point ::init(); diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 6ab7bc16ef..3e9cd9a27d 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -116,21 +116,6 @@ short Body::mustExecute() const return Part::BodyBase::mustExecute(); } -App::DocumentObject* Body::getPrevFeature(App::DocumentObject *start) const -{ - std::vector features = Group.getValues(); - if (features.empty()) return NULL; - App::DocumentObject* st = (start == NULL ? Tip.getValue() : start); - if (st == NULL) - return st; // Tip is NULL - - std::vector::iterator it = std::find(features.begin(), features.end(), st); - if (it == features.end()) return NULL; // Invalid start object - - it--; - return *it; -} - App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start) { if (!start) { // default to tip @@ -246,7 +231,8 @@ bool Body::isAllowed(const App::DocumentObject* f) f->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()) || // TODO Shouldn't we replace it with Sketcher::SketchObject? (2015-08-13, Fat-Zer) f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId()) || - f->getTypeId().isDerivedFrom(PartDesign::ShapeBinder::getClassTypeId()) + f->getTypeId().isDerivedFrom(PartDesign::ShapeBinder::getClassTypeId()) || + f->getTypeId().isDerivedFrom(PartDesign::SubShapeBinder::getClassTypeId()) // TODO Why this lines was here? why should we allow anything of those? (2015-08-13, Fat-Zer) //f->getTypeId().isDerivedFrom(Part::FeaturePython::getClassTypeId()) // trouble with this line on Windows!? Linker fails to find getClassTypeId() of the Part::FeaturePython... //f->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()) @@ -281,6 +267,17 @@ std::vector Body::addObject(App::DocumentObject *feature) if (isSolidFeature(feature)) { Tip.setValue (feature); } + + if(feature->Visibility.getValue() + && feature->isDerivedFrom(PartDesign::Feature::getClassTypeId())) + { + for(auto obj : Group.getValues()) { + if(obj->Visibility.getValue() + && obj!=feature + && obj->isDerivedFrom(PartDesign::Feature::getClassTypeId())) + obj->Visibility.setValue(false); + } + } std::vector result = {feature}; return result; @@ -330,6 +327,9 @@ void Body::insertObject(App::DocumentObject* feature, App::DocumentObject* targe Group.setValues (model); + if(feature->isDerivedFrom(PartDesign::Feature::getClassTypeId())) + static_cast(feature)->_Body.setValue(this); + // Set the BaseFeature property setBaseProperty(feature); } @@ -445,7 +445,9 @@ void Body::onSettingDocument() { void Body::onChanged (const App::Property* prop) { // we neither load a project nor perform undo/redo - if (!this->isRestoring() && !this->getDocument()->isPerformingTransaction()) { + if (!this->isRestoring() + && this->getDocument() + && !this->getDocument()->isPerformingTransaction()) { if (prop == &BaseFeature) { FeatureBase* bf = nullptr; auto first = Group.getValues().empty() ? nullptr : Group.getValues().front(); @@ -523,3 +525,12 @@ App::DocumentObject *Body::getSubObject(const char *subname, *pmat *= Placement.getValue().toMatrix(); return const_cast(this); } + +void Body::onDocumentRestored() +{ + for(auto obj : Group.getValues()) { + if(obj->isDerivedFrom(PartDesign::Feature::getClassTypeId())) + static_cast(obj)->_Body.setValue(this); + } + DocumentObject::onDocumentRestored(); +} diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 7dd32ce75a..5cbd717f53 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -61,9 +61,6 @@ public: } //@} - /// Return the previous feature - App::DocumentObject* getPrevFeature(App::DocumentObject *start = NULL) const; - /** * Add the feature into the body at the current insert point. * The insertion poin is the before next solid after the Tip feature @@ -128,12 +125,6 @@ public: showTip = enable; } -protected: - virtual void onSettingDocument() override; - - /// Adjusts the first solid's feature's base on BaseFeature getting set - virtual void onChanged (const App::Property* prop) override; - /** * Return the solid feature before the given feature, or before the Tip feature * That is, sketches and datum features are skipped @@ -146,11 +137,19 @@ protected: */ App::DocumentObject *getNextSolidFeature(App::DocumentObject* start = NULL); +protected: + virtual void onSettingDocument() override; + + /// Adjusts the first solid's feature's base on BaseFeature getting set + virtual void onChanged (const App::Property* prop) override; + /// Creates the corresponding Origin object virtual void setupObject () override; /// Removes all planes and axis if they are still linked to the document virtual void unsetupObject () override; + virtual void onDocumentRestored() override; + private: boost::signals2::scoped_connection connection; bool showTip = false; diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index 9803f53975..4ecaf053ab 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -45,6 +45,7 @@ #include "Mod/Part/App/DatumFeature.h" #include +FC_LOG_LEVEL_INIT("PartDesign",true,true) namespace PartDesign { @@ -55,6 +56,8 @@ PROPERTY_SOURCE(PartDesign::Feature,Part::Feature) Feature::Feature() { ADD_PROPERTY(BaseFeature,(0)); + ADD_PROPERTY_TYPE(_Body,(0),"Base",(App::PropertyType)( + App::Prop_ReadOnly|App::Prop_Hidden|App::Prop_Output|App::Prop_Transient),0); Placement.setStatus(App::Property::Hidden, true); BaseFeature.setStatus(App::Property::Hidden, true); } @@ -136,7 +139,9 @@ Part::Feature* Feature::getBaseObject(bool silent) const { const TopoDS_Shape& Feature::getBaseShape() const { const Part::Feature* BaseObject = getBaseObject(); - if (BaseObject->isDerivedFrom(PartDesign::ShapeBinder::getClassTypeId())) { + if (BaseObject->isDerivedFrom(PartDesign::ShapeBinder::getClassTypeId())|| + BaseObject->isDerivedFrom(PartDesign::SubShapeBinder::getClassTypeId())) + { throw Base::ValueError("Base shape of shape binder cannot be used"); } @@ -201,7 +206,11 @@ TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj) return builder.Shape(); } -Body* Feature::getFeatureBody() { +Body* Feature::getFeatureBody() const { + + auto body = Base::freecad_dynamic_cast(_Body.getValue()); + if(body) + return body; auto list = getInList(); for (auto in : list) { diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index ce393fbb2b..cccb5de692 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -35,6 +35,8 @@ class gp_Pln; namespace PartDesign { +typedef Part::TopoShape TopoShape; + class Body; /** PartDesign feature @@ -50,6 +52,7 @@ public: /// Base feature which this feature will be fused into or cut out of App::PropertyLink BaseFeature; + App::PropertyLinkHidden _Body; short mustExecute() const; @@ -57,7 +60,7 @@ public: static bool isDatum(const App::DocumentObject* feature); /// Returns the body the feature is in, or none - Body* getFeatureBody(); + Body* getFeatureBody() const; /** * Returns the BaseFeature property's object (if any) diff --git a/src/Mod/PartDesign/App/ShapeBinder.cpp b/src/Mod/PartDesign/App/ShapeBinder.cpp index dbb3c89c94..d3eabb5979 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.cpp +++ b/src/Mod/PartDesign/App/ShapeBinder.cpp @@ -32,11 +32,17 @@ # include #endif +#include + +#include +#include +#include #include "ShapeBinder.h" #include #include #include #include +FC_LOG_LEVEL_INIT("PartDesign",true,true); #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -261,3 +267,348 @@ void ShapeBinder::slotChangedObject(const App::DocumentObject& Obj, const App::P } } } + +// ============================================================================ + +PROPERTY_SOURCE(PartDesign::SubShapeBinder, Part::Feature) + +SubShapeBinder::SubShapeBinder() +{ + ADD_PROPERTY_TYPE(Support, (0), "",(App::PropertyType)(App::Prop_Hidden|App::Prop_None), + "Support of the geometry"); + Support.setStatus(App::Property::Immutable,true); + ADD_PROPERTY_TYPE(Fuse, (false), "Base",App::Prop_None,"Fused linked solid shapes"); + ADD_PROPERTY_TYPE(MakeFace, (true), "Base",App::Prop_None,"Create face for linked wires"); + ADD_PROPERTY_TYPE(ClaimChildren, (false), "Base",App::Prop_Output,"Claim linked object as children"); + ADD_PROPERTY_TYPE(Relative, (true), "Base",App::Prop_None,"Enable relative sub-object linking"); + ADD_PROPERTY_TYPE(BindMode, ((long)0), "Base", App::Prop_None, "Binding mode"); + ADD_PROPERTY_TYPE(PartialLoad, (false), "Base", App::Prop_None, "Enable partial loading"); + PartialLoad.setStatus(App::Property::PartialTrigger,true); + static const char *BindModeEnum[] = {"Synchronized", "Frozen", "Detached", 0}; + BindMode.setEnums(BindModeEnum); + + ADD_PROPERTY_TYPE(Context, (0), "Base", App::Prop_Hidden, "Enable partial loading"); + Context.setScope(App::LinkScope::Hidden); + + ADD_PROPERTY_TYPE(_Version,(0),"Base",(App::PropertyType)( + App::Prop_Hidden|App::Prop_ReadOnly), ""); +} + +void SubShapeBinder::setupObject() { + _Version.setValue(1); + checkPropertyStatus(); +} + +void SubShapeBinder::update() { + Part::TopoShape result; + std::vector shapes; + + std::string errMsg; + auto parent = Context.getValue(); + std::string parentSub = Context.getSubName(false); + if(!Relative.getValue()) + parent = 0; + else { + if(parent && parent->getSubObject(parentSub.c_str())==this) { + auto parents = parent->getParents(); + if(parents.size()) { + parent = parents.begin()->first; + parentSub = parents.begin()->second + parentSub; + } + } else + parent = 0; + if(!parent && parentSub.empty()) { + auto parents = getParents(); + if(parents.size()) { + parent = parents.begin()->first; + parentSub = parents.begin()->second; + } + } + if(parent && (parent!=Context.getValue() || parentSub!=Context.getSubName(false))) + Context.setValue(parent,parentSub.c_str()); + } + bool first = false; + std::map mats; + for(auto &l : Support.getSubListValues()) { + auto obj = l.getValue(); + if(!obj || !obj->getNameInDocument()) + continue; + auto res = mats.emplace(obj,Base::Matrix4D()); + if(parent && res.second) { + std::string resolvedSub = parentSub; + std::string linkSub; + auto link = obj; + auto resolved = parent->resolveRelativeLink(resolvedSub,link,linkSub); + if(!resolved) { + if(!link) { + FC_WARN(getFullName() << " cannot resolve relative link of " + << parent->getFullName() << '.' << parentSub + << " -> " << obj->getFullName()); + } + }else{ + Base::Matrix4D mat; + auto sobj = resolved->getSubObject(resolvedSub.c_str(),0,&mat); + if(sobj!=this) { + FC_LOG(getFullName() << " skip invalid parent " << resolved->getFullName() + << '.' << resolvedSub); + }else if(_Version.getValue()==0) { + // For existing legacy SubShapeBinder, we use its Placement + // to store the position adjustment of the first Support + if(first) { + auto pla = Placement.getValue()*Base::Placement(mat).inverse(); + Placement.setValue(pla); + first = false; + } else { + // The remaining support will cancel the Placement + mat.inverse(); + res.first->second = mat; + } + }else{ + // For newer SubShapeBinder, the Placement property is free + // to use by the user to add additional offset to the + // binding object + mat.inverse(); + res.first->second = Placement.getValue().toMatrix()*mat; + } + } + } + const auto &subvals = l.getSubValues(); + std::set subs(subvals.begin(),subvals.end()); + static std::string none(""); + if(subs.empty()) + subs.insert(none); + else if(subs.size()>1) + subs.erase(none); + for(const auto &sub : subs) { + try { + auto shape = Part::Feature::getTopoShape(obj,sub.c_str(),true); + if(!shape.isNull()) { + shape = shape.makETransform(res.first->second); + // if(shape.Hasher + // && shape.getElementMapSize() + // && shape.Hasher != getDocument()->getStringHasher()) + // { + // shape.reTagElementMap(getID(), + // getDocument()->getStringHasher(),TOPOP_SHAPEBINDER); + // } + shapes.push_back(shape); + } + } catch(Base::Exception &e) { + e.ReportException(); + FC_ERR(getFullName() << " failed to obtain shape from " + << obj->getFullName() << '.' << sub); + if(errMsg.empty()) { + std::ostringstream ss; + ss << "Failed to obtain shape " << + obj->getFullName() << '.' + << Data::ComplexGeoData::oldElementName(sub.c_str()); + errMsg = ss.str(); + } + } + } + } + if(errMsg.size()) + FC_THROWM(Base::RuntimeError, errMsg); + + if(shapes.size()==_Cache.size()) { + bool hit = true; + for(size_t i=0;i solids; + for(auto &s : _Cache) { + if(s.shapeType(true) == TopAbs_SOLID) + solids.push_back(s.getShape()); + } + if(solids.size()) { + result.fuse(solids); + result = result.makERefine(); + fused = true; + } + } + + if(!fused && MakeFace.getValue() && + !result.hasSubShape(TopAbs_FACE) && + result.hasSubShape(TopAbs_EDGE)) + { + result = result.makEWires(); + try { + result = result.makEFace(0); + }catch(...){} + } + + Shape.setValue(result); +} + +void SubShapeBinder::slotRecomputedObject(const App::DocumentObject& Obj) { + if(Context.getValue() == &Obj + && !this->testStatus(App::ObjectStatus::Recompute2)) + { + update(); + } +} + +App::DocumentObjectExecReturn* SubShapeBinder::execute(void) { + if(BindMode.getValue()==0) + update(); + return inherited::execute(); +} + +void SubShapeBinder::onDocumentRestored() { + if(Shape.testStatus(App::Property::Transient)) + update(); + inherited::onDocumentRestored(); +} + +void SubShapeBinder::onChanged(const App::Property *prop) { + if(prop == &Context || prop == &Relative) { + if(!Context.getValue() || !Relative.getValue()) { + connRecomputedObj.disconnect(); + } else if(contextDoc != Context.getValue()->getDocument() + || !connRecomputedObj.connected()) + { + contextDoc = Context.getValue()->getDocument(); + connRecomputedObj = contextDoc->signalRecomputedObject.connect( + boost::bind(&SubShapeBinder::slotRecomputedObject, this, _1)); + } + }else if(!isRestoring()) { + if(prop == &Support) { + if(Support.getSubListValues().size()) { + update(); + if(BindMode.getValue() == 2) + Support.setValue(0); + } + }else if(prop == &BindMode) { + if(BindMode.getValue() == 2) + Support.setValue(0); + else if(BindMode.getValue() == 0) + update(); + checkPropertyStatus(); + }else if(prop == &PartialLoad) { + checkPropertyStatus(); + } + } + inherited::onChanged(prop); +} + +void SubShapeBinder::checkPropertyStatus() { + Support.setAllowPartial(PartialLoad.getValue()); + + // Make Shape transient can reduce some file size, and maybe reduce file + // loading time as well. But there maybe complication arise when doing + // TopoShape version upgrade. So we DO NOT set trasient at the moment. + // + // Shape.setStatus(App::Property::Transient, !PartialLoad.getValue() && BindMode.getValue()==0); +} + +void SubShapeBinder::setLinks(std::map >&&values, bool reset) +{ + if(values.empty()) { + if(reset) { + Support.setValue(0); + Shape.setValue(Part::TopoShape()); + } + return; + } + auto inSet = getInListEx(true); + inSet.insert(this); + + for(auto &v : values) { + if(!v.first || !v.first->getNameInDocument()) + FC_THROWM(Base::ValueError,"Invalid document object"); + if(inSet.find(v.first)!=inSet.end()) + FC_THROWM(Base::ValueError, "Cyclic referece to " << v.first->getFullName()); + + if(v.second.empty()) { + v.second.push_back(""); + continue; + } + + std::vector wholeSubs; + for(auto &sub : v.second) { + if(sub.empty()) { + wholeSubs.clear(); + v.second.resize(1); + v.second[0].clear(); + break; + }else if(sub[sub.size()-1] == '.') + wholeSubs.push_back(sub); + } + for(auto &whole : wholeSubs) { + for(auto it=v.second.begin();it!=v.second.end();) { + auto &sub = *it; + if(!boost::starts_with(sub,whole) || sub.size()==whole.size()) + ++it; + else { + FC_LOG("Remove subname " << sub <<" because of whole selection " << whole); + it = v.second.erase(it); + } + } + } + } + + if(!reset) { + for(auto &link : Support.getSubListValues()) { + auto subs = link.getSubValues(); + auto &s = values[link.getValue()]; + if(s.empty()) { + s = std::move(subs); + continue; + }else if(subs.empty() || s[0].empty()) + continue; + + for(auto &sub : s) { + for(auto it=subs.begin();it!=subs.end();) { + if(sub[sub.size()-1] == '.') { + if(boost::starts_with(*it,sub)) { + FC_LOG("Remove subname " << *it <<" because of whole selection " << sub); + it = subs.erase(it); + } else + ++it; + }else if(it->empty() + || (it->back()=='.' && boost::starts_with(sub,*it))) + { + FC_LOG("Remove whole subname " << *it <<" because of " << sub); + it = subs.erase(it); + } else + ++it; + } + } + subs.insert(subs.end(),s.begin(),s.end()); + s = std::move(subs); + } + } + Support.setValues(std::move(values)); +} + +void SubShapeBinder::handleChangedPropertyType( + Base::XMLReader &reader, const char * TypeName, App::Property * prop) +{ + if(prop == &Support) { + Support.upgrade(reader,TypeName); + return; + } + inherited::handleChangedPropertyType(reader,TypeName,prop); +} + diff --git a/src/Mod/PartDesign/App/ShapeBinder.h b/src/Mod/PartDesign/App/ShapeBinder.h index 2ef74fa63e..23d4993770 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.h +++ b/src/Mod/PartDesign/App/ShapeBinder.h @@ -71,6 +71,57 @@ private: Connection connectDocumentChangedObject; }; +class PartDesignExport SubShapeBinder : public Part::Feature { + PROPERTY_HEADER(PartDesign::SubShapeBinder); +public: + typedef Part::Feature inherited; + + SubShapeBinder(); + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderSubShapeBinder"; + } + + void setLinks(std::map > &&values, bool reset=false); + + App::PropertyXLinkSubList Support; + App::PropertyBool ClaimChildren; + App::PropertyBool Relative; + App::PropertyBool Fuse; + App::PropertyBool MakeFace; + App::PropertyEnumeration BindMode; + App::PropertyBool PartialLoad; + App::PropertyXLink Context; + App::PropertyInteger _Version; + + void update(); + + virtual int canLoadPartial() const override { + return PartialLoad.getValue()?1:0; + } + + virtual bool canLinkProperties() const {return false;} + +protected: + virtual App::DocumentObjectExecReturn* execute(void) override; + virtual void onChanged(const App::Property *prop) override; + + virtual void handleChangedPropertyType( + Base::XMLReader &reader, const char * TypeName, App::Property * prop) override; + + virtual void onDocumentRestored() override; + virtual void setupObject() override; + + void checkPropertyStatus(); + + void slotRecomputedObject(const App::DocumentObject& Obj); + + typedef boost::signals2::scoped_connection Connection; + Connection connRecomputedObj; + App::Document *contextDoc=0; + + std::vector _Cache; +}; + } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index 7fcb2d0d06..880ffddefb 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -150,6 +150,7 @@ PyMOD_INIT_FUNC(PartDesignGui) PartDesignGui::ViewProviderDatumPlane ::init(); PartDesignGui::ViewProviderDatumCoordinateSystem::init(); PartDesignGui::ViewProviderShapeBinder ::init(); + PartDesignGui::ViewProviderSubShapeBinder::init(); PartDesignGui::ViewProviderBoolean ::init(); PartDesignGui::ViewProviderAddSub ::init(); PartDesignGui::ViewProviderPrimitive ::init(); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 674dc9bce0..50f53f9584 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -71,6 +71,8 @@ // TODO Remove this header after fixing code so it won;t be needed here (2015-10-20, Fat-Zer) #include "ui_DlgReference.h" +FC_LOG_LEVEL_INIT("PartDesign",true,true); + using namespace std; using namespace Attacher; @@ -105,38 +107,40 @@ void UnifiedDatumCommand(Gui::Command &cmd, Base::Type type, std::string name) if (bEditSelected) { std::string tmp = std::string("Edit ")+name; cmd.openCommand(tmp.c_str()); - cmd.doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s')",support.getValue()->getNameInDocument()); + PartDesignGui::setEdit(support.getValue(),pcActiveBody); } else if (pcActiveBody) { // TODO Check how this will work outside of a body (2015-10-20, Fat-Zer) - std::string FeatName = cmd.getUniqueObjectName(name.c_str()); + std::string FeatName = cmd.getUniqueObjectName(name.c_str(), pcActiveBody); std::string tmp = std::string("Create ")+name; cmd.openCommand(tmp.c_str()); - cmd.doCommand(Gui::Command::Doc,"App.activeDocument().%s.newObject('%s','%s')", pcActiveBody->getNameInDocument(), - fullTypeName.c_str(),FeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('" << fullTypeName << "','" << FeatName << "')"); // remove the body from links in case it's selected as // otherwise a cyclic dependency will be created support.removeValue(pcActiveBody); + auto Feat = pcActiveBody->getDocument()->getObject(FeatName.c_str()); + if(!Feat) return; + //test if current selection fits a mode. if (support.getSize() > 0) { - Part::AttachExtension* pcDatum = cmd.getDocument()->getObject(FeatName.c_str())->getExtensionByType(); + Part::AttachExtension* pcDatum = Feat->getExtensionByType(); pcDatum->attacher().references.Paste(support); SuggestResult sugr; pcDatum->attacher().suggestMapModes(sugr); if (sugr.message == Attacher::SuggestResult::srOK) { //fits some mode. Populate support property. - cmd.doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),support.getPyReprString().c_str()); - cmd.doCommand(Gui::Command::Doc,"App.activeDocument().%s.MapMode = '%s'",FeatName.c_str(),AttachEngine::getModeName(sugr.bestFitMode).c_str()); + FCMD_OBJ_CMD(Feat,"Support = " << support.getPyReprString()); + FCMD_OBJ_CMD(Feat,"MapMode = '" << AttachEngine::getModeName(sugr.bestFitMode) << "'"); } else { QMessageBox::information(Gui::getMainWindow(),QObject::tr("Invalid selection"), QObject::tr("There are no attachment modes that fit selected objects. Select something else.")); } } cmd.doCommand(Gui::Command::Doc,"App.activeDocument().recompute()"); // recompute the feature based on its references - cmd.doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + PartDesignGui::setEdit(Feat,pcActiveBody); } else { QMessageBox::warning(Gui::getMainWindow(),QObject::tr("Error"), QObject::tr("There is no active body. Please make a body active before inserting a datum entity.")); } @@ -293,30 +297,30 @@ void CmdPartDesignShapeBinder::activated(int iMsg) if (bEditSelected) { openCommand("Edit ShapeBinder"); - doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s')", - support.getValue()->getNameInDocument()); + PartDesignGui::setEdit(support.getValue()); } else { PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true); if (pcActiveBody == 0) return; - std::string FeatName = getUniqueObjectName("ShapeBinder"); + std::string FeatName = getUniqueObjectName("ShapeBinder",pcActiveBody); openCommand("Create ShapeBinder"); - doCommand(Gui::Command::Doc,"App.activeDocument().%s.newObject('%s','%s')", - pcActiveBody->getNameInDocument(), "PartDesign::ShapeBinder",FeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::ShapeBinder','" << FeatName << "')"); // remove the body from links in case it's selected as // otherwise a cyclic dependency will be created support.removeValue(pcActiveBody); + auto Feat = pcActiveBody->getObject(FeatName.c_str()); + if(!Feat) return; + //test if current selection fits a mode. if (support.getSize() > 0) { - doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = %s", - FeatName.c_str(), support.getPyReprString().c_str()); + FCMD_OBJ_CMD(Feat,"Support = " << support.getPyReprString()); } updateActive(); - doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + PartDesignGui::setEdit(Feat,pcActiveBody); } // TODO do a proper error processing (2015-09-11, Fat-Zer) } @@ -326,6 +330,122 @@ bool CmdPartDesignShapeBinder::isActive(void) return hasActiveDocument (); } +//=========================================================================== +// PartDesign_SubShapeBinder +//=========================================================================== + +DEF_STD_CMD_A(CmdPartDesignSubShapeBinder); + +CmdPartDesignSubShapeBinder::CmdPartDesignSubShapeBinder() + :Command("PartDesign_SubShapeBinder") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create a sub-object(s) shape binder"); + sToolTipText = QT_TR_NOOP("Create a sub-object(s) shape binder"); + sWhatsThis = "PartDesign_SubShapeBinder"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_SubShapeBinder"; +} + +void CmdPartDesignSubShapeBinder::activated(int iMsg) +{ + Q_UNUSED(iMsg); + + PartDesign::SubShapeBinder *binder = 0; + App::DocumentObject *binderParent = 0; + std::string binderSub; + std::map > values; + for(auto &sel : Gui::Selection().getCompleteSelection(0)) { + if(!sel.pObject) continue; + if(!binder) { + const char *dot = sel.SubName?strrchr(sel.SubName,'.'):0; + if(!dot || dot[1]==0) { + auto sobj = sel.pObject->getSubObject(sel.SubName); + if(!sobj) continue; + binder = dynamic_cast(sobj->getLinkedObject(true)); + if(binder) { + binderParent = sel.pObject; + if(sel.SubName) + binderSub = sel.SubName; + continue; + } + } + } + auto &subs = values[sel.pObject]; + if(sel.SubName && sel.SubName[0]) + subs.emplace_back(sel.SubName); + } + + PartDesign::Body *pcActiveBody = 0; + std::string FeatName; + if(!binder) { + pcActiveBody = PartDesignGui::getBody(false,true,true,&binderParent,&binderSub); + FeatName = getUniqueObjectName("Binder",pcActiveBody); + } + Base::Matrix4D mat; + if(values.size()==1 && binderParent && binderParent!=binder) { + App::DocumentObject *obj = values.begin()->first; + auto subs = values.begin()->second; + App::DocumentObject *sobj = 0; + App::DocumentObject *parent = 0; + std::string parentSub = binderSub; + for(auto &sub : subs) { + auto link = obj; + auto linkSub = binderSub; + auto res = binderParent->resolveRelativeLink(linkSub,link,sub); + if(!sobj) { + sobj = link; + parent = res; + parentSub = linkSub; + }else if(sobj!=link || parent!=res) { + QMessageBox::critical(Gui::getMainWindow(), QObject::tr("SubShapeBinder"), + QObject::tr("Cannot link to more than one object")); + return; + } + } + if(sobj) { + values.clear(); + values[sobj] = std::move(subs); + } + if(parent) { + binderParent = parent; + binderSub = parentSub; + binderParent->getSubObject(binderSub.c_str(),0,&mat); + } + } + + try { + if (binder) + openCommand("Change SubShapeBinder"); + else { + openCommand("Create SubShapeBinder"); + if(pcActiveBody) { + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::SubShapeBinder','" << FeatName << "')"); + binder = dynamic_cast(pcActiveBody->getObject(FeatName.c_str())); + } else { + doCommand(Command::Doc, + "App.ActiveDocument.addObject('PartDesign::SubShapeBinder','%s')",FeatName.c_str()); + binder = dynamic_cast( + App::GetApplication().getActiveDocument()->getObject(FeatName.c_str())); + } + if(!binder) return; + } + binder->setLinks(std::move(values)); + updateActive(); + commitCommand(); + }catch(Base::Exception &e) { + e.ReportException(); + QMessageBox::critical(Gui::getMainWindow(), + QObject::tr("Sub-Shape Binder"), QString::fromUtf8(e.what())); + abortCommand(); + } +} + +bool CmdPartDesignSubShapeBinder::isActive(void) { + return hasActiveDocument(); +} + //=========================================================================== // PartDesign_Clone //=========================================================================== @@ -347,8 +467,6 @@ CmdPartDesignClone::CmdPartDesignClone() void CmdPartDesignClone::activated(int iMsg) { Q_UNUSED(iMsg); - std::string BodyName = getUniqueObjectName("Body"); - std::string FeatName = getUniqueObjectName("Clone"); std::vector objs = getSelection().getObjectsOfType (Part::Feature::getClassTypeId()); if (objs.size() == 1) { @@ -357,26 +475,25 @@ void CmdPartDesignClone::activated(int iMsg) // This also fixes bug #3447 because the clone is a PD feature and thus // requires a body where it is part of. openCommand("Create Clone"); - doCommand(Command::Doc,"App.ActiveDocument.addObject('PartDesign::Body','%s')", - BodyName.c_str()); - doCommand(Command::Doc,"App.ActiveDocument.addObject('PartDesign::FeatureBase','%s')", - FeatName.c_str()); - doCommand(Command::Doc,"App.ActiveDocument.ActiveObject.BaseFeature = App.ActiveDocument.%s", - objs.front()->getNameInDocument()); - doCommand(Command::Doc,"App.ActiveDocument.ActiveObject.Placement = App.ActiveDocument.%s.Placement", - objs.front()->getNameInDocument()); - doCommand(Command::Doc,"App.ActiveDocument.ActiveObject.setEditorMode('Placement',0)"); - doCommand(Command::Doc,"App.ActiveDocument.%s.Group = [App.ActiveDocument.%s]", - BodyName.c_str(), FeatName.c_str()); + auto obj = objs[0]; + std::string FeatName = getUniqueObjectName("Clone",obj); + std::string BodyName = getUniqueObjectName("Body",obj); + FCMD_OBJ_DOC_CMD(obj,"addObject('PartDesign::Body','" << BodyName << "')"); + FCMD_OBJ_DOC_CMD(obj,"addObject('PartDesign::FeatureBase','" << FeatName << "')"); + auto Feat = obj->getDocument()->getObject(FeatName.c_str()); + auto objCmd = getObjectCmd(obj); + FCMD_OBJ_CMD(Feat,"BaseFeature = " << objCmd); + FCMD_OBJ_CMD(Feat,"Placement = " << objCmd << ".Placement"); + FCMD_OBJ_CMD(Feat,"setEditorMode('Placement',0)"); + + auto Body = obj->getDocument()->getObject(BodyName.c_str()); + FCMD_OBJ_CMD(Body,"Group = [" << getObjectCmd(Feat) << "]"); // Set the tip of the body - doCommand(Command::Doc,"App.ActiveDocument.%s.Tip = App.ActiveDocument.%s", - BodyName.c_str(), FeatName.c_str()); + FCMD_OBJ_CMD(Body,"Tip = " << getObjectCmd(Feat)); updateActive(); - doCommand(Command::Doc,"App.ActiveDocument.ActiveObject.ViewObject.DiffuseColor = App.ActiveDocument.%s.ViewObject.DiffuseColor", - objs.front()->getNameInDocument()); - doCommand(Command::Doc,"App.ActiveDocument.ActiveObject.ViewObject.Transparency = App.ActiveDocument.%s.ViewObject.Transparency", - objs.front()->getNameInDocument()); + copyVisual(Feat, "Transparency", obj); + copyVisual(Feat, "DisplayMode", obj); commitCommand(); } } @@ -446,8 +563,8 @@ void CmdPartDesignNewSketch::activated(int iMsg) if (SketchFilter.match()) { Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); - openCommand("Edit Sketch"); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); + // openCommand("Edit Sketch"); + PartDesignGui::setEdit(Sketch,pcActiveBody); } else if ( FaceFilter.match() || PlaneFilter.match() ) { if (!pcActiveBody) { @@ -530,7 +647,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) } else { obj = static_cast(PlaneFilter.Result[0][0].getObject()); - supportString = std::string("(App.activeDocument().") + obj->getNameInDocument() + ", '')"; + supportString = getObjectCmd(obj,"(",",'')"); } @@ -562,26 +679,26 @@ void CmdPartDesignNewSketch::activated(int iMsg) else if (pcActivePart) pcActivePart->addObject(copy); - if (PlaneFilter.match()) - supportString = std::string("(App.activeDocument().") + copy->getNameInDocument() + ", '')"; + if(PlaneFilter.match()) + supportString = getObjectCmd(copy,"(",",'')"); else //it is ensured that only a single face is selected, hence it must always be Face1 of the shapebinder - supportString = std::string("(App.activeDocument().") + copy->getNameInDocument() + ", 'Face1')"; - + supportString = getObjectCmd(copy,"(",",'Face1')"); commitCommand(); } } } // create Sketch on Face or Plane - std::string FeatName = getUniqueObjectName("Sketch"); + std::string FeatName = getUniqueObjectName("Sketch",pcActiveBody); openCommand("Create a Sketch on Face"); - doCommand(Doc,"App.activeDocument().%s.newObject('Sketcher::SketchObject','%s')",pcActiveBody->getNameInDocument(), FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - doCommand(Doc,"App.activeDocument().%s.MapMode = '%s'",FeatName.c_str(),Attacher::AttachEngine::getModeName(Attacher::mmFlatFace).c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('Sketcher::SketchObject','" << FeatName << "')"); + auto Feat = pcActiveBody->getDocument()->getObject(FeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Support = " << supportString); + FCMD_OBJ_CMD(Feat,"MapMode = '" << Attacher::AttachEngine::getModeName(Attacher::mmFlatFace)<<"'"); updateActive(); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + PartDesignGui::setEdit(Feat,pcActiveBody); } else { App::GeoFeatureGroupExtension *geoGroup( nullptr ); @@ -674,6 +791,8 @@ void CmdPartDesignNewSketch::activated(int iMsg) // Collect also shape binders consisting of a single planar face auto shapeBinders( getDocument()->getObjectsOfType(PartDesign::ShapeBinder::getClassTypeId()) ); + auto binders( getDocument()->getObjectsOfType(PartDesign::SubShapeBinder::getClassTypeId()) ); + shapeBinders.insert(shapeBinders.end(),binders.begin(),binders.end()); for (auto binder : shapeBinders) { // Check whether this plane belongs to the active body if (pcActiveBody->hasObject(binder)) { @@ -705,15 +824,15 @@ void CmdPartDesignNewSketch::activated(int iMsg) if (features.empty()) return; App::Plane* plane = static_cast(features.front()); - std::string FeatName = getUniqueObjectName("Sketch"); - std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + - ", [''])"; + std::string FeatName = getUniqueObjectName("Sketch",pcActiveBody); + std::string supportString = getObjectCmd(plane,"(",",[''])"); - Gui::Command::doCommand(Doc,"App.activeDocument().%s.newObject('Sketcher::SketchObject','%s')", pcActiveBody->getNameInDocument(), FeatName.c_str()); - Gui::Command::doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - Gui::Command::doCommand(Doc,"App.activeDocument().%s.MapMode = '%s'",FeatName.c_str(),Attacher::AttachEngine::getModeName(Attacher::mmFlatFace).c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('Sketcher::SketchObject','" << FeatName << "')"); + auto Feat = pcActiveBody->getDocument()->getObject(FeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Support = " << supportString); + FCMD_OBJ_CMD(Feat,"MapMode = '" << Attacher::AttachEngine::getModeName(Attacher::mmFlatFace)<<"'"); Gui::Command::updateActive(); // Make sure the Support's Placement property is updated - Gui::Command::doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + PartDesignGui::setEdit(Feat,pcActiveBody); }; // Called by dialog for "Cancel", or "OK" if accepter returns false @@ -773,7 +892,7 @@ bool CmdPartDesignNewSketch::isActive(void) // Common utility functions for all features creating solids //=========================================================================== -void finishFeature(const Gui::Command* cmd, const std::string& FeatName, +void finishFeature(const Gui::Command* cmd, App::DocumentObject *Feat, App::DocumentObject* prevSolidFeature = nullptr, const bool hidePrevSolid = true, const bool updateDocument = true) @@ -787,23 +906,30 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName, } if (hidePrevSolid && prevSolidFeature) - cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + FCMD_OBJ_HIDE(prevSolidFeature); if (updateDocument) cmd->updateActive(); + auto base = dynamic_cast(Feat); + if(base) + base = dynamic_cast(base->getBaseObject(true)); + App::DocumentObject *obj = base; + if(!obj) + obj = pcActiveBody; + // Do this before calling setEdit to avoid to override the 'Shape preview' mode (#0003621) - if (pcActiveBody) { - cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); - cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); - cmd->copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); - cmd->copyVisual(FeatName.c_str(), "Transparency", pcActiveBody->getNameInDocument()); - cmd->copyVisual(FeatName.c_str(), "DisplayMode", pcActiveBody->getNameInDocument()); + if (obj) { + cmd->copyVisual(Feat, "ShapeColor", obj); + cmd->copyVisual(Feat, "LineColor", obj); + cmd->copyVisual(Feat, "PointColor", obj); + cmd->copyVisual(Feat, "Transparency", obj); + cmd->copyVisual(Feat, "DisplayMode", obj); } // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer - cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); + PartDesignGui::setEdit(Feat,pcActiveBody); cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); //cmd->doCommand(cmd->Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); } @@ -902,10 +1028,10 @@ unsigned validateSketches(std::vector& sketches, return freeSketches; } -void prepareProfileBased(Gui::Command* cmd, const std::string& which, - boost::function func) +void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, const std::string& which, + boost::function func) { - auto base_worker = [which, cmd, func](App::DocumentObject* feature, std::string sub) { + auto base_worker = [=](App::DocumentObject* feature, std::string sub) { if (!feature || !feature->isDerivedFrom(Part::Feature::getClassTypeId())) return; @@ -916,22 +1042,22 @@ void prepareProfileBased(Gui::Command* cmd, const std::string& which, if (feature->isTouched()) feature->recomputeFeature(); - std::string FeatName = cmd->getUniqueObjectName(which.c_str()); + std::string FeatName = cmd->getUniqueObjectName(which.c_str(),pcActiveBody); Gui::Command::openCommand((std::string("Make ") + which).c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.newObject(\"PartDesign::%s\",\"%s\")", - PartDesignGui::getBody(false)->getNameInDocument(), which.c_str(), FeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::" << which << "','" << FeatName << "')"); + auto Feat = pcActiveBody->getDocument()->getObject(FeatName.c_str()); + + auto objCmd = Gui::Command::getObjectCmd(feature); if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId())) { - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Profile = App.activeDocument().%s", - FeatName.c_str(), feature->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"Profile = " << objCmd); } else { - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Profile = (App.activeDocument().%s, [\"%s\"])", - FeatName.c_str(), feature->getNameInDocument(), sub.c_str()); - } + FCMD_OBJ_CMD(Feat,"Profile = (" << objCmd << ", ['" << sub << "'])"); + } - func(static_cast(feature), FeatName); + func(static_cast(feature), Feat); }; //if a profile is selected we can make our life easy and fast @@ -985,7 +1111,6 @@ void prepareProfileBased(Gui::Command* cmd, const std::string& which, ) != status.end(); // TODO Clean this up (2015-10-20, Fat-Zer) - auto* pcActiveBody = PartDesignGui::getBody(false); if (pcActiveBody && !bNoSketchWasSelected && extReference) { // Hint: In an older version the function expected the body to be inside @@ -1061,11 +1186,11 @@ void prepareProfileBased(Gui::Command* cmd, const std::string& which, } } -void finishProfileBased(const Gui::Command* cmd, const Part::Feature* sketch, const std::string& FeatName) +void finishProfileBased(const Gui::Command* cmd, const Part::Feature* sketch, App::DocumentObject *Feat) { if(sketch && sketch->isDerivedFrom(Part::Part2DObject::getClassTypeId())) - cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - finishFeature(cmd, FeatName); + FCMD_OBJ_HIDE(sketch); + finishFeature(cmd, Feat); } //=========================================================================== @@ -1098,20 +1223,20 @@ void CmdPartDesignPad::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](Part::Feature* profile, std::string FeatName) { + auto worker = [cmd](Part::Feature* profile, App::DocumentObject *Feat) { - if (FeatName.empty()) return; + if (!Feat) return; // specific parameters for Pad - Gui::Command::doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Length = 10.0"); Gui::Command::updateActive(); Part::Part2DObject* sketch = dynamic_cast(profile); - finishProfileBased(cmd, sketch, FeatName); + finishProfileBased(cmd, sketch, Feat); cmd->adjustCameraPosition(); }; - prepareProfileBased(this, "Pad", worker); + prepareProfileBased(pcActiveBody, this, "Pad", worker); } bool CmdPartDesignPad::isActive(void) @@ -1149,16 +1274,16 @@ void CmdPartDesignPocket::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](Part::Feature* sketch, std::string FeatName) { + auto worker = [cmd](Part::Feature* sketch, App::DocumentObject *Feat) { - if (FeatName.empty()) return; + if (!Feat) return; - Gui::Command::doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); - finishProfileBased(cmd, sketch, FeatName); + FCMD_OBJ_CMD(Feat,"Length = 5.0"); + finishProfileBased(cmd, sketch, Feat); cmd->adjustCameraPosition(); }; - prepareProfileBased(this, "Pocket", worker); + prepareProfileBased(pcActiveBody, this, "Pocket", worker); } bool CmdPartDesignPocket::isActive(void) @@ -1196,15 +1321,15 @@ void CmdPartDesignHole::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](Part::Feature* sketch, std::string FeatName) { + auto worker = [cmd](Part::Feature* sketch, App::DocumentObject *Feat) { - if (FeatName.empty()) return; + if(!Feat) return; - finishProfileBased(cmd, sketch, FeatName); + finishProfileBased(cmd, sketch, Feat); cmd->adjustCameraPosition(); }; - prepareProfileBased(this, "Hole", worker); + prepareProfileBased(pcActiveBody, this, "Hole", worker); } bool CmdPartDesignHole::isActive(void) @@ -1242,29 +1367,27 @@ void CmdPartDesignRevolution::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd, &pcActiveBody](Part::Feature* sketch, std::string FeatName) { + auto worker = [cmd, &pcActiveBody](Part::Feature* sketch, App::DocumentObject *Feat) { - if (FeatName.empty()) return; + if (!Feat) return; if (sketch->isDerivedFrom(Part::Part2DObject::getClassTypeId())) { - Gui::Command::doCommand(Doc, "App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", - FeatName.c_str(), sketch->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"ReferenceAxis = (" << getObjectCmd(sketch) << ",['V_Axis'])"); } else { - Gui::Command::doCommand(Doc, "App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,[\"\"])", - FeatName.c_str(), pcActiveBody->getOrigin()->getY()->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"ReferenceAxis = (" << getObjectCmd(pcActiveBody->getOrigin()->getY()) << ",[''])"); } - Gui::Command::doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); - PartDesign::Revolution* pcRevolution = static_cast(cmd->getDocument()->getObject(FeatName.c_str())); + FCMD_OBJ_CMD(Feat,"Angle = 360.0"); + PartDesign::Revolution* pcRevolution = dynamic_cast(Feat); if (pcRevolution && pcRevolution->suggestReversed()) - Gui::Command::doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Reversed = 1"); - finishProfileBased(cmd, sketch, FeatName); + finishProfileBased(cmd, sketch, Feat); cmd->adjustCameraPosition(); }; - prepareProfileBased(this, "Revolution", worker); + prepareProfileBased(pcActiveBody, this, "Revolution", worker); } bool CmdPartDesignRevolution::isActive(void) @@ -1302,37 +1425,35 @@ void CmdPartDesignGroove::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd, &pcActiveBody](Part::Feature* sketch, std::string FeatName) { + auto worker = [cmd, &pcActiveBody](Part::Feature* sketch, App::DocumentObject *Feat) { - if (FeatName.empty()) return; + if (!Feat) return; if (sketch->isDerivedFrom(Part::Part2DObject::getClassTypeId())) { - Gui::Command::doCommand(Doc, "App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", - FeatName.c_str(), sketch->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"ReferenceAxis = ("<getOrigin()->getY()->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"ReferenceAxis = ("<getOrigin()->getY())<<",[''])"); } - - Gui::Command::doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); + + FCMD_OBJ_CMD(Feat,"Angle = 360.0"); try { // This raises as exception if line is perpendicular to sketch/support face. // Here we should continue to give the user a chance to change the default values. - PartDesign::Groove* pcGroove = static_cast(cmd->getDocument()->getObject(FeatName.c_str())); + PartDesign::Groove* pcGroove = dynamic_cast(Feat); if (pcGroove && pcGroove->suggestReversed()) - Gui::Command::doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Reversed = 1"); } catch (const Base::Exception& e) { e.ReportException(); } - finishProfileBased(cmd, sketch, FeatName); + finishProfileBased(cmd, sketch, Feat); cmd->adjustCameraPosition(); }; - prepareProfileBased(this, "Groove", worker); + prepareProfileBased(pcActiveBody, this, "Groove", worker); } bool CmdPartDesignGroove::isActive(void) @@ -1370,18 +1491,18 @@ void CmdPartDesignAdditivePipe::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](Part::Feature* sketch, std::string FeatName) { + auto worker = [cmd](Part::Feature* sketch, App::DocumentObject *Feat) { - if (FeatName.empty()) return; + if (!Feat) return; // specific parameters for pipe Gui::Command::updateActive(); - finishProfileBased(cmd, sketch, FeatName); + finishProfileBased(cmd, sketch, Feat); cmd->adjustCameraPosition(); }; - prepareProfileBased(this, "AdditivePipe", worker); + prepareProfileBased(pcActiveBody, this, "AdditivePipe", worker); } bool CmdPartDesignAdditivePipe::isActive(void) @@ -1420,18 +1541,18 @@ void CmdPartDesignSubtractivePipe::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](Part::Feature* sketch, std::string FeatName) { + auto worker = [cmd](Part::Feature* sketch, App::DocumentObject *Feat) { - if (FeatName.empty()) return; + if (!Feat) return; // specific parameters for pipe Gui::Command::updateActive(); - finishProfileBased(cmd, sketch, FeatName); + finishProfileBased(cmd, sketch, Feat); cmd->adjustCameraPosition(); }; - prepareProfileBased(this, "SubtractivePipe", worker); + prepareProfileBased(pcActiveBody, this, "SubtractivePipe", worker); } bool CmdPartDesignSubtractivePipe::isActive(void) @@ -1470,18 +1591,18 @@ void CmdPartDesignAdditiveLoft::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](Part::Feature* sketch, std::string FeatName) { + auto worker = [cmd](Part::Feature* sketch, App::DocumentObject *Feat) { - if (FeatName.empty()) return; + if (!Feat) return; // specific parameters for pipe Gui::Command::updateActive(); - finishProfileBased(cmd, sketch, FeatName); + finishProfileBased(cmd, sketch, Feat); cmd->adjustCameraPosition(); }; - prepareProfileBased(this, "AdditiveLoft", worker); + prepareProfileBased(pcActiveBody, this, "AdditiveLoft", worker); } bool CmdPartDesignAdditiveLoft::isActive(void) @@ -1520,18 +1641,18 @@ void CmdPartDesignSubtractiveLoft::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](Part::Feature* sketch, std::string FeatName) { + auto worker = [cmd](Part::Feature* sketch, App::DocumentObject *Feat) { - if (FeatName.empty()) return; + if (!Feat) return; // specific parameters for pipe Gui::Command::updateActive(); - finishProfileBased(cmd, sketch, FeatName); + finishProfileBased(cmd, sketch, Feat); cmd->adjustCameraPosition(); }; - prepareProfileBased(this, "SubtractiveLoft", worker); + prepareProfileBased(pcActiveBody, this, "SubtractiveLoft", worker); } bool CmdPartDesignSubtractiveLoft::isActive(void) @@ -1606,29 +1727,23 @@ void finishDressupFeature(const Gui::Command* cmd, const std::string& which, return; } - std::string SelString; - SelString += "(App."; - SelString += "ActiveDocument"; - SelString += "."; - SelString += base->getNameInDocument(); - SelString += ",["; + std::ostringstream str; + str << '(' << Gui::Command::getObjectCmd(base) << ",["; for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ - SelString += "\""; - SelString += *it; - SelString += "\""; - if(it != --SubNames.end()) - SelString += ","; + str << "'" << *it << "',"; } - SelString += "])"; + str << "])"; - std::string FeatName = cmd->getUniqueObjectName(which.c_str()); + std::string FeatName = cmd->getUniqueObjectName(which.c_str(),base); + auto body = PartDesignGui::getBodyFor(base,false); + if(!body) return; cmd->openCommand((std::string("Make ") + which).c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.newObject(\"PartDesign::%s\",\"%s\")", - PartDesignGui::getBodyFor(base,false)->getNameInDocument(), which.c_str(), FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + FCMD_OBJ_CMD(body,"newObject('PartDesign::"<getDocument()->getObject(FeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Base = " << str.str()); cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); - finishFeature(cmd, FeatName, base); + finishFeature(cmd, Feat, base); } void makeChamferOrFillet(Gui::Command* cmd, const std::string& which) @@ -1810,10 +1925,10 @@ bool CmdPartDesignThickness::isActive(void) // Common functions for all Transformed features //=========================================================================== -void prepareTransformed(Gui::Command* cmd, const std::string& which, - boost::function)> func) +void prepareTransformed(PartDesign::Body *pcActiveBody, Gui::Command* cmd, const std::string& which, + boost::function)> func) { - std::string FeatName = cmd->getUniqueObjectName(which.c_str()); + std::string FeatName = cmd->getUniqueObjectName(which.c_str(),pcActiveBody); auto accepter = [=](std::vector features) -> bool{ @@ -1825,42 +1940,37 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, auto worker = [=](std::vector features) { std::stringstream str; - str << "App.activeDocument()." << FeatName << ".Originals = ["; + str << cmd->getObjectCmd(FeatName.c_str(),pcActiveBody->getDocument()) << ".Originals = ["; for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + str << cmd->getObjectCmd(*it) << ","; } str << "]"; - std::string bodyName = PartDesignGui::getBody(false)->getNameInDocument(); - std::string msg("Make "); msg += which; Gui::Command::openCommand(msg.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.newObject(\"PartDesign::%s\",\"%s\")", - bodyName.c_str(), which.c_str(), FeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::"<getDocument()->getObject(FeatName.c_str()); + // TODO Wjat that function supposed to do? (2015-08-05, Fat-Zer) - func(FeatName, features); + func(Feat, features); // Set the tip of the body - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", - bodyName.c_str(), FeatName.c_str()); - - // Adjust visibility to show only the tip feature - Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeDocument().show(\"%s\")", - FeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"Tip = " << Gui::Command::getObjectCmd(Feat)); Gui::Command::updateActive(); }; // Get a valid original from the user // First check selections - std::vector features = cmd->getSelection().getObjectsOfType(PartDesign::FeatureAddSub::getClassTypeId()); + std::vector features = cmd->getSelection().getObjectsOfType(PartDesign::Feature::getClassTypeId()); // Next create a list of all eligible objects if (features.size() == 0) { - features = cmd->getDocument()->getObjectsOfType(PartDesign::FeatureAddSub::getClassTypeId()); + features = cmd->getDocument()->getObjectsOfType(PartDesign::Feature::getClassTypeId()); // If there is more than one selected or eligible object, show dialog and let user pick one if (features.size() > 1) { std::vector status; @@ -1887,31 +1997,32 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, Gui::Selection().clearSelection(); Gui::Control().showDialog(new PartDesignGui::TaskDlgFeaturePick(features, status, accepter, worker)); - } else { + return; + } else if(features.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); + QObject::tr("Please create a feature first.")); return; } } - else if (features.size() > 1) { + if (features.size() > 1) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Multiple Features Selected"), - QObject::tr("Please select only one subtractive or additive feature first.")); + QObject::tr("Please select only one feature first.")); return; } else { PartDesign::Body *pcActiveBody = PartDesignGui::getBody(true); if (pcActiveBody != PartDesignGui::getBodyFor(features[0], false)) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection is not in Active Body"), - QObject::tr("Please select only one subtractive or additive feature in an active body.")); + QObject::tr("Please select only one feature in an active body.")); return; } worker(features); } } -void finishTransformed(Gui::Command* cmd, std::string& FeatName) +void finishTransformed(Gui::Command* cmd, App::DocumentObject *Feat) { - finishFeature(cmd, FeatName); + finishFeature(cmd, Feat); } //=========================================================================== @@ -1945,32 +2056,30 @@ void CmdPartDesignMirrored::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](std::string FeatName, std::vector features) { + auto worker = [cmd](App::DocumentObject *Feat, std::vector features) { if (features.empty()) - return; + return; bool direction = false; if(features.front()->isDerivedFrom(PartDesign::ProfileBased::getClassTypeId())) { Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(/* silent =*/ true); if (sketch) { - doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", - FeatName.c_str(), sketch->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"MirrorPlane = ("<(Part::BodyBase::findBodyOf(features.front())); - if(body) { - doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"\"])", FeatName.c_str(), - body->getOrigin()->getXY()->getNameInDocument()); + if(body) { + FCMD_OBJ_CMD(Feat,"MirrorPlane = ("<getOrigin()->getXY())<<", [''])"); } } - finishTransformed(cmd, FeatName); + finishTransformed(cmd, Feat); }; - prepareTransformed(this, "Mirrored", worker); + prepareTransformed(pcActiveBody, this, "Mirrored", worker); } bool CmdPartDesignMirrored::isActive(void) @@ -2009,34 +2118,32 @@ void CmdPartDesignLinearPattern::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](std::string FeatName, std::vector features) { + auto worker = [cmd](App::DocumentObject *Feat, std::vector features) { - if (features.empty()) + if (!Feat || features.empty()) return; bool direction = false; if(features.front()->isDerivedFrom(PartDesign::ProfileBased::getClassTypeId())) { Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(/* silent =*/ true); if (sketch) { - doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", - FeatName.c_str(), sketch->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"Direction = ("<(Part::BodyBase::findBodyOf(features.front())); - if(body) { - doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"\"])", FeatName.c_str(), - body->getOrigin()->getX()->getNameInDocument()); + if(body) { + FCMD_OBJ_CMD(Feat,"Direction = ("<getOrigin()->getX())<<",[''])"); } } - doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Length = 100"); + FCMD_OBJ_CMD(Feat,"Occurrences = 2"); - finishTransformed(cmd, FeatName); + finishTransformed(cmd, Feat); }; - prepareTransformed(this, "LinearPattern", worker); + prepareTransformed(pcActiveBody, this, "LinearPattern", worker); } bool CmdPartDesignLinearPattern::isActive(void) @@ -2075,35 +2182,33 @@ void CmdPartDesignPolarPattern::activated(int iMsg) return; Gui::Command* cmd = this; - auto worker = [cmd](std::string FeatName, std::vector features) { + auto worker = [cmd](App::DocumentObject *Feat, std::vector features) { - if (features.empty()) + if (!Feat || features.empty()) return; bool direction = false; if(features.front()->isDerivedFrom(PartDesign::ProfileBased::getClassTypeId())) { Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(/* silent =*/ true); if (sketch) { - doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", - FeatName.c_str(), sketch->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"Axis = ("<(Part::BodyBase::findBodyOf(features.front())); - if(body) { - doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"\"])", FeatName.c_str(), - body->getOrigin()->getZ()->getNameInDocument()); + if(body) { + FCMD_OBJ_CMD(Feat,"Axis = ("<getOrigin()->getZ())<<",[''])"); } } - doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Angle = 360"); + FCMD_OBJ_CMD(Feat,"Occurrences = 2"); - finishTransformed(cmd, FeatName); + finishTransformed(cmd, Feat); }; - prepareTransformed(this, "PolarPattern", worker); + prepareTransformed(pcActiveBody, this, "PolarPattern", worker); } bool CmdPartDesignPolarPattern::isActive(void) @@ -2131,19 +2236,28 @@ CmdPartDesignScaled::CmdPartDesignScaled() void CmdPartDesignScaled::activated(int iMsg) { Q_UNUSED(iMsg); - Gui::Command* cmd = this; - auto worker = [cmd](std::string FeatName, std::vector features) { + App::Document *doc = getDocument(); + if (!PartDesignGui::assureModernWorkflow(doc)) + return; - if (features.empty()) + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(true); + + if (!pcActiveBody) + return; + + Gui::Command* cmd = this; + auto worker = [cmd](App::DocumentObject *Feat, std::vector features) { + + if (!Feat || features.empty()) return; - doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Factor = 2"); + FCMD_OBJ_CMD(Feat,"Occurrences = 2"); - finishTransformed(cmd, FeatName); + finishTransformed(cmd, Feat); }; - prepareTransformed(this, "Scaled", worker); + prepareTransformed(pcActiveBody, this, "Scaled", worker); } bool CmdPartDesignScaled::isActive(void) @@ -2203,14 +2317,16 @@ void CmdPartDesignMultiTransform::activated(int iMsg) App::DocumentObject* prevFeature = 0; if (pcActiveBody){ oldTip = pcActiveBody->Tip.getValue(); - prevFeature = pcActiveBody->getPrevFeature(trFeat); + prevFeature = pcActiveBody->getPrevSolidFeature(trFeat); } Gui::Selection().clearSelection(); if (prevFeature != NULL) Gui::Selection().addSelection(prevFeature->getDocument()->getName(), prevFeature->getNameInDocument()); - // TODO Review this (2015-09-05, Fat-Zer) + openCommand("Convert to MultiTransform feature"); - doCommand(Gui, "FreeCADGui.runCommand('PartDesign_MoveTip')"); + + Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + rcCmdMgr.runCommandByName("PartDesign_MoveTip"); // We cannot remove the Transform feature from the body as otherwise // we will have a PartDesign feature without a body which is not allowed @@ -2220,48 +2336,48 @@ void CmdPartDesignMultiTransform::activated(int iMsg) // #0003509 #if 0 // Remove the Transformed feature from the Body - if (pcActiveBody) { - doCommand(Doc, "App.activeDocument().%s.removeObject(App.activeDocument().%s)", - pcActiveBody->getNameInDocument(), trFeat->getNameInDocument()); - } + if(pcActiveBody) + FCMD_OBJ_CMD(pcActiveBody,"removeObject("<getNameInDocument(), FeatName.c_str()); - doCommand(Doc, "App.activeDocument().%s.Originals = App.activeDocument().%s.Originals", FeatName.c_str(), trFeat->getNameInDocument()); - doCommand(Doc, "App.activeDocument().%s.Originals = []", trFeat->getNameInDocument()); - doCommand(Doc, "App.activeDocument().%s.Transformations = [App.activeDocument().%s]", FeatName.c_str(), trFeat->getNameInDocument()); + std::string FeatName = getUniqueObjectName("MultiTransform",pcActiveBody); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::MultiTransform','"<getDocument()->getObject(FeatName.c_str()); + auto objCmd = getObjectCmd(trFeat); + FCMD_OBJ_CMD(Feat,"OriginalSubs = "<getDocument()->getName(), oldTip->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + rcCmdMgr.runCommandByName("PartDesign_MoveTip"); Gui::Selection().clearSelection(); } // otherwise the insert point remains at the new MultiTransform, which is fine } else { Gui::Command* cmd = this; - auto worker = [cmd, pcActiveBody](std::string FeatName, std::vector features) { + auto worker = [cmd, pcActiveBody](App::DocumentObject *Feat, std::vector features) { - if (features.empty()) + if (!Feat || features.empty()) return; // Make sure the user isn't presented with an empty screen because no transformations are defined yet... App::DocumentObject* prevSolid = pcActiveBody->Tip.getValue(); if (prevSolid != NULL) { Part::Feature* feat = static_cast(prevSolid); - doCommand(Doc,"App.activeDocument().%s.Shape = App.activeDocument().%s.Shape", - FeatName.c_str(), feat->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"Shape = "<getNameInDocument(), FeatName.c_str()); - + std::string FeatName = getUniqueObjectName("Boolean",pcActiveBody); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::Boolean','"<getDocument()->getObject(FeatName.c_str()); + // If we don't add an object to the boolean group then don't update the body // as otherwise this will fail and it will be marked as invalid bool updateDocument = false; @@ -2314,15 +2431,14 @@ void CmdPartDesignBoolean::activated(int iMsg) bodies.push_back(j->getObject()); } } - if (!bodies.empty()) { updateDocument = true; std::string bodyString = PartDesignGui::buildLinkListPythonStr(bodies); - doCommand(Doc,"App.activeDocument().%s.addObjects(%s)",FeatName.c_str(),bodyString.c_str()); + FCMD_OBJ_CMD(Feat,"addObjects("<commandManager(); rcCmdMgr.addCommand(new CmdPartDesignShapeBinder()); + rcCmdMgr.addCommand(new CmdPartDesignSubShapeBinder()); rcCmdMgr.addCommand(new CmdPartDesignClone()); rcCmdMgr.addCommand(new CmdPartDesignPlane()); rcCmdMgr.addCommand(new CmdPartDesignLine()); diff --git a/src/Mod/PartDesign/Gui/CommandBody.cpp b/src/Mod/PartDesign/Gui/CommandBody.cpp index c432e48cd0..97b7e03678 100644 --- a/src/Mod/PartDesign/Gui/CommandBody.cpp +++ b/src/Mod/PartDesign/Gui/CommandBody.cpp @@ -265,18 +265,16 @@ void CmdPartDesignBody::activated(int iMsg) }; // Called by dialog when user hits "OK" and accepter returns true - std::string FeatName = baseFeature->getNameInDocument(); - auto worker = [FeatName](const std::vector& features) { + auto worker = [baseFeature](const std::vector& features) { // may happen when the user switched to an empty document while the // dialog is open if (features.empty()) return; App::Plane* plane = static_cast(features.front()); - std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + - ", [''])"; + std::string supportString = Gui::Command::getObjectCmd(plane,"(",", [''])"); - Gui::Command::doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - Gui::Command::doCommand(Doc,"App.activeDocument().%s.MapMode = '%s'",FeatName.c_str(),Attacher::AttachEngine::getModeName(Attacher::mmFlatFace).c_str()); + FCMD_OBJ_CMD(baseFeature,"Support = " << supportString); + FCMD_OBJ_CMD(baseFeature,"MapMode = '" << Attacher::AttachEngine::getModeName(Attacher::mmFlatFace) << "'"); Gui::Command::updateActive(); }; @@ -602,13 +600,12 @@ void CmdPartDesignMoveTip::activated(int iMsg) openCommand("Move tip to selected feature"); if (selFeature == body) { - doCommand(Doc,"App.activeDocument().%s.Tip = None", body->getNameInDocument()); + FCMD_OBJ_CMD(body,"Tip = None"); } else { - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",body->getNameInDocument(), - selFeature->getNameInDocument()); + FCMD_OBJ_CMD(body,"Tip = " << getObjectCmd(selFeature)); // Adjust visibility to show only the Tip feature - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", selFeature->getNameInDocument()); + FCMD_OBJ_SHOW(selFeature); } // TODO: Hide all datum features after the Tip feature? But the user might have already hidden some and wants to see @@ -659,14 +656,13 @@ void CmdPartDesignDuplicateSelection::activated(int iMsg) for (auto feature : newFeatures) { if (PartDesign::Body::isAllowed(feature)) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)", - pcActiveBody->getNameInDocument(), feature->getNameInDocument()); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", feature->getNameInDocument()); + FCMD_OBJ_CMD(pcActiveBody,"addObject(" << getObjectCmd(feature) << ")"); + FCMD_OBJ_HIDE(feature); } } // Adjust visibility of features - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", newFeatures.back()->getNameInDocument()); + FCMD_OBJ_SHOW(newFeatures.back()); } updateActive(); @@ -766,17 +762,16 @@ void CmdPartDesignMoveFeature::activated(int iMsg) openCommand("Move an object"); std::stringstream stream; - stream << "features_ = [App.ActiveDocument." << features.back()->getNameInDocument(); + stream << "features_ = [" << getObjectCmd(features.back()); features.pop_back(); for (auto feat: features) - stream << ", App.ActiveDocument." << feat->getNameInDocument(); + stream << ", " << getObjectCmd(feat); stream << "]"; - doCommand(Doc, stream.str().c_str()); - if (source_body) - doCommand(Doc, "App.ActiveDocument.%s.removeObjects(features_)", source_body->getNameInDocument()); - doCommand(Doc, "App.ActiveDocument.%s.addObjects(features_)", target->getNameInDocument()); + runCommand(Doc, stream.str().c_str()); + FCMD_OBJ_CMD(source_body,"removeObjects(features_)"); + FCMD_OBJ_CMD(target,"addObjects(features_)"); /* // Find body of this feature @@ -919,26 +914,55 @@ void CmdPartDesignMoveFeatureInTree::activated(int iMsg) for ( auto feat: features ) { if ( feat == target ) continue; - std::string targetStr; - if (target) { - targetStr.append("App.activeDocument().").append(target->getNameInDocument()); - } else { - targetStr = "None"; - } - // Remove and re-insert the feature to/from the Body // TODO: if tip was moved the new position of tip is quite undetermined (2015-08-07, Fat-Zer) // TODO: warn the user if we are moving an object to some place before the object's link (2015-08-07, Fat-Zer) - doCommand ( Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)", - body->getNameInDocument(), feat->getNameInDocument() ); - doCommand ( Doc, "App.activeDocument().%s.insertObject(App.activeDocument().%s, %s, True)", - body->getNameInDocument(), feat->getNameInDocument(), targetStr.c_str () ); + FCMD_OBJ_CMD(body,"removeObject(" << getObjectCmd(feat) << ")"); + FCMD_OBJ_CMD(body,"insertObject(" << getObjectCmd(feat) << ","<< getObjectCmd(target) << ", True)"); if (!lastObject) lastObject = feat; } - updateActive(); + // Dependency order check. + // We must make sure the resulting objects of PartDesign::Feature do not + // depend on later objects + std::vector bodyFeatures; + std::map orders; + for(auto obj : body->Group.getValues()) { + if(obj->isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + orders.emplace(obj,bodyFeatures.size()); + bodyFeatures.push_back(obj); + } + } + bool failed = false; + std::ostringstream ss; + for(size_t i=0;igetOutList()) { + if(obj->isDerivedFrom(PartDesign::Feature::getClassTypeId())) + continue; + for(auto dep : App::Document::getDependencyList({obj})) { + auto it = orders.find(dep); + if(it != orders.end() && it->second > i) { + ss << feat->Label.getValue() << ", " << + obj->Label.getValue() << " -> " << + it->first->Label.getValue(); + if(!failed) + failed = true; + else + ss << std::endl; + } + } + } + } + if(failed) { + QMessageBox::critical (0, QObject::tr( "Dependency violation" ), + QObject::tr( "Early feature must not depend on later feature.\n\n") + + QString::fromUtf8(ss.str().c_str())); + abortCommand(); + return; + } // If the selected objects have been moved after the current tip then ask the // user if he wants the last object to be the new tip. @@ -951,19 +975,11 @@ void CmdPartDesignMoveFeatureInTree::activated(int iMsg) msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); int ret = msgBox.exec(); - if (ret == QMessageBox::Yes) { - openCommand("Move tip to selected feature"); - - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", - body->getNameInDocument(), - lastObject->getNameInDocument()); - - // Adjust visibility to show only the Tip feature - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", lastObject->getNameInDocument()); - - updateActive(); - } + if (ret == QMessageBox::Yes) + FCMD_OBJ_CMD(body,"Tip = " << getObjectCmd(lastObject)); } + + updateActive(); } bool CmdPartDesignMoveFeatureInTree::isActive(void) diff --git a/src/Mod/PartDesign/Gui/CommandPrimitive.cpp b/src/Mod/PartDesign/Gui/CommandPrimitive.cpp index 9c3ac5ba2a..2a47d76187 100644 --- a/src/Mod/PartDesign/Gui/CommandPrimitive.cpp +++ b/src/Mod/PartDesign/Gui/CommandPrimitive.cpp @@ -98,7 +98,6 @@ void CmdPrimtiveCompAdditive::activated(int iMsg) pcAction->setIcon(pcAction->actions().at(iMsg)->icon()); auto shapeType( primitiveIntToName(iMsg) ); - auto FeatName( getUniqueObjectName(shapeType) ); Gui::Command::openCommand( (std::string("Make additive ") + shapeType).c_str() ); if (shouldMakeBody) { @@ -109,26 +108,29 @@ void CmdPrimtiveCompAdditive::activated(int iMsg) return; } - Gui::Command::doCommand( - Gui::Command::Doc, - "App.ActiveDocument.addObject(\'PartDesign::Additive%s\',\'%s\')", - shapeType, FeatName.c_str() ); + auto FeatName( getUniqueObjectName(shapeType, pcActiveBody) ); - Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addObject(App.activeDocument().%s)" - ,pcActiveBody->getNameInDocument(), FeatName.c_str()); + FCMD_OBJ_DOC_CMD(pcActiveBody,"addObject('PartDesign::Additive"<( + pcActiveBody->getDocument()->getObject(FeatName.c_str())); + + if(!prm) return; + FCMD_OBJ_CMD(pcActiveBody,"addObject("<(getDocument()->getObject(FeatName.c_str())); - if (prm->BaseFeature.getValue()) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prm->BaseFeature.getValue()->getNameInDocument()); + auto base = prm->BaseFeature.getValue(); + FCMD_OBJ_HIDE(base); - copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); - copyVisual(FeatName.c_str(), "Transparency", pcActiveBody->getNameInDocument()); - copyVisual(FeatName.c_str(), "DisplayMode", pcActiveBody->getNameInDocument()); - - Gui::Command::doCommand(Gui, "Gui.activeDocument().setEdit(\'%s\')", FeatName.c_str()); + if(!base) + base = pcActiveBody; + copyVisual(prm, "ShapeColor", base); + copyVisual(prm, "LineColor", base); + copyVisual(prm, "PointColor", base); + copyVisual(prm, "Transparency", base); + copyVisual(prm, "DisplayMode", base); + + PartDesignGui::setEdit(prm,pcActiveBody); } Gui::Action * CmdPrimtiveCompAdditive::createAction(void) @@ -266,32 +268,25 @@ void CmdPrimtiveCompSubtractive::activated(int iMsg) } auto shapeType( primitiveIntToName(iMsg) ); - auto FeatName( getUniqueObjectName(shapeType) ); + auto FeatName( getUniqueObjectName(shapeType, pcActiveBody) ); Gui::Command::openCommand( (std::string("Make subtractive ") + shapeType).c_str() ); - Gui::Command::doCommand( - Gui::Command::Doc, - "App.ActiveDocument.addObject(\'PartDesign::Subtractive%s\',\'%s\')", - shapeType, FeatName.c_str() ); - - Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addObject(App.activeDocument().%s)" - ,pcActiveBody->getNameInDocument(), FeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::Subtractive"<getDocument()->getObject(FeatName.c_str()); + copyVisual(Feat, "ShapeColor", prevSolid); + copyVisual(Feat, "LineColor", prevSolid); + copyVisual(Feat, "PointColor", prevSolid); + copyVisual(Feat, "Transparency", prevSolid); + copyVisual(Feat, "DisplayMode", prevSolid); + if ( isActiveObjectValid() ) { // TODO (2015-08-05, Fat-Zer) - if (prevSolid) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolid->getNameInDocument()); - } + FCMD_OBJ_HIDE(prevSolid); } - copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); - copyVisual(FeatName.c_str(), "Transparency", pcActiveBody->getNameInDocument()); - copyVisual(FeatName.c_str(), "DisplayMode", pcActiveBody->getNameInDocument()); - - Gui::Command::doCommand(Gui, "Gui.activeDocument().setEdit(\'%s\')", FeatName.c_str()); + PartDesignGui::setEdit(Feat,pcActiveBody); } Gui::Action * CmdPrimtiveCompSubtractive::createAction(void) diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index dc7562b1a9..3b9d8dcd21 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -130,15 +131,15 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c return false; } - // Handle selection of geometry elements - if (!sSubName || sSubName[0] == '\0') - return false; if (!allowOtherBody) { if (support == NULL) return false; if (pObj != support) return false; } + // Handle selection of geometry elements + if (!sSubName || sSubName[0] == '\0') + return whole; std::string subName(sSubName); if (edge && subName.size() > 4 && subName.substr(0,4) == "Edge") { const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); @@ -289,9 +290,9 @@ std::string buildLinkSingleSubPythonStr(const App::DocumentObject* obj, return "None"; if (PartDesign::Feature::isDatum(obj)) - return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"\"])"; + return Gui::Command::getObjectCmd(obj,"(",", [''])"); else - return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"" + subs.front() + "\"])"; + return Gui::Command::getObjectCmd(obj,"(",", ['") + subs.front() + "'])"; } std::string buildLinkListPythonStr(const std::vector & objs) @@ -303,7 +304,7 @@ std::string buildLinkListPythonStr(const std::vector & obj std::string result("["); for (std::vector::const_iterator o = objs.begin(); o != objs.end(); o++) - result += std::string("App.activeDocument().") + (*o)->getNameInDocument() + ","; + result += Gui::Command::getObjectCmd(*o,0,","); result += "]"; return result; @@ -323,7 +324,7 @@ std::string buildLinkSubListPythonStr(const std::vector & for (size_t i=0, objs_sz=objs.size(); i < objs_sz; i++) { if (objs[i] ) { result += '('; - result += std::string("App.activeDocument().").append( objs[i]->getNameInDocument () ); + result += Gui::Command::getObjectCmd(objs[i]); result += ",\""; result += subs[i]; result += "\"),"; diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.h b/src/Mod/PartDesign/Gui/ReferenceSelection.h index ebab48f908..d45d415e37 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.h +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.h @@ -39,12 +39,16 @@ class ReferenceSelection : public Gui::SelectionFilterGate bool point; // If set to true, allow picking objects from another body in the same part bool allowOtherBody; + // Allow whole object selection + bool whole; public: ReferenceSelection(const App::DocumentObject* support_, - const bool edge_, const bool plane_, const bool planar_, const bool point_ = false) + const bool edge_, const bool plane_, const bool planar_, + const bool point_ = false, bool whole_ = false) : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), - support(support_), edge(edge_), plane(plane_), planar(planar_), point(point_), allowOtherBody(true) + support(support_), edge(edge_), plane(plane_), + planar(planar_), point(point_), allowOtherBody(true), whole(whole_) { } /** diff --git a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc index e3db3b3252..99255c7710 100644 --- a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc +++ b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc @@ -17,6 +17,7 @@ icons/PartDesign_Body.svg icons/PartDesign_Boolean.svg icons/PartDesign_ShapeBinder.svg + icons/PartDesign_SubShapeBinder.svg icons/PartDesign_Clone.svg icons/PartDesign_Plane.svg icons/PartDesign_Line.svg diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_SubShapeBinder.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_SubShapeBinder.svg new file mode 100644 index 0000000000..9a1f793110 --- /dev/null +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_SubShapeBinder.svg @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + [Stefan Tröger] + + + PartDesign_ShapeBinder + 2015-07-18 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_ShapeBinder.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp index a4184f334f..056dcbd636 100644 --- a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp @@ -340,10 +340,10 @@ void TaskDlgBooleanParameters::clicked(int) bool TaskDlgBooleanParameters::accept() { - std::string name = BooleanView->getObject()->getNameInDocument(); - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc != NULL) - doc->setShow(name.c_str()); + auto obj = BooleanView->getObject(); + if(!obj || !obj->getNameInDocument()) + return false; + BooleanView->Visibility.setValue(true); try { std::vector bodies = parameter->getBodies(); @@ -353,9 +353,9 @@ bool TaskDlgBooleanParameters::accept() return false; } std::stringstream str; - str << "App.ActiveDocument." << name.c_str() << ".setObjects( ["; + str << Gui::Command::getObjectCmd(obj) << ".setObjects( ["; for (std::vector::const_iterator it = bodies.begin(); it != bodies.end(); ++it) - str << "App.ActiveDocument." << *it << ","; + str << "App.getDocument('" << obj->getDocument()->getName() << "').getObject('" << *it << "'),"; str << "])"; Gui::Command::runCommand(Gui::Command::Doc,str.str().c_str()); } @@ -364,7 +364,7 @@ bool TaskDlgBooleanParameters::accept() return false; } - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getType()); + FCMD_OBJ_CMD(obj,"Type = " << parameter->getType()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); Gui::Command::commitCommand(); diff --git a/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp b/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp index 79c71977d9..e7b25fa001 100644 --- a/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp @@ -121,6 +121,7 @@ void TaskChamferParameters::onRefDeleted(void) App::DocumentObject* base = pcChamfer->Base.getValue(); std::vector refs = pcChamfer->Base.getSubValues(); refs.erase(refs.begin() + ui->listWidgetReferences->currentRow()); + setupTransaction(); pcChamfer->Base.setValue(base, refs); ui->listWidgetReferences->model()->removeRow(ui->listWidgetReferences->currentRow()); pcChamfer->getDocument()->recomputeFeature(pcChamfer); @@ -129,6 +130,7 @@ void TaskChamferParameters::onRefDeleted(void) void TaskChamferParameters::onLengthChanged(double len) { PartDesign::Chamfer* pcChamfer = static_cast(DressUpView->getObject()); + setupTransaction(); pcChamfer->Size.setValue(len); pcChamfer->getDocument()->recomputeFeature(pcChamfer); } diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp index 291607472f..bbc82262a8 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp @@ -132,6 +132,7 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) getReferencedSelection(pcDraft, msg, selObj, planes); if(!selObj) return; + setupTransaction(); pcDraft->NeutralPlane.setValue(selObj, planes); ui->linePlane->setText(getRefStr(selObj, planes)); @@ -145,6 +146,7 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) getReferencedSelection(pcDraft, msg, selObj, edges); if(!selObj) return; + setupTransaction(); pcDraft->PullDirection.setValue(selObj, edges); ui->lineLine->setText(getRefStr(selObj, edges)); @@ -192,6 +194,7 @@ void TaskDraftParameters::onRefDeleted(void) App::DocumentObject* base = pcDraft->Base.getValue(); std::vector faces = pcDraft->Base.getSubValues(); faces.erase(faces.begin() + ui->listWidgetReferences->currentRow()); + setupTransaction(); pcDraft->Base.setValue(base, faces); ui->listWidgetReferences->model()->removeRow(ui->listWidgetReferences->currentRow()); pcDraft->getDocument()->recomputeFeature(pcDraft); @@ -219,6 +222,7 @@ void TaskDraftParameters::onAngleChanged(double angle) { clearButtons(none); PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); + setupTransaction(); pcDraft->Angle.setValue(angle); pcDraft->getDocument()->recomputeFeature(pcDraft); } @@ -231,6 +235,7 @@ double TaskDraftParameters::getAngle(void) const void TaskDraftParameters::onReversedChanged(const bool on) { clearButtons(none); PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); + setupTransaction(); pcDraft->Reversed.setValue(on); pcDraft->getDocument()->recomputeFeature(pcDraft); } @@ -300,18 +305,21 @@ bool TaskDlgDraftParameters::accept() std::string pullDirection = buildLinkSingleSubPythonStr(obj, strings); // Force the user to select a neutral plane - if (neutralPlane.empty() || neutralPlane == "None") { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Missing neutral plane"), - QObject::tr("Please select a plane or an edge plus a pull direction")); - return false; - } + // if (neutralPlane.empty() || neutralPlane == "None") { + // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Missing neutral plane"), + // QObject::tr("Please select a plane or an edge plus a pull direction")); + // return false; + // } - std::string name = vp->getObject()->getNameInDocument(); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),draftparameter->getAngle()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),draftparameter->getReversed()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = %s", name.c_str(), neutralPlane.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = %s", name.c_str(), pullDirection.c_str()); + auto tobj = vp->getObject(); + FCMD_OBJ_CMD(tobj,"Angle = " << draftparameter->getAngle()); + FCMD_OBJ_CMD(tobj,"Reversed = " << draftparameter->getReversed()); + if(neutralPlane.empty()) + neutralPlane = "None"; + FCMD_OBJ_CMD(tobj,"NeutralPlane = " << neutralPlane); + if(pullDirection.empty()) + pullDirection = "None"; + FCMD_OBJ_CMD(tobj,"PullDirection = " << pullDirection); return TaskDlgDressUpParameters::accept(); } diff --git a/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp index dbd621d702..d0e09f69d0 100644 --- a/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp @@ -27,6 +27,7 @@ # include #endif +#include #include "TaskDressUpParameters.h" #include #include @@ -42,6 +43,8 @@ #include #include +FC_LOG_LEVEL_INIT("PartDesign",true,true) + using namespace PartDesignGui; using namespace Gui; @@ -58,6 +61,7 @@ TaskDressUpParameters::TaskDressUpParameters(ViewProviderDressUp *DressUpView, b , allowEdges(selectEdges) { selectionMode = none; + showObject(); } TaskDressUpParameters::~TaskDressUpParameters() @@ -66,6 +70,15 @@ TaskDressUpParameters::~TaskDressUpParameters() Gui::Selection().rmvSelectionGate(); } +void TaskDressUpParameters::setupTransaction() { + int tid = 0; + const char *name = App::GetApplication().getActiveTransaction(&tid); + std::string n("Edit "); + n += DressUpView->getObject()->Label.getValue(); + if(!name || n != name) + App::GetApplication().setActiveTransaction(n.c_str()); +} + bool TaskDressUpParameters::referenceSelected(const Gui::SelectionChanges& msg) { if ((msg.Type == Gui::SelectionChanges::AddSelection) && ( @@ -98,6 +111,7 @@ bool TaskDressUpParameters::referenceSelected(const Gui::SelectionChanges& msg) return false; } DressUpView->highlightReferences(false); + setupTransaction(); pcDressUp->Base.setValue(base, refs); pcDressUp->getDocument()->recomputeFeature(pcDressUp); @@ -152,22 +166,19 @@ void TaskDressUpParameters::removeItemFromListWidget(QListWidget* widget, const void TaskDressUpParameters::hideObject() { - Gui::Document* doc = Gui::Application::Instance->activeDocument(); App::DocumentObject* base = getBase(); - if (doc != NULL && base != NULL) { - doc->setHide(DressUpView->getObject()->getNameInDocument()); - doc->setShow(base->getNameInDocument()); + if(base) { + DressUpView->getObject()->Visibility.setValue(false); + base->Visibility.setValue(true); } } void TaskDressUpParameters::showObject() { - Gui::Document* doc = Gui::Application::Instance->activeDocument(); + DressUpView->getObject()->Visibility.setValue(true); App::DocumentObject* base = getBase(); - if (doc != NULL && base != NULL) { - doc->setShow(DressUpView->getObject()->getNameInDocument()); - doc->setHide(base->getNameInDocument()); - } + if (base) + base->Visibility.setValue(false); } Part::Feature* TaskDressUpParameters::getBase(void) const @@ -209,19 +220,23 @@ TaskDlgDressUpParameters::~TaskDlgDressUpParameters() bool TaskDlgDressUpParameters::accept() { - std::string name = vp->getObject()->getNameInDocument(); getDressUpView()->highlightReferences(false); std::vector refs = parameter->getReferences(); std::stringstream str; - str << "App.ActiveDocument." << name.c_str() << ".Base = (App.ActiveDocument." - << parameter->getBase()->getNameInDocument() << ",["; + str << Gui::Command::getObjectCmd(vp->getObject()) << ".Base = (" + << Gui::Command::getObjectCmd(parameter->getBase()) << ",["; for (std::vector::const_iterator it = refs.begin(); it != refs.end(); ++it) str << "\"" << *it << "\","; str << "])"; Gui::Command::runCommand(Gui::Command::Doc,str.str().c_str()); - return TaskDlgFeatureParameters::accept(); } +bool TaskDlgDressUpParameters::reject() +{ + getDressUpView()->highlightReferences(false); + return TaskDlgFeatureParameters::reject(); +} + #include "moc_TaskDressUpParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskDressUpParameters.h b/src/Mod/PartDesign/Gui/TaskDressUpParameters.h index 7212ba87cf..91c164d045 100644 --- a/src/Mod/PartDesign/Gui/TaskDressUpParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDressUpParameters.h @@ -51,6 +51,7 @@ public: void hideObject(); void showObject(); + void setupTransaction(); /// Apply the changes made to the object to it virtual void apply() {}; @@ -79,6 +80,7 @@ protected: bool allowFaces, allowEdges; selectionModes selectionMode; + int transactionID; }; /// simulation dialog for the TaskView @@ -96,6 +98,7 @@ public: public: /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); + virtual bool reject(); protected: TaskDressUpParameters *parameter; diff --git a/src/Mod/PartDesign/Gui/TaskFeatureParameters.cpp b/src/Mod/PartDesign/Gui/TaskFeatureParameters.cpp index 9e7b32c276..6e18f38a15 100644 --- a/src/Mod/PartDesign/Gui/TaskFeatureParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskFeatureParameters.cpp @@ -108,10 +108,7 @@ bool TaskDlgFeatureParameters::accept() { App::DocumentObject* previous = static_cast(feature)->getBaseObject(/* silent = */ true ); - if (previous) { - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().hide(\"%s\")", - previous->getNameInDocument()); - } + FCMD_OBJ_HIDE(previous); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); diff --git a/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp b/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp index 23f87c5435..100265b80e 100644 --- a/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp @@ -121,6 +121,7 @@ void TaskFilletParameters::onRefDeleted(void) App::DocumentObject* base = pcFillet->Base.getValue(); std::vector refs = pcFillet->Base.getSubValues(); refs.erase(refs.begin() + ui->listWidgetReferences->currentRow()); + setupTransaction(); pcFillet->Base.setValue(base, refs); ui->listWidgetReferences->model()->removeRow(ui->listWidgetReferences->currentRow()); pcFillet->getDocument()->recomputeFeature(pcFillet); @@ -130,6 +131,7 @@ void TaskFilletParameters::onLengthChanged(double len) { clearButtons(none); PartDesign::Fillet* pcFillet = static_cast(DressUpView->getObject()); + setupTransaction(); pcFillet->Radius.setValue(len); pcFillet->getDocument()->recomputeFeature(pcFillet); } diff --git a/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp b/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp index d8067f0061..b6345d0141 100644 --- a/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp @@ -116,7 +116,8 @@ TaskHoleParameters::TaskHoleParameters(ViewProviderHole *HoleView, QWidget *pare ui->DrillPointAngle->bind(pcHole->DrillPointAngle); ui->TaperedAngle->bind(pcHole->TaperedAngle); - connectPropChanged = App::GetApplication().signalChangePropertyEditor.connect(boost::bind(&TaskHoleParameters::changedObject, this, _1)); + connectPropChanged = App::GetApplication().signalChangePropertyEditor.connect( + boost::bind(&TaskHoleParameters::changedObject, this, _1, _2)); this->groupLayout()->addWidget(proxy); } @@ -328,7 +329,7 @@ void TaskHoleParameters::changeEvent(QEvent *e) } } -void TaskHoleParameters::changedObject(const App::Property &Prop) +void TaskHoleParameters::changedObject(const App::Document&, const App::Property &Prop) { // happens when aborting the command if (vp == nullptr) @@ -691,9 +692,8 @@ Base::Quantity TaskHoleParameters::getTaperedAngle() const void TaskHoleParameters::apply() { - std::string name = vp->getObject()->getNameInDocument(); + auto obj = vp->getObject(); PartDesign::Hole* pcHole = static_cast(vp->getObject()); - const char * cname = name.c_str(); isApplying = true; @@ -710,27 +710,27 @@ void TaskHoleParameters::apply() ui->TaperedAngle->apply(); if (!pcHole->Threaded.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Threaded = %u", cname, getThreaded() ? 1 : 0); + FCMD_OBJ_CMD(obj,"Threaded = " << (getThreaded() ? 1 : 0)); if (!pcHole->ModelActualThread.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ModelActualThread = %u", cname, getThreaded() ? 1 : 0); + FCMD_OBJ_CMD(obj,"ModelActualThread = " << (getThreaded() ? 1 : 0)); if (!pcHole->ThreadType.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadType = %u", cname, getThreadType()); + FCMD_OBJ_CMD(obj,"ThreadType = " << getThreadType()); if (!pcHole->ThreadSize.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadSize = %u", cname, getThreadSize()); + FCMD_OBJ_CMD(obj,"ThreadSize = " << getThreadSize()); if (!pcHole->ThreadClass.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadClass = %u", cname, getThreadClass()); - if (!pcHole->ThreadFit.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadFit = %u", cname, getThreadFit()); + FCMD_OBJ_CMD(obj,"ThreadClass = " << getThreadClass()); + if (!pcHole->ThreadFit.isReadOnly()) + FCMD_OBJ_CMD(obj,"ThreadFit = " << getThreadFit()); if (!pcHole->ThreadDirection.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadDirection = %u", cname, getThreadDirection()); + FCMD_OBJ_CMD(obj,"ThreadDirection = " << getThreadDirection()); if (!pcHole->HoleCutType.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.HoleCutType = %u", cname, getHoleCutType()); + FCMD_OBJ_CMD(obj,"HoleCutType = " << getHoleCutType()); if (!pcHole->DepthType.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.DepthType = %u", cname, getDepthType()); + FCMD_OBJ_CMD(obj,"DepthType = " << getDepthType()); if (!pcHole->DrillPoint.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.DrillPoint = %u", cname, getDrillPoint()); + FCMD_OBJ_CMD(obj,"DrillPoint = " << getDrillPoint()); if (!pcHole->Tapered.isReadOnly()) - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Tapered = %u", cname, getTapered()); + FCMD_OBJ_CMD(obj,"Tapered = " << getTapered()); isApplying = false; } @@ -767,6 +767,7 @@ void TaskHoleParameters::Observer::slotChangedObject(const App::DocumentObject & { if (&Obj == hole) { Base::Console().Log("Parameter %s was updated with a new value\n", Prop.getName()); - owner->changedObject(Prop); + if(Obj.getDocument()) + owner->changedObject(*Obj.getDocument(),Prop); } } diff --git a/src/Mod/PartDesign/Gui/TaskHoleParameters.h b/src/Mod/PartDesign/Gui/TaskHoleParameters.h index 7a00c9fd64..447197c2b9 100644 --- a/src/Mod/PartDesign/Gui/TaskHoleParameters.h +++ b/src/Mod/PartDesign/Gui/TaskHoleParameters.h @@ -114,7 +114,7 @@ private: protected: void changeEvent(QEvent *e) override; - void changedObject(const App::Property& Prop); + void changedObject(const App::Document&, const App::Property& Prop); private: void onSelectionChanged(const Gui::SelectionChanges &msg) override; diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index fdac8415dc..07c4f30ae5 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -218,6 +218,7 @@ void TaskLinearPatternParameters::updateUI() void TaskLinearPatternParameters::onUpdateViewTimer() { + setupTransaction(); recomputeFeature(); } @@ -228,25 +229,8 @@ void TaskLinearPatternParameters::kickUpdateViewTimer() const void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { - if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (selectionMode!=none && msg.Type == Gui::SelectionChanges::AddSelection) { if (originalSelected(msg)) { - Gui::SelectionObject selObj(msg); - App::DocumentObject* obj = selObj.getObject(); - Q_ASSERT(obj); - - QString label = QString::fromUtf8(obj->Label.getValue()); - QString objectName = QString::fromLatin1(msg.pObjectName); - - if (selectionMode == addFeature) { - QListWidgetItem* item = new QListWidgetItem(); - item->setText(label); - item->setData(Qt::UserRole, objectName); - ui->listWidgetFeatures->addItem(item); - } - else { - removeItemFromListWidget(ui->listWidgetFeatures, label); - } - exitSelectionMode(); } else { // TODO check if this works correctly (2015-09-01, Fat-Zer) @@ -263,8 +247,8 @@ void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges selObj->isDerivedFrom(Part::Feature::getClassTypeId()) || selObj->isDerivedFrom(PartDesign::Line::getClassTypeId()) || selObj->isDerivedFrom(PartDesign::Plane::getClassTypeId()))) { + setupTransaction(); pcLinearPattern->Direction.setValue(selObj, directions); - recomputeFeature(); updateUI(); } @@ -342,6 +326,7 @@ void TaskLinearPatternParameters::onUpdateView(bool on) std::vector directions; App::DocumentObject* obj; + setupTransaction(); getDirection(obj, directions); pcLinearPattern->Direction.setValue(obj,directions); pcLinearPattern->Reversed.setValue(getReverse()); @@ -357,6 +342,7 @@ void TaskLinearPatternParameters::onFeatureDeleted(void) PartDesign::Transformed* pcTransformed = getObject(); std::vector originals = pcTransformed->Originals.getValues(); originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + setupTransaction(); pcTransformed->Originals.setValues(originals); ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); recomputeFeature(); @@ -415,15 +401,14 @@ void TaskLinearPatternParameters::changeEvent(QEvent *e) void TaskLinearPatternParameters::apply() { - std::string name = TransformedView->getObject()->getNameInDocument(); - std::vector directions; App::DocumentObject* obj; getDirection(obj, directions); std::string direction = buildLinkSingleSubPythonStr(obj, directions); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), direction.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),getReverse()); + auto tobj = TransformedView->getObject(); + FCMD_OBJ_CMD(tobj,"Direction = " << direction); + FCMD_OBJ_CMD(tobj,"Reversed = " << getReverse()); ui->spinLength->apply(); ui->spinOccurrences->apply(); diff --git a/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp b/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp index 441559edd6..21cfccd6a8 100644 --- a/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp @@ -324,8 +324,8 @@ bool TaskDlgLoftParameters::accept() // TODO Fill this with commands (2015-09-11, Fat-Zer) PartDesign::Loft* pcLoft = static_cast(vp->getObject()); - for (App::DocumentObject* obj : pcLoft->Sections.getValues()) { - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().hide(\"%s\")", obj->getNameInDocument()); + for(App::DocumentObject* obj : pcLoft->Sections.getValues()) { + FCMD_OBJ_HIDE(obj); } diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index f3e55f8134..765972bc70 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -182,25 +182,9 @@ void TaskMirroredParameters::updateUI() void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { - if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (selectionMode!=none && msg.Type == Gui::SelectionChanges::AddSelection) { if (originalSelected(msg)) { - Gui::SelectionObject selObj(msg); - App::DocumentObject* obj = selObj.getObject(); - Q_ASSERT(obj); - - QString label = QString::fromUtf8(obj->Label.getValue()); - QString objectName = QString::fromLatin1(msg.pObjectName); - - if (selectionMode == addFeature) { - QListWidgetItem* item = new QListWidgetItem(); - item->setText(label); - item->setData(Qt::UserRole, objectName); - ui->listWidgetFeatures->addItem(item); - } - else { - removeItemFromListWidget(ui->listWidgetFeatures, label); - } exitSelectionMode(); } else { std::vector mirrorPlanes; @@ -211,6 +195,7 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg return; if ( selectionMode == reference || selObj->isDerivedFrom ( App::Plane::getClassTypeId () ) ) { + setupTransaction(); pcMirrored->MirrorPlane.setValue(selObj, mirrorPlanes); recomputeFeature(); updateUI(); @@ -230,6 +215,7 @@ void TaskMirroredParameters::onPlaneChanged(int /*num*/) { if (blockUpdate) return; + setupTransaction(); PartDesign::Mirrored* pcMirrored = static_cast(getObject()); try{ if(planeLinks.getCurrentLink().getValue() == 0){ @@ -254,6 +240,7 @@ void TaskMirroredParameters::onUpdateView(bool on) { blockUpdate = !on; if (on) { + setupTransaction(); // Do the same like in TaskDlgMirroredParameters::accept() but without doCommand PartDesign::Mirrored* pcMirrored = static_cast(getObject()); std::vector mirrorPlanes; @@ -271,6 +258,7 @@ void TaskMirroredParameters::onFeatureDeleted(void) PartDesign::Transformed* pcTransformed = getObject(); std::vector originals = pcTransformed->Originals.getValues(); originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + setupTransaction(); pcTransformed->Originals.setValues(originals); ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); recomputeFeature(); @@ -331,15 +319,13 @@ TaskDlgMirroredParameters::TaskDlgMirroredParameters(ViewProviderMirrored *Mirro bool TaskDlgMirroredParameters::accept() { - std::string name = vp->getObject()->getNameInDocument(); - TaskMirroredParameters* mirrorParameter = static_cast(parameter); std::vector mirrorPlanes; App::DocumentObject* obj; mirrorParameter->getMirrorPlane(obj, mirrorPlanes); std::string mirrorPlane = buildLinkSingleSubPythonStr(obj, mirrorPlanes); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirrorPlane = %s", name.c_str(), mirrorPlane.c_str()); + FCMD_OBJ_CMD(vp->getObject(),"MirrorPlane = " << mirrorPlane); return TaskDlgTransformedParameters::accept(); } diff --git a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp index 288b00e362..d0021dd1c9 100644 --- a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp @@ -159,22 +159,6 @@ TaskMultiTransformParameters::TaskMultiTransformParameters(ViewProviderTransform void TaskMultiTransformParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (originalSelected(msg)) { - Gui::SelectionObject selObj(msg); - App::DocumentObject* obj = selObj.getObject(); - Q_ASSERT(obj); - - QString label = QString::fromUtf8(obj->Label.getValue()); - QString objectName = QString::fromLatin1(msg.pObjectName); - - if (selectionMode == addFeature) { - QListWidgetItem* item = new QListWidgetItem(); - item->setText(label); - item->setData(Qt::UserRole, objectName); - ui->listWidgetFeatures->addItem(item); - } - else { - removeItemFromListWidget(ui->listWidgetFeatures, label); - } exitSelectionMode(); } } @@ -190,6 +174,7 @@ void TaskMultiTransformParameters::onFeatureDeleted(void) PartDesign::Transformed* pcTransformed = getObject(); std::vector originals = pcTransformed->Originals.getValues(); originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + setupTransaction(); pcTransformed->Originals.setValues(originals); ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); recomputeFeature(); @@ -222,6 +207,8 @@ void TaskMultiTransformParameters::onTransformDelete() App::DocumentObject* feature = transformFeatures[row]; if (feature == this->subFeature) this->subFeature = nullptr; + + setupTransaction(); pcMultiTransform->getDocument()->removeObject(feature->getNameInDocument()); closeSubTask(); @@ -270,15 +257,16 @@ void TaskMultiTransformParameters::onTransformAddMirrored() { closeSubTask(); std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("Mirrored"); + auto pcActiveBody = PartDesignGui::getBody(false); + if(!pcActiveBody) return; Gui::Command::openCommand("Mirrored"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.newObject(\"PartDesign::Mirrored\",\"%s\")", - PartDesignGui::getBody(false)->getNameInDocument(), newFeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::Mirrored','"<getDocument()->getObject(newFeatName.c_str()); //Gui::Command::updateActive(); App::DocumentObject* sketch = getSketchObject(); if (sketch) - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", - newFeatName.c_str(), sketch->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"MirrorPlane = ("<getObject()->getDocument()->getUniqueObjectName("LinearPattern"); + auto pcActiveBody = PartDesignGui::getBody(false); + if(!pcActiveBody) return; Gui::Command::openCommand("Make LinearPattern"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.newObject(\"PartDesign::LinearPattern\",\"%s\")", - PartDesignGui::getBody(false)->getNameInDocument(), newFeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::LinearPattern','"<getDocument()->getObject(newFeatName.c_str()); //Gui::Command::updateActive(); App::DocumentObject* sketch = getSketchObject(); if (sketch) { - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", - newFeatName.c_str(), sketch->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"Direction = ("<(Part::BodyBase::findBodyOf(getObject())); if (body) { - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"\"])", - newFeatName.c_str(), body->getOrigin()->getX()->getNameInDocument()); + FCMD_OBJ_CMD(Feat,"Direction = ("<getOrigin()->getX())<<",[''])"); } } - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Length = 100", newFeatName.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Occurrences = 2", newFeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Length = 100"); + FCMD_OBJ_CMD(Feat,"Occurrences = 2"); finishAdd(newFeatName); } @@ -319,17 +307,18 @@ void TaskMultiTransformParameters::onTransformAddPolarPattern() { closeSubTask(); std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("PolarPattern"); + auto pcActiveBody = PartDesignGui::getBody(false); + if(!pcActiveBody) return; Gui::Command::openCommand("PolarPattern"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.newObject(\"PartDesign::PolarPattern\",\"%s\")", - PartDesignGui::getBody(false)->getNameInDocument(), newFeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::PolarPattern','"<getDocument()->getObject(newFeatName.c_str()); //Gui::Command::updateActive(); App::DocumentObject* sketch = getSketchObject(); if (sketch) - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", - newFeatName.c_str(), sketch->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Angle = 360", newFeatName.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Occurrences = 2", newFeatName.c_str()); + FCMD_OBJ_CMD(Feat, "Axis = ("<getObject()->getDocument()->getUniqueObjectName("Scaled"); + auto pcActiveBody = PartDesignGui::getBody(false); + if(!pcActiveBody) return; Gui::Command::openCommand("Scaled"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.newObject(\"PartDesign::Scaled\",\"%s\")", - PartDesignGui::getBody(false)->getNameInDocument(), newFeatName.c_str()); + FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::Scaled','"<getDocument()->getObject(newFeatName.c_str()); //Gui::Command::updateActive(); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Factor = 2", newFeatName.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Occurrences = 2", newFeatName.c_str()); + FCMD_OBJ_CMD(Feat,"Factor = 2"); + FCMD_OBJ_CMD(Feat,"Occurrences = 2"); finishAdd(newFeatName); } @@ -355,6 +346,7 @@ void TaskMultiTransformParameters::finishAdd(std::string &newFeatName) //Gui::Command::copyVisual(newFeatName.c_str(), "ShapeColor", getOriginals().front()->getNameInDocument().c_str()); //Gui::Command::copyVisual(newFeatName.c_str(), "DisplayMode", getOriginals().front()->getNameInDocument().c_str()); + setupTransaction(); PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); if (editHint) { // Remove hint, first feature is being added @@ -388,8 +380,7 @@ void TaskMultiTransformParameters::finishAdd(std::string &newFeatName) recomputeFeature(); // Set state to hidden - only the MultiTransform should be visible - Gui::Command::doCommand( - Gui::Command::Doc,"Gui.activeDocument().getObject(\"%s\").Visibility=False", newFeatName.c_str()); + FCMD_OBJ_HIDE(newFeature); editHint = false; onTransformEdit(); @@ -397,6 +388,7 @@ void TaskMultiTransformParameters::finishAdd(std::string &newFeatName) void TaskMultiTransformParameters::moveTransformFeature(const int increment) { + setupTransaction(); int row = ui->listTransformFeatures->currentIndex().row(); PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); std::vector transformFeatures = pcMultiTransform->Transformations.getValues(); @@ -445,8 +437,10 @@ void TaskMultiTransformParameters::onSubTaskButtonOK() { void TaskMultiTransformParameters::onUpdateView(bool on) { blockUpdate = !on; - if (on) + if (on) { + setupTransaction(); recomputeFeature(); + } } const std::vector TaskMultiTransformParameters::getTransformFeatures(void) const @@ -491,17 +485,15 @@ TaskDlgMultiTransformParameters::TaskDlgMultiTransformParameters(ViewProviderMul bool TaskDlgMultiTransformParameters::accept() { - std::string name = vp->getObject()->getNameInDocument(); - // Set up transformations TaskMultiTransformParameters* mtParameter = static_cast(parameter); std::vector transformFeatures = mtParameter->getTransformFeatures(); std::stringstream str; - str << "App.ActiveDocument." << name.c_str() << ".Transformations = ["; + str << Gui::Command::getObjectCmd(vp->getObject()) << ".Transformations = ["; for (std::vector::const_iterator it = transformFeatures.begin(); it != transformFeatures.end(); it++) { if ((*it) != NULL) - str << "App.ActiveDocument." << (*it)->getNameInDocument() << ","; + str << Gui::Command::getObjectCmd(*it) << ","; } str << "]"; Gui::Command::runCommand(Gui::Command::Doc,str.str().c_str()); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index eadfadf766..12e11f43da 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -458,19 +458,18 @@ void TaskPadParameters::saveHistory(void) void TaskPadParameters::apply() { - std::string name = vp->getObject()->getNameInDocument(); - const char * cname = name.c_str(); + auto obj = vp->getObject(); ui->lengthEdit->apply(); ui->lengthEdit2->apply(); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u", cname, getMode()); + FCMD_OBJ_CMD(obj,"Type = " << getMode()); QString facename = getFaceName(); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", - cname, facename.toLatin1().data()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i", cname, getReversed()?1:0); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i", cname, getMidplane()?1:0); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f", name.c_str(), getOffset()); + + FCMD_OBJ_CMD(obj,"UpToFace = " << facename.toLatin1().data()); + FCMD_OBJ_CMD(obj,"Reversed = " << (getReversed()?1:0)); + FCMD_OBJ_CMD(obj,"Midplane = " << (getMidplane()?1:0)); + FCMD_OBJ_CMD(obj,"Offset = " << getOffset()); } //************************************************************************** diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index bfacc66cad..65ce47ac9b 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -485,19 +485,17 @@ void TaskPocketParameters::saveHistory(void) void TaskPocketParameters::apply() { - std::string name = vp->getObject()->getNameInDocument(); - const char * cname = name.c_str(); + auto obj = vp->getObject(); ui->lengthEdit->apply(); ui->lengthEdit2->apply(); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u", cname, getMode()); + FCMD_OBJ_CMD(obj,"Type = " << getMode()); QString facename = getFaceName(); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", - cname, facename.toLatin1().data()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i", cname, getReversed()?1:0); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i", cname, getMidplane()?1:0); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f", name.c_str(), getOffset()); + FCMD_OBJ_CMD(obj,"UpToFace = " << facename.toLatin1().data()); + FCMD_OBJ_CMD(obj,"Reversed = " << (getReversed()?1:0)); + FCMD_OBJ_CMD(obj,"Midplane = " << (getMidplane()?1:0)); + FCMD_OBJ_CMD(obj,"Offset = " << getOffset()); } //************************************************************************** diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index c706c4351f..8096daaa42 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -213,6 +213,7 @@ void TaskPolarPatternParameters::updateUI() void TaskPolarPatternParameters::onUpdateViewTimer() { + setupTransaction(); recomputeFeature(); } @@ -223,25 +224,9 @@ void TaskPolarPatternParameters::kickUpdateViewTimer() const void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { - if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (selectionMode!=none && msg.Type == Gui::SelectionChanges::AddSelection) { if (originalSelected(msg)) { - Gui::SelectionObject selObj(msg); - App::DocumentObject* obj = selObj.getObject(); - Q_ASSERT(obj); - - QString label = QString::fromUtf8(obj->Label.getValue()); - QString objectName = QString::fromLatin1(msg.pObjectName); - - if (selectionMode == addFeature) { - QListWidgetItem* item = new QListWidgetItem(); - item->setText(label); - item->setData(Qt::UserRole, objectName); - ui->listWidgetFeatures->addItem(item); - } - else { - removeItemFromListWidget(ui->listWidgetFeatures, label); - } exitSelectionMode(); } else { @@ -253,6 +238,7 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& return; if (selectionMode == reference || selObj->isDerivedFrom ( App::Line::getClassTypeId () ) ) { + setupTransaction(); pcPolarPattern->Axis.setValue(selObj, axes); recomputeFeature(); updateUI(); @@ -332,6 +318,7 @@ void TaskPolarPatternParameters::onUpdateView(bool on) std::vector axes; App::DocumentObject* obj; + setupTransaction(); getAxis(obj, axes); pcPolarPattern->Axis.setValue(obj,axes); pcPolarPattern->Reversed.setValue(getReverse()); @@ -347,6 +334,7 @@ void TaskPolarPatternParameters::onFeatureDeleted(void) PartDesign::Transformed* pcTransformed = getObject(); std::vector originals = pcTransformed->Originals.getValues(); originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + setupTransaction(); pcTransformed->Originals.setValues(originals); ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); recomputeFeature(); @@ -405,14 +393,14 @@ void TaskPolarPatternParameters::changeEvent(QEvent *e) void TaskPolarPatternParameters::apply() { - std::string name = TransformedView->getObject()->getNameInDocument(); + auto tobj = TransformedView->getObject(); std::vector axes; App::DocumentObject* obj; getAxis(obj, axes); std::string axis = buildLinkSingleSubPythonStr(obj, axes); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Axis = %s", name.c_str(), axis.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),getReverse()); + FCMD_OBJ_CMD(tobj,"Axis = " << axis.c_str()); + FCMD_OBJ_CMD(tobj,"Reversed = " << getReverse()); ui->polarAngle->apply(); ui->spinOccurrences->apply(); } diff --git a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp index e19f5129fa..82a54be62d 100644 --- a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp @@ -512,9 +512,10 @@ void TaskBoxPrimitives::onWedgeZmaxChanged(double v) { -void TaskBoxPrimitives::setPrimitive(QString name) +void TaskBoxPrimitives::setPrimitive(App::DocumentObject *obj) { try { + QString name(QString::fromLatin1(Gui::Command::getObjectCmd(obj).c_str())); QString cmd; App::Document* doc = App::GetApplication().getActiveDocument(); if (!doc) { @@ -523,9 +524,9 @@ void TaskBoxPrimitives::setPrimitive(QString name) switch(ui.widgetStack->currentIndex()) { case 1: // box cmd = QString::fromLatin1( - "App.ActiveDocument.%1.Length=%2\n" - "App.ActiveDocument.%1.Width=%3\n" - "App.ActiveDocument.%1.Height=%4\n") + "%1.Length=%2\n" + "%1.Width=%3\n" + "%1.Height=%4\n") .arg(name) .arg(ui.boxLength->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) .arg(ui.boxWidth->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) @@ -534,9 +535,9 @@ void TaskBoxPrimitives::setPrimitive(QString name) case 2: // cylinder cmd = QString::fromLatin1( - "App.ActiveDocument.%1.Radius=%2\n" - "App.ActiveDocument.%1.Height=%3\n" - "App.ActiveDocument.%1.Angle=%4\n") + "%1.Radius=%2\n" + "%1.Height=%3\n" + "%1.Angle=%4\n") .arg(name) .arg(ui.cylinderRadius->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) .arg(ui.cylinderHeight->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) @@ -545,10 +546,10 @@ void TaskBoxPrimitives::setPrimitive(QString name) case 3: // cone cmd = QString::fromLatin1( - "App.ActiveDocument.%1.Radius1=%2\n" - "App.ActiveDocument.%1.Radius2=%3\n" - "App.ActiveDocument.%1.Height=%4\n" - "App.ActiveDocument.%1.Angle=%5\n") + "%1.Radius1=%2\n" + "%1.Radius2=%3\n" + "%1.Height=%4\n" + "%1.Angle=%5\n") .arg(name) .arg(ui.coneRadius1->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) .arg(ui.coneRadius2->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) @@ -558,10 +559,10 @@ void TaskBoxPrimitives::setPrimitive(QString name) case 4: // sphere cmd = QString::fromLatin1( - "App.ActiveDocument.%1.Radius=%2\n" - "App.ActiveDocument.%1.Angle1=%3\n" - "App.ActiveDocument.%1.Angle2=%4\n" - "App.ActiveDocument.%1.Angle3=%5\n") + "%1.Radius=%2\n" + "%1.Angle1=%3\n" + "%1.Angle2=%4\n" + "%1.Angle3=%5\n") .arg(name) .arg(ui.sphereRadius->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) .arg(ui.sphereAngle1->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) @@ -570,12 +571,12 @@ void TaskBoxPrimitives::setPrimitive(QString name) break; case 5: // ellipsoid cmd = QString::fromLatin1( - "App.ActiveDocument.%1.Radius1=%2\n" - "App.ActiveDocument.%1.Radius2=%3\n" - "App.ActiveDocument.%1.Radius3=%4\n" - "App.ActiveDocument.%1.Angle1=%5\n" - "App.ActiveDocument.%1.Angle2=%6\n" - "App.ActiveDocument.%1.Angle3=%7\n") + "%1.Radius1=%2\n" + "%1.Radius2=%3\n" + "%1.Radius3=%4\n" + "%1.Angle1=%5\n" + "%1.Angle2=%6\n" + "%1.Angle3=%7\n") .arg(name) .arg(ui.ellipsoidRadius1->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) .arg(ui.ellipsoidRadius2->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) @@ -587,11 +588,11 @@ void TaskBoxPrimitives::setPrimitive(QString name) case 6: // torus cmd = QString::fromLatin1( - "App.ActiveDocument.%1.Radius1=%2\n" - "App.ActiveDocument.%1.Radius2=%3\n" - "App.ActiveDocument.%1.Angle1=%4\n" - "App.ActiveDocument.%1.Angle2=%5\n" - "App.ActiveDocument.%1.Angle3=%6\n") + "%1.Radius1=%2\n" + "%1.Radius2=%3\n" + "%1.Angle1=%4\n" + "%1.Angle2=%5\n" + "%1.Angle3=%6\n") .arg(name) .arg(ui.torusRadius1->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) .arg(ui.torusRadius2->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) @@ -601,9 +602,9 @@ void TaskBoxPrimitives::setPrimitive(QString name) break; case 7: // prism cmd = QString::fromLatin1( - "App.ActiveDocument.%1.Polygon=%2\n" - "App.ActiveDocument.%1.Circumradius=%3\n" - "App.ActiveDocument.%1.Height=%4\n") + "%1.Polygon=%2\n" + "%1.Circumradius=%3\n" + "%1.Height=%4\n") .arg(name) .arg(ui.prismPolygon->value()) .arg(ui.prismCircumradius->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) @@ -611,16 +612,16 @@ void TaskBoxPrimitives::setPrimitive(QString name) break; case 8: // wedge cmd = QString::fromLatin1( - "App.ActiveDocument.%1.Xmin=%2\n" - "App.ActiveDocument.%1.Ymin=%3\n" - "App.ActiveDocument.%1.Zmin=%4\n" - "App.ActiveDocument.%1.X2min=%5\n" - "App.ActiveDocument.%1.Z2min=%6\n" - "App.ActiveDocument.%1.Xmax=%7\n" - "App.ActiveDocument.%1.Ymax=%8\n" - "App.ActiveDocument.%1.Zmax=%9\n" - "App.ActiveDocument.%1.X2max=%10\n" - "App.ActiveDocument.%1.Z2max=%11\n") + "%1.Xmin=%2\n" + "%1.Ymin=%3\n" + "%1.Zmin=%4\n" + "%1.X2min=%5\n" + "%1.Z2min=%6\n" + "%1.Xmax=%7\n" + "%1.Ymax=%8\n" + "%1.Zmax=%9\n" + "%1.X2max=%10\n" + "%1.Z2max=%11\n") .arg(name) .arg(ui.wedgeXmin->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) .arg(ui.wedgeYmin->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) @@ -668,7 +669,7 @@ TaskPrimitiveParameters::~TaskPrimitiveParameters() bool TaskPrimitiveParameters::accept() { - primitive->setPrimitive(QString::fromUtf8(vp_prm->getObject()->getNameInDocument())); + primitive->setPrimitive(vp_prm->getObject()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); diff --git a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h index 1dcb2cf90d..d66109d28a 100644 --- a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h @@ -57,7 +57,7 @@ public: TaskBoxPrimitives(ViewProviderPrimitive* vp, QWidget* parent = 0); ~TaskBoxPrimitives(); - void setPrimitive(QString name); + void setPrimitive(App::DocumentObject *); public Q_SLOTS: void onBoxLengthChanged(double); diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 99a0ae16bc..267d167866 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -392,17 +392,16 @@ void TaskRevolutionParameters::changeEvent(QEvent *e) void TaskRevolutionParameters::apply() { - std::string name = vp->getObject()->getNameInDocument(); - //Gui::Command::openCommand("Revolution changed"); ui->revolveAngle->apply(); std::vector sub; App::DocumentObject* obj; getReferenceAxis(obj, sub); std::string axis = buildLinkSingleSubPythonStr(obj, sub); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(), getReversed() ? 1 : 0); + auto tobj = vp->getObject(); + FCMD_OBJ_CMD(tobj,"ReferenceAxis = " << axis); + FCMD_OBJ_CMD(tobj,"Midplane = " << (getMidplane() ? 1 : 0)); + FCMD_OBJ_CMD(tobj,"Reversed = " << (getReversed() ? 1 : 0)); } //************************************************************************** diff --git a/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp b/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp index a8eee96342..7a556afd29 100644 --- a/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp @@ -59,6 +59,7 @@ using namespace Gui; TaskShapeBinder::TaskShapeBinder(ViewProviderShapeBinder *view, bool /*newObj*/, QWidget *parent) : Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("PartDesign_ShapeBinder"), tr("Datum shape parameters"), true, parent) + , SelectionObserver(view) { // we need a separate container widget to add all controls to proxy = new QWidget(this); diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index 02ec7fb0e9..17386a0fcd 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -241,9 +241,7 @@ bool TaskDlgSketchBasedParameters::accept() { App::DocumentObject* sketch = static_cast(feature)->Profile.getValue(); - if (sketch) { - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - } + FCMD_OBJ_HIDE(sketch); return TaskDlgFeatureParameters::accept(); } diff --git a/src/Mod/PartDesign/Gui/TaskThicknessParameters.cpp b/src/Mod/PartDesign/Gui/TaskThicknessParameters.cpp index c5d55db47c..595457db6a 100644 --- a/src/Mod/PartDesign/Gui/TaskThicknessParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskThicknessParameters.cpp @@ -138,6 +138,7 @@ void TaskThicknessParameters::onRefDeleted(void) App::DocumentObject* base = pcThickness->Base.getValue(); std::vector faces = pcThickness->Base.getSubValues(); faces.erase(faces.begin() + ui->listWidgetReferences->currentRow()); + setupTransaction(); pcThickness->Base.setValue(base, faces); ui->listWidgetReferences->model()->removeRow(ui->listWidgetReferences->currentRow()); pcThickness->getDocument()->recomputeFeature(pcThickness); @@ -149,6 +150,7 @@ void TaskThicknessParameters::onValueChanged(double angle) { clearButtons(none); PartDesign::Thickness* pcThickness = static_cast(DressUpView->getObject()); + setupTransaction(); pcThickness->Value.setValue(angle); pcThickness->getDocument()->recomputeFeature(pcThickness); } @@ -157,6 +159,7 @@ void TaskThicknessParameters::onJoinTypeChanged(int join) { clearButtons(none); PartDesign::Thickness* pcThickness = static_cast(DressUpView->getObject()); + setupTransaction(); pcThickness->Join.setValue(join); pcThickness->getDocument()->recomputeFeature(pcThickness); } @@ -165,6 +168,7 @@ void TaskThicknessParameters::onModeChanged(int mode) { clearButtons(none); PartDesign::Thickness* pcThickness = static_cast(DressUpView->getObject()); + setupTransaction(); pcThickness->Mode.setValue(mode); pcThickness->getDocument()->recomputeFeature(pcThickness); } @@ -178,6 +182,7 @@ double TaskThicknessParameters::getValue(void) const void TaskThicknessParameters::onReversedChanged(const bool on) { clearButtons(none); PartDesign::Thickness* pcThickness = static_cast(DressUpView->getObject()); + setupTransaction(); pcThickness->Reversed.setValue(on); pcThickness->getDocument()->recomputeFeature(pcThickness); } @@ -254,12 +259,12 @@ bool TaskDlgThicknessParameters::accept() TaskThicknessParameters* draftparameter = static_cast(parameter); - std::string name = vp->getObject()->getNameInDocument(); + auto obj = vp->getObject(); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Value = %f",name.c_str(),draftparameter->getValue()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),draftparameter->getReversed()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Mode = %u",name.c_str(),draftparameter->getMode()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Join = %u",name.c_str(),draftparameter->getJoinType()); + FCMD_OBJ_CMD(obj,"Value = " << draftparameter->getValue()); + FCMD_OBJ_CMD(obj,"Reversed = " << draftparameter->getReversed()); + FCMD_OBJ_CMD(obj,"Mode = " << draftparameter->getMode()); + FCMD_OBJ_CMD(obj,"Join = " << draftparameter->getJoinType()); return TaskDlgDressUpParameters::accept(); } diff --git a/src/Mod/PartDesign/Gui/TaskTransformedMessages.cpp b/src/Mod/PartDesign/Gui/TaskTransformedMessages.cpp index da9f94ee01..7eb917bfd9 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedMessages.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedMessages.cpp @@ -52,6 +52,7 @@ TaskTransformedMessages::TaskTransformedMessages(ViewProviderTransformed *transf QMetaObject::connectSlotsByName(this); this->groupLayout()->addWidget(proxy); + ui->labelTransformationStatus->setText(transformedView->getMessage()); connectionDiagnosis = transformedView->signalDiagnosis.connect(boost::bind(&PartDesignGui::TaskTransformedMessages::slotDiagnosis, this,_1)); } diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index 29d9bca1e0..1c4f5b51c5 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -31,6 +31,8 @@ # include #endif +#include + #include #include #include @@ -54,6 +56,7 @@ #include "TaskTransformedParameters.h" +FC_LOG_LEVEL_INIT("PartDesign",true,true) using namespace PartDesignGui; using namespace Gui; @@ -139,6 +142,7 @@ bool TaskTransformedParameters::originalSelected(const Gui::SelectionChanges& ms else return false; } + setupTransaction(); pcTransformed->Originals.setValues(originals); recomputeFeature(); @@ -149,6 +153,15 @@ bool TaskTransformedParameters::originalSelected(const Gui::SelectionChanges& ms return false; } +void TaskTransformedParameters::setupTransaction() { + int tid = 0; + const char *name = App::GetApplication().getActiveTransaction(&tid); + std::string n("Edit "); + n += getObject()->Label.getValue(); + if(!name || n != name) + App::GetApplication().setActiveTransaction(n.c_str()); +} + void TaskTransformedParameters::onButtonAddFeature(bool checked) { if (checked) { @@ -161,11 +174,28 @@ void TaskTransformedParameters::onButtonAddFeature(bool checked) } } +// Make sure only some feature before the given one is visible +void TaskTransformedParameters::checkVisibility() { + auto feat = getObject(); + auto body = feat->getFeatureBody(); + if(!body) return; + auto inset = feat->getInListEx(true); + inset.emplace(feat); + for(auto o : body->Group.getValues()) { + if(!o->Visibility.getValue() + || !o->isDerivedFrom(PartDesign::Feature::getClassTypeId())) + continue; + if(inset.count(o)) + break; + return; + } + FCMD_OBJ_SHOW(getBaseObject()); +} + void TaskTransformedParameters::onButtonRemoveFeature(bool checked) { if (checked) { - hideObject(); - showBase(); + checkVisibility(); selectionMode = removeFeature; Gui::Selection().clearSelection(); } else { @@ -289,14 +319,16 @@ PartDesign::Transformed *TaskTransformedParameters::getObject() const { return nullptr; } -Part::Feature *TaskTransformedParameters::getBaseObject() const { +App::DocumentObject *TaskTransformedParameters::getBaseObject() const { PartDesign::Feature* feature = getTopTransformedObject (); // NOTE: getBaseObject() throws if there is no base; shouldn't happen here. - return feature->getBaseObject(); -} - -const std::vector & TaskTransformedParameters::getOriginals(void) const { - return getTopTransformedObject()->Originals.getValues(); + App::DocumentObject *base = feature->getBaseObject(true); + if(!base) { + auto body = feature->getFeatureBody(); + if(body) + base = body->getPrevSolidFeature(feature); + } + return base; } App::DocumentObject* TaskTransformedParameters::getSketchObject() const { @@ -305,52 +337,40 @@ App::DocumentObject* TaskTransformedParameters::getSketchObject() const { void TaskTransformedParameters::hideObject() { - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - doc->setHide(getTopTransformedObject()->getNameInDocument()); - } + FCMD_OBJ_HIDE(getTopTransformedObject()); } void TaskTransformedParameters::showObject() { - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - doc->setShow(getTopTransformedObject()->getNameInDocument()); - } + FCMD_OBJ_SHOW(getTopTransformedObject()); } void TaskTransformedParameters::hideBase() { - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - try { - doc->setHide(getBaseObject()->getNameInDocument()); - } catch (const Base::Exception &) { } - } + FCMD_OBJ_HIDE(getBaseObject()); } void TaskTransformedParameters::showBase() { - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - try { - doc->setShow(getBaseObject()->getNameInDocument()); - } catch (const Base::Exception &) { } - } + FCMD_OBJ_SHOW(getBaseObject()); } void TaskTransformedParameters::exitSelectionMode() { - clearButtons(); - selectionMode = none; - Gui::Selection().rmvSelectionGate(); - showObject(); - hideBase(); + try { + clearButtons(); + selectionMode = none; + Gui::Selection().rmvSelectionGate(); + showObject(); + } catch(Base::Exception &e) { + e.ReportException(); + } } -void TaskTransformedParameters::addReferenceSelectionGate(bool edge, bool face) +void TaskTransformedParameters::addReferenceSelectionGate(bool edge, bool face, bool planar, bool whole) { - std::unique_ptr gateRefPtr(new ReferenceSelection(getBaseObject(), edge, face, /*point =*/ true)); + std::unique_ptr gateRefPtr( + new ReferenceSelection(getBaseObject(), edge, face, planar,false,whole)); std::unique_ptr gateDepPtr(new NoDependentsSelection(getTopTransformedObject())); Gui::Selection().addSelectionGate(new CombineSelectionFilterGates(gateRefPtr, gateDepPtr)); } @@ -373,19 +393,7 @@ TaskDlgTransformedParameters::TaskDlgTransformedParameters(ViewProviderTransform bool TaskDlgTransformedParameters::accept() { - std::string name = vp->getObject()->getNameInDocument(); - - //Gui::Command::openCommand(featureName + " changed"); - std::vector originals = parameter->getOriginals(); - std::stringstream str; - str << "App.ActiveDocument." << name.c_str() << ".Originals = ["; - for (std::vector::const_iterator it = originals.begin(); it != originals.end(); ++it) - { - if ((*it) != NULL) - str << "App.ActiveDocument." << (*it)->getNameInDocument() << ","; - } - str << "]"; - Gui::Command::runCommand(Gui::Command::Doc,str.str().c_str()); + parameter->exitSelectionMode(); // Continue (usually in virtual method accept()) return TaskDlgFeatureParameters::accept (); diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h index 2986338ca3..3b7aacf23b 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h @@ -133,7 +133,7 @@ public: /// Get the TransformedFeature object associated with this task // Either through the ViewProvider or the currently active subFeature of the parentTask - Part::Feature *getBaseObject() const; + App::DocumentObject *getBaseObject() const; /// Get the sketch object of the first original either of the object associated with this feature or with the parent feature (MultiTransform mode) App::DocumentObject* getSketchObject() const; @@ -142,6 +142,7 @@ public: virtual void apply() = 0; + void setupTransaction(); protected Q_SLOTS: /** * Returns the base transformation view provider @@ -181,11 +182,13 @@ protected: void hideBase(); void showBase(); - void addReferenceSelectionGate(bool edge, bool face); + void addReferenceSelectionGate(bool edge, bool face, bool planar=true, bool whole=false); bool isViewUpdated() const; int getUpdateViewTimeout() const; + void checkVisibility(); + protected: /** Notifies when the object is about to be removed. */ virtual void slotDeletedObject(const Gui::ViewProviderDocumentObject& Obj); diff --git a/src/Mod/PartDesign/Gui/Utils.cpp b/src/Mod/PartDesign/Gui/Utils.cpp index 8f0cec62c9..cc7a899f6b 100644 --- a/src/Mod/PartDesign/Gui/Utils.cpp +++ b/src/Mod/PartDesign/Gui/Utils.cpp @@ -28,6 +28,7 @@ # include #endif +#include #include #include #include @@ -51,6 +52,7 @@ #include "Utils.h" #include "WorkflowManager.h" +FC_LOG_LEVEL_INIT("PartDesignGui",true,true); //=========================================================================== // Helper for Body @@ -59,6 +61,35 @@ using namespace Attacher; namespace PartDesignGui { +bool setEdit(App::DocumentObject *obj, PartDesign::Body *body) { + if(!obj || !obj->getNameInDocument()) { + FC_ERR("invalid object"); + return false; + } + if(body == 0) { + body = getBodyFor(obj, false); + if(!body) { + FC_ERR("no body found"); + return false; + } + } + auto *activeView = Gui::Application::Instance->activeView(); + if(!activeView) return false; + App::DocumentObject *parent = 0; + std::string subname; + auto activeBody = activeView->getActiveObject(PDBODYKEY,&parent,&subname); + if(activeBody != body) { + parent = obj; + subname.clear(); + }else{ + subname += obj->getNameInDocument(); + subname += '.'; + } + _FCMD_OBJ_DOC_CMD(Gui,parent,"setEdit(" << Gui::Command::getObjectCmd(parent) + << ",0,'" << subname << "')"); + return true; +} + /*! * \brief Return active body or show a warning message. * If \a autoActivate is true (the default) then if there is @@ -67,7 +98,8 @@ namespace PartDesignGui { * \param autoActivate * \return Body */ -PartDesign::Body *getBody(bool messageIfNot, bool autoActivate, bool assertModern) +PartDesign::Body *getBody(bool messageIfNot, bool autoActivate, bool assertModern, + App::DocumentObject **topParent, std::string *subname) { PartDesign::Body * activeBody = nullptr; Gui::MDIView *activeView = Gui::Application::Instance->activeView(); @@ -76,14 +108,33 @@ PartDesign::Body *getBody(bool messageIfNot, bool autoActivate, bool assertModer bool singleBodyDocument = activeView->getAppDocument()-> countObjectsOfType(PartDesign::Body::getClassTypeId()) == 1; if (assertModern && PartDesignGui::assureModernWorkflow ( activeView->getAppDocument() ) ) { - activeBody = activeView->getActiveObject(PDBODYKEY); + activeBody = activeView->getActiveObject(PDBODYKEY,topParent,subname); if (!activeBody && singleBodyDocument && autoActivate) { - Gui::Command::doCommand( Gui::Command::Gui, - "Gui.activateView('Gui::View3DInventor', True)\n" - "Gui.activeView().setActiveObject('pdbody',App.ActiveDocument.findObjects('PartDesign::Body')[0])"); - activeBody = activeView->getActiveObject(PDBODYKEY); - return activeBody; + auto doc = activeView->getAppDocument(); + auto bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); + App::DocumentObject *parent = 0; + App::DocumentObject *body = 0; + std::string sub; + if(bodies.size()==1) { + body = bodies[0]; + for(auto &v : body->getParents()) { + if(v.first->getDocument()!=doc) + continue; + if(parent) { + body = 0; + break; + } + parent = v.first; + sub = v.second; + } + } + if(body) { + auto doc = parent?parent->getDocument():body->getDocument(); + _FCMD_DOC_CMD(Gui,doc,"ActiveView.setActiveObject('" << PDBODYKEY << "'," + << Gui::Command::getObjectCmd(parent?parent:body) << ",'" << sub << "')"); + return activeView->getActiveObject(PDBODYKEY,topParent,subname); + } } if (!activeBody && messageIfNot) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), @@ -113,24 +164,27 @@ PartDesign::Body * makeBody(App::Document *doc) // This is intended as a convenience when starting a new document. auto bodyName( doc->getUniqueObjectName("Body") ); Gui::Command::doCommand( Gui::Command::Doc, - "App.activeDocument().addObject('PartDesign::Body','%s')", - bodyName.c_str() ); - Gui::Command::doCommand( Gui::Command::Gui, - "Gui.activateView('Gui::View3DInventor', True)\n" - "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", - PDBODYKEY, bodyName.c_str() ); - - auto activeView( Gui::Application::Instance->activeView() ); - return activeView->getActiveObject(PDBODYKEY); + "App.getDocument('%s').addObject('PartDesign::Body','%s')", + doc->getName(), bodyName.c_str() ); + auto body = dynamic_cast(doc->getObject(bodyName.c_str())); + if(body) { + auto vp = Gui::Application::Instance->getViewProvider(body); + if(vp) { + // make the new body active + vp->doubleClicked(); + } + } + return body; } PartDesign::Body *getBodyFor(const App::DocumentObject* obj, bool messageIfNot, - bool autoActivate, bool assertModern) + bool autoActivate, bool assertModern, + App::DocumentObject **topParent, std::string *subname) { if(!obj) return nullptr; - PartDesign::Body * rv = getBody(/*messageIfNot =*/false, autoActivate, assertModern); + PartDesign::Body * rv = getBody(/*messageIfNot =*/false, autoActivate, assertModern, topParent, subname); if (rv && rv->hasObject(obj)) return rv; @@ -238,12 +292,9 @@ void fixSketchSupport (Sketcher::SketchObject* sketch) if (fabs(offset) < Precision::Confusion()) { // One of the base planes - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,[''])", - sketch->getNameInDocument(), plane->getNameInDocument () ); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.MapReversed = %s", - sketch->getNameInDocument(), reverseSketch ? "True" : "False"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.MapMode = '%s'", - sketch->getNameInDocument(), Attacher::AttachEngine::getModeName(Attacher::mmFlatFace).c_str()); + FCMD_OBJ_CMD(sketch,"Support = (" << Gui::Command::getObjectCmd(plane) << ",[''])"); + FCMD_OBJ_CMD(sketch,"MapReversed = " << (reverseSketch ? "True" : "False")); + FCMD_OBJ_CMD(sketch,"MapMode = '" << Attacher::AttachEngine::getModeName(Attacher::mmFlatFace) << "'"); } else { // Offset to base plane @@ -253,26 +304,16 @@ void fixSketchSupport (Sketcher::SketchObject* sketch) offset *= -1.0; std::string Datum = doc->getUniqueObjectName("DatumPlane"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')", - Datum.c_str()); - QString refStr = QString::fromLatin1("[(App.activeDocument().%1,'')]") - .arg ( QString::fromLatin1 ( plane->getNameInDocument () ) ); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = %s", - Datum.c_str(), refStr.toStdString().c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.MapMode = '%s'", - Datum.c_str(), AttachEngine::getModeName(Attacher::mmFlatFace).c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.AttachmentOffset.Base.z = %f", - Datum.c_str(), offset); - Gui::Command::doCommand(Gui::Command::Doc, - "App.activeDocument().%s.insertObject(App.activeDocument().%s, App.activeDocument().%s)", - body->getNameInDocument(), Datum.c_str(), sketch->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Doc, - "App.activeDocument().%s.Support = (App.activeDocument().%s,[''])", - sketch->getNameInDocument(), Datum.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.MapReversed = %s", - sketch->getNameInDocument(), reverseSketch ? "True" : "False"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.MapMode = '%s'", - sketch->getNameInDocument(),Attacher::AttachEngine::getModeName(Attacher::mmFlatFace).c_str()); + FCMD_DOC_CMD(doc,"addObject('PartDesign::Plane','"<getObject(Datum.c_str()); + FCMD_OBJ_CMD(obj,"Support = [(" << Gui::Command::getObjectCmd(plane) << ",'')]"); + FCMD_OBJ_CMD(obj,"MapMode = '" << AttachEngine::getModeName(Attacher::mmFlatFace) << "'"); + FCMD_OBJ_CMD(obj,"AttachmentOffset.Base.z = " << offset); + FCMD_OBJ_CMD(body,"insertObject("<getNameInDocument (); - for ( const auto & obj: doc->getObjects () ) { if ( !isPartDesignAwareObjecta ( obj ) ) { std::vector properties; @@ -341,7 +380,7 @@ void relinkToBody (PartDesign::Feature *feature) { if ( propLink->getValue() != feature ) { continue; } - valueStr = std::string ( "App.activeDocument()." ).append ( bodyName ); + valueStr = Gui::Command::getObjectCmd(body); } else if ( prop->isDerivedFrom ( App::PropertyLinkSub::getClassTypeId() ) ) { App::PropertyLinkSub *propLink = static_cast ( prop ); if ( propLink->getValue() != feature ) { @@ -381,8 +420,7 @@ void relinkToBody (PartDesign::Feature *feature) { } if ( !valueStr.empty () ) { - Gui::Command::doCommand ( Gui::Command::Doc, "App.activeDocument().%s.%s=%s", - obj->getNameInDocument (), prop->getName (), valueStr.c_str() ); + FCMD_OBJ_CMD(obj,prop->getName() << '=' << valueStr); } } } diff --git a/src/Mod/PartDesign/Gui/Utils.h b/src/Mod/PartDesign/Gui/Utils.h index 446a8ed011..e9a3aede92 100644 --- a/src/Mod/PartDesign/Gui/Utils.h +++ b/src/Mod/PartDesign/Gui/Utils.h @@ -43,8 +43,12 @@ namespace Sketcher { namespace PartDesignGui { +/// Activate edit mode of the given object +bool setEdit(App::DocumentObject *obj, PartDesign::Body *body = 0); + /// Return active body or show a warning message -PartDesign::Body *getBody(bool messageIfNot, bool autoActivate=true, bool assertModern=true); +PartDesign::Body *getBody(bool messageIfNot, bool autoActivate=true, bool assertModern=true, + App::DocumentObject **topParent=0, std::string *subname=0); /// Display error when there are existing Body objects, but none are active void needActiveBodyError(void); @@ -57,7 +61,9 @@ PartDesign::Body * makeBody(App::Document *doc); * Also unlike Body::findBodyFor it checks if the active body has the feature first. */ PartDesign::Body *getBodyFor(const App::DocumentObject*, bool messageIfNot, - bool autoActivate=true, bool assertModern=true); + bool autoActivate=true, bool assertModern=true, + App::DocumentObject **topParent=0, std::string *subname=0); + App::Part *getPartFor(const App::DocumentObject*, bool messageIfNot); App::Part *getActivePart(); diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 6c45ca3e50..6858522f59 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -42,6 +42,7 @@ #include #include +#include "Utils.h" #include "TaskFeatureParameters.h" #include "ViewProvider.h" @@ -64,7 +65,6 @@ ViewProvider::~ViewProvider() bool ViewProvider::doubleClicked(void) { #if 0 - PartDesign::Body* body = PartDesign::Body::findBodyOf(getObject()); // TODO May be move to setEdit()? (2015-07-26, Fat-Zer) if (body != NULL) { // Drop into insert mode so that the user doesn't see all the geometry that comes later in the tree @@ -80,11 +80,11 @@ bool ViewProvider::doubleClicked(void) #endif try { + PartDesign::Body* body = PartDesign::Body::findBodyOf(getObject()); std::string Msg("Edit "); Msg += this->pcObject->Label.getValue(); Gui::Command::openCommand(Msg.c_str()); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)", - this->pcObject->getNameInDocument()); + PartDesignGui::setEdit(pcObject,body); } catch (const Base::Exception&) { Gui::Command::abortCommand(); @@ -201,12 +201,9 @@ void ViewProvider::onChanged(const App::Property* prop) { for(App::DocumentObject* obj : body->Group.getValues()) { if(obj->isDerivedFrom(PartDesign::Feature::getClassTypeId()) && obj != getObject()) { - Gui::ViewProvider* vp = Gui::Application::Instance->activeDocument()->getViewProvider(obj); - if(!vp) - return; - - Gui::ViewProviderDocumentObject* vpd = static_cast(vp); - if (vpd->Visibility.getValue()) + auto vpd = Base::freecad_dynamic_cast( + Gui::Application::Instance->getViewProvider(obj)); + if(vpd && vpd->Visibility.getValue()) vpd->Visibility.setValue(false); } } @@ -282,8 +279,7 @@ bool ViewProvider::onDelete(const std::vector &) // // fixes (#3084) - Gui::Command::doCommand ( Gui::Command::Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)", - body->getNameInDocument(), feature->getNameInDocument() ); + FCMD_OBJ_CMD(body,"removeObject(" << Gui::Command::getObjectCmd(feature) << ')'); } return true; @@ -318,7 +314,7 @@ void ViewProvider::makeTemporaryVisible(bool onoff) //make sure to not use the overridden versions, as they change properties if (onoff) { if (VisualTouched) { - updateVisual(static_cast(getObject())->Shape.getValue()); + updateVisual(); } Gui::ViewProvider::show(); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderAddSub.cpp b/src/Mod/PartDesign/Gui/ViewProviderAddSub.cpp index 2bc9cb4473..85bcf6e551 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderAddSub.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderAddSub.cpp @@ -279,13 +279,17 @@ void ViewProviderAddSub::setPreviewDisplayMode(bool onoff) { // displays an object and when restoring the previous state it's // not sufficient to only revert the mask mode. Also the child // number of the switch node must be reverted. - if (onoff && displayMode!="Shape preview") { + if (onoff) { + if(pcModeSwitch->getChild(getDefaultMode()) == previewShape) + return; displayMode = getActiveDisplayMode(); whichChild = pcModeSwitch->whichChild.getValue(); setDisplayMaskMode("Shape preview"); } if (!onoff) { + if(pcModeSwitch->getChild(getDefaultMode()) != previewShape) + return; setDisplayMaskMode(displayMode.c_str()); pcModeSwitch->whichChild.setValue(whichChild); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderBase.cpp b/src/Mod/PartDesign/Gui/ViewProviderBase.cpp index c728137cd8..20f51a2ab9 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBase.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBase.cpp @@ -26,6 +26,7 @@ #ifndef _PreComp_ #endif +#include #include "ViewProviderBase.h" #include #include @@ -58,8 +59,7 @@ bool ViewProviderBase::doubleClicked(void) std::string Msg("Edit "); Msg += base->Label.getValue(); Gui::Command::openCommand(Msg.c_str()); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)", - base->getNameInDocument()); + FCMD_SET_EDIT(base); } catch (const Base::Exception&) { Gui::Command::abortCommand(); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 82541f4761..97d172d267 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -143,19 +143,16 @@ void ViewProviderBody::setupContextMenu(QMenu* menu, QObject* receiver, const ch bool ViewProviderBody::doubleClicked(void) { //first, check if the body is already active. - App::DocumentObject* activeBody = nullptr; - Gui::MDIView* activeView = this->getActiveView(); - if ( activeView ) { - activeBody = activeView->getActiveObject (PDBODYKEY); - } + auto activeDoc = Gui::Application::Instance->activeDocument(); + if(!activeDoc) + activeDoc = getDocument(); + auto activeView = activeDoc->getActiveView(); + if(!activeView) return false; - if (activeBody == this->getObject()){ + if (activeView->isActiveObject(getObject(),PDBODYKEY)) { //active body double-clicked. Deactivate. Gui::Command::doCommand(Gui::Command::Gui, - "Gui.activateView('Gui::View3DInventor', True)\n" - "Gui.getDocument('%s').ActiveView.setActiveObject('%s', None)", - this->getObject()->getDocument()->getName(), - PDBODYKEY); + "Gui.ActiveDocument.ActiveView.setActiveObject('%s', None)", PDBODYKEY); } else { // assure the PartDesign workbench @@ -165,21 +162,13 @@ bool ViewProviderBody::doubleClicked(void) auto* part = App::Part::getPartOfObject ( getObject() ); if ( part && part != getActiveView()->getActiveObject ( PARTKEY ) ) { Gui::Command::doCommand(Gui::Command::Gui, - "Gui.activateView('Gui::View3DInventor', True)\n" - "Gui.getDocument('%s').ActiveView.setActiveObject('%s', App.getDocument('%s').getObject('%s'))", - part->getDocument()->getName(), - PARTKEY, - part->getDocument()->getName(), - part->getNameInDocument()); + "Gui.ActiveDocument.ActiveView.setActiveObject('%s',%s)", + PARTKEY, Gui::Command::getObjectCmd(part).c_str()); } Gui::Command::doCommand(Gui::Command::Gui, - "Gui.activateView('Gui::View3DInventor', True)\n" - "Gui.getDocument('%s').ActiveView.setActiveObject('%s', App.getDocument('%s').getObject('%s'))", - this->getObject()->getDocument()->getName(), - PDBODYKEY, - this->getObject()->getDocument()->getName(), - this->getObject()->getNameInDocument()); + "Gui.ActiveDocument.ActiveView.setActiveObject('%s',%s)", + PDBODYKEY, Gui::Command::getObjectCmd(getObject()).c_str()); } return true; @@ -212,9 +201,7 @@ bool ViewProviderBody::doubleClicked(void) bool ViewProviderBody::onDelete ( const std::vector &) { // TODO May be do it conditionally? (2015-09-05, Fat-Zer) - Gui::Command::doCommand(Gui::Command::Doc, - "App.getDocument(\"%s\").getObject(\"%s\").removeObjectsFromDocument()" - ,getObject()->getDocument()->getName(), getObject()->getNameInDocument()); + FCMD_OBJ_CMD(getObject(),"removeObjectsFromDocument()"); return true; } @@ -250,6 +237,9 @@ void ViewProviderBody::updateData(const App::Property* prop) void ViewProviderBody::slotChangedObjectApp ( const App::DocumentObject& obj, const App::Property& prop ) { + if(App::GetApplication().isRestoring()) + return; + if (!obj.isDerivedFrom ( Part::Feature::getClassTypeId () ) || obj.isDerivedFrom ( Part::BodyBase::getClassTypeId () ) ) { // we are interested only in Part::Features, not in bodies return; @@ -364,7 +354,8 @@ void ViewProviderBody::updateOriginDatumSize () { void ViewProviderBody::onChanged(const App::Property* prop) { if(prop == &DisplayModeBody) { - + auto body = dynamic_cast(getObject()); + if ( DisplayModeBody.getValue() == 0 ) { //if we are in an override mode we need to make sure to come out, because //otherwise the maskmode is blocked and won't go into "through" @@ -374,8 +365,12 @@ void ViewProviderBody::onChanged(const App::Property* prop) { overrideMode = mode; } setDisplayMaskMode("Group"); + if(body) + body->setShowTip(false); } else { + if(body) + body->setShowTip(true); if(getOverrideMode() == "As Is") setDisplayMaskMode(DisplayMode.getValueAsString()); else { @@ -396,9 +391,15 @@ void ViewProviderBody::onChanged(const App::Property* prop) { void ViewProviderBody::unifyVisualProperty(const App::Property* prop) { + if(!pcObject || isRestoring()) + return; + if(prop == &Visibility || prop == &Selectable || - prop == &DisplayModeBody) + prop == &DisplayModeBody || + prop == &DiffuseColor || + prop == &PointColorArray || + prop == &LineColorArray) return; Gui::Document *gdoc = Gui::Application::Instance->getDocument ( pcObject->getDocument() ) ; diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 1d807538cf..d5f3f0420e 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -283,27 +283,28 @@ bool ViewProviderDatum::setEdit(int ModNum) bool ViewProviderDatum::doubleClicked(void) { + auto activeDoc = Gui::Application::Instance->activeDocument(); + if(!activeDoc) + activeDoc = getDocument(); + auto activeView = activeDoc->getActiveView(); + if(!activeView) return false; + std::string Msg("Edit "); Msg += this->pcObject->Label.getValue(); Gui::Command::openCommand(Msg.c_str()); Part::Datum* pcDatum = static_cast(getObject()); - PartDesign::Body* activeBody = getActiveView()->getActiveObject(PDBODYKEY); + PartDesign::Body* activeBody = activeView->getActiveObject(PDBODYKEY); auto datumBody = PartDesignGui::getBodyFor(pcDatum, false); if (datumBody != NULL) { if (datumBody != activeBody) { - Gui::Command::doCommand(Gui::Command::Gui, - "Gui.activateView('Gui::View3DInventor', True)\n" - "Gui.getDocument('%s').ActiveView.setActiveObject('%s', App.getDocument('%s').getObject('%s'))", - datumBody->getDocument()->getName(), - PDBODYKEY, - datumBody->getDocument()->getName(), - datumBody->getNameInDocument()); + _FCMD_OBJ_DOC_CMD(Gui,datumBody,"ActiveView.setActiveObject('" << PDBODYKEY << "', " + << Gui::Command::getObjectCmd(datumBody) << ")"); + activeBody = datumBody; } } - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)",this->pcObject->getNameInDocument()); - return true; + return PartDesignGui::setEdit(pcObject,activeBody); } void ViewProviderDatum::unsetEdit(int ModNum) diff --git a/src/Mod/PartDesign/Gui/ViewProviderLoft.cpp b/src/Mod/PartDesign/Gui/ViewProviderLoft.cpp index 6ae3bf5cd9..0add8ea7f9 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderLoft.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderLoft.cpp @@ -30,6 +30,7 @@ # include #endif +#include "Utils.h" #include "ViewProviderLoft.h" //#include "TaskLoftParameters.h" #include "TaskLoftParameters.h" @@ -82,8 +83,7 @@ void ViewProviderLoft::setupContextMenu(QMenu* menu, QObject* receiver, const ch bool ViewProviderLoft::doubleClicked(void) { - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)",this->pcObject->getNameInDocument()); - return true; + return PartDesignGui::setEdit(pcObject); } bool ViewProviderLoft::setEdit(int ModNum) diff --git a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp index 6feef1e935..398c7e318c 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp @@ -59,7 +59,8 @@ bool ViewProviderMultiTransform::onDelete(const std::vector &svec) { if ((*it) != NULL) Gui::Command::doCommand( - Gui::Command::Doc,"App.ActiveDocument.removeObject(\"%s\")", (*it)->getNameInDocument()); + Gui::Command::Doc,"App.getDocument('%s').removeObject(\"%s\")", \ + (*it)->getDocument()->getName(), (*it)->getNameInDocument()); } // Handle Originals diff --git a/src/Mod/PartDesign/Gui/ViewProviderPipe.cpp b/src/Mod/PartDesign/Gui/ViewProviderPipe.cpp index 3c7fb58431..dfeae56676 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPipe.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPipe.cpp @@ -30,6 +30,7 @@ # include #endif +#include "Utils.h" #include "ViewProviderPipe.h" //#include "TaskPipeParameters.h" #include "TaskPipeParameters.h" @@ -64,6 +65,11 @@ std::vector ViewProviderPipe::claimChildren(void)const if (sketch != NULL) temp.push_back(sketch); + for(App::DocumentObject* obj : pcPipe->Sections.getValues()) { + if (obj != NULL && obj->isDerivedFrom(Part::Part2DObject::getClassTypeId())) + temp.push_back(obj); + } + App::DocumentObject* spine = pcPipe->Spine.getValue(); if (spine != NULL && spine->isDerivedFrom(Part::Part2DObject::getClassTypeId())) temp.push_back(spine); @@ -85,8 +91,7 @@ void ViewProviderPipe::setupContextMenu(QMenu* menu, QObject* receiver, const ch bool ViewProviderPipe::doubleClicked(void) { - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)",this->pcObject->getNameInDocument()); - return true; + return PartDesignGui::setEdit(pcObject); } bool ViewProviderPipe::setEdit(int ModNum) { diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp index e69bc34fdd..553e31019e 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp @@ -24,8 +24,9 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include -#include +# include # include # include # include @@ -34,12 +35,15 @@ #include #include #include +#include #include #include "ViewProviderShapeBinder.h" #include "TaskShapeBinder.h" +FC_LOG_LEVEL_INIT("ShapeBinder",true,true); + using namespace PartDesignGui; PROPERTY_SOURCE(PartDesignGui::ViewProviderShapeBinder,PartGui::ViewProviderPart) @@ -188,3 +192,160 @@ void ViewProviderShapeBinder::setupContextMenu(QMenu* menu, QObject* receiver, c act = menu->addAction(QObject::tr("Edit shape binder"), receiver, member); act->setData(QVariant((int)ViewProvider::Default)); } + +//===================================================================================== + +PROPERTY_SOURCE(PartDesignGui::ViewProviderSubShapeBinder,PartGui::ViewProviderPart) + +ViewProviderSubShapeBinder::ViewProviderSubShapeBinder() { + sPixmap = "PartDesign_SubShapeBinder.svg"; + + //get the datum coloring sheme + // 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); +} + +bool ViewProviderSubShapeBinder::canDropObjectEx(App::DocumentObject *, + App::DocumentObject *, const char *, const std::vector &) const +{ + return true; +} + +std::string ViewProviderSubShapeBinder::dropObjectEx(App::DocumentObject *obj, App::DocumentObject *owner, + const char *subname, const std::vector &elements) +{ + auto self = dynamic_cast(getObject()); + if(!self) return std::string(); + std::map > values; + if(!subname) subname = ""; + std::string sub(subname); + if(sub.empty()) + values[owner?owner:obj] = elements; + else { + std::vector subs; + if(elements.size()) { + subs.reserve(elements.size()); + for(auto &element : elements) + subs.push_back(sub+element); + }else + subs.push_back(sub); + values[owner?owner:obj] = std::move(subs); + } + + self->setLinks(std::move(values),QApplication::keyboardModifiers()==Qt::ControlModifier); + if(self->Relative.getValue()) + updatePlacement(false); + return std::string(); +} + + +bool ViewProviderSubShapeBinder::doubleClicked() { + updatePlacement(true); + return true; +} + +void ViewProviderSubShapeBinder::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr("Synchronize"), receiver, member); + act->setData(QVariant((int)0)); + act = menu->addAction(QObject::tr("Select bound object"), receiver, member); + act->setData(QVariant((int)1)); +} + +bool ViewProviderSubShapeBinder::setEdit(int ModNum) { + + switch(ModNum) { + case 0: + updatePlacement(true); + break; + case 1: { + auto self = dynamic_cast(getObject()); + if(!self || !self->Support.getValue()) + break; + + Gui::Selection().selStackPush(); + Gui::Selection().clearSelection(); + for(auto &link : self->Support.getSubListValues()) { + auto obj = link.getValue(); + if(!obj || !obj->getNameInDocument()) + continue; + const auto &subs = link.getSubValues(); + if(subs.size()) + Gui::Selection().addSelections(obj->getDocument()->getName(), + obj->getNameInDocument(),subs); + else + Gui::Selection().addSelection(obj->getDocument()->getName(), + obj->getNameInDocument()); + } + Gui::Selection().selStackPush(); + break; + }} + return false; +} + +void ViewProviderSubShapeBinder::updatePlacement(bool transaction) { + auto self = dynamic_cast(getObject()); + if(!self || !self->Support.getValue()) + return; + + std::vector mats; + bool relative = self->Relative.getValue(); + App::DocumentObject *parent = 0; + std::string parentSub; + if(relative && self->getParents().size()) { + const auto &sel = Gui::Selection().getSelection("",0); + if(sel.size()!=1 || !sel[0].pObject || + sel[0].pObject->getSubObject(sel[0].SubName)!=self) + { + FC_WARN("invalid selection"); + } else { + parent = sel[0].pObject; + parentSub = sel[0].SubName; + } + } + + if(!transaction) { + if(relative) + self->Context.setValue(parent,parentSub.c_str()); + self->update(); + return; + } + + App::GetApplication().setActiveTransaction("Sync binder"); + try{ + if(relative) + self->Context.setValue(parent,parentSub.c_str()); + self->update(); + App::GetApplication().closeActiveTransaction(); + return; + }catch(Base::Exception &e) { + e.ReportException(); + }catch(Standard_Failure &e) { + std::ostringstream str; + Standard_CString msg = e.GetMessageString(); + str << typeid(e).name() << " "; + if (msg) {str << msg;} + else {str << "No OCCT Exception Message";} + FC_ERR(str.str()); + } + App::GetApplication().closeActiveTransaction(true); +} + +std::vector ViewProviderSubShapeBinder::claimChildren(void) const { + std::vector ret; + auto self = dynamic_cast(getObject()); + if(self && self->ClaimChildren.getValue() && self->Support.getValue()) + ret.push_back(self->Support.getValue()); + return ret; +} + diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h index 1cc8478a76..260a7ec631 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h @@ -51,6 +51,31 @@ private: }; +class PartDesignGuiExport ViewProviderSubShapeBinder : public PartGui::ViewProviderPart +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderShapeBinder); + +public: + + /// Constructor + ViewProviderSubShapeBinder(); + + bool canDropObjects() const override {return true;} + bool canDragAndDropObject(App::DocumentObject*) const override {return false;} + bool canDropObjectEx(App::DocumentObject *obj, App::DocumentObject *owner, + const char *subname, const std::vector &elements) const override; + std::string dropObjectEx(App::DocumentObject*, App::DocumentObject*, const char *, + const std::vector &) override; + std::vector claimChildren(void) const override; + + virtual bool doubleClicked() override; + virtual void setupContextMenu(QMenu* menu, QObject* receiver, const char* member) override; + virtual bool setEdit(int ModNum) override; + +private: + void updatePlacement(bool transaction); +}; + } // namespace PartDesignGui diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp index c853f389bd..1b3b9e3008 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp @@ -57,6 +57,7 @@ #include #include #include +#include using namespace PartDesignGui; @@ -70,6 +71,21 @@ void ViewProviderTransformed::setupContextMenu(QMenu* menu, QObject* receiver, c PartDesignGui::ViewProvider::setupContextMenu(menu, receiver, member); } +Gui::ViewProvider *ViewProviderTransformed::startEditing(int ModNum) { + PartDesign::Transformed* pcTransformed = static_cast(getObject()); + if(!pcTransformed->Originals.getSize()) { + for(auto obj : pcTransformed->getInList()) { + if(obj->isDerivedFrom(PartDesign::MultiTransform::getClassTypeId())) { + auto vp = Gui::Application::Instance->getViewProvider(obj); + if(vp) + return vp->startEditing(ModNum); + return 0; + } + } + } + return ViewProvider::startEditing(ModNum); +} + bool ViewProviderTransformed::setEdit(int ModNum) { pcRejectedRoot = new SoSeparator(); @@ -107,7 +123,7 @@ bool ViewProviderTransformed::setEdit(int ModNum) pcRejectedRoot->addChild(rejectedNormb); // NOTE: The code relies on the last child added here being index 6 pcRoot->addChild(pcRejectedRoot); - recomputeFeature(); + recomputeFeature(false); return ViewProvider::setEdit(ModNum); } @@ -136,12 +152,12 @@ bool ViewProviderTransformed::onDelete(const std::vector &s) return ViewProvider::onDelete(s); } -void ViewProviderTransformed::recomputeFeature(void) +void ViewProviderTransformed::recomputeFeature(bool recompute) { PartDesign::Transformed* pcTransformed = static_cast(getObject()); - pcTransformed->getDocument()->recomputeFeature(pcTransformed); - const std::vector log = pcTransformed->getDocument()->getRecomputeLog(); - PartDesign::Transformed::rejectedMap rejected_trsf = pcTransformed->getRejectedTransformations(); + if(recompute || (pcTransformed->isError() || pcTransformed->mustExecute())) + pcTransformed->recomputeFeature(true); + const PartDesign::Transformed::rejectedMap &rejected_trsf = pcTransformed->getRejectedTransformations(); unsigned rejected = 0; for (PartDesign::Transformed::rejectedMap::const_iterator r = rejected_trsf.begin(); r != rejected_trsf.end(); r++) rejected += r->second.size(); @@ -155,13 +171,15 @@ void ViewProviderTransformed::recomputeFeature(void) msg = msg.arg(rejected); } } - if (log.size() > 0) { + auto error = pcTransformed->getDocument()->getErrorDescription(pcTransformed); + if (error) { msg = msg.arg(QString::fromLatin1("%1
")); - msg = msg.arg(QString::fromStdString(log.back()->Why)); + msg = msg.arg(QString::fromUtf8(error)); } else { msg = msg.arg(QString::fromLatin1("%1
")); msg = msg.arg(QObject::tr("Transformation succeeded")); } + diagMessage = msg; signalDiagnosis(msg); // Clear all the rejected stuff diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.h b/src/Mod/PartDesign/Gui/ViewProviderTransformed.h index db8ee43169..da5828b987 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.h +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.h @@ -52,6 +52,8 @@ public: // The feature name of the subclass std::string featureName; + virtual Gui::ViewProvider *startEditing(int ModNum=0) override; + protected: virtual bool setEdit(int ModNum); virtual void unsetEdit(int ModNum); @@ -61,8 +63,11 @@ protected: // node for the representation of rejected repetitions SoGroup * pcRejectedRoot; + QString diagMessage; + public: - void recomputeFeature(); + void recomputeFeature(bool recompute=true); + QString getMessage() const {return diagMessage;} }; diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index bf037e4990..ac7407d2cc 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -480,6 +480,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "PartDesign_Plane" << "PartDesign_CoordinateSystem" << "PartDesign_ShapeBinder" + << "PartDesign_SubShapeBinder" << "PartDesign_Clone" << "Separator" << "PartDesign_Pad" @@ -546,6 +547,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "PartDesign_Plane" << "PartDesign_CoordinateSystem" << "PartDesign_ShapeBinder" + << "PartDesign_SubShapeBinder" << "PartDesign_Clone"; part = new Gui::ToolBarItem(root);