Extend python interface for groups and fix test cases
This commit is contained in:
@@ -55,6 +55,20 @@
|
||||
<UserDocu>Recomputes this object</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getParentGroup">
|
||||
<Documentation>
|
||||
<UserDocu>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.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getParentGeoFeatureGroup">
|
||||
<Documentation>
|
||||
<UserDocu>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.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="OutList" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>A list of all objects this object links to.</UserDocu>
|
||||
|
||||
@@ -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 <App/DocumentObjectPy.h>
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -283,6 +283,9 @@ std::vector<App::DocumentObject*> Body::addObject(App::DocumentObject *feature)
|
||||
if (isSolidFeature(feature)) {
|
||||
Tip.setValue (feature);
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> result = {feature};
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -380,6 +383,8 @@ std::vector<App::DocumentObject*> Body::removeObject(App::DocumentObject* featur
|
||||
model.erase(it);
|
||||
Group.setValues(model);
|
||||
}
|
||||
std::vector<App::DocumentObject*> result = {feature};
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<App::DocumentObject*> 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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user