diff --git a/src/App/DocumentObjectPy.xml b/src/App/DocumentObjectPy.xml
index 156d6e6c49..31e009cbbe 100644
--- a/src/App/DocumentObjectPy.xml
+++ b/src/App/DocumentObjectPy.xml
@@ -55,6 +55,20 @@
Recomputes this object
+
+
+ Returns the group the object is in or None if it is not part of a group.
+ Note that an object can only be in a single group, hence only a single return
+ value.
+
+
+
+
+ Returns the GeoFeatureGroup, and hence the local coorinate system, the object
+ is in or None if it is not part of a group. Note that an object can only be
+ in a single group, hence only a single return value.
+
+
A list of all objects this object links to.
diff --git a/src/App/DocumentObjectPyImp.cpp b/src/App/DocumentObjectPyImp.cpp
index da62d024d2..cb5835d7ed 100644
--- a/src/App/DocumentObjectPyImp.cpp
+++ b/src/App/DocumentObjectPyImp.cpp
@@ -25,6 +25,8 @@
#include "DocumentObject.h"
#include "Document.h"
#include "Expression.h"
+#include "GroupExtension.h"
+#include "GeoFeatureGroupExtension.h"
// inclusion of the generated files (generated out of DocumentObjectPy.xml)
#include
@@ -315,6 +317,42 @@ PyObject* DocumentObjectPy::recompute(PyObject *args)
}
}
+PyObject* DocumentObjectPy::getParentGroup(PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ try {
+ auto grp = GroupExtension::getGroupOfObject(getDocumentObjectPtr());
+ if(!grp) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return grp->getPyObject();
+ }
+ catch (const Base::Exception& e) {
+ throw Py::RuntimeError(e.what());
+ }
+}
+
+PyObject* DocumentObjectPy::getParentGeoFeatureGroup(PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ try {
+ auto grp = GeoFeatureGroupExtension::getGroupOfObject(getDocumentObjectPtr());
+ if(!grp) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return grp->getPyObject();
+ }
+ catch (const Base::Exception& e) {
+ throw Py::RuntimeError(e.what());
+ }
+}
+
PyObject *DocumentObjectPy::getCustomAttributes(const char* attr) const
{
// search for dynamic property
diff --git a/src/App/ExtensionContainer.cpp b/src/App/ExtensionContainer.cpp
index 64ff37606c..cbc203a76b 100644
--- a/src/App/ExtensionContainer.cpp
+++ b/src/App/ExtensionContainer.cpp
@@ -80,7 +80,7 @@ bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const {
}
return false;
}
- return true;
+ return found;
}
bool ExtensionContainer::hasExtension(const std::string& name) const {
diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp
index af835ad33e..d7320b47d7 100644
--- a/src/App/PropertyLinks.cpp
+++ b/src/App/PropertyLinks.cpp
@@ -40,6 +40,7 @@
#include "PropertyLinks.h"
#include "GeoFeatureGroupExtension.h"
+#include "OriginFeature.h"
using namespace App;
using namespace Base;
@@ -88,6 +89,14 @@ void ensureCorrectGroups(PropertyContainer* container, App::DocumentObject* obje
if(!container->isDerivedFrom(App::DocumentObject::getClassTypeId()))
return;
+ //links to origin feature can go over CS borders, as they are the same everywere anyway. This is
+ //a workaround to allow moving of objects between GeoFeatureGroups that link to origin features.
+ //During movement there is always a link in to the wron CS and the error would occure. If we
+ //surpress the error at least the origin links can be fixed afterwards
+ //TODO: Find a more elegant solution
+ if(object->isDerivedFrom(App::OriginFeature::getClassTypeId()))
+ return;
+
//undo and redo do not need to be handled as they can only go to already checked stated (the link
//state during those actions can get messed up, we really don't want to check for that)
if(object->getDocument()->performsTransactionOperation())
diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp
index 7ec008b9aa..ca713c5571 100644
--- a/src/Mod/PartDesign/App/Body.cpp
+++ b/src/Mod/PartDesign/App/Body.cpp
@@ -283,6 +283,9 @@ std::vector Body::addObject(App::DocumentObject *feature)
if (isSolidFeature(feature)) {
Tip.setValue (feature);
}
+
+ std::vector result = {feature};
+ return result;
}
@@ -380,6 +383,8 @@ std::vector Body::removeObject(App::DocumentObject* featur
model.erase(it);
Group.setValues(model);
}
+ std::vector result = {feature};
+ return result;
}
diff --git a/src/Mod/PartDesign/Gui/CommandBody.cpp b/src/Mod/PartDesign/Gui/CommandBody.cpp
index e19488bcfb..4b1df7b51c 100644
--- a/src/Mod/PartDesign/Gui/CommandBody.cpp
+++ b/src/Mod/PartDesign/Gui/CommandBody.cpp
@@ -615,6 +615,9 @@ CmdPartDesignMoveFeature::CmdPartDesignMoveFeature()
void CmdPartDesignMoveFeature::activated(int iMsg)
{
+ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Features moving is diabled"),
+ QObject::tr("Moving features is currently disabled as there is no way of handling origin connected moves"));
+ /*
Q_UNUSED(iMsg);
std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId());
if (features.empty()) return;
@@ -731,7 +734,7 @@ void CmdPartDesignMoveFeature::activated(int iMsg)
PartDesignGui::relinkToOrigin(feat, target);
}
- updateActive();
+ updateActive();*/
}
bool CmdPartDesignMoveFeature::isActive(void)
diff --git a/src/Mod/PartDesign/TestPartDesignGui.py b/src/Mod/PartDesign/TestPartDesignGui.py
index cac9c51803..5daa2d4db0 100644
--- a/src/Mod/PartDesign/TestPartDesignGui.py
+++ b/src/Mod/PartDesign/TestPartDesignGui.py
@@ -86,121 +86,121 @@ class PartDesignGuiTestCases(unittest.TestCase):
def setUp(self):
self.Doc = FreeCAD.newDocument("SketchGuiTest")
- def testRefuseToMoveSingleFeature(self):
- FreeCAD.Console.PrintMessage('Testing refuse to move the feature with dependecies from one body to another\n')
- self.BodySource = self.Doc.addObject('PartDesign::Body','Body')
- Gui.activeView().setActiveObject('pdbody', self.BodySource)
+ #def testRefuseToMoveSingleFeature(self):
+ #FreeCAD.Console.PrintMessage('Testing refuse to move the feature with dependecies from one body to another\n')
+ #self.BodySource = self.Doc.addObject('PartDesign::Body','Body')
+ #Gui.activeView().setActiveObject('pdbody', self.BodySource)
- self.BoxObj = self.Doc.addObject('PartDesign::AdditiveBox','Box')
- self.BoxObj.Length=10.0
- self.BoxObj.Width=10.0
- self.BoxObj.Height=10.0
- self.BodySource.addObject(self.BoxObj)
+ #self.BoxObj = self.Doc.addObject('PartDesign::AdditiveBox','Box')
+ #self.BoxObj.Length=10.0
+ #self.BoxObj.Width=10.0
+ #self.BoxObj.Height=10.0
+ #self.BodySource.addObject(self.BoxObj)
- App.ActiveDocument.recompute()
+ #App.ActiveDocument.recompute()
- self.Sketch = self.Doc.addObject('Sketcher::SketchObject','Sketch')
- self.Sketch.Support = (self.BoxObj, ('Face3',))
- self.Sketch.MapMode = 'FlatFace'
- self.BodySource.addObject(self.Sketch)
+ #self.Sketch = self.Doc.addObject('Sketcher::SketchObject','Sketch')
+ #self.Sketch.Support = (self.BoxObj, ('Face3',))
+ #self.Sketch.MapMode = 'FlatFace'
+ #self.BodySource.addObject(self.Sketch)
- geoList = []
- geoList.append(Part.LineSegment(App.Vector(2.0,8.0,0),App.Vector(8.0,8.0,0)))
- geoList.append(Part.LineSegment(App.Vector(8.0,8.0,0),App.Vector(8.0,2.0,0)))
- geoList.append(Part.LineSegment(App.Vector(8.0,2.0,0),App.Vector(2.0,2.0,0)))
- geoList.append(Part.LineSegment(App.Vector(2.0,2.0,0),App.Vector(2.0,8.0,0)))
- self.Sketch.addGeometry(geoList,False)
- conList = []
- conList.append(Sketcher.Constraint('Coincident',0,2,1,1))
- conList.append(Sketcher.Constraint('Coincident',1,2,2,1))
- conList.append(Sketcher.Constraint('Coincident',2,2,3,1))
- conList.append(Sketcher.Constraint('Coincident',3,2,0,1))
- conList.append(Sketcher.Constraint('Horizontal',0))
- conList.append(Sketcher.Constraint('Horizontal',2))
- conList.append(Sketcher.Constraint('Vertical',1))
- conList.append(Sketcher.Constraint('Vertical',3))
- self.Sketch.addConstraint(conList)
+ #geoList = []
+ #geoList.append(Part.LineSegment(App.Vector(2.0,8.0,0),App.Vector(8.0,8.0,0)))
+ #geoList.append(Part.LineSegment(App.Vector(8.0,8.0,0),App.Vector(8.0,2.0,0)))
+ #geoList.append(Part.LineSegment(App.Vector(8.0,2.0,0),App.Vector(2.0,2.0,0)))
+ #geoList.append(Part.LineSegment(App.Vector(2.0,2.0,0),App.Vector(2.0,8.0,0)))
+ #self.Sketch.addGeometry(geoList,False)
+ #conList = []
+ #conList.append(Sketcher.Constraint('Coincident',0,2,1,1))
+ #conList.append(Sketcher.Constraint('Coincident',1,2,2,1))
+ #conList.append(Sketcher.Constraint('Coincident',2,2,3,1))
+ #conList.append(Sketcher.Constraint('Coincident',3,2,0,1))
+ #conList.append(Sketcher.Constraint('Horizontal',0))
+ #conList.append(Sketcher.Constraint('Horizontal',2))
+ #conList.append(Sketcher.Constraint('Vertical',1))
+ #conList.append(Sketcher.Constraint('Vertical',3))
+ #self.Sketch.addConstraint(conList)
- self.Pad = self.Doc.addObject("PartDesign::Pad","Pad")
- self.Pad.Profile = self.Sketch
- self.Pad.Length = 10.000000
- self.Pad.Length2 = 100.000000
- self.Pad.Type = 0
- self.Pad.UpToFace = None
- self.Pad.Reversed = 0
- self.Pad.Midplane = 0
- self.Pad.Offset = 0.000000
+ #self.Pad = self.Doc.addObject("PartDesign::Pad","Pad")
+ #self.Pad.Profile = self.Sketch
+ #self.Pad.Length = 10.000000
+ #self.Pad.Length2 = 100.000000
+ #self.Pad.Type = 0
+ #self.Pad.UpToFace = None
+ #self.Pad.Reversed = 0
+ #self.Pad.Midplane = 0
+ #self.Pad.Offset = 0.000000
- self.BodySource.addObject(self.Pad)
+ #self.BodySource.addObject(self.Pad)
- self.Doc.recompute()
- Gui.SendMsgToActiveView("ViewFit")
+ #self.Doc.recompute()
+ #Gui.SendMsgToActiveView("ViewFit")
- self.BodyTarget = self.Doc.addObject('PartDesign::Body','Body')
+ #self.BodyTarget = self.Doc.addObject('PartDesign::Body','Body')
- Gui.Selection.addSelection(App.ActiveDocument.Pad)
- cobj = CallableCheckWarning(self)
- QtCore.QTimer.singleShot(500, cobj)
- Gui.runCommand('PartDesign_MoveFeature')
- #assert depenedencies of the Sketch
- self.assertEqual(len(self.BodySource.Group), 3, "Source body feature count is wrong")
- self.assertEqual(len(self.BodyTarget.Group), 0, "Target body feature count is wrong")
+ #Gui.Selection.addSelection(App.ActiveDocument.Pad)
+ #cobj = CallableCheckWarning(self)
+ #QtCore.QTimer.singleShot(500, cobj)
+ #Gui.runCommand('PartDesign_MoveFeature')
+ ##assert depenedencies of the Sketch
+ #self.assertEqual(len(self.BodySource.Group), 3, "Source body feature count is wrong")
+ #self.assertEqual(len(self.BodyTarget.Group), 0, "Target body feature count is wrong")
- def testMoveSingleFeature(self):
- FreeCAD.Console.PrintMessage('Testing moving one feature from one body to another\n')
- self.BodySource = self.Doc.addObject('PartDesign::Body','Body')
- Gui.activeView().setActiveObject('pdbody', self.BodySource)
+ #def testMoveSingleFeature(self):
+ #FreeCAD.Console.PrintMessage('Testing moving one feature from one body to another\n')
+ #self.BodySource = self.Doc.addObject('PartDesign::Body','Body')
+ #Gui.activeView().setActiveObject('pdbody', self.BodySource)
- self.Sketch = self.Doc.addObject('Sketcher::SketchObject','Sketch')
- self.Sketch.Support = (self.Doc.XY_Plane, [''])
- self.Sketch.MapMode = 'FlatFace'
- self.BodySource.addObject(self.Sketch)
-
- geoList = []
- geoList.append(Part.LineSegment(App.Vector(-10.000000,10.000000,0),App.Vector(10.000000,10.000000,0)))
- geoList.append(Part.LineSegment(App.Vector(10.000000,10.000000,0),App.Vector(10.000000,-10.000000,0)))
- geoList.append(Part.LineSegment(App.Vector(10.000000,-10.000000,0),App.Vector(-10.000000,-10.000000,0)))
- geoList.append(Part.LineSegment(App.Vector(-10.000000,-10.000000,0),App.Vector(-10.000000,10.000000,0)))
- self.Sketch.addGeometry(geoList,False)
- conList = []
- conList.append(Sketcher.Constraint('Coincident',0,2,1,1))
- conList.append(Sketcher.Constraint('Coincident',1,2,2,1))
- conList.append(Sketcher.Constraint('Coincident',2,2,3,1))
- conList.append(Sketcher.Constraint('Coincident',3,2,0,1))
- conList.append(Sketcher.Constraint('Horizontal',0))
- conList.append(Sketcher.Constraint('Horizontal',2))
- conList.append(Sketcher.Constraint('Vertical',1))
- conList.append(Sketcher.Constraint('Vertical',3))
- self.Sketch.addConstraint(conList)
-
- self.Pad = self.Doc.addObject("PartDesign::Pad","Pad")
- self.Pad.Profile = self.Sketch
- self.Pad.Length = 10.000000
- self.Pad.Length2 = 100.000000
- self.Pad.Type = 0
- self.Pad.UpToFace = None
- self.Pad.Reversed = 0
- self.Pad.Midplane = 0
- self.Pad.Offset = 0.000000
-
- self.BodySource.addObject(self.Pad)
-
- self.Doc.recompute()
- Gui.SendMsgToActiveView("ViewFit")
-
- self.BodyTarget = self.Doc.addObject('PartDesign::Body','Body')
-
- Gui.Selection.addSelection(App.ActiveDocument.Pad)
- cobj = CallableComboBox(self)
- QtCore.QTimer.singleShot(500, cobj)
- Gui.runCommand('PartDesign_MoveFeature')
- #assert depenedencies of the Sketch
- self.Doc.recompute()
+ #self.Sketch = self.Doc.addObject('Sketcher::SketchObject','Sketch')
+ #self.BodySource.addObject(self.Sketch)
+ #self.Sketch.Support = (self.BodySource.Origin.OriginFeatures[3], [''])
+ #self.Sketch.MapMode = 'FlatFace'
- self.assertFalse(self.Sketch.Support[0][0] in self.BodySource.Origin.OriginFeatures)
- self.assertTrue(self.Sketch.Support[0][0] in self.BodyTarget.Origin.OriginFeatures)
- self.assertEqual(len(self.BodySource.Group), 0, "Source body feature count is wrong")
- self.assertEqual(len(self.BodyTarget.Group), 2, "Target body feature count is wrong")
+
+ #geoList = []
+ #geoList.append(Part.LineSegment(App.Vector(-10.000000,10.000000,0),App.Vector(10.000000,10.000000,0)))
+ #geoList.append(Part.LineSegment(App.Vector(10.000000,10.000000,0),App.Vector(10.000000,-10.000000,0)))
+ #geoList.append(Part.LineSegment(App.Vector(10.000000,-10.000000,0),App.Vector(-10.000000,-10.000000,0)))
+ #geoList.append(Part.LineSegment(App.Vector(-10.000000,-10.000000,0),App.Vector(-10.000000,10.000000,0)))
+ #self.Sketch.addGeometry(geoList,False)
+ #conList = []
+ #conList.append(Sketcher.Constraint('Coincident',0,2,1,1))
+ #conList.append(Sketcher.Constraint('Coincident',1,2,2,1))
+ #conList.append(Sketcher.Constraint('Coincident',2,2,3,1))
+ #conList.append(Sketcher.Constraint('Coincident',3,2,0,1))
+ #conList.append(Sketcher.Constraint('Horizontal',0))
+ #conList.append(Sketcher.Constraint('Horizontal',2))
+ #conList.append(Sketcher.Constraint('Vertical',1))
+ #conList.append(Sketcher.Constraint('Vertical',3))
+ #self.Sketch.addConstraint(conList)
+
+ #self.Pad = self.Doc.addObject("PartDesign::Pad","Pad")
+ #self.BodySource.addObject(self.Pad)
+ #self.Pad.Profile = self.Sketch
+ #self.Pad.Length = 10.000000
+ #self.Pad.Length2 = 100.000000
+ #self.Pad.Type = 0
+ #self.Pad.UpToFace = None
+ #self.Pad.Reversed = 0
+ #self.Pad.Midplane = 0
+ #self.Pad.Offset = 0.000000
+
+ #self.Doc.recompute()
+ #Gui.SendMsgToActiveView("ViewFit")
+
+ #self.BodyTarget = self.Doc.addObject('PartDesign::Body','Body')
+
+ #Gui.Selection.addSelection(App.ActiveDocument.Pad)
+ #cobj = CallableComboBox(self)
+ #QtCore.QTimer.singleShot(500, cobj)
+ #Gui.runCommand('PartDesign_MoveFeature')
+ ##assert depenedencies of the Sketch
+ #self.Doc.recompute()
+
+ #self.assertFalse(self.Sketch.Support[0][0] in self.BodySource.Origin.OriginFeatures)
+ #self.assertTrue(self.Sketch.Support[0][0] in self.BodyTarget.Origin.OriginFeatures)
+ #self.assertEqual(len(self.BodySource.Group), 0, "Source body feature count is wrong")
+ #self.assertEqual(len(self.BodyTarget.Group), 2, "Target body feature count is wrong")
def tearDown(self):
FreeCAD.closeDocument("SketchGuiTest")
diff --git a/src/Mod/Test/Document.py b/src/Mod/Test/Document.py
index 039a9c581c..0413e9db7f 100644
--- a/src/Mod/Test/Document.py
+++ b/src/Mod/Test/Document.py
@@ -841,6 +841,8 @@ class UndoRedoCases(unittest.TestCase):
grp1 = self.Doc.addObject("App::DocumentObjectGroup","Group1")
grp2 = self.Doc.addObject("App::DocumentObjectGroup","Group2")
grp1.addObject(obj1)
+ self.failUnless(obj1.getParentGroup()==grp1)
+ self.failUnless(obj1.getParentGeoFeatureGroup()==None)
self.failUnless(grp1.hasObject(obj1))
grp2.addObject(obj1)
self.failUnless(grp1.hasObject(obj1)==False)
@@ -851,6 +853,8 @@ class UndoRedoCases(unittest.TestCase):
prt2 = self.Doc.addObject("App::Part","Part2")
prt1.addObject(grp2)
+ self.failUnless(grp2.getParentGeoFeatureGroup()==prt1)
+ self.failUnless(grp2.getParentGroup()==None)
self.failUnless(grp2.hasObject(obj1))
self.failUnless(prt1.hasObject(grp2))
self.failUnless(prt1.hasObject(obj1))