diff --git a/src/App/GeoFeatureGroupExtension.cpp b/src/App/GeoFeatureGroupExtension.cpp index a9dadff5f..f32872634 100644 --- a/src/App/GeoFeatureGroupExtension.cpp +++ b/src/App/GeoFeatureGroupExtension.cpp @@ -57,7 +57,7 @@ void GeoFeatureGroupExtension::initExtension(ExtensionContainer* obj) { if(!obj->isDerivedFrom(App::GeoFeature::getClassTypeId())) throw Base::Exception("GeoFeatureGroupExtension can only be applied to GeoFeatures"); - App::Extension::initExtension(obj); + App::GroupExtension::initExtension(obj); } PropertyPlacement& GeoFeatureGroupExtension::placement() { @@ -143,9 +143,9 @@ bool GeoFeatureGroupExtension::geoHasObject (const DocumentObject* obj) const { DocumentObject* GeoFeatureGroupExtension::getGroupOfObject(const DocumentObject* obj, bool indirect) { const Document* doc = obj->getDocument(); - std::vector grps = doc->getObjectsOfType(GeoFeatureGroupExtension::getExtensionClassTypeId()); + std::vector grps = doc->getObjectsWithExtension(GeoFeatureGroupExtension::getExtensionClassTypeId()); for (std::vector::const_iterator it = grps.begin(); it != grps.end(); ++it) { - GeoFeatureGroupExtension* grp = (GeoFeatureGroupExtension*)(*it); + GeoFeatureGroupExtension* grp = (*it)->getExtensionByType(); if ( indirect ) { if (grp->geoHasObject(obj)) { return dynamic_cast(grp); diff --git a/src/App/GroupExtension.cpp b/src/App/GroupExtension.cpp index 54e3ce95a..0ed16d8f1 100644 --- a/src/App/GroupExtension.cpp +++ b/src/App/GroupExtension.cpp @@ -63,6 +63,11 @@ void GroupExtension::addObject(DocumentObject* obj) if(!allowObject(obj)) return; + //only one group per object + auto *group = App::GroupExtension::getGroupOfObject(obj); + if(group && group != getExtendedObject()) + group->getExtensionByType()->removeObject(obj); + if (!hasObject(obj)) { std::vector grp = Group.getValues(); grp.push_back(obj); @@ -180,9 +185,9 @@ int GroupExtension::countObjectsOfType(const Base::Type& typeId) const DocumentObject* GroupExtension::getGroupOfObject(const DocumentObject* obj) { const Document* doc = obj->getDocument(); - std::vector grps = doc->getObjectsOfType(GroupExtension::getExtensionClassTypeId()); + std::vector grps = doc->getObjectsWithExtension(GroupExtension::getExtensionClassTypeId()); for (std::vector::const_iterator it = grps.begin(); it != grps.end(); ++it) { - GroupExtension* grp = (GroupExtension*)(*it); + GroupExtension* grp = (*it)->getExtensionByType(); if (grp->hasObject(obj)) return *it; } diff --git a/src/App/OriginGroupExtension.cpp b/src/App/OriginGroupExtension.cpp index 739d01f83..0235ea6b8 100644 --- a/src/App/OriginGroupExtension.cpp +++ b/src/App/OriginGroupExtension.cpp @@ -129,6 +129,69 @@ void OriginGroupExtension::onExtendedUnsetupObject () { GeoFeatureGroupExtension::onExtendedUnsetupObject (); } +void OriginGroupExtension::relinkToOrigin(App::DocumentObject* obj) +{ + //we get all links and replace the origin objects if needed (subnames need not to change, they + //would stay the same) + std::vector< App::DocumentObject* > result; + std::vector list; + obj->getPropertyList(list); + for(App::Property* prop : list) { + if(prop->getTypeId().isDerivedFrom(App::PropertyLink::getClassTypeId())) { + + auto p = static_cast(prop); + if(!p->getValue() || !p->getValue()->isDerivedFrom(App::OriginFeature::getClassTypeId())) + continue; + + p->setValue(getOrigin()->getOriginFeature(static_cast(p->getValue())->Role.getValue())); + } + else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkList::getClassTypeId())) { + auto p = static_cast(prop); + auto vec = p->getValues(); + std::vector result; + bool changed = false; + for(App::DocumentObject* o : vec) { + if(!o || !o->isDerivedFrom(App::OriginFeature::getClassTypeId())) + result.push_back(o); + else { + result.push_back(getOrigin()->getOriginFeature(static_cast(o)->Role.getValue())); + changed = true; + } + } + if(changed) + static_cast(prop)->setValues(result); + } + else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSub::getClassTypeId())) { + auto p = static_cast(prop); + if(!p->getValue() || !p->getValue()->isDerivedFrom(App::OriginFeature::getClassTypeId())) + continue; + + p->setValue(getOrigin()->getOriginFeature(static_cast(p->getValue())->Role.getValue())); + } + else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSubList::getClassTypeId())) { + auto p = static_cast(prop); + auto vec = p->getValues(); + std::vector result; + bool changed = false; + for(App::DocumentObject* o : vec) { + if(!o || !o->isDerivedFrom(App::OriginFeature::getClassTypeId())) + result.push_back(o); + else { + result.push_back(getOrigin()->getOriginFeature(static_cast(o)->Role.getValue())); + changed = true; + } + } + if(changed) + static_cast(prop)->setValues(result); + } + } +} + +void OriginGroupExtension::addObject(DocumentObject* obj) { + relinkToOrigin(obj); + App::GeoFeatureGroupExtension::addObject(obj); +} + // Python feature --------------------------------------------------------- diff --git a/src/App/OriginGroupExtension.h b/src/App/OriginGroupExtension.h index fe5cb89f3..53938ade2 100644 --- a/src/App/OriginGroupExtension.h +++ b/src/App/OriginGroupExtension.h @@ -62,6 +62,11 @@ public: /// Origin linked to the group PropertyLink Origin; + + //changes all links of obj to a origin to point to this groupes origin + void relinkToOrigin(App::DocumentObject* obj); + + virtual void addObject(DocumentObject* obj); protected: /// Checks integrity of the Origin diff --git a/src/Gui/ViewProviderGeoFeatureGroupExtension.cpp b/src/Gui/ViewProviderGeoFeatureGroupExtension.cpp index 41255be87..fe9d8f6d8 100644 --- a/src/Gui/ViewProviderGeoFeatureGroupExtension.cpp +++ b/src/Gui/ViewProviderGeoFeatureGroupExtension.cpp @@ -29,6 +29,9 @@ #endif #include "ViewProviderGeoFeatureGroupExtension.h" +#include "Command.h" +#include "Application.h" +#include "Document.h" #include #include @@ -91,6 +94,89 @@ void ViewProviderGeoFeatureGroupExtension::extensionUpdateData(const App::Proper } } +std::vector< App::DocumentObject* > ViewProviderGeoFeatureGroupExtension::getLinkedObjects(App::DocumentObject* obj) { + + if(!obj) + return std::vector< App::DocumentObject* >(); + + //we get all linked objects, and that recursively + std::vector< App::DocumentObject* > result; + std::vector list; + obj->getPropertyList(list); + for(App::Property* prop : list) { + if(prop->getTypeId().isDerivedFrom(App::PropertyLink::getClassTypeId())) + result.push_back(static_cast(prop)->getValue()); + else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkList::getClassTypeId())) { + auto vec = static_cast(prop)->getValues(); + result.insert(result.end(), vec.begin(), vec.end()); + } + else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSub::getClassTypeId())) + result.push_back(static_cast(prop)->getValue()); + else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSubList::getClassTypeId())) { + auto vec = static_cast(prop)->getValues(); + result.insert(result.end(), vec.begin(), vec.end()); + } + } + + //clear all null objects + result.erase(std::remove(result.begin(), result.end(), nullptr), result.end()); + + //collect all dependencies of those objects + for(App::DocumentObject *obj : result) { + auto vec = getLinkedObjects(obj); + result.insert(result.end(), vec.begin(), vec.end()); + } + + return result; +} + +void ViewProviderGeoFeatureGroupExtension::extensionDropObject(App::DocumentObject* obj) { + + // Open command + App::DocumentObject* grp = static_cast(getExtendedViewProvider()->getObject()); + App::Document* doc = grp->getDocument(); + Gui::Document* gui = Gui::Application::Instance->getDocument(doc); + gui->openCommand("Move object"); + + //links between different CS are not allowed, hence we need to ensure if all dependencies are in + //the same geofeaturegroup + auto vec = getLinkedObjects(obj); + + //remove all objects already in the correct group + vec.erase(std::remove_if(vec.begin(), vec.end(), [this](App::DocumentObject* o){ + return App::GroupExtension::getGroupOfObject(o) == this->getExtendedViewProvider()->getObject(); + }), vec.end()); + + vec.push_back(obj); + + for(App::DocumentObject* o : vec) { + // build Python command for execution + QString cmd; + cmd = QString::fromLatin1("App.getDocument(\"%1\").getObject(\"%2\").addObject(" + "App.getDocument(\"%1\").getObject(\"%3\"))") + .arg(QString::fromLatin1(doc->getName())) + .arg(QString::fromLatin1(grp->getNameInDocument())) + .arg(QString::fromLatin1(o->getNameInDocument())); + + Gui::Command::doCommand(Gui::Command::App, cmd.toUtf8()); + } + gui->commitCommand(); +} + + +void ViewProviderGeoFeatureGroupExtension::extensionDragObject(App::DocumentObject* obj) { + //links between different coordinate systems are not allowed, hence draging one object also needs + //to drag out all dependend objects + auto vec = getLinkedObjects(obj); + + //add this object + vec.push_back(obj); + + for(App::DocumentObject* obj : vec) + ViewProviderGroupExtension::extensionDragObject(obj); +} + + namespace Gui { EXTENSION_PROPERTY_SOURCE_TEMPLATE(Gui::ViewProviderGeoFeatureGroupExtensionPython, Gui::ViewProviderGeoFeatureGroupExtension) diff --git a/src/Gui/ViewProviderGeoFeatureGroupExtension.h b/src/Gui/ViewProviderGeoFeatureGroupExtension.h index 0521ac0b2..fc17992c8 100644 --- a/src/Gui/ViewProviderGeoFeatureGroupExtension.h +++ b/src/Gui/ViewProviderGeoFeatureGroupExtension.h @@ -58,8 +58,13 @@ public: virtual void extensionUpdateData(const App::Property*) override; + virtual void extensionDropObject(App::DocumentObject*); + virtual void extensionDragObject(App::DocumentObject*); + protected: SoGroup *pcGroupChildren; + + std::vector getLinkedObjects(App::DocumentObject* obj); }; typedef ViewProviderExtensionPythonT ViewProviderGeoFeatureGroupExtensionPython; diff --git a/src/Gui/ViewProviderOriginGroupExtension.cpp b/src/Gui/ViewProviderOriginGroupExtension.cpp index 226af9a9c..d03faf42b 100644 --- a/src/Gui/ViewProviderOriginGroupExtension.cpp +++ b/src/Gui/ViewProviderOriginGroupExtension.cpp @@ -34,6 +34,7 @@ #include "ViewProviderOrigin.h" #include "View3DInventorViewer.h" #include "View3DInventor.h" +#include "Command.h" #include #include #include @@ -196,6 +197,63 @@ void ViewProviderOriginGroupExtension::updateOriginSize () { vpOrigin->Size.setValue ( size * 1.3 ); } +void ViewProviderOriginGroupExtension::extensionDragObject(App::DocumentObject* obj) { + + //links between different coordinate systems are not allowed, hence draging one object also needs + //to drag out all dependend objects + auto vec = getLinkedObjects(obj); + + //remove all origin objects + vec.erase(std::remove_if(vec.begin(), vec.end(), [this](App::DocumentObject* o) { + return o->isDerivedFrom(App::OriginFeature::getClassTypeId());}), vec.end()); + + //add the original object + vec.push_back(obj); + + for(App::DocumentObject* obj : vec) + ViewProviderGroupExtension::extensionDragObject(obj); +} + +void ViewProviderOriginGroupExtension::extensionDropObject(App::DocumentObject* obj) { + + // Open command + App::DocumentObject* grp = static_cast(getExtendedViewProvider()->getObject()); + App::Document* doc = grp->getDocument(); + Gui::Document* gui = Gui::Application::Instance->getDocument(doc); + gui->openCommand("Move object"); + + //links between different CS are not allowed, hence we need to enure if all dependencies are in + //the same geofeaturegroup + auto vec = getLinkedObjects(obj); + + //remove all origin objects + vec.erase(std::remove_if(vec.begin(), vec.end(), [](App::DocumentObject* o) { + return o->isDerivedFrom(App::OriginFeature::getClassTypeId());}), vec.end()); + + //remove all objects already in the correct group + vec.erase(std::remove_if(vec.begin(), vec.end(), [this](App::DocumentObject* o){ + return App::GroupExtension::getGroupOfObject(o) == this->getExtendedViewProvider()->getObject(); + }), vec.end()); + + //add the original object + vec.push_back(obj); + + for(App::DocumentObject* o : vec) { + + // build Python command for execution + QString cmd; + cmd = QString::fromLatin1("App.getDocument(\"%1\").getObject(\"%2\").addObject(" + "App.getDocument(\"%1\").getObject(\"%3\"))") + .arg(QString::fromLatin1(doc->getName())) + .arg(QString::fromLatin1(grp->getNameInDocument())) + .arg(QString::fromLatin1(o->getNameInDocument())); + + Gui::Command::doCommand(Gui::Command::App, cmd.toUtf8()); + } + gui->commitCommand(); + +} + namespace Gui { EXTENSION_PROPERTY_SOURCE_TEMPLATE(Gui::ViewProviderOriginGroupExtensionPython, Gui::ViewProviderOriginGroupExtension) diff --git a/src/Gui/ViewProviderOriginGroupExtension.h b/src/Gui/ViewProviderOriginGroupExtension.h index 33137c8a7..1d42bd26e 100644 --- a/src/Gui/ViewProviderOriginGroupExtension.h +++ b/src/Gui/ViewProviderOriginGroupExtension.h @@ -46,6 +46,9 @@ public: virtual void extensionAttach(App::DocumentObject *pcObject) override; virtual void extensionUpdateData(const App::Property* prop) override; + virtual void extensionDragObject(App::DocumentObject*) override; + virtual void extensionDropObject(App::DocumentObject*); + void updateOriginSize(); protected: diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 3e4212e96..ad6ee7639 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -169,7 +169,7 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start) start = Tip.getValue(); } - if ( !start ) { // no tip + if ( !start || !hasObject(start) ) { // no or faulty tip return nullptr; } @@ -268,7 +268,12 @@ void Body::addObject(App::DocumentObject *feature) { if(!isAllowed(feature)) throw Base::Exception("Body: object is not allowed"); - + + //only one group per object + auto *group = App::GroupExtension::getGroupOfObject(feature); + if(group && group != getExtendedObject()) + group->getExtensionByType()->removeObject(feature); + insertObject (feature, getNextSolidFeature (), /*after = */ false); // Move the Tip if we added a solid if (isSolidFeature(feature)) { @@ -292,6 +297,9 @@ void Body::insertObject(App::DocumentObject* feature, App::DocumentObject* targe throw Base::Exception("Body: the feature we should insert relative to is not part of that body"); } } + + //ensure that all origin links are ok + relinkToOrigin(feature); std::vector model = Group.getValues(); std::vector::iterator insertInto;