Merge branch 'master' into RRF-PP-for-Path
This commit is contained in:
@@ -162,9 +162,22 @@ def getPreferences():
|
||||
'EXPORT_MODEL': ['arch', 'struct', 'hybrid'][p.GetInt("ifcExportModel", 0)]
|
||||
}
|
||||
|
||||
# get ifcopenshell version
|
||||
ifcos_version = 0.0
|
||||
if hasattr(ifcopenshell, "version"):
|
||||
if ifcopenshell.version.startswith("0"):
|
||||
ifcos_version = float(ifcopenshell.version[:3]) # < 0.6
|
||||
elif ifcopenshell.version.startswith("v"):
|
||||
ifcos_version = float(ifcopenshell.version[1:4]) # 0.7
|
||||
else:
|
||||
print("Could not retrieve IfcOpenShell version. Version is set to {}".format(ifcos_version))
|
||||
else:
|
||||
print("Could not retrieve IfcOpenShell version. Version is set to {}".format(ifcos_version))
|
||||
|
||||
# set schema
|
||||
if hasattr(ifcopenshell, "schema_identifier"):
|
||||
schema = ifcopenshell.schema_identifier
|
||||
elif hasattr(ifcopenshell, "version") and (float(ifcopenshell.version[:3]) >= 0.6):
|
||||
elif ifcos_version >= 0.6:
|
||||
# v0.6 onwards allows to set our own schema
|
||||
schema = ["IFC4", "IFC2X3"][p.GetInt("IfcVersion", 0)]
|
||||
else:
|
||||
|
||||
@@ -151,34 +151,25 @@ def getTeighaConverter():
|
||||
-------
|
||||
str
|
||||
The full path of the converter executable
|
||||
'/usr/bin/TeighaFileConverter'
|
||||
'/usr/bin/ODAFileConverter'
|
||||
"""
|
||||
import FreeCAD, os, platform
|
||||
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
p = p.GetString("TeighaFileConverter")
|
||||
if p:
|
||||
path = p.GetString("TeighaFileConverter")
|
||||
if path:
|
||||
# path set manually
|
||||
teigha = p
|
||||
else:
|
||||
# try to find teigha
|
||||
teigha = None
|
||||
if platform.system() == "Linux":
|
||||
teigha = "/usr/bin/TeighaFileConverter"
|
||||
if not os.path.exists(teigha):
|
||||
teigha = "/usr/bin/ODAFileConverter"
|
||||
elif platform.system() == "Windows":
|
||||
odadir = os.path.expandvars("%ProgramFiles%\ODA")
|
||||
if os.path.exists(odadir):
|
||||
subdirs = os.walk(odadir).next()[1]
|
||||
for sub in subdirs:
|
||||
t = (odadir + os.sep + sub + os.sep
|
||||
+ "TeighaFileConverter.exe")
|
||||
t = os.path.join(odadir, sub, "TeighaFileConverter.exe")
|
||||
if os.path.exists(t):
|
||||
teigha = t
|
||||
if teigha:
|
||||
if os.path.exists(teigha):
|
||||
return teigha
|
||||
return path
|
||||
elif platform.system() == "Linux":
|
||||
path = "/usr/bin/ODAFileConverter"
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
elif platform.system() == "Windows":
|
||||
odadir = os.path.expandvars("%ProgramFiles%\ODA")
|
||||
if os.path.exists(odadir):
|
||||
for sub in os.listdir(odadir):
|
||||
path = os.path.join(odadir, sub, "ODAFileConverter.exe")
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
return None
|
||||
|
||||
|
||||
@@ -249,7 +240,7 @@ def convertToDxf(dwgfilename):
|
||||
outdir = tempfile.mkdtemp()
|
||||
basename = os.path.basename(dwgfilename)
|
||||
result = outdir + os.sep + os.path.splitext(basename)[0] + ".dxf"
|
||||
proc = subprocess.Popen((path, "-o", result, dwgfilename))
|
||||
proc = subprocess.Popen((path, "-f", "-o", result, dwgfilename))
|
||||
proc.communicate()
|
||||
return result
|
||||
except Exception:
|
||||
|
||||
@@ -44,6 +44,9 @@ public:
|
||||
QIcon getIcon(void) const;
|
||||
void updateData(const App::Property*);
|
||||
bool onDelete(const std::vector<std::string> &);
|
||||
|
||||
virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; }
|
||||
|
||||
};
|
||||
|
||||
/// ViewProvider for the MultiFuse feature
|
||||
|
||||
@@ -126,6 +126,8 @@ public:
|
||||
/// grouping handling
|
||||
std::vector<App::DocumentObject*> claimChildren(void)const;
|
||||
bool onDelete(const std::vector<std::string> &);
|
||||
|
||||
virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; }
|
||||
};
|
||||
|
||||
class ViewProviderSweep : public ViewProviderPart
|
||||
@@ -141,6 +143,8 @@ public:
|
||||
/// grouping handling
|
||||
std::vector<App::DocumentObject*> claimChildren(void)const;
|
||||
bool onDelete(const std::vector<std::string> &);
|
||||
|
||||
virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; }
|
||||
};
|
||||
|
||||
class ViewProviderOffset : public ViewProviderPart
|
||||
@@ -188,6 +192,8 @@ public:
|
||||
void setupContextMenu(QMenu*, QObject*, const char*);
|
||||
bool onDelete(const std::vector<std::string> &);
|
||||
|
||||
virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; }
|
||||
|
||||
protected:
|
||||
virtual bool setEdit(int ModNum);
|
||||
virtual void unsetEdit(int ModNum);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <App/PropertyStandard.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
#include <Mod/PartDesign/PartDesignGlobal.h>
|
||||
|
||||
class gp_Pnt;
|
||||
class gp_Pln;
|
||||
|
||||
@@ -55,7 +55,7 @@ PROPERTY_SOURCE(PartDesign::Loft, PartDesign::ProfileBased)
|
||||
Loft::Loft()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Sections,(0),"Loft",App::Prop_None,"List of sections");
|
||||
Sections.setSize(0);
|
||||
Sections.setValue(0);
|
||||
ADD_PROPERTY_TYPE(Ruled,(false),"Loft",App::Prop_None,"Create ruled surface");
|
||||
ADD_PROPERTY_TYPE(Closed,(false),"Loft",App::Prop_None,"Close Last to First Profile");
|
||||
}
|
||||
@@ -95,44 +95,56 @@ App::DocumentObjectExecReturn *Loft::execute(void)
|
||||
}
|
||||
|
||||
try {
|
||||
//setup the location
|
||||
// setup the location
|
||||
this->positionByPrevious();
|
||||
TopLoc_Location invObjLoc = this->getLocation().Inverted();
|
||||
if(!base.IsNull())
|
||||
if (!base.IsNull())
|
||||
base.Move(invObjLoc);
|
||||
|
||||
//build up multisections
|
||||
// build up multisections
|
||||
auto multisections = Sections.getValues();
|
||||
if(multisections.empty())
|
||||
if (multisections.empty())
|
||||
return new App::DocumentObjectExecReturn("Loft: At least one section is needed");
|
||||
|
||||
std::vector<std::vector<TopoDS_Wire>> wiresections;
|
||||
for(TopoDS_Wire& wire : wires)
|
||||
for (TopoDS_Wire& wire : wires)
|
||||
wiresections.emplace_back(1, wire);
|
||||
|
||||
for(App::DocumentObject* obj : multisections) {
|
||||
if(!obj->isDerivedFrom(Part::Feature::getClassTypeId()))
|
||||
for (auto obj : multisections) {
|
||||
if (!obj->isDerivedFrom(Part::Feature::getClassTypeId()))
|
||||
return new App::DocumentObjectExecReturn("Loft: All sections need to be part features");
|
||||
|
||||
// if the section is an object's face then take just the face
|
||||
TopoDS_Shape shape;
|
||||
if (obj->isDerivedFrom(Part::Part2DObject::getClassTypeId()))
|
||||
shape = static_cast<Part::Part2DObject*>(obj)->Shape.getValue();
|
||||
else {
|
||||
auto subValues = Sections.getSubValues(obj);
|
||||
if (subValues.empty())
|
||||
throw Base::ValueError("Loft: No valid subelement linked in Part::Feature");
|
||||
|
||||
shape = static_cast<Part::Feature*>(obj)->Shape.getShape(). getSubShape(subValues[0].c_str());
|
||||
}
|
||||
|
||||
TopExp_Explorer ex;
|
||||
size_t i=0;
|
||||
for (ex.Init(static_cast<Part::Feature*>(obj)->Shape.getValue(), TopAbs_WIRE); ex.More(); ex.Next(), ++i) {
|
||||
if(i>=wiresections.size())
|
||||
for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next(), ++i) {
|
||||
if (i>=wiresections.size())
|
||||
return new App::DocumentObjectExecReturn("Loft: Sections need to have the same amount of inner wires as the base section");
|
||||
wiresections[i].push_back(TopoDS::Wire(ex.Current()));
|
||||
}
|
||||
if(i<wiresections.size())
|
||||
if (i<wiresections.size())
|
||||
return new App::DocumentObjectExecReturn("Loft: Sections need to have the same amount of inner wires as the base section");
|
||||
|
||||
}
|
||||
|
||||
//build all shells
|
||||
// build all shells
|
||||
std::vector<TopoDS_Shape> shells;
|
||||
for(std::vector<TopoDS_Wire>& wires : wiresections) {
|
||||
for (std::vector<TopoDS_Wire>& wires : wiresections) {
|
||||
|
||||
BRepOffsetAPI_ThruSections mkTS(false, Ruled.getValue(), Precision::Confusion());
|
||||
|
||||
for(TopoDS_Wire& wire : wires) {
|
||||
for (TopoDS_Wire& wire : wires) {
|
||||
wire.Move(invObjLoc);
|
||||
mkTS.AddWire(wire);
|
||||
}
|
||||
@@ -149,7 +161,7 @@ App::DocumentObjectExecReturn *Loft::execute(void)
|
||||
TopoDS_Shape front = getVerifiedFace();
|
||||
front.Move(invObjLoc);
|
||||
std::vector<TopoDS_Wire> backwires;
|
||||
for(std::vector<TopoDS_Wire>& wires : wiresections)
|
||||
for (std::vector<TopoDS_Wire>& wires : wiresections)
|
||||
backwires.push_back(wires.back());
|
||||
|
||||
TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires);
|
||||
@@ -158,7 +170,7 @@ App::DocumentObjectExecReturn *Loft::execute(void)
|
||||
sewer.SetTolerance(Precision::Confusion());
|
||||
sewer.Add(front);
|
||||
sewer.Add(back);
|
||||
for(TopoDS_Shape& s : shells)
|
||||
for (TopoDS_Shape& s : shells)
|
||||
sewer.Add(s);
|
||||
|
||||
sewer.Perform();
|
||||
@@ -166,7 +178,7 @@ App::DocumentObjectExecReturn *Loft::execute(void)
|
||||
//build the solid
|
||||
BRepBuilderAPI_MakeSolid mkSolid;
|
||||
mkSolid.Add(TopoDS::Shell(sewer.SewedShape()));
|
||||
if(!mkSolid.IsDone())
|
||||
if (!mkSolid.IsDone())
|
||||
return new App::DocumentObjectExecReturn("Loft: Result is not a solid");
|
||||
|
||||
TopoDS_Shape result = mkSolid.Shape();
|
||||
@@ -178,7 +190,7 @@ App::DocumentObjectExecReturn *Loft::execute(void)
|
||||
|
||||
AddSubShape.setValue(result);
|
||||
|
||||
if(base.IsNull()) {
|
||||
if (base.IsNull()) {
|
||||
if (getAddSubType() == FeatureAddSub::Subtractive)
|
||||
return new App::DocumentObjectExecReturn("Loft: There is nothing to subtract from\n");
|
||||
|
||||
@@ -186,7 +198,7 @@ App::DocumentObjectExecReturn *Loft::execute(void)
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
if(getAddSubType() == FeatureAddSub::Additive) {
|
||||
if (getAddSubType() == FeatureAddSub::Additive) {
|
||||
|
||||
BRepAlgoAPI_Fuse mkFuse(base, result);
|
||||
if (!mkFuse.IsDone())
|
||||
@@ -204,7 +216,7 @@ App::DocumentObjectExecReturn *Loft::execute(void)
|
||||
boolOp = refineShapeIfActive(boolOp);
|
||||
Shape.setValue(getSolid(boolOp));
|
||||
}
|
||||
else if(getAddSubType() == FeatureAddSub::Subtractive) {
|
||||
else if (getAddSubType() == FeatureAddSub::Subtractive) {
|
||||
|
||||
BRepAlgoAPI_Cut mkCut(base, result);
|
||||
if (!mkCut.IsDone())
|
||||
@@ -244,3 +256,14 @@ PROPERTY_SOURCE(PartDesign::SubtractiveLoft, PartDesign::Loft)
|
||||
SubtractiveLoft::SubtractiveLoft() {
|
||||
addSubType = Subtractive;
|
||||
}
|
||||
|
||||
void Loft::handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property* prop)
|
||||
{
|
||||
// property Sections had the App::PropertyLinkList and was changed to App::PropertyXLinkSubList
|
||||
if (prop == &Sections && strcmp(TypeName, "App::PropertyLinkList") == 0) {
|
||||
Sections.upgrade(reader, TypeName);
|
||||
}
|
||||
else {
|
||||
ProfileBased::handleChangedPropertyType(reader, TypeName, prop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,9 +40,9 @@ class PartDesignExport Loft : public ProfileBased
|
||||
public:
|
||||
Loft();
|
||||
|
||||
App::PropertyLinkList Sections;
|
||||
App::PropertyBool Ruled;
|
||||
App::PropertyBool Closed;
|
||||
App::PropertyXLinkSubList Sections;
|
||||
App::PropertyBool Ruled;
|
||||
App::PropertyBool Closed;
|
||||
|
||||
/** @name methods override feature */
|
||||
//@{
|
||||
@@ -54,20 +54,24 @@ public:
|
||||
}
|
||||
//@}
|
||||
|
||||
protected:
|
||||
// handle changed property
|
||||
virtual void handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property* prop);
|
||||
|
||||
private:
|
||||
//static const char* TypeEnums[];
|
||||
//static const char* SideEnums[];
|
||||
};
|
||||
|
||||
class PartDesignExport AdditiveLoft : public Loft {
|
||||
|
||||
|
||||
PROPERTY_HEADER(PartDesign::AdditiveLoft);
|
||||
public:
|
||||
AdditiveLoft();
|
||||
};
|
||||
|
||||
class PartDesignExport SubtractiveLoft : public Loft {
|
||||
|
||||
|
||||
PROPERTY_HEADER(PartDesign::SubtractiveLoft);
|
||||
public:
|
||||
SubtractiveLoft();
|
||||
|
||||
@@ -147,7 +147,7 @@ App::DocumentObjectExecReturn *Pad::execute(void)
|
||||
Base::Vector3d paddingDirection;
|
||||
|
||||
if (!UseCustomVector.getValue()) {
|
||||
if (ReferenceAxis.getValue() == nullptr) {
|
||||
if (!ReferenceAxis.getValue()) {
|
||||
// use sketch's normal vector for direction
|
||||
paddingDirection = SketchVector;
|
||||
AlongSketchNormal.setReadOnly(true);
|
||||
|
||||
@@ -82,7 +82,7 @@ PROPERTY_SOURCE(PartDesign::Pipe, PartDesign::ProfileBased)
|
||||
Pipe::Pipe()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Sections,(0),"Sweep",App::Prop_None,"List of sections");
|
||||
Sections.setSize(0);
|
||||
Sections.setValue(0);
|
||||
ADD_PROPERTY_TYPE(Spine,(0),"Sweep",App::Prop_None,"Path to sweep along");
|
||||
ADD_PROPERTY_TYPE(SpineTangent,(false),"Sweep",App::Prop_None,"Include tangent edges into path");
|
||||
ADD_PROPERTY_TYPE(AuxillerySpine,(0),"Sweep",App::Prop_None,"Secondary path to orient sweep");
|
||||
@@ -129,7 +129,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
//We would need a method to translate the front shape to match the shell starting position somehow...
|
||||
TopoDS_Face face = TopoDS::Face(sketchshape);
|
||||
BRepAdaptor_Surface adapt(face);
|
||||
if(adapt.GetType() != GeomAbs_Plane)
|
||||
if (adapt.GetType() != GeomAbs_Plane)
|
||||
return new App::DocumentObjectExecReturn("Pipe: Only planar faces supported");
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
//setup the location
|
||||
this->positionByPrevious();
|
||||
TopLoc_Location invObjLoc = this->getLocation().Inverted();
|
||||
if(!base.IsNull())
|
||||
if (!base.IsNull())
|
||||
base.Move(invObjLoc);
|
||||
|
||||
//build the paths
|
||||
@@ -162,7 +162,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
|
||||
// auxiliary
|
||||
TopoDS_Shape auxpath;
|
||||
if(Mode.getValue()==3) {
|
||||
if (Mode.getValue()==3) {
|
||||
App::DocumentObject* auxspine = AuxillerySpine.getValue();
|
||||
if (!(auxspine && auxspine->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
|
||||
return new App::DocumentObjectExecReturn("No auxiliary spine linked.");
|
||||
@@ -176,38 +176,50 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
//build up multisections
|
||||
auto multisections = Sections.getValues();
|
||||
std::vector<std::vector<TopoDS_Wire>> wiresections;
|
||||
for(TopoDS_Wire& wire : wires)
|
||||
for (TopoDS_Wire& wire : wires)
|
||||
wiresections.emplace_back(1, wire);
|
||||
//maybe we need a sacling law
|
||||
Handle(Law_Function) scalinglaw;
|
||||
|
||||
//see if we shall use multiple sections
|
||||
if(Transformation.getValue() == 1) {
|
||||
if (Transformation.getValue() == 1) {
|
||||
|
||||
//TODO: we need to order the sections to prevent occ from crahsing, as makepieshell connects
|
||||
//the sections in the order of adding
|
||||
|
||||
for(App::DocumentObject* obj : multisections) {
|
||||
if(!obj->isDerivedFrom(Part::Feature::getClassTypeId()))
|
||||
for (App::DocumentObject* obj : multisections) {
|
||||
if (!obj->isDerivedFrom(Part::Feature::getClassTypeId()))
|
||||
return new App::DocumentObjectExecReturn("All sections need to be part features");
|
||||
|
||||
// if the section is an object's face then take just the face
|
||||
TopoDS_Shape shape;
|
||||
if (obj->isDerivedFrom(Part::Part2DObject::getClassTypeId()))
|
||||
shape = static_cast<Part::Part2DObject*>(obj)->Shape.getValue();
|
||||
else {
|
||||
auto subValues = Sections.getSubValues(obj);
|
||||
if (subValues.empty())
|
||||
throw Base::ValueError("Pipe: No valid subelement in multisection");
|
||||
|
||||
shape = static_cast<Part::Feature*>(obj)->Shape.getShape(). getSubShape(subValues[0].c_str());
|
||||
}
|
||||
|
||||
TopExp_Explorer ex;
|
||||
size_t i=0;
|
||||
for (ex.Init(static_cast<Part::Feature*>(obj)->Shape.getValue(), TopAbs_WIRE); ex.More(); ex.Next()) {
|
||||
if(i>=wiresections.size())
|
||||
for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) {
|
||||
if (i>=wiresections.size())
|
||||
return new App::DocumentObjectExecReturn("Multisections need to have the same amount of inner wires as the base section");
|
||||
wiresections[i].push_back(TopoDS::Wire(ex.Current()));
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if(i<wiresections.size())
|
||||
if (i<wiresections.size())
|
||||
return new App::DocumentObjectExecReturn("Multisections need to have the same amount of inner wires as the base section");
|
||||
}
|
||||
}
|
||||
/*//build the law functions instead
|
||||
else if(Transformation.getValue() == 2) {
|
||||
if(ScalingData.getValues().size()<1)
|
||||
else if (Transformation.getValue() == 2) {
|
||||
if (ScalingData.getValues().size()<1)
|
||||
return new App::DocumentObjectExecReturn("No valid data given for linear scaling mode");
|
||||
|
||||
Handle(Law_Linear) lin = new Law_Linear();
|
||||
@@ -215,8 +227,8 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
|
||||
scalinglaw = lin;
|
||||
}
|
||||
else if(Transformation.getValue() == 3) {
|
||||
if(ScalingData.getValues().size()<1)
|
||||
else if (Transformation.getValue() == 3) {
|
||||
if (ScalingData.getValues().size()<1)
|
||||
return new App::DocumentObjectExecReturn("No valid data given for S-shape scaling mode");
|
||||
|
||||
Handle(Law_S) s = new Law_S();
|
||||
@@ -229,22 +241,22 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
if (path.IsNull())
|
||||
return new App::DocumentObjectExecReturn("Path must not be a null shape");
|
||||
|
||||
//build all shells
|
||||
// build all shells
|
||||
std::vector<TopoDS_Shape> shells;
|
||||
std::vector<TopoDS_Wire> frontwires, backwires;
|
||||
for(std::vector<TopoDS_Wire>& wires : wiresections) {
|
||||
for (std::vector<TopoDS_Wire>& wires : wiresections) {
|
||||
|
||||
BRepOffsetAPI_MakePipeShell mkPS(TopoDS::Wire(path));
|
||||
setupAlgorithm(mkPS, auxpath);
|
||||
|
||||
if(!scalinglaw) {
|
||||
for(TopoDS_Wire& wire : wires) {
|
||||
if (!scalinglaw) {
|
||||
for (TopoDS_Wire& wire : wires) {
|
||||
wire.Move(invObjLoc);
|
||||
mkPS.Add(wire);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(TopoDS_Wire& wire : wires) {
|
||||
for (TopoDS_Wire& wire : wires) {
|
||||
wire.Move(invObjLoc);
|
||||
mkPS.SetLaw(wire, scalinglaw);
|
||||
}
|
||||
@@ -277,7 +289,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
sewer.Add(front);
|
||||
sewer.Add(back);
|
||||
|
||||
for(TopoDS_Shape& s : shells)
|
||||
for (TopoDS_Shape& s : shells)
|
||||
sewer.Add(s);
|
||||
|
||||
sewer.Perform();
|
||||
@@ -289,7 +301,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
}
|
||||
}
|
||||
|
||||
if(!mkSolid.IsDone())
|
||||
if (!mkSolid.IsDone())
|
||||
return new App::DocumentObjectExecReturn("Result is not a solid");
|
||||
|
||||
TopoDS_Shape result = mkSolid.Shape();
|
||||
@@ -302,7 +314,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
//result.Move(invObjLoc);
|
||||
AddSubShape.setValue(result);
|
||||
|
||||
if(base.IsNull()) {
|
||||
if (base.IsNull()) {
|
||||
if (getAddSubType() == FeatureAddSub::Subtractive)
|
||||
return new App::DocumentObjectExecReturn("Pipe: There is nothing to subtract from\n");
|
||||
|
||||
@@ -311,7 +323,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
if(getAddSubType() == FeatureAddSub::Additive) {
|
||||
if (getAddSubType() == FeatureAddSub::Additive) {
|
||||
|
||||
BRepAlgoAPI_Fuse mkFuse(base, result);
|
||||
if (!mkFuse.IsDone())
|
||||
@@ -330,7 +342,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
|
||||
boolOp = refineShapeIfActive(boolOp);
|
||||
Shape.setValue(getSolid(boolOp));
|
||||
}
|
||||
else if(getAddSubType() == FeatureAddSub::Subtractive) {
|
||||
else if (getAddSubType() == FeatureAddSub::Subtractive) {
|
||||
|
||||
BRepAlgoAPI_Cut mkCut(base, result);
|
||||
if (!mkCut.IsDone())
|
||||
@@ -394,7 +406,7 @@ void Pipe::setupAlgorithm(BRepOffsetAPI_MakePipeShell& mkPipeShell, TopoDS_Shape
|
||||
break;
|
||||
}
|
||||
|
||||
if(auxiliary) {
|
||||
if (auxiliary) {
|
||||
mkPipeShell.SetMode(TopoDS::Wire(auxshape), AuxilleryCurvelinear.getValue());
|
||||
//mkPipeShell.SetMode(TopoDS::Wire(auxshape), AuxilleryCurvelinear.getValue(), BRepFill_ContactOnBorder);
|
||||
}
|
||||
@@ -410,7 +422,7 @@ void Pipe::getContinuousEdges(Part::TopoShape /*TopShape*/, std::vector< std::st
|
||||
TopExp::MapShapes(TopShape.getShape(), TopAbs_EDGE, mapOfEdges);
|
||||
|
||||
Base::Console().Message("Initial edges:\n");
|
||||
for(int i=0; i<SubNames.size(); ++i)
|
||||
for (int i=0; i<SubNames.size(); ++i)
|
||||
Base::Console().Message("Subname: %s\n", SubNames[i].c_str());
|
||||
|
||||
unsigned int i = 0;
|
||||
@@ -422,7 +434,7 @@ void Pipe::getContinuousEdges(Part::TopoShape /*TopShape*/, std::vector< std::st
|
||||
TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str()));
|
||||
const TopTools_ListOfShape& los = mapEdgeEdge.FindFromKey(edge);
|
||||
|
||||
if(los.Extent() != 2)
|
||||
if (los.Extent() != 2)
|
||||
{
|
||||
SubNames.erase(SubNames.begin()+i);
|
||||
continue;
|
||||
@@ -447,7 +459,7 @@ void Pipe::getContinuousEdges(Part::TopoShape /*TopShape*/, std::vector< std::st
|
||||
}
|
||||
|
||||
Base::Console().Message("Final edges:\n");
|
||||
for(int i=0; i<SubNames.size(); ++i)
|
||||
for (int i=0; i<SubNames.size(); ++i)
|
||||
Base::Console().Message("Subname: %s\n", SubNames[i].c_str());
|
||||
*/
|
||||
}
|
||||
@@ -457,7 +469,7 @@ void Pipe::buildPipePath(const Part::TopoShape& shape, const std::vector< std::s
|
||||
if (!shape.getShape().IsNull()) {
|
||||
try {
|
||||
if (!subedge.empty()) {
|
||||
//if(SpineTangent.getValue())
|
||||
//if (SpineTangent.getValue())
|
||||
//getContinuousEdges(shape, subedge);
|
||||
|
||||
BRepBuilderAPI_MakeWire mkWire;
|
||||
@@ -506,8 +518,6 @@ void Pipe::buildPipePath(const Part::TopoShape& shape, const std::vector< std::s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
PROPERTY_SOURCE(PartDesign::AdditivePipe, PartDesign::Pipe)
|
||||
AdditivePipe::AdditivePipe() {
|
||||
addSubType = Additive;
|
||||
@@ -517,3 +527,14 @@ PROPERTY_SOURCE(PartDesign::SubtractivePipe, PartDesign::Pipe)
|
||||
SubtractivePipe::SubtractivePipe() {
|
||||
addSubType = Subtractive;
|
||||
}
|
||||
|
||||
void Pipe::handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property* prop)
|
||||
{
|
||||
// property Sections had the App::PropertyLinkList and was changed to App::PropertyXLinkSubList
|
||||
if (prop == &Sections && strcmp(TypeName, "App::PropertyLinkList") == 0) {
|
||||
Sections.upgrade(reader, TypeName);
|
||||
}
|
||||
else {
|
||||
ProfileBased::handleChangedPropertyType(reader, TypeName, prop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,17 +38,16 @@ class PartDesignExport Pipe : public ProfileBased
|
||||
public:
|
||||
Pipe();
|
||||
|
||||
|
||||
App::PropertyLinkSub Spine;
|
||||
App::PropertyBool SpineTangent;
|
||||
App::PropertyLinkSub AuxillerySpine;
|
||||
App::PropertyBool AuxillerySpineTangent;
|
||||
App::PropertyBool AuxilleryCurvelinear;
|
||||
App::PropertyLinkSub Spine;
|
||||
App::PropertyBool SpineTangent;
|
||||
App::PropertyLinkSub AuxillerySpine;
|
||||
App::PropertyBool AuxillerySpineTangent;
|
||||
App::PropertyBool AuxilleryCurvelinear;
|
||||
App::PropertyEnumeration Mode;
|
||||
App::PropertyVector Binormal;
|
||||
App::PropertyVector Binormal;
|
||||
App::PropertyEnumeration Transition;
|
||||
App::PropertyEnumeration Transformation;
|
||||
App::PropertyLinkList Sections;
|
||||
App::PropertyXLinkSubList Sections;
|
||||
|
||||
App::DocumentObjectExecReturn *execute(void);
|
||||
short mustExecute() const;
|
||||
@@ -56,13 +55,14 @@ public:
|
||||
const char* getViewProviderName(void) const {
|
||||
return "PartDesignGui::ViewProviderPipe";
|
||||
}
|
||||
//@}
|
||||
|
||||
protected:
|
||||
///get the given edges and all their tangent ones
|
||||
/// get the given edges and all their tangent ones
|
||||
void getContinuousEdges(Part::TopoShape TopShape, std::vector< std::string >& SubNames);
|
||||
void buildPipePath(const Part::TopoShape& input, const std::vector<std::string>& edges, TopoDS_Shape& result);
|
||||
void setupAlgorithm(BRepOffsetAPI_MakePipeShell& mkPipeShell, TopoDS_Shape& auxshape);
|
||||
/// handle changed property
|
||||
virtual void handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property* prop);
|
||||
|
||||
private:
|
||||
static const char* TypeEnums[];
|
||||
|
||||
@@ -67,6 +67,10 @@ Pocket::Pocket()
|
||||
Type.setEnums(TypeEnums);
|
||||
ADD_PROPERTY_TYPE(Length,(100.0),"Pocket",App::Prop_None,"Pocket length");
|
||||
ADD_PROPERTY_TYPE(Length2,(100.0),"Pocket",App::Prop_None,"P");
|
||||
ADD_PROPERTY_TYPE(UseCustomVector, (false), "Pocket", App::Prop_None, "Use custom vector for pocket direction");
|
||||
ADD_PROPERTY_TYPE(Direction, (Base::Vector3d(1.0, 1.0, 1.0)), "Pocket", App::Prop_None, "Pocket direction vector");
|
||||
ADD_PROPERTY_TYPE(ReferenceAxis, (0), "Pocket", App::Prop_None, "Reference axis of direction");
|
||||
ADD_PROPERTY_TYPE(AlongSketchNormal, (true), "Pocket", App::Prop_None, "Measure pocket length along the sketch normal direction");
|
||||
ADD_PROPERTY_TYPE(UpToFace,(0),"Pocket",App::Prop_None,"Face where pocket will end");
|
||||
ADD_PROPERTY_TYPE(Offset,(0.0),"Pocket",App::Prop_None,"Offset from face in which pocket will end");
|
||||
static const App::PropertyQuantityConstraint::Constraints signedLengthConstraint = {-DBL_MAX, DBL_MAX, 1.0};
|
||||
@@ -84,6 +88,10 @@ short Pocket::mustExecute() const
|
||||
Length.isTouched() ||
|
||||
Length2.isTouched() ||
|
||||
Offset.isTouched() ||
|
||||
UseCustomVector.isTouched() ||
|
||||
Direction.isTouched() ||
|
||||
ReferenceAxis.isTouched() ||
|
||||
AlongSketchNormal.isTouched() ||
|
||||
UpToFace.isTouched())
|
||||
return 1;
|
||||
return ProfileBased::mustExecute();
|
||||
@@ -130,6 +138,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
|
||||
|
||||
// get the Sketch plane
|
||||
Base::Placement SketchPos = obj->Placement.getValue();
|
||||
// get the normal vector of the sketch
|
||||
Base::Vector3d SketchVector = getProfileNormal();
|
||||
|
||||
// turn around for pockets
|
||||
@@ -141,7 +150,78 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
|
||||
|
||||
base.Move(invObjLoc);
|
||||
|
||||
gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z);
|
||||
Base::Vector3d pocketDirection;
|
||||
|
||||
if (!UseCustomVector.getValue()) {
|
||||
if (!ReferenceAxis.getValue()) {
|
||||
// use sketch's normal vector for direction
|
||||
pocketDirection = SketchVector;
|
||||
AlongSketchNormal.setReadOnly(true);
|
||||
}
|
||||
else {
|
||||
// update Direction from ReferenceAxis
|
||||
try {
|
||||
App::DocumentObject* pcReferenceAxis = ReferenceAxis.getValue();
|
||||
const std::vector<std::string>& subReferenceAxis = ReferenceAxis.getSubValues();
|
||||
Base::Vector3d base;
|
||||
Base::Vector3d dir;
|
||||
getAxis(pcReferenceAxis, subReferenceAxis, base, dir, false);
|
||||
pocketDirection = dir;
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
return new App::DocumentObjectExecReturn(e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// use the given vector
|
||||
// if null vector, use SketchVector
|
||||
if ((fabs(Direction.getValue().x) < Precision::Confusion())
|
||||
&& (fabs(Direction.getValue().y) < Precision::Confusion())
|
||||
&& (fabs(Direction.getValue().z) < Precision::Confusion())) {
|
||||
Direction.setValue(SketchVector);
|
||||
}
|
||||
pocketDirection = Direction.getValue();
|
||||
}
|
||||
|
||||
// disable options of UseCustomVector
|
||||
Direction.setReadOnly(!UseCustomVector.getValue());
|
||||
ReferenceAxis.setReadOnly(UseCustomVector.getValue());
|
||||
// UseCustomVector allows AlongSketchNormal but !UseCustomVector does not forbid it
|
||||
if (UseCustomVector.getValue())
|
||||
AlongSketchNormal.setReadOnly(false);
|
||||
|
||||
// create vector in pocketing direction with length 1
|
||||
gp_Dir dir(pocketDirection.x, pocketDirection.y, pocketDirection.z);
|
||||
|
||||
// store the finally used direction to display it in the dialog
|
||||
Direction.setValue(dir.X(), dir.Y(), dir.Z());
|
||||
|
||||
// The length of a gp_Dir is 1 so the resulting pocket would have
|
||||
// the length L in the direction of dir. But we want to have its height in the
|
||||
// direction of the normal vector.
|
||||
// Therefore we must multiply L by the factor that is necessary
|
||||
// to make dir as long that its projection to the SketchVector
|
||||
// equals the SketchVector.
|
||||
// This is the scalar product of both vectors.
|
||||
// Since the pocket length cannot be negative, the factor must not be negative.
|
||||
|
||||
double factor = fabs(dir * gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z));
|
||||
|
||||
// factor would be zero if vectors are orthogonal
|
||||
if (factor < Precision::Confusion())
|
||||
return new App::DocumentObjectExecReturn("Pocket: Creation failed because direction is orthogonal to sketch's normal vector");
|
||||
|
||||
// perform the length correction if not along custom vector
|
||||
if (AlongSketchNormal.getValue()) {
|
||||
L = L / factor;
|
||||
L2 = L2 / factor;
|
||||
}
|
||||
|
||||
// explicitly set the Direction so that the dialog shows also the used direction
|
||||
// if the sketch's normal vector was used
|
||||
Direction.setValue(pocketDirection);
|
||||
|
||||
dir.Transform(invObjLoc.Transformation());
|
||||
|
||||
if (profileshape.IsNull())
|
||||
|
||||
@@ -37,10 +37,14 @@ class PartDesignExport Pocket : public ProfileBased
|
||||
public:
|
||||
Pocket();
|
||||
|
||||
App::PropertyEnumeration Type;
|
||||
App::PropertyLength Length;
|
||||
App::PropertyLength Length2;
|
||||
App::PropertyLength Offset;
|
||||
App::PropertyEnumeration Type;
|
||||
App::PropertyLength Length;
|
||||
App::PropertyLength Length2;
|
||||
App::PropertyLength Offset;
|
||||
App::PropertyBool UseCustomVector;
|
||||
App::PropertyVector Direction;
|
||||
App::PropertyBool AlongSketchNormal;
|
||||
App::PropertyLinkSub ReferenceAxis;
|
||||
|
||||
/** @name methods override feature */
|
||||
//@{
|
||||
|
||||
@@ -1019,10 +1019,12 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons
|
||||
std::vector<Gui::SelectionObject> selection = cmd->getSelection().getSelectionEx();
|
||||
if (selection.size() > 1) { //treat additional selected objects as sections
|
||||
for (std::vector<Gui::SelectionObject>::size_type ii = 1; ii < selection.size(); ii++) {
|
||||
if (selection[ii].getObject()->isDerivedFrom(Part::Part2DObject::getClassTypeId())) {
|
||||
auto objCmdSection = Gui::Command::getObjectCmd(selection[ii].getObject());
|
||||
FCMD_OBJ_CMD(Feat, "Sections += [" << objCmdSection << "]");
|
||||
}
|
||||
// Add subvalues even for sketches in case we just want points
|
||||
auto objCmdSection = Gui::Command::getObjectCmd(selection[ii].getObject());
|
||||
std::ostringstream ss;
|
||||
for (auto &s : selection[ii].getSubNames())
|
||||
ss << "'" << s << "',";
|
||||
FCMD_OBJ_CMD(Feat, "Sections += [(" << objCmdSection << ", [" << ss.str() << "])]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,46 +140,54 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c
|
||||
// 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<const Part::Feature*>(pObj)->Shape.getValue();
|
||||
TopoDS_Shape sh = shape.getSubShape(subName.c_str());
|
||||
const TopoDS_Edge& edgeShape = TopoDS::Edge(sh);
|
||||
if (!edgeShape.IsNull()) {
|
||||
if (planar) {
|
||||
BRepAdaptor_Curve adapt(edgeShape);
|
||||
if (adapt.GetType() == GeomAbs_Line)
|
||||
|
||||
// resolve links if needed
|
||||
if (!pObj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
|
||||
pObj = Part::Feature::getShapeOwner(pObj, sSubName);
|
||||
}
|
||||
|
||||
if (pObj && pObj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
|
||||
std::string subName(sSubName);
|
||||
if (edge && subName.size() > 4 && subName.substr(0,4) == "Edge") {
|
||||
const Part::TopoShape &shape = static_cast<const Part::Feature*>(pObj)->Shape.getValue();
|
||||
TopoDS_Shape sh = shape.getSubShape(subName.c_str());
|
||||
const TopoDS_Edge& edgeShape = TopoDS::Edge(sh);
|
||||
if (!edgeShape.IsNull()) {
|
||||
if (planar) {
|
||||
BRepAdaptor_Curve adapt(edgeShape);
|
||||
if (adapt.GetType() == GeomAbs_Line)
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (plane && subName.size() > 4 && subName.substr(0,4) == "Face") {
|
||||
const Part::TopoShape &shape = static_cast<const Part::Feature*>(pObj)->Shape.getValue();
|
||||
TopoDS_Shape sh = shape.getSubShape(subName.c_str());
|
||||
const TopoDS_Face& face = TopoDS::Face(sh);
|
||||
if (!face.IsNull()) {
|
||||
if (planar) {
|
||||
BRepAdaptor_Surface adapt(face);
|
||||
if (adapt.GetType() == GeomAbs_Plane)
|
||||
if (plane && subName.size() > 4 && subName.substr(0,4) == "Face") {
|
||||
const Part::TopoShape &shape = static_cast<const Part::Feature*>(pObj)->Shape.getValue();
|
||||
TopoDS_Shape sh = shape.getSubShape(subName.c_str());
|
||||
const TopoDS_Face& face = TopoDS::Face(sh);
|
||||
if (!face.IsNull()) {
|
||||
if (planar) {
|
||||
BRepAdaptor_Surface adapt(face);
|
||||
if (adapt.GetType() == GeomAbs_Plane)
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (point && subName.size() > 6 && subName.substr(0,6) == "Vertex") {
|
||||
return true;
|
||||
}
|
||||
if (circle && subName.size() > 4 && subName.substr(0,4) == "Edge") {
|
||||
const Part::TopoShape &shape = static_cast<const Part::Feature*>(pObj)->Shape.getValue();
|
||||
TopoDS_Shape sh = shape.getSubShape(subName.c_str());
|
||||
const TopoDS_Edge& edgeShape = TopoDS::Edge(sh);
|
||||
BRepAdaptor_Curve adapt(edgeShape);
|
||||
if (adapt.GetType() == GeomAbs_Circle) {
|
||||
if (point && subName.size() > 6 && subName.substr(0,6) == "Vertex") {
|
||||
return true;
|
||||
}
|
||||
if (circle && subName.size() > 4 && subName.substr(0,4) == "Edge") {
|
||||
const Part::TopoShape &shape = static_cast<const Part::Feature*>(pObj)->Shape.getValue();
|
||||
TopoDS_Shape sh = shape.getSubShape(subName.c_str());
|
||||
const TopoDS_Edge& edgeShape = TopoDS::Edge(sh);
|
||||
BRepAdaptor_Curve adapt(edgeShape);
|
||||
if (adapt.GetType() == GeomAbs_Circle) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -103,14 +103,14 @@ TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView, bool /*newObj
|
||||
if (profile) {
|
||||
Gui::Application::Instance->showViewProvider(profile);
|
||||
|
||||
QString label = QString::fromUtf8(profile->Label.getValue());
|
||||
QString label = make2DLabel(profile, loft->Profile.getSubValues());
|
||||
ui->profileBaseEdit->setText(label);
|
||||
}
|
||||
|
||||
for (auto obj : loft->Sections.getValues()) {
|
||||
Gui::Application::Instance->showViewProvider(obj);
|
||||
|
||||
QString label = QString::fromUtf8(obj->Label.getValue());
|
||||
QString label = make2DLabel(obj, loft->Sections.getSubValues(obj));
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(label);
|
||||
item->setData(Qt::UserRole, QByteArray(obj->getNameInDocument()));
|
||||
@@ -121,10 +121,6 @@ TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView, bool /*newObj
|
||||
ui->checkBoxRuled->setChecked(loft->Ruled.getValue());
|
||||
ui->checkBoxClosed->setChecked(loft->Closed.getValue());
|
||||
|
||||
if (!loft->Sections.getValues().empty()) {
|
||||
LoftView->makeTemporaryVisible(true);
|
||||
}
|
||||
|
||||
// activate and de-activate dialog elements as appropriate
|
||||
for (QWidget* child : proxy->findChildren<QWidget*>())
|
||||
child->blockSignals(false);
|
||||
@@ -138,6 +134,10 @@ TaskLoftParameters::~TaskLoftParameters()
|
||||
|
||||
void TaskLoftParameters::updateUI()
|
||||
{
|
||||
// we must assure the changed loft is kept visible on section changes,
|
||||
// see https://forum.freecadweb.org/viewtopic.php?f=3&t=63252
|
||||
PartDesign::Loft* loft = static_cast<PartDesign::Loft*>(vp->getObject());
|
||||
vp->makeTemporaryVisible(!loft->Sections.getValues().empty());
|
||||
}
|
||||
|
||||
void TaskLoftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
@@ -150,7 +150,7 @@ void TaskLoftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
App::Document* document = App::GetApplication().getDocument(msg.pDocName);
|
||||
App::DocumentObject* object = document ? document->getObject(msg.pObjectName) : nullptr;
|
||||
if (object) {
|
||||
QString label = QString::fromUtf8(object->Label.getValue());
|
||||
QString label = make2DLabel(object, {msg.pSubName});
|
||||
if (selectionMode == refProfile) {
|
||||
ui->profileBaseEdit->setText(label);
|
||||
}
|
||||
@@ -172,6 +172,7 @@ void TaskLoftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
|
||||
clearButtons();
|
||||
exitSelectionMode();
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +196,7 @@ bool TaskLoftParameters::referenceSelected(const Gui::SelectionChanges& msg) con
|
||||
App::DocumentObject* obj = loft->getDocument()->getObject(msg.pObjectName);
|
||||
|
||||
if (selectionMode == refProfile) {
|
||||
loft->Profile.setValue(obj);
|
||||
loft->Profile.setValue(obj, {msg.pSubName});
|
||||
return true;
|
||||
}
|
||||
else if (selectionMode == refAdd || selectionMode == refRemove) {
|
||||
@@ -205,18 +206,19 @@ bool TaskLoftParameters::referenceSelected(const Gui::SelectionChanges& msg) con
|
||||
|
||||
if (selectionMode == refAdd) {
|
||||
if (f == refs.end())
|
||||
refs.push_back(obj);
|
||||
loft->Sections.addValue(obj, {msg.pSubName});
|
||||
else
|
||||
return false; // duplicate selection
|
||||
}
|
||||
else if (selectionMode == refRemove) {
|
||||
if (f != refs.end())
|
||||
refs.erase(f);
|
||||
// Removing just the object this way instead of `refs.erase` and
|
||||
// `setValues(ref)` cleanly ensures subnames are preserved.
|
||||
loft->Sections.removeValue(obj);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static_cast<PartDesign::Loft*>(vp->getObject())->Sections.setValues(refs);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -250,11 +252,13 @@ void TaskLoftParameters::onDeleteSection()
|
||||
App::DocumentObject* obj = loft->getDocument()->getObject(data.constData());
|
||||
std::vector<App::DocumentObject*>::iterator f = std::find(refs.begin(), refs.end(), obj);
|
||||
if (f != refs.end()) {
|
||||
refs.erase(f);
|
||||
loft->Sections.setValues(refs);
|
||||
// Removing just the object this way instead of `refs.erase` and
|
||||
// `setValues(ref)` cleanly ensures subnames are preserved.
|
||||
loft->Sections.removeValue(obj);
|
||||
|
||||
//static_cast<ViewProviderLoft*>(vp)->highlightReferences(false, true);
|
||||
recomputeFeature();
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,16 +282,21 @@ void TaskLoftParameters::indexesMoved()
|
||||
|
||||
loft->Sections.setValues(originals);
|
||||
recomputeFeature();
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void TaskLoftParameters::clearButtons() {
|
||||
|
||||
ui->buttonRefAdd->setChecked(false);
|
||||
ui->buttonRefRemove->setChecked(false);
|
||||
void TaskLoftParameters::clearButtons(const selectionModes notThis)
|
||||
{
|
||||
if (notThis != refProfile)
|
||||
ui->buttonProfileBase->setChecked(false);
|
||||
if (notThis != refAdd)
|
||||
ui->buttonRefAdd->setChecked(false);
|
||||
if (notThis != refRemove)
|
||||
ui->buttonRefRemove->setChecked(false);
|
||||
}
|
||||
|
||||
void TaskLoftParameters::exitSelectionMode() {
|
||||
|
||||
void TaskLoftParameters::exitSelectionMode()
|
||||
{
|
||||
selectionMode = none;
|
||||
Gui::Selection().clearSelection();
|
||||
}
|
||||
@@ -309,23 +318,27 @@ void TaskLoftParameters::onRuled(bool val) {
|
||||
void TaskLoftParameters::onProfileButton(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
clearButtons(refProfile);
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refProfile;
|
||||
//static_cast<ViewProviderLoft*>(vp)->highlightReferences(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskLoftParameters::onRefButtonAdd(bool checked) {
|
||||
void TaskLoftParameters::onRefButtonAdd(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
clearButtons(refAdd);
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refAdd;
|
||||
//static_cast<ViewProviderLoft*>(vp)->highlightReferences(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskLoftParameters::onRefButtonRemove(bool checked) {
|
||||
|
||||
void TaskLoftParameters::onRefButtonRemove(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
clearButtons(refRemove);
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refRemove;
|
||||
//static_cast<ViewProviderLoft*>(vp)->highlightReferences(true, true);
|
||||
|
||||
@@ -50,7 +50,7 @@ class TaskLoftParameters : public TaskSketchBasedParameters
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TaskLoftParameters(ViewProviderLoft *LoftView,bool newObj=false,QWidget *parent = 0);
|
||||
TaskLoftParameters(ViewProviderLoft *LoftView, bool newObj=false, QWidget *parent = 0);
|
||||
~TaskLoftParameters();
|
||||
|
||||
private Q_SLOTS:
|
||||
@@ -63,6 +63,8 @@ private Q_SLOTS:
|
||||
void indexesMoved();
|
||||
|
||||
protected:
|
||||
enum selectionModes { none, refAdd, refRemove, refProfile };
|
||||
|
||||
void changeEvent(QEvent *e);
|
||||
|
||||
private:
|
||||
@@ -70,14 +72,13 @@ private:
|
||||
void updateUI();
|
||||
bool referenceSelected(const Gui::SelectionChanges& msg) const;
|
||||
void removeFromListWidget(QListWidget*w, QString name);
|
||||
void clearButtons();
|
||||
void clearButtons(const selectionModes notThis=none);
|
||||
void exitSelectionMode();
|
||||
|
||||
private:
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskLoftParameters> ui;
|
||||
|
||||
enum selectionModes { none, refAdd, refRemove, refProfile };
|
||||
selectionModes selectionMode = none;
|
||||
};
|
||||
|
||||
|
||||
@@ -361,12 +361,12 @@ void TaskPadParameters::fillDirectionCombo()
|
||||
PartDesign::ProfileBased* pcFeat = static_cast<PartDesign::ProfileBased*>(vp->getObject());
|
||||
Part::Part2DObject* pcSketch = dynamic_cast<Part::Part2DObject*>(pcFeat->Profile.getValue());
|
||||
if (pcSketch)
|
||||
addAxisToCombo(pcSketch, "N_Axis", QObject::tr("Sketch normal"));
|
||||
addAxisToCombo(pcSketch, "N_Axis", tr("Sketch normal"));
|
||||
// add the other entries
|
||||
addAxisToCombo(0, std::string(), tr("Select reference..."));
|
||||
// we start with the sketch normal as proposal for the custom direction
|
||||
if (pcSketch)
|
||||
addAxisToCombo(pcSketch, "N_Axis", QObject::tr("Custom direction"));
|
||||
addAxisToCombo(pcSketch, "N_Axis", tr("Custom direction"));
|
||||
}
|
||||
|
||||
// add current link, if not in list
|
||||
@@ -420,7 +420,7 @@ void TaskPadParameters::onDirectionCBChanged(int num)
|
||||
{
|
||||
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
|
||||
|
||||
if (axesInList.empty() || !pcPad)
|
||||
if (axesInList.empty())
|
||||
return;
|
||||
|
||||
App::PropertyLinkSub& lnk = *(axesInList[num]);
|
||||
@@ -457,7 +457,6 @@ void TaskPadParameters::onDirectionCBChanged(int num)
|
||||
// if custom direction is used, show it
|
||||
if (num == 2) {
|
||||
ui->checkBoxDirection->setChecked(true);
|
||||
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
|
||||
pcPad->UseCustomVector.setValue(true);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -108,20 +108,29 @@ TaskPipeParameters::TaskPipeParameters(ViewProviderPipe *PipeView, bool /*newObj
|
||||
PartDesign::Pipe* pipe = static_cast<PartDesign::Pipe*>(PipeView->getObject());
|
||||
Gui::Document* doc = PipeView->getDocument();
|
||||
|
||||
//make sure the user sees all important things: the
|
||||
//spine/auxiliary spine he already selected
|
||||
// make sure the user sees all important things and load the values
|
||||
// also save visibility state to reset it later when pipe is closed
|
||||
// first the spine
|
||||
if (pipe->Spine.getValue()) {
|
||||
auto* svp = doc->getViewProvider(pipe->Spine.getValue());
|
||||
spineShow = svp->isShow();
|
||||
svp->setVisible(true);
|
||||
}
|
||||
|
||||
//add initial values
|
||||
if (pipe->Profile.getValue())
|
||||
ui->profileBaseEdit->setText(QString::fromUtf8(pipe->Profile.getValue()->Label.getValue()));
|
||||
if (pipe->Spine.getValue())
|
||||
auto* spineVP = doc->getViewProvider(pipe->Spine.getValue());
|
||||
spineShow = spineVP->isShow();
|
||||
spineVP->setVisible(true);
|
||||
ui->spineBaseEdit->setText(QString::fromUtf8(pipe->Spine.getValue()->Label.getValue()));
|
||||
|
||||
}
|
||||
// the profile
|
||||
if (pipe->Profile.getValue()) {
|
||||
auto* profileVP = doc->getViewProvider(pipe->Profile.getValue());
|
||||
profileShow = profileVP->isShow();
|
||||
profileVP->setVisible(true);
|
||||
ui->profileBaseEdit->setText(make2DLabel(pipe->Profile.getValue(), pipe->Profile.getSubValues()));
|
||||
}
|
||||
// the auxiliary spine
|
||||
if (pipe->AuxillerySpine.getValue()) {
|
||||
auto* svp = doc->getViewProvider(pipe->AuxillerySpine.getValue());
|
||||
auxSpineShow = svp->isShow();
|
||||
svp->show();
|
||||
}
|
||||
// the spine edges
|
||||
std::vector<std::string> strings = pipe->Spine.getSubValues();
|
||||
for (std::vector<std::string>::const_iterator it = strings.begin(); it != strings.end(); ++it) {
|
||||
QString label = QString::fromStdString(*it);
|
||||
@@ -145,19 +154,11 @@ TaskPipeParameters::~TaskPipeParameters()
|
||||
try {
|
||||
if (vp) {
|
||||
PartDesign::Pipe* pipe = static_cast<PartDesign::Pipe*>(vp->getObject());
|
||||
Gui::Document* doc = vp->getDocument();
|
||||
|
||||
//make sure the user sees all important things: the
|
||||
//spine/auxiliary spine he already selected
|
||||
if (pipe->Spine.getValue()) {
|
||||
auto* svp = doc->getViewProvider(pipe->Spine.getValue());
|
||||
svp->setVisible(spineShow);
|
||||
spineShow = false;
|
||||
}
|
||||
|
||||
//setting visibility to true is needed when preselecting profile and path prior to invoking sweep
|
||||
// setting visibility to true is needed when preselecting profile and path prior to invoking sweep
|
||||
Gui::cmdGuiObject(pipe, "Visibility = True");
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::Spine, false);
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::Profile, false);
|
||||
}
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
@@ -186,7 +187,7 @@ void TaskPipeParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
App::Document* document = App::GetApplication().getDocument(msg.pDocName);
|
||||
App::DocumentObject* object = document ? document->getObject(msg.pObjectName) : nullptr;
|
||||
if (object) {
|
||||
QString label = QString::fromUtf8(object->Label.getValue());
|
||||
QString label = make2DLabel(object, {msg.pSubName});
|
||||
ui->profileBaseEdit->setText(label);
|
||||
}
|
||||
}
|
||||
@@ -215,7 +216,7 @@ void TaskPipeParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
ui->spineBaseEdit->clear();
|
||||
}
|
||||
}
|
||||
else if(selectionMode == refObjAdd) {
|
||||
else if (selectionMode == refObjAdd) {
|
||||
ui->listWidgetReferences->clear();
|
||||
|
||||
App::Document* document = App::GetApplication().getDocument(msg.pDocName);
|
||||
@@ -235,16 +236,16 @@ void TaskPipeParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeParameters::onTransitionChanged(int idx) {
|
||||
|
||||
void TaskPipeParameters::onTransitionChanged(int idx)
|
||||
{
|
||||
static_cast<PartDesign::Pipe*>(vp->getObject())->Transition.setValue(idx);
|
||||
recomputeFeature();
|
||||
}
|
||||
|
||||
void TaskPipeParameters::onButtonRefAdd(bool checked) {
|
||||
|
||||
void TaskPipeParameters::onButtonRefAdd(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
//clearButtons(refAdd);
|
||||
clearButtons(refAdd);
|
||||
//hideObject();
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refAdd;
|
||||
@@ -257,10 +258,10 @@ void TaskPipeParameters::onButtonRefAdd(bool checked) {
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeParameters::onButtonRefRemove(bool checked) {
|
||||
|
||||
void TaskPipeParameters::onButtonRefRemove(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
//clearButtons(refRemove);
|
||||
clearButtons(refRemove);
|
||||
//hideObject();
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refRemove;
|
||||
@@ -273,10 +274,10 @@ void TaskPipeParameters::onButtonRefRemove(bool checked) {
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeParameters::onBaseButton(bool checked) {
|
||||
|
||||
void TaskPipeParameters::onBaseButton(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
//clearButtons(refRemove);
|
||||
clearButtons(refObjAdd);
|
||||
//hideObject();
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refObjAdd;
|
||||
@@ -300,7 +301,7 @@ void TaskPipeParameters::onProfileButton(bool checked)
|
||||
pvp->setVisible(true);
|
||||
}
|
||||
|
||||
//clearButtons(refRemove);
|
||||
clearButtons(refProfile);
|
||||
//hideObject();
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refProfile;
|
||||
@@ -313,14 +314,14 @@ void TaskPipeParameters::onProfileButton(bool checked)
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeParameters::onTangentChanged(bool checked) {
|
||||
|
||||
void TaskPipeParameters::onTangentChanged(bool checked)
|
||||
{
|
||||
static_cast<PartDesign::Pipe*>(vp->getObject())->SpineTangent.setValue(checked);
|
||||
recomputeFeature();
|
||||
}
|
||||
|
||||
void TaskPipeParameters::removeFromListWidget(QListWidget* widget, QString itemstr) {
|
||||
|
||||
void TaskPipeParameters::removeFromListWidget(QListWidget* widget, QString itemstr)
|
||||
{
|
||||
QList<QListWidgetItem*> items = widget->findItems(itemstr, Qt::MatchExactly);
|
||||
if (!items.empty()) {
|
||||
for (QList<QListWidgetItem*>::const_iterator i = items.begin(); i != items.end(); i++) {
|
||||
@@ -355,8 +356,8 @@ void TaskPipeParameters::onDeleteEdge()
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskPipeParameters::referenceSelected(const SelectionChanges& msg) const {
|
||||
|
||||
bool TaskPipeParameters::referenceSelected(const SelectionChanges& msg) const
|
||||
{
|
||||
if (msg.Type == Gui::SelectionChanges::AddSelection && selectionMode != none) {
|
||||
if (strcmp(msg.pDocName, vp->getObject()->getDocument()->getName()) != 0)
|
||||
return false;
|
||||
@@ -382,12 +383,13 @@ bool TaskPipeParameters::referenceSelected(const SelectionChanges& msg) const {
|
||||
success = false;
|
||||
}
|
||||
else {
|
||||
pipe->Profile.setValue(profile);
|
||||
pipe->Profile.setValue(profile, {msg.pSubName});
|
||||
}
|
||||
|
||||
// hide the old or new profile again
|
||||
auto* pvp = doc->getViewProvider(pipe->Profile.getValue());
|
||||
if(pvp) pvp->setVisible(false);
|
||||
if (pvp)
|
||||
pvp->setVisible(false);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -423,32 +425,66 @@ bool TaskPipeParameters::referenceSelected(const SelectionChanges& msg) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void TaskPipeParameters::clearButtons() {
|
||||
|
||||
ui->buttonProfileBase->setChecked(false);
|
||||
ui->buttonRefAdd->setChecked(false);
|
||||
ui->buttonRefRemove->setChecked(false);
|
||||
ui->buttonSpineBase->setChecked(false);
|
||||
void TaskPipeParameters::clearButtons(const selectionModes notThis)
|
||||
{
|
||||
// TODO: Clear buttons in the other pipe taskboxes as well
|
||||
if (notThis != refProfile)
|
||||
ui->buttonProfileBase->setChecked(false);
|
||||
if (notThis != refAdd)
|
||||
ui->buttonRefAdd->setChecked(false);
|
||||
if (notThis != refRemove)
|
||||
ui->buttonRefRemove->setChecked(false);
|
||||
if (notThis != refObjAdd)
|
||||
ui->buttonSpineBase->setChecked(false);
|
||||
}
|
||||
|
||||
void TaskPipeParameters::exitSelectionMode() {
|
||||
|
||||
void TaskPipeParameters::exitSelectionMode()
|
||||
{
|
||||
selectionMode = none;
|
||||
Gui::Selection().clearSelection();
|
||||
}
|
||||
|
||||
void TaskPipeParameters::setVisibilityOfSpineAndProfile()
|
||||
{
|
||||
if (vp) {
|
||||
PartDesign::Pipe* pipe = static_cast<PartDesign::Pipe*>(vp->getObject());
|
||||
Gui::Document* doc = vp->getDocument();
|
||||
|
||||
// set visibility to the state when the pipe was opened
|
||||
for (auto obj : pipe->Sections.getValues()) {
|
||||
auto* sectionVP = doc->getViewProvider(obj);
|
||||
sectionVP->setVisible(profileShow);
|
||||
}
|
||||
if (pipe->Spine.getValue()) {
|
||||
auto* spineVP = doc->getViewProvider(pipe->Spine.getValue());
|
||||
spineVP->setVisible(spineShow);
|
||||
spineShow = false;
|
||||
}
|
||||
if (pipe->Profile.getValue()) {
|
||||
auto* profileVP = doc->getViewProvider(pipe->Profile.getValue());
|
||||
profileVP->setVisible(profileShow);
|
||||
profileShow = false;
|
||||
}
|
||||
if (pipe->AuxillerySpine.getValue()) {
|
||||
auto* svp = doc->getViewProvider(pipe->AuxillerySpine.getValue());
|
||||
svp->setVisible(auxSpineShow);
|
||||
auxSpineShow = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskPipeParameters::accept()
|
||||
{
|
||||
//see what to do with external references
|
||||
//check the prerequisites for the selected objects
|
||||
//the user has to decide which option we should take if external references are used
|
||||
PartDesign::Pipe* pcPipe = static_cast<PartDesign::Pipe*>(getPipeView()->getObject());
|
||||
auto pcActiveBody = PartDesignGui::getBodyFor(pcPipe, false);
|
||||
auto pcActiveBody = PartDesignGui::getBodyFor (pcPipe, false);
|
||||
if (!pcActiveBody) {
|
||||
QMessageBox::warning(this, tr("Input error"), tr("No active body"));
|
||||
return false;
|
||||
}
|
||||
//auto pcActivePart = PartDesignGui::getPartFor(pcActiveBody, false);
|
||||
//auto pcActivePart = PartDesignGui::getPartFor (pcActiveBody, false);
|
||||
std::vector<App::DocumentObject*> copies;
|
||||
|
||||
bool extReference = false;
|
||||
@@ -473,7 +509,7 @@ bool TaskPipeParameters::accept()
|
||||
extReference = true;
|
||||
}
|
||||
else {
|
||||
for(App::DocumentObject* obj : pcPipe->Sections.getValues()) {
|
||||
for (App::DocumentObject* obj : pcPipe->Sections.getValues()) {
|
||||
if (!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) {
|
||||
extReference = true;
|
||||
break;
|
||||
@@ -491,7 +527,6 @@ bool TaskPipeParameters::accept()
|
||||
return false;
|
||||
|
||||
if (!dlg.radioXRef->isChecked()) {
|
||||
|
||||
if (!pcActiveBody->hasObject(spine) && !pcActiveBody->getOrigin()->hasObject(spine)) {
|
||||
pcPipe->Spine.setValue(PartDesignGui::TaskFeaturePick::makeCopy(spine, "",
|
||||
dlg.radioIndependent->isChecked()),
|
||||
@@ -507,9 +542,8 @@ bool TaskPipeParameters::accept()
|
||||
|
||||
std::vector<App::DocumentObject*> objs;
|
||||
int index = 0;
|
||||
for(App::DocumentObject* obj : pcPipe->Sections.getValues()) {
|
||||
|
||||
if(!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) {
|
||||
for (App::DocumentObject* obj : pcPipe->Sections.getValues()) {
|
||||
if (!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) {
|
||||
objs.push_back(PartDesignGui::TaskFeaturePick::makeCopy(obj, "", dlg.radioIndependent->isChecked()));
|
||||
copies.push_back(objs.back());
|
||||
}
|
||||
@@ -525,6 +559,8 @@ bool TaskPipeParameters::accept()
|
||||
}
|
||||
|
||||
try {
|
||||
setVisibilityOfSpineAndProfile();
|
||||
|
||||
App::DocumentObject* spine = pcPipe->Spine.getValue();
|
||||
std::vector<std::string> subNames = pcPipe->Spine.getSubValues();
|
||||
App::PropertyLinkT propT(spine, subNames);
|
||||
@@ -600,15 +636,6 @@ TaskPipeOrientation::TaskPipeOrientation(ViewProviderPipe* PipeView, bool /*newO
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
PartDesign::Pipe* pipe = static_cast<PartDesign::Pipe*>(PipeView->getObject());
|
||||
Gui::Document* doc = Gui::Application::Instance->getDocument(pipe->getDocument());
|
||||
|
||||
//make sure the user sees an important things: the base feature to select edges and the
|
||||
//spine/auxiliary spine he already selected
|
||||
if(pipe->AuxillerySpine.getValue()) {
|
||||
auto* svp = doc->getViewProvider(pipe->AuxillerySpine.getValue());
|
||||
auxSpineShow = svp->isShow();
|
||||
svp->show();
|
||||
}
|
||||
|
||||
//add initial values
|
||||
if (pipe->AuxillerySpine.getValue())
|
||||
@@ -633,49 +660,38 @@ TaskPipeOrientation::TaskPipeOrientation(ViewProviderPipe* PipeView, bool /*newO
|
||||
|
||||
TaskPipeOrientation::~TaskPipeOrientation()
|
||||
{
|
||||
try {
|
||||
if (vp) {
|
||||
PartDesign::Pipe* pipe = static_cast<PartDesign::Pipe*>(vp->getObject());
|
||||
Gui::Document* doc = vp->getDocument();
|
||||
|
||||
//make sure the user sees al important things: the base feature to select edges and the
|
||||
//spine/auxiliary spine he already selected
|
||||
if (pipe->AuxillerySpine.getValue()) {
|
||||
auto* svp = doc->getViewProvider(pipe->AuxillerySpine.getValue());
|
||||
svp->setVisible(auxSpineShow);
|
||||
auxSpineShow = false;
|
||||
}
|
||||
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::AuxiliarySpine, false);
|
||||
}
|
||||
}
|
||||
catch (const Base::RuntimeError&) {
|
||||
// getDocument() may raise an exception
|
||||
if (vp) {
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::AuxiliarySpine, false);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeOrientation::onOrientationChanged(int idx) {
|
||||
|
||||
void TaskPipeOrientation::onOrientationChanged(int idx)
|
||||
{
|
||||
static_cast<PartDesign::Pipe*>(vp->getObject())->Mode.setValue(idx);
|
||||
recomputeFeature();
|
||||
}
|
||||
|
||||
void TaskPipeOrientation::clearButtons() {
|
||||
|
||||
ui->buttonRefAdd->setChecked(false);
|
||||
ui->buttonRefRemove->setChecked(false);
|
||||
ui->buttonProfileBase->setChecked(false);
|
||||
void TaskPipeOrientation::clearButtons(const selectionModes notThis)
|
||||
{
|
||||
// TODO: Clear buttons in the other pipe taskboxes as well
|
||||
if (notThis != refAdd)
|
||||
ui->buttonRefAdd->setChecked(false);
|
||||
if (notThis != refRemove)
|
||||
ui->buttonRefRemove->setChecked(false);
|
||||
if (notThis != refObjAdd)
|
||||
ui->buttonProfileBase->setChecked(false);
|
||||
}
|
||||
|
||||
void TaskPipeOrientation::exitSelectionMode() {
|
||||
|
||||
void TaskPipeOrientation::exitSelectionMode()
|
||||
{
|
||||
selectionMode = none;
|
||||
Gui::Selection().clearSelection();
|
||||
}
|
||||
|
||||
void TaskPipeOrientation::onButtonRefAdd(bool checked) {
|
||||
|
||||
void TaskPipeOrientation::onButtonRefAdd(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
clearButtons(refAdd);
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refAdd;
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::AuxiliarySpine, true);
|
||||
@@ -687,9 +703,10 @@ void TaskPipeOrientation::onButtonRefAdd(bool checked) {
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeOrientation::onButtonRefRemove(bool checked) {
|
||||
|
||||
void TaskPipeOrientation::onButtonRefRemove(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
clearButtons(refRemove);
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refRemove;
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::AuxiliarySpine, true);
|
||||
@@ -704,6 +721,7 @@ void TaskPipeOrientation::onButtonRefRemove(bool checked) {
|
||||
void TaskPipeOrientation::onBaseButton(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
clearButtons(refObjAdd);
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refObjAdd;
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::AuxiliarySpine, true);
|
||||
@@ -740,8 +758,8 @@ void TaskPipeOrientation::onBinormalChanged(double)
|
||||
recomputeFeature();
|
||||
}
|
||||
|
||||
void TaskPipeOrientation::onSelectionChanged(const SelectionChanges& msg) {
|
||||
|
||||
void TaskPipeOrientation::onSelectionChanged(const SelectionChanges& msg)
|
||||
{
|
||||
if (selectionMode == none)
|
||||
return;
|
||||
|
||||
@@ -771,7 +789,7 @@ void TaskPipeOrientation::onSelectionChanged(const SelectionChanges& msg) {
|
||||
ui->profileBaseEdit->clear();
|
||||
}
|
||||
}
|
||||
else if(selectionMode == refObjAdd) {
|
||||
else if (selectionMode == refObjAdd) {
|
||||
ui->listWidgetReferences->clear();
|
||||
|
||||
App::Document* document = App::GetApplication().getDocument(msg.pDocName);
|
||||
@@ -792,8 +810,8 @@ void TaskPipeOrientation::onSelectionChanged(const SelectionChanges& msg) {
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskPipeOrientation::referenceSelected(const SelectionChanges& msg) const {
|
||||
|
||||
bool TaskPipeOrientation::referenceSelected(const SelectionChanges& msg) const
|
||||
{
|
||||
if (msg.Type == Gui::SelectionChanges::AddSelection && selectionMode != none) {
|
||||
if (strcmp(msg.pDocName, vp->getObject()->getDocument()->getName()) != 0)
|
||||
return false;
|
||||
@@ -832,8 +850,8 @@ bool TaskPipeOrientation::referenceSelected(const SelectionChanges& msg) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void TaskPipeOrientation::removeFromListWidget(QListWidget* widget, QString name) {
|
||||
|
||||
void TaskPipeOrientation::removeFromListWidget(QListWidget* widget, QString name)
|
||||
{
|
||||
QList<QListWidgetItem*> items = widget->findItems(name, Qt::MatchExactly);
|
||||
if (!items.empty()) {
|
||||
for (QList<QListWidgetItem*>::const_iterator i = items.begin(); i != items.end(); i++) {
|
||||
@@ -868,8 +886,8 @@ void TaskPipeOrientation::onDeleteItem()
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeOrientation::updateUI(int idx) {
|
||||
|
||||
void TaskPipeOrientation::updateUI(int idx)
|
||||
{
|
||||
//make sure we resize to the size of the current page
|
||||
for (int i=0; i<ui->stackedWidget->count(); ++i)
|
||||
ui->stackedWidget->widget(i)->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||
@@ -918,7 +936,7 @@ TaskPipeScaling::TaskPipeScaling(ViewProviderPipe* PipeView, bool /*newObj*/, QW
|
||||
PartDesign::Pipe* pipe = static_cast<PartDesign::Pipe*>(PipeView->getObject());
|
||||
for (auto obj : pipe->Sections.getValues()) {
|
||||
Gui::Application::Instance->showViewProvider(obj);
|
||||
QString label = QString::fromUtf8(obj->Label.getValue());
|
||||
QString label = make2DLabel(obj, pipe->Sections.getSubValues(obj));
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(label);
|
||||
item->setData(Qt::UserRole, QByteArray(obj->getNameInDocument()));
|
||||
@@ -932,25 +950,32 @@ TaskPipeScaling::TaskPipeScaling(ViewProviderPipe* PipeView, bool /*newObj*/, QW
|
||||
QGenericReturnArgument(), Q_ARG(int,pipe->Transformation.getValue()));
|
||||
}
|
||||
|
||||
TaskPipeScaling::~TaskPipeScaling() {
|
||||
|
||||
TaskPipeScaling::~TaskPipeScaling()
|
||||
{
|
||||
if (vp) {
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::Section, false);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeScaling::clearButtons() {
|
||||
|
||||
ui->buttonRefAdd->setChecked(false);
|
||||
ui->buttonRefRemove->setChecked(false);
|
||||
void TaskPipeScaling::clearButtons(const selectionModes notThis)
|
||||
{
|
||||
// TODO: Clear buttons in the other pipe taskboxes as well
|
||||
if (notThis != refRemove)
|
||||
ui->buttonRefRemove->setChecked(false);
|
||||
if (notThis != refAdd)
|
||||
ui->buttonRefAdd->setChecked(false);
|
||||
}
|
||||
|
||||
void TaskPipeScaling::exitSelectionMode() {
|
||||
|
||||
void TaskPipeScaling::exitSelectionMode()
|
||||
{
|
||||
selectionMode = none;
|
||||
Gui::Selection().clearSelection();
|
||||
}
|
||||
|
||||
void TaskPipeScaling::onButtonRefAdd(bool checked) {
|
||||
|
||||
void TaskPipeScaling::onButtonRefAdd(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
clearButtons(refAdd);
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refAdd;
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::Section, true);
|
||||
@@ -962,9 +987,10 @@ void TaskPipeScaling::onButtonRefAdd(bool checked) {
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeScaling::onButtonRefRemove(bool checked) {
|
||||
|
||||
void TaskPipeScaling::onButtonRefRemove(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
clearButtons(refRemove);
|
||||
Gui::Selection().clearSelection();
|
||||
selectionMode = refRemove;
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::Section, true);
|
||||
@@ -976,14 +1002,14 @@ void TaskPipeScaling::onButtonRefRemove(bool checked) {
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeScaling::onScalingChanged(int idx) {
|
||||
|
||||
void TaskPipeScaling::onScalingChanged(int idx)
|
||||
{
|
||||
updateUI(idx);
|
||||
static_cast<PartDesign::Pipe*>(vp->getObject())->Transformation.setValue(idx);
|
||||
}
|
||||
|
||||
void TaskPipeScaling::onSelectionChanged(const SelectionChanges& msg) {
|
||||
|
||||
void TaskPipeScaling::onSelectionChanged(const SelectionChanges& msg)
|
||||
{
|
||||
if (selectionMode == none)
|
||||
return;
|
||||
|
||||
@@ -992,7 +1018,7 @@ void TaskPipeScaling::onSelectionChanged(const SelectionChanges& msg) {
|
||||
App::Document* document = App::GetApplication().getDocument(msg.pDocName);
|
||||
App::DocumentObject* object = document ? document->getObject(msg.pObjectName) : nullptr;
|
||||
if (object) {
|
||||
QString label = QString::fromUtf8(object->Label.getValue());
|
||||
QString label = make2DLabel(object, {msg.pSubName});
|
||||
if (selectionMode == refAdd) {
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(label);
|
||||
@@ -1012,11 +1038,10 @@ void TaskPipeScaling::onSelectionChanged(const SelectionChanges& msg) {
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskPipeScaling::referenceSelected(const SelectionChanges& msg) const {
|
||||
|
||||
bool TaskPipeScaling::referenceSelected(const SelectionChanges& msg) const
|
||||
{
|
||||
if ((msg.Type == Gui::SelectionChanges::AddSelection) && (
|
||||
(selectionMode == refAdd) || (selectionMode == refRemove))) {
|
||||
|
||||
if (strcmp(msg.pDocName, vp->getObject()->getDocument()->getName()) != 0)
|
||||
return false;
|
||||
|
||||
@@ -1029,33 +1054,35 @@ bool TaskPipeScaling::referenceSelected(const SelectionChanges& msg) const {
|
||||
//supported, not individual edges of a part
|
||||
|
||||
//change the references
|
||||
std::vector<App::DocumentObject*> refs = static_cast<PartDesign::Pipe*>(vp->getObject())->Sections.getValues();
|
||||
PartDesign::Pipe* pipe = static_cast<PartDesign::Pipe*>(vp->getObject());
|
||||
std::vector<App::DocumentObject*> refs = pipe->Sections.getValues();
|
||||
App::DocumentObject* obj = vp->getObject()->getDocument()->getObject(msg.pObjectName);
|
||||
std::vector<App::DocumentObject*>::iterator f = std::find(refs.begin(), refs.end(), obj);
|
||||
|
||||
if (selectionMode == refAdd) {
|
||||
if (f == refs.end())
|
||||
refs.push_back(obj);
|
||||
pipe->Sections.addValue(obj, {msg.pSubName});
|
||||
else
|
||||
return false; // duplicate selection
|
||||
}
|
||||
else {
|
||||
if (f != refs.end())
|
||||
refs.erase(f);
|
||||
// Removing just the object this way instead of `refs.erase` and
|
||||
// `setValues(ref)` cleanly ensures subnames are preserved.
|
||||
pipe->Sections.removeValue(obj);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static_cast<ViewProviderPipe*>(vp)->highlightReferences(ViewProviderPipe::Section, false);
|
||||
static_cast<PartDesign::Pipe*>(vp->getObject())->Sections.setValues(refs);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TaskPipeScaling::removeFromListWidget(QListWidget* widget, QString name) {
|
||||
|
||||
void TaskPipeScaling::removeFromListWidget(QListWidget* widget, QString name)
|
||||
{
|
||||
QList<QListWidgetItem*> items = widget->findItems(name, Qt::MatchExactly);
|
||||
if (!items.empty()) {
|
||||
for (QList<QListWidgetItem*>::const_iterator i = items.begin(); i != items.end(); i++) {
|
||||
@@ -1082,18 +1109,19 @@ void TaskPipeScaling::onDeleteSection()
|
||||
|
||||
// if something was found, delete it and update the section list
|
||||
if (f != refs.end()) {
|
||||
refs.erase(f);
|
||||
pipe->Sections.setValues(refs);
|
||||
// Removing just the object this way instead of `refs.erase` and
|
||||
// `setValues(ref)` cleanly ensures subnames are preserved.
|
||||
pipe->Sections.removeValue(obj);
|
||||
clearButtons();
|
||||
recomputeFeature();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPipeScaling::updateUI(int idx) {
|
||||
|
||||
void TaskPipeScaling::updateUI(int idx)
|
||||
{
|
||||
//make sure we resize to the size of the current page
|
||||
for(int i=0; i<ui->stackedWidget->count(); ++i)
|
||||
for (int i=0; i<ui->stackedWidget->count(); ++i)
|
||||
ui->stackedWidget->widget(i)->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||
|
||||
if (idx < ui->stackedWidget->count())
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Gui {
|
||||
class ViewProvider;
|
||||
}
|
||||
|
||||
namespace PartDesignGui {
|
||||
namespace PartDesignGui {
|
||||
|
||||
class Ui_TaskPipeParameters;
|
||||
class Ui_TaskPipeOrientation;
|
||||
@@ -53,7 +53,7 @@ class TaskPipeParameters : public TaskSketchBasedParameters
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TaskPipeParameters(ViewProviderPipe *PipeView,bool newObj=false,QWidget *parent = 0);
|
||||
TaskPipeParameters(ViewProviderPipe *PipeView, bool newObj=false, QWidget *parent = 0);
|
||||
~TaskPipeParameters();
|
||||
|
||||
bool accept();
|
||||
@@ -66,25 +66,28 @@ private Q_SLOTS:
|
||||
void onBaseButton(bool checked);
|
||||
void onProfileButton(bool checked);
|
||||
void onDeleteEdge();
|
||||
|
||||
|
||||
protected:
|
||||
enum selectionModes { none, refAdd, refRemove, refObjAdd, refProfile };
|
||||
selectionModes selectionMode = none;
|
||||
|
||||
|
||||
void removeFromListWidget(QListWidget*w, QString name);
|
||||
bool referenceSelected(const Gui::SelectionChanges& msg) const;
|
||||
|
||||
private:
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg);
|
||||
void updateUI();
|
||||
void clearButtons();
|
||||
void clearButtons(const selectionModes notThis=none);
|
||||
void exitSelectionMode();
|
||||
void setVisibilityOfSpineAndProfile();
|
||||
|
||||
ViewProviderPipe* getPipeView() const
|
||||
{ return static_cast<ViewProviderPipe*>(vp); }
|
||||
|
||||
bool spineShow = false;
|
||||
|
||||
bool profileShow = false;
|
||||
bool auxSpineShow = false;
|
||||
|
||||
private:
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPipeParameters> ui;
|
||||
@@ -95,10 +98,10 @@ class TaskPipeOrientation : public TaskSketchBasedParameters
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TaskPipeOrientation(ViewProviderPipe *PipeView,bool newObj=false,QWidget *parent = 0);
|
||||
TaskPipeOrientation(ViewProviderPipe *PipeView, bool newObj=false, QWidget *parent = 0);
|
||||
virtual ~TaskPipeOrientation();
|
||||
|
||||
|
||||
|
||||
private Q_SLOTS:
|
||||
void onOrientationChanged(int);
|
||||
void onButtonRefAdd(bool checked);
|
||||
@@ -109,20 +112,18 @@ private Q_SLOTS:
|
||||
void onCurvelinearChanged(bool checked);
|
||||
void onBinormalChanged(double);
|
||||
void onDeleteItem();
|
||||
|
||||
|
||||
protected:
|
||||
enum selectionModes { none, refAdd, refRemove, refObjAdd };
|
||||
selectionModes selectionMode = none;
|
||||
|
||||
|
||||
void removeFromListWidget(QListWidget*w, QString name);
|
||||
bool referenceSelected(const Gui::SelectionChanges& msg) const;
|
||||
|
||||
private:
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg);
|
||||
void clearButtons();
|
||||
void clearButtons(const selectionModes notThis=none);
|
||||
void exitSelectionMode();
|
||||
|
||||
bool auxSpineShow = false;
|
||||
|
||||
private:
|
||||
QWidget* proxy;
|
||||
@@ -144,17 +145,17 @@ private Q_SLOTS:
|
||||
void onButtonRefRemove(bool checked);
|
||||
void updateUI(int idx);
|
||||
void onDeleteSection();
|
||||
|
||||
|
||||
protected:
|
||||
enum selectionModes { none, refAdd, refRemove };
|
||||
selectionModes selectionMode = none;
|
||||
|
||||
|
||||
void removeFromListWidget(QListWidget*w, QString name);
|
||||
bool referenceSelected(const Gui::SelectionChanges& msg) const;
|
||||
|
||||
private:
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg);
|
||||
void clearButtons();
|
||||
void clearButtons(const selectionModes notThis=none);
|
||||
void exitSelectionMode();
|
||||
|
||||
private:
|
||||
|
||||
@@ -34,14 +34,15 @@
|
||||
#include "TaskPocketParameters.h"
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/UnitsApi.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Document.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/Document.h>
|
||||
#include <Gui/Selection.h>
|
||||
#include <Gui/ViewProvider.h>
|
||||
#include <Gui/WaitCursor.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Gui/Selection.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Mod/PartDesign/App/FeaturePocket.h>
|
||||
#include <Mod/Sketcher/App/SketchObject.h>
|
||||
#include "TaskSketchBasedParameters.h"
|
||||
@@ -76,6 +77,11 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
|
||||
Base::Quantity l = pcPocket->Length.getQuantityValue();
|
||||
Base::Quantity l2 = pcPocket->Length2.getQuantityValue();
|
||||
Base::Quantity off = pcPocket->Offset.getQuantityValue();
|
||||
bool alongNormal = pcPocket->AlongSketchNormal.getValue();
|
||||
bool useCustom = pcPocket->UseCustomVector.getValue();
|
||||
double xs = pcPocket->Direction.getValue().x;
|
||||
double ys = pcPocket->Direction.getValue().y;
|
||||
double zs = pcPocket->Direction.getValue().z;
|
||||
bool midplane = pcPocket->Midplane.getValue();
|
||||
bool reversed = pcPocket->Reversed.getValue();
|
||||
int index = pcPocket->Type.getValue(); // must extract value here, clear() kills it!
|
||||
@@ -89,10 +95,30 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
|
||||
faceId = std::atoi(&upToFace[4]);
|
||||
}
|
||||
|
||||
// set decimals for the direction edits
|
||||
// do this here before the edits are filed to avoid rounding mistakes
|
||||
int UserDecimals = Base::UnitsApi::getDecimals();
|
||||
ui->XDirectionEdit->setDecimals(UserDecimals);
|
||||
ui->YDirectionEdit->setDecimals(UserDecimals);
|
||||
ui->ZDirectionEdit->setDecimals(UserDecimals);
|
||||
|
||||
// Fill data into dialog elements
|
||||
// the direction combobox is later filled in updateUI()
|
||||
ui->lengthEdit->setValue(l);
|
||||
ui->lengthEdit2->setValue(l2);
|
||||
ui->offsetEdit->setValue(off);
|
||||
ui->checkBoxAlongDirection->setChecked(alongNormal);
|
||||
ui->checkBoxDirection->setChecked(useCustom);
|
||||
onDirectionToggled(useCustom);
|
||||
// disable to change the direction if not custom
|
||||
if (!useCustom) {
|
||||
ui->XDirectionEdit->setEnabled(false);
|
||||
ui->YDirectionEdit->setEnabled(false);
|
||||
ui->ZDirectionEdit->setEnabled(false);
|
||||
}
|
||||
ui->XDirectionEdit->setValue(xs);
|
||||
ui->YDirectionEdit->setValue(ys);
|
||||
ui->ZDirectionEdit->setValue(zs);
|
||||
ui->checkBoxMidplane->setChecked(midplane);
|
||||
ui->checkBoxReversed->setChecked(reversed);
|
||||
|
||||
@@ -127,6 +153,9 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
|
||||
ui->lengthEdit->bind(pcPocket->Length);
|
||||
ui->lengthEdit2->bind(pcPocket->Length2);
|
||||
ui->offsetEdit->bind(pcPocket->Offset);
|
||||
ui->XDirectionEdit->bind(App::ObjectIdentifier::parse(pcPocket, std::string("Direction.x")));
|
||||
ui->YDirectionEdit->bind(App::ObjectIdentifier::parse(pcPocket, std::string("Direction.y")));
|
||||
ui->ZDirectionEdit->bind(App::ObjectIdentifier::parse(pcPocket, std::string("Direction.z")));
|
||||
|
||||
QMetaObject::connectSlotsByName(this);
|
||||
|
||||
@@ -136,6 +165,18 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
|
||||
this, SLOT(onLength2Changed(double)));
|
||||
connect(ui->offsetEdit, SIGNAL(valueChanged(double)),
|
||||
this, SLOT(onOffsetChanged(double)));
|
||||
connect(ui->directionCB, SIGNAL(activated(int)),
|
||||
this, SLOT(onDirectionCBChanged(int)));
|
||||
connect(ui->checkBoxAlongDirection, SIGNAL(toggled(bool)),
|
||||
this, SLOT(onAlongSketchNormalChanged(bool)));
|
||||
connect(ui->checkBoxDirection, SIGNAL(toggled(bool)),
|
||||
this, SLOT(onDirectionToggled(bool)));
|
||||
connect(ui->XDirectionEdit, SIGNAL(valueChanged(double)),
|
||||
this, SLOT(onXDirectionEditChanged(double)));
|
||||
connect(ui->YDirectionEdit, SIGNAL(valueChanged(double)),
|
||||
this, SLOT(onYDirectionEditChanged(double)));
|
||||
connect(ui->ZDirectionEdit, SIGNAL(valueChanged(double)),
|
||||
this, SLOT(onZDirectionEditChanged(double)));
|
||||
connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)),
|
||||
this, SLOT(onMidplaneChanged(bool)));
|
||||
connect(ui->checkBoxReversed, SIGNAL(toggled(bool)),
|
||||
@@ -149,12 +190,14 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
|
||||
connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)),
|
||||
this, SLOT(onUpdateView(bool)));
|
||||
|
||||
this->propReferenceAxis = &(pcPocket->ReferenceAxis);
|
||||
|
||||
// Due to signals attached after changes took took into effect we should update the UI now.
|
||||
updateUI(index);
|
||||
|
||||
// if it is a newly created object use the last value of the history
|
||||
// TODO: newObj doesn't supplied normally by any caller (2015-07-24, Fat-Zer)
|
||||
if(newObj){
|
||||
if (newObj){
|
||||
ui->lengthEdit->setToLastUsedValue();
|
||||
ui->lengthEdit->selectNumber();
|
||||
ui->lengthEdit2->setToLastUsedValue();
|
||||
@@ -166,10 +209,13 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
|
||||
|
||||
void TaskPocketParameters::updateUI(int index)
|
||||
{
|
||||
// update direction combobox
|
||||
fillDirectionCombo();
|
||||
|
||||
// disable/hide everything unless we are sure we don't need it
|
||||
bool isLengthEditVisable = false;
|
||||
bool isLengthEdit2Visable = false;
|
||||
bool isOffsetEditVisable = false;
|
||||
bool isLengthEditVisible = false;
|
||||
bool isLengthEdit2Visible = false;
|
||||
bool isOffsetEditVisible = false;
|
||||
bool isOffsetEditEnabled = true;
|
||||
bool isMidplateEnabled = false;
|
||||
bool isReversedEnabled = false;
|
||||
@@ -177,7 +223,7 @@ void TaskPocketParameters::updateUI(int index)
|
||||
|
||||
// dimension
|
||||
if (index == 0) {
|
||||
isLengthEditVisable = true;
|
||||
isLengthEditVisible = true;
|
||||
ui->lengthEdit->selectNumber();
|
||||
// Make sure that the spin box has the focus to get key events
|
||||
// Calling setFocus() directly doesn't work because the spin box is not
|
||||
@@ -189,14 +235,14 @@ void TaskPocketParameters::updateUI(int index)
|
||||
}
|
||||
// through all
|
||||
else if (index == 1) {
|
||||
isOffsetEditVisable = true;
|
||||
isOffsetEditVisible = true;
|
||||
isOffsetEditEnabled = false; // offset may have some meaning for through all but it doesn't work
|
||||
isMidplateEnabled = true;
|
||||
isReversedEnabled = !ui->checkBoxMidplane->isChecked();
|
||||
}
|
||||
// up to first
|
||||
else if (index == 2) {
|
||||
isOffsetEditVisable = true;
|
||||
isOffsetEditVisible = true;
|
||||
isReversedEnabled = true; // Will change the direction it seeks for its first face?
|
||||
// It may work not quite as expected but useful if sketch oriented upside-down.
|
||||
// (may happen in bodies)
|
||||
@@ -204,7 +250,7 @@ void TaskPocketParameters::updateUI(int index)
|
||||
}
|
||||
// up to face
|
||||
else if (index == 3) {
|
||||
isOffsetEditVisable = true;
|
||||
isOffsetEditVisible = true;
|
||||
isReversedEnabled = true;
|
||||
isFaceEditEnabled = true;
|
||||
QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection);
|
||||
@@ -214,22 +260,23 @@ void TaskPocketParameters::updateUI(int index)
|
||||
}
|
||||
// two dimensions
|
||||
else {
|
||||
isLengthEditVisable = true;
|
||||
isLengthEdit2Visable = true;
|
||||
isLengthEditVisible = true;
|
||||
isLengthEdit2Visible = true;
|
||||
isReversedEnabled = true;
|
||||
}
|
||||
|
||||
ui->lengthEdit->setVisible( isLengthEditVisable );
|
||||
ui->lengthEdit->setEnabled( isLengthEditVisable );
|
||||
ui->labelLength->setVisible( isLengthEditVisable );
|
||||
ui->lengthEdit->setVisible( isLengthEditVisible );
|
||||
ui->lengthEdit->setEnabled( isLengthEditVisible );
|
||||
ui->labelLength->setVisible( isLengthEditVisible );
|
||||
ui->checkBoxAlongDirection->setVisible(isLengthEditVisible);
|
||||
|
||||
ui->lengthEdit2->setVisible( isLengthEdit2Visable );
|
||||
ui->lengthEdit2->setEnabled( isLengthEdit2Visable );
|
||||
ui->labelLength2->setVisible( isLengthEdit2Visable );
|
||||
ui->lengthEdit2->setVisible( isLengthEdit2Visible );
|
||||
ui->lengthEdit2->setEnabled( isLengthEdit2Visible );
|
||||
ui->labelLength2->setVisible( isLengthEdit2Visible );
|
||||
|
||||
ui->offsetEdit->setVisible( isOffsetEditVisable );
|
||||
ui->offsetEdit->setEnabled( isOffsetEditVisable && isOffsetEditEnabled );
|
||||
ui->labelOffset->setVisible( isOffsetEditVisable );
|
||||
ui->offsetEdit->setVisible( isOffsetEditVisible );
|
||||
ui->offsetEdit->setEnabled( isOffsetEditVisible && isOffsetEditEnabled );
|
||||
ui->labelOffset->setVisible( isOffsetEditVisible );
|
||||
|
||||
ui->checkBoxMidplane->setEnabled( isMidplateEnabled );
|
||||
|
||||
@@ -245,21 +292,36 @@ void TaskPocketParameters::updateUI(int index)
|
||||
void TaskPocketParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
{
|
||||
if (msg.Type == Gui::SelectionChanges::AddSelection) {
|
||||
QString refText = onAddSelection(msg);
|
||||
if (refText.length() > 0) {
|
||||
ui->lineFaceName->blockSignals(true);
|
||||
ui->lineFaceName->setText(refText);
|
||||
ui->lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName));
|
||||
ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName));
|
||||
ui->lineFaceName->blockSignals(false);
|
||||
// Turn off reference selection mode
|
||||
onButtonFace(false);
|
||||
} else {
|
||||
ui->lineFaceName->blockSignals(true);
|
||||
ui->lineFaceName->clear();
|
||||
ui->lineFaceName->setProperty("FeatureName", QVariant());
|
||||
ui->lineFaceName->setProperty("FaceName", QVariant());
|
||||
ui->lineFaceName->blockSignals(false);
|
||||
// if we have an edge selection for the pocket direction
|
||||
if (!selectionFace) {
|
||||
std::vector<std::string> edge;
|
||||
App::DocumentObject* selObj;
|
||||
if (getReferencedSelection(vp->getObject(), msg, selObj, edge) && selObj) {
|
||||
exitSelectionMode();
|
||||
propReferenceAxis->setValue(selObj, edge);
|
||||
recomputeFeature();
|
||||
// update direction combobox
|
||||
fillDirectionCombo();
|
||||
}
|
||||
}
|
||||
else { // if we have a selection of a face
|
||||
QString refText = onAddSelection(msg);
|
||||
if (refText.length() > 0) {
|
||||
ui->lineFaceName->blockSignals(true);
|
||||
ui->lineFaceName->setText(refText);
|
||||
ui->lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName));
|
||||
ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName));
|
||||
ui->lineFaceName->blockSignals(false);
|
||||
// Turn off reference selection mode
|
||||
onButtonFace(false);
|
||||
}
|
||||
else {
|
||||
ui->lineFaceName->blockSignals(true);
|
||||
ui->lineFaceName->clear();
|
||||
ui->lineFaceName->setProperty("FeatureName", QVariant());
|
||||
ui->lineFaceName->setProperty("FaceName", QVariant());
|
||||
ui->lineFaceName->blockSignals(false);
|
||||
}
|
||||
}
|
||||
} else if (msg.Type == Gui::SelectionChanges::ClrSelection) {
|
||||
ui->lineFaceName->blockSignals(true);
|
||||
@@ -291,6 +353,193 @@ void TaskPocketParameters::onOffsetChanged(double len)
|
||||
recomputeFeature();
|
||||
}
|
||||
|
||||
void TaskPocketParameters::fillDirectionCombo()
|
||||
{
|
||||
bool oldVal_blockUpdate = blockUpdate;
|
||||
blockUpdate = true;
|
||||
|
||||
if (axesInList.empty()) {
|
||||
ui->directionCB->clear();
|
||||
// add sketch normal
|
||||
PartDesign::ProfileBased* pcFeat = static_cast<PartDesign::ProfileBased*>(vp->getObject());
|
||||
Part::Part2DObject* pcSketch = dynamic_cast<Part::Part2DObject*>(pcFeat->Profile.getValue());
|
||||
if (pcSketch)
|
||||
addAxisToCombo(pcSketch, "N_Axis", QObject::tr("Sketch normal"));
|
||||
// add the other entries
|
||||
addAxisToCombo(0, std::string(), tr("Select reference..."));
|
||||
// we start with the sketch normal as proposal for the custom direction
|
||||
if (pcSketch)
|
||||
addAxisToCombo(pcSketch, "N_Axis", QObject::tr("Custom direction"));
|
||||
}
|
||||
|
||||
// add current link, if not in list
|
||||
// first, figure out the item number for current axis
|
||||
int indexOfCurrent = -1;
|
||||
App::DocumentObject* ax = propReferenceAxis->getValue();
|
||||
const std::vector<std::string>& subList = propReferenceAxis->getSubValues();
|
||||
for (size_t i = 0; i < axesInList.size(); i++) {
|
||||
if (ax == axesInList[i]->getValue() && subList == axesInList[i]->getSubValues()) {
|
||||
indexOfCurrent = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the axis is not yet listed in the combobox
|
||||
if (indexOfCurrent == -1 && ax) {
|
||||
assert(subList.size() <= 1);
|
||||
std::string sub;
|
||||
if (!subList.empty())
|
||||
sub = subList[0];
|
||||
addAxisToCombo(ax, sub, getRefStr(ax, subList));
|
||||
indexOfCurrent = axesInList.size() - 1;
|
||||
// the axis is not the normal, thus enable along direction
|
||||
ui->checkBoxAlongDirection->setEnabled(true);
|
||||
// we don't have custom direction thus disable its settings
|
||||
ui->XDirectionEdit->setEnabled(false);
|
||||
ui->YDirectionEdit->setEnabled(false);
|
||||
ui->ZDirectionEdit->setEnabled(false);
|
||||
}
|
||||
|
||||
// highlight either current index or set custom direction
|
||||
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
|
||||
bool hasCustom = pcPocket->UseCustomVector.getValue();
|
||||
if (indexOfCurrent != -1 && !hasCustom)
|
||||
ui->directionCB->setCurrentIndex(indexOfCurrent);
|
||||
if (hasCustom)
|
||||
ui->directionCB->setCurrentIndex(2);
|
||||
|
||||
blockUpdate = oldVal_blockUpdate;
|
||||
}
|
||||
|
||||
void TaskPocketParameters::addAxisToCombo(App::DocumentObject* linkObj,
|
||||
std::string linkSubname, QString itemText)
|
||||
{
|
||||
this->ui->directionCB->addItem(itemText);
|
||||
this->axesInList.emplace_back(new App::PropertyLinkSub);
|
||||
App::PropertyLinkSub& lnk = *(axesInList.back());
|
||||
lnk.setValue(linkObj, std::vector<std::string>(1, linkSubname));
|
||||
}
|
||||
|
||||
void TaskPocketParameters::onDirectionCBChanged(int num)
|
||||
{
|
||||
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
|
||||
|
||||
if (axesInList.empty() || !pcPocket)
|
||||
return;
|
||||
|
||||
App::PropertyLinkSub& lnk = *(axesInList[num]);
|
||||
if (lnk.getValue() == 0) {
|
||||
// enter reference selection mode
|
||||
this->blockConnection(false);
|
||||
// to distinguish that this is the direction selection
|
||||
selectionFace = false;
|
||||
TaskSketchBasedParameters::onSelectReference(true, true, false, true, true);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (!pcPocket->getDocument()->isIn(lnk.getValue())) {
|
||||
Base::Console().Error("Object was deleted\n");
|
||||
return;
|
||||
}
|
||||
propReferenceAxis->Paste(lnk);
|
||||
// in case user is in selection mode, but changed his mind before selecting anything
|
||||
exitSelectionMode();
|
||||
}
|
||||
|
||||
try {
|
||||
recomputeFeature();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
e.ReportException();
|
||||
}
|
||||
|
||||
// disable AlongSketchNormal when the direction is already normal
|
||||
if (num == 0)
|
||||
ui->checkBoxAlongDirection->setEnabled(false);
|
||||
else
|
||||
ui->checkBoxAlongDirection->setEnabled(true);
|
||||
// if custom direction is used, show it
|
||||
if (num == 2) {
|
||||
ui->checkBoxDirection->setChecked(true);
|
||||
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
|
||||
pcPocket->UseCustomVector.setValue(true);
|
||||
}
|
||||
else {
|
||||
ui->checkBoxDirection->setChecked(false);
|
||||
pcPocket->UseCustomVector.setValue(false);
|
||||
}
|
||||
// if we dont use custom direction, only allow to show its direction
|
||||
if (num != 2) {
|
||||
ui->XDirectionEdit->setEnabled(false);
|
||||
ui->YDirectionEdit->setEnabled(false);
|
||||
ui->ZDirectionEdit->setEnabled(false);
|
||||
}
|
||||
else {
|
||||
ui->XDirectionEdit->setEnabled(true);
|
||||
ui->YDirectionEdit->setEnabled(true);
|
||||
ui->ZDirectionEdit->setEnabled(true);
|
||||
}
|
||||
// recompute and update the direction
|
||||
recomputeFeature();
|
||||
updateDirectionEdits();
|
||||
}
|
||||
|
||||
void TaskPocketParameters::onAlongSketchNormalChanged(bool on)
|
||||
{
|
||||
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
|
||||
pcPocket->AlongSketchNormal.setValue(on);
|
||||
recomputeFeature();
|
||||
}
|
||||
|
||||
void TaskPocketParameters::onDirectionToggled(bool on)
|
||||
{
|
||||
if (on)
|
||||
ui->groupBoxDirection->show();
|
||||
else
|
||||
ui->groupBoxDirection->hide();
|
||||
}
|
||||
|
||||
void TaskPocketParameters::onXDirectionEditChanged(double len)
|
||||
{
|
||||
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
|
||||
pcPocket->Direction.setValue(len, pcPocket->Direction.getValue().y, pcPocket->Direction.getValue().z);
|
||||
recomputeFeature();
|
||||
// checking for case of a null vector is done in FeaturePocket.cpp
|
||||
// if there was a null vector, the normal vector of the sketch is used.
|
||||
// therefore the vector component edits must be updated
|
||||
updateDirectionEdits();
|
||||
}
|
||||
|
||||
void TaskPocketParameters::onYDirectionEditChanged(double len)
|
||||
{
|
||||
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
|
||||
pcPocket->Direction.setValue(pcPocket->Direction.getValue().x, len, pcPocket->Direction.getValue().z);
|
||||
recomputeFeature();
|
||||
updateDirectionEdits();
|
||||
}
|
||||
|
||||
void TaskPocketParameters::onZDirectionEditChanged(double len)
|
||||
{
|
||||
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
|
||||
pcPocket->Direction.setValue(pcPocket->Direction.getValue().x, pcPocket->Direction.getValue().y, len);
|
||||
recomputeFeature();
|
||||
updateDirectionEdits();
|
||||
}
|
||||
|
||||
void TaskPocketParameters::updateDirectionEdits(void)
|
||||
{
|
||||
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
|
||||
// we don't want to execute the onChanged edits, but just update their contents
|
||||
ui->XDirectionEdit->blockSignals(true);
|
||||
ui->YDirectionEdit->blockSignals(true);
|
||||
ui->ZDirectionEdit->blockSignals(true);
|
||||
ui->XDirectionEdit->setValue(pcPocket->Direction.getValue().x);
|
||||
ui->YDirectionEdit->setValue(pcPocket->Direction.getValue().y);
|
||||
ui->ZDirectionEdit->setValue(pcPocket->Direction.getValue().z);
|
||||
ui->XDirectionEdit->blockSignals(false);
|
||||
ui->YDirectionEdit->blockSignals(false);
|
||||
ui->ZDirectionEdit->blockSignals(false);
|
||||
}
|
||||
|
||||
void TaskPocketParameters::onMidplaneChanged(bool on)
|
||||
{
|
||||
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
|
||||
@@ -394,6 +643,39 @@ double TaskPocketParameters::getOffset(void) const
|
||||
return ui->offsetEdit->value().getValue();
|
||||
}
|
||||
|
||||
bool TaskPocketParameters::getAlongSketchNormal(void) const
|
||||
{
|
||||
return ui->checkBoxAlongDirection->isChecked();
|
||||
}
|
||||
|
||||
bool TaskPocketParameters::getCustom(void) const
|
||||
{
|
||||
return ui->checkBoxDirection->isChecked();
|
||||
}
|
||||
|
||||
std::string TaskPocketParameters::getReferenceAxis(void) const
|
||||
{
|
||||
std::vector<std::string> sub;
|
||||
App::DocumentObject* obj;
|
||||
getReferenceAxis(obj, sub);
|
||||
return buildLinkSingleSubPythonStr(obj, sub);
|
||||
}
|
||||
|
||||
double TaskPocketParameters::getXDirection(void) const
|
||||
{
|
||||
return ui->XDirectionEdit->value();
|
||||
}
|
||||
|
||||
double TaskPocketParameters::getYDirection(void) const
|
||||
{
|
||||
return ui->YDirectionEdit->value();
|
||||
}
|
||||
|
||||
double TaskPocketParameters::getZDirection(void) const
|
||||
{
|
||||
return ui->ZDirectionEdit->value();
|
||||
}
|
||||
|
||||
bool TaskPocketParameters::getReversed(void) const
|
||||
{
|
||||
return ui->checkBoxReversed->isChecked();
|
||||
@@ -433,9 +715,19 @@ void TaskPocketParameters::changeEvent(QEvent *e)
|
||||
ui->lengthEdit->blockSignals(true);
|
||||
ui->lengthEdit2->blockSignals(true);
|
||||
ui->offsetEdit->blockSignals(true);
|
||||
ui->XDirectionEdit->blockSignals(true);
|
||||
ui->YDirectionEdit->blockSignals(true);
|
||||
ui->ZDirectionEdit->blockSignals(true);
|
||||
ui->directionCB->blockSignals(true);
|
||||
int index = ui->directionCB->currentIndex();
|
||||
ui->directionCB->clear();
|
||||
ui->directionCB->addItem(tr("Sketch normal"));
|
||||
ui->directionCB->addItem(tr("Select reference..."));
|
||||
ui->directionCB->addItem(tr("Custom direction"));
|
||||
ui->directionCB->setCurrentIndex(index);
|
||||
ui->lineFaceName->blockSignals(true);
|
||||
ui->changeMode->blockSignals(true);
|
||||
int index = ui->changeMode->currentIndex();
|
||||
index = ui->changeMode->currentIndex();
|
||||
ui->retranslateUi(proxy);
|
||||
ui->changeMode->clear();
|
||||
ui->changeMode->addItem(tr("Dimension"));
|
||||
@@ -477,6 +769,29 @@ void TaskPocketParameters::changeEvent(QEvent *e)
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPocketParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector<std::string>& sub) const
|
||||
{
|
||||
if (axesInList.empty())
|
||||
throw Base::RuntimeError("Not initialized!");
|
||||
|
||||
int num = ui->directionCB->currentIndex();
|
||||
const App::PropertyLinkSub& lnk = *(axesInList[num]);
|
||||
if (lnk.getValue() == 0) {
|
||||
// Note: Is is possible that a face of an object is directly pocketed without defining a profile shape
|
||||
obj = nullptr;
|
||||
sub.clear();
|
||||
//throw Base::RuntimeError("Still in reference selection mode; reference wasn't selected yet");
|
||||
}
|
||||
else {
|
||||
PartDesign::ProfileBased* pcDirection = static_cast<PartDesign::ProfileBased*>(vp->getObject());
|
||||
if (!pcDirection->getDocument()->isIn(lnk.getValue()))
|
||||
throw Base::RuntimeError("Object was deleted");
|
||||
|
||||
obj = lnk.getValue();
|
||||
sub = lnk.getSubValues();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPocketParameters::saveHistory(void)
|
||||
{
|
||||
// save the user values to history
|
||||
|
||||
@@ -55,10 +55,19 @@ public:
|
||||
virtual void saveHistory() override;
|
||||
virtual void apply() override;
|
||||
|
||||
void fillDirectionCombo();
|
||||
void addAxisToCombo(App::DocumentObject* linkObj, std::string linkSubname, QString itemText);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onLengthChanged(double);
|
||||
void onLength2Changed(double);
|
||||
void onOffsetChanged(double);
|
||||
void onDirectionCBChanged(int);
|
||||
void onAlongSketchNormalChanged(bool);
|
||||
void onDirectionToggled(bool);
|
||||
void onXDirectionEditChanged(double);
|
||||
void onYDirectionEditChanged(double);
|
||||
void onZDirectionEditChanged(double);
|
||||
void onMidplaneChanged(bool);
|
||||
void onReversedChanged(bool);
|
||||
void onButtonFace(const bool pressed = true);
|
||||
@@ -67,11 +76,19 @@ private Q_SLOTS:
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e) override;
|
||||
App::PropertyLinkSub* propReferenceAxis;
|
||||
void getReferenceAxis(App::DocumentObject*& obj, std::vector<std::string>& sub) const;
|
||||
|
||||
private:
|
||||
double getLength(void) const;
|
||||
double getLength2(void) const;
|
||||
double getOffset(void) const;
|
||||
bool getAlongSketchNormal(void) const;
|
||||
bool getCustom(void) const;
|
||||
std::string getReferenceAxis(void) const;
|
||||
double getXDirection(void) const;
|
||||
double getYDirection(void) const;
|
||||
double getZDirection(void) const;
|
||||
int getMode(void) const;
|
||||
bool getMidplane(void) const;
|
||||
bool getReversed(void) const;
|
||||
@@ -79,11 +96,14 @@ private:
|
||||
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg) override;
|
||||
void updateUI(int index);
|
||||
void updateDirectionEdits(void);
|
||||
|
||||
private:
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPocketParameters> ui;
|
||||
double oldLength;
|
||||
bool selectionFace;
|
||||
std::vector<std::unique_ptr<App::PropertyLinkSub>> axesInList;
|
||||
};
|
||||
|
||||
/// simulation dialog for the TaskView
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>193</width>
|
||||
<height>272</height>
|
||||
<width>300</width>
|
||||
<height>436</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -65,6 +65,179 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Direction</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelEdge">
|
||||
<property name="text">
|
||||
<string>Direction/edge:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="directionCB">
|
||||
<property name="toolTip">
|
||||
<string>Set a direction or select an edge
|
||||
from the model as reference</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Sketch normal</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Select reference...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Custom direction</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxDirection">
|
||||
<property name="text">
|
||||
<string>Show direction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="groupBoxDirection">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Use custom vector for pad direction, otherwise
|
||||
the sketch plane's normal vector will be used</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::DoubleSpinBox" name="XDirectionEdit">
|
||||
<property name="toolTip">
|
||||
<string>x-component of direction vector</string>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelZSkew">
|
||||
<property name="text">
|
||||
<string>z</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::DoubleSpinBox" name="YDirectionEdit">
|
||||
<property name="toolTip">
|
||||
<string>y-component of direction vector</string>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelYSkew">
|
||||
<property name="text">
|
||||
<string>y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::DoubleSpinBox" name="ZDirectionEdit">
|
||||
<property name="toolTip">
|
||||
<string>z-component of direction vector</string>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelXSkew">
|
||||
<property name="text">
|
||||
<string>x</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxAlongDirection">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>If unchecked, the length will be
|
||||
measured along the specified direction</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Length along sketch normal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxMidplane">
|
||||
<property name="enabled">
|
||||
@@ -139,6 +312,11 @@
|
||||
<extends>QWidget</extends>
|
||||
<header>Gui/QuantitySpinBox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::DoubleSpinBox</class>
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
<header>Gui/SpinBox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefQuantitySpinBox</class>
|
||||
<extends>Gui::QuantitySpinBox</extends>
|
||||
|
||||
@@ -220,6 +220,20 @@ QString TaskSketchBasedParameters::getFaceReference(const QString& obj, const QS
|
||||
.arg(QString::fromLatin1(doc->getName()), o, sub);
|
||||
}
|
||||
|
||||
QString TaskSketchBasedParameters::make2DLabel(const App::DocumentObject* section,
|
||||
const std::vector<std::string>& subValues)
|
||||
{
|
||||
if(section->isDerivedFrom(Part::Part2DObject::getClassTypeId()))
|
||||
return QString::fromUtf8(section->Label.getValue());
|
||||
else {
|
||||
if(subValues.empty())
|
||||
throw Base::ValueError("No valid subelement linked in Part::Feature");
|
||||
|
||||
return QString::fromUtf8((std::string(section->getNameInDocument())
|
||||
+ ":" + subValues[0]).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TaskSketchBasedParameters::~TaskSketchBasedParameters()
|
||||
{
|
||||
Gui::Selection().rmvSelectionGate();
|
||||
|
||||
@@ -61,6 +61,10 @@ protected:
|
||||
QVariant objectNameByLabel(const QString& label, const QVariant& suggest) const;
|
||||
|
||||
QString getFaceReference(const QString& obj, const QString& sub) const;
|
||||
/// Create a label for the 2D feature: the objects name if it's already 2D,
|
||||
/// or the subelement's name if the object is a solid.
|
||||
QString make2DLabel(const App::DocumentObject* section,
|
||||
const std::vector<std::string>& subValues);
|
||||
};
|
||||
|
||||
class TaskDlgSketchBasedParameters : public PartDesignGui::TaskDlgFeatureParameters
|
||||
|
||||
@@ -235,7 +235,7 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
|
||||
|
||||
void ViewProviderAddSub::updateData(const App::Property* p) {
|
||||
|
||||
if(strcmp(p->getName(), "AddSubShape")==0)
|
||||
if(p->getName() && strcmp(p->getName(), "AddSubShape")==0)
|
||||
updateAddSubShapeIndicator();
|
||||
|
||||
PartDesignGui::ViewProvider::updateData(p);
|
||||
|
||||
@@ -44,7 +44,9 @@ public:
|
||||
|
||||
virtual bool onDelete(const std::vector<std::string> &);
|
||||
void highlightReferences(const bool on, bool auxiliary);
|
||||
|
||||
|
||||
virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; }
|
||||
|
||||
protected:
|
||||
virtual bool setEdit(int ModNum);
|
||||
virtual void unsetEdit(int ModNum);
|
||||
|
||||
@@ -52,7 +52,9 @@ public:
|
||||
|
||||
virtual bool onDelete(const std::vector<std::string> &);
|
||||
void highlightReferences(Reference mode, bool on);
|
||||
|
||||
|
||||
virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; }
|
||||
|
||||
protected:
|
||||
virtual QIcon getIcon(void) const;
|
||||
virtual bool setEdit(int ModNum);
|
||||
|
||||
48
src/Mod/PartDesign/PartDesignGlobal.h
Normal file
48
src/Mod/PartDesign/PartDesignGlobal.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2021 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef PARTDESIGN_GLOBAL_H
|
||||
#define PARTDESIGN_GLOBAL_H
|
||||
|
||||
#include <FCGlobal.h>
|
||||
|
||||
|
||||
// PartDesign
|
||||
#ifndef PartDesignExport
|
||||
#ifdef PartDesign_EXPORTS
|
||||
# define PartDesignExport FREECAD_DECL_EXPORT
|
||||
#else
|
||||
# define PartDesignExport FREECAD_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// PartDesignGui
|
||||
#ifndef PartDesignGuiExport
|
||||
#ifdef PartDesignGui_EXPORTS
|
||||
# define PartDesignGuiExport FREECAD_DECL_EXPORT
|
||||
#else
|
||||
# define PartDesignGuiExport FREECAD_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif //PARTDESIGN_GLOBAL_H
|
||||
@@ -129,7 +129,7 @@ This is done by analyzing the sketch geometries and constraints</string>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="delConstrExtr">
|
||||
<property name="toolTip">
|
||||
<string>Deletes constrains refering to external geometry</string>
|
||||
<string>Deletes constraints referring to external geometry</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete constraints to external geom.</string>
|
||||
|
||||
@@ -39,14 +39,17 @@ using namespace TechDrawGui;
|
||||
qApp->translate("Workbench", "Add Lines");
|
||||
qApp->translate("Workbench", "Add Vertices");
|
||||
qApp->translate("Workbench", "TechDraw");
|
||||
// Translations for View > Toolbars
|
||||
qApp->translate("Workbench", "TechDraw Pages");
|
||||
qApp->translate("Workbench", "TechDraw Views");
|
||||
qApp->translate("Workbench", "TechDraw Clips");
|
||||
qApp->translate("Workbench", "TechDraw Dimensions");
|
||||
qApp->translate("Workbench", "TechDraw Tool Attributes");
|
||||
qApp->translate("Workbench", "TechDraw File Access");
|
||||
qApp->translate("Workbench", "TechDraw Decoration");
|
||||
qApp->translate("Workbench", "TechDraw Annotation");
|
||||
qApp->translate("Workbench", "Views");
|
||||
qApp->translate("Workbench", "Extensions: Centerlines/Threading");
|
||||
#endif
|
||||
|
||||
TYPESYSTEM_SOURCE(TechDrawGui::Workbench, Gui::StdWorkbench)
|
||||
@@ -82,7 +85,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||
|
||||
// toolattributes
|
||||
Gui::MenuItem* toolattrib = new Gui::MenuItem;
|
||||
toolattrib->setCommand("Extensions: centerlines and threading");
|
||||
toolattrib->setCommand("Extensions: Centerlines/Threading");
|
||||
*toolattrib << "TechDraw_ExtensionCircleCenterLines";
|
||||
*toolattrib << "TechDraw_ExtensionThreadHoleSide";
|
||||
*toolattrib << "TechDraw_ExtensionThreadBoltSide";
|
||||
@@ -198,7 +201,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
// *dims << "TechDraw_Dimension"
|
||||
|
||||
Gui::ToolBarItem *attribs = new Gui::ToolBarItem(root);
|
||||
attribs->setCommand("TechDraw Toolattributes");
|
||||
attribs->setCommand("TechDraw Tool Attributes");
|
||||
*attribs << "TechDraw_ExtensionCircleCenterLines";
|
||||
*attribs << "TechDraw_ExtensionThreadHoleSide";
|
||||
*attribs << "TechDraw_ExtensionThreadBoltSide";
|
||||
@@ -280,7 +283,7 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const
|
||||
// *dims << "TechDraw_Dimension";
|
||||
|
||||
Gui::ToolBarItem *attribs = new Gui::ToolBarItem(root);
|
||||
attribs->setCommand("TechDraw Toolattributes");
|
||||
attribs->setCommand("TechDraw Tool Attributes");
|
||||
*attribs << "TechDraw_ExtensionCircleCenterLines";
|
||||
*attribs << "TechDraw_ExtensionThreadHoleSide";
|
||||
*attribs << "TechDraw_ExtensionThreadBoltSide";
|
||||
|
||||
@@ -13,6 +13,7 @@ SET(Test_SRCS
|
||||
unittestgui.py
|
||||
testmakeWireString.py
|
||||
TestPythonSyntax.py
|
||||
TreeView.py
|
||||
)
|
||||
SOURCE_GROUP("" FILES ${Test_SRCS})
|
||||
|
||||
|
||||
@@ -77,4 +77,5 @@ Gui.addWorkbench(TestWorkbench())
|
||||
FreeCAD.__unit_test__ += [ "Workbench",
|
||||
"Menu",
|
||||
"Menu.MenuDeleteCases",
|
||||
"Menu.MenuCreateCases" ]
|
||||
"Menu.MenuCreateCases",
|
||||
"TreeView"]
|
||||
|
||||
244
src/Mod/Test/TreeView.py
Normal file
244
src/Mod/Test/TreeView.py
Normal file
@@ -0,0 +1,244 @@
|
||||
|
||||
# TreeView test module
|
||||
|
||||
import os
|
||||
import time
|
||||
import tempfile
|
||||
import unittest
|
||||
import FreeCAD
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
import FreeCADGui
|
||||
|
||||
|
||||
class TreeViewTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def getTreeWidget(self):
|
||||
mainWnd = FreeCADGui.getMainWindow()
|
||||
treeDock = mainWnd.findChild(QtGui.QDockWidget, "Tree View")
|
||||
if treeDock is None:
|
||||
treeDock = mainWnd.findChild(QtGui.QDockWidget, "Combo View")
|
||||
if not treeDock is None:
|
||||
tabWidget = treeDock.findChild(QtGui.QTabWidget, "combiTab")
|
||||
if not tabWidget is None:
|
||||
tabWidget.setCurrentIndex(0)
|
||||
self.assertTrue(not treeDock is None, "No Tree View docks available")
|
||||
|
||||
treeView = treeDock.findChild(QtGui.QTreeWidget)
|
||||
self.assertTrue(not treeView is None, "No Tree View widget found")
|
||||
|
||||
return treeView
|
||||
|
||||
def waitForTreeViewSync(self):
|
||||
start = time.time()
|
||||
while time.time() < start + 0.5:
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
def selectDocItem(self, docItem):
|
||||
|
||||
treeView = self.getTreeWidget()
|
||||
|
||||
if docItem.TypeId == "App::Document":
|
||||
appNode = treeView.topLevelItem(0)
|
||||
self.assertTrue(not appNode is None, "No Application top level node")
|
||||
|
||||
docNode = next((appNode.child(i) for i in range(appNode.childCount())
|
||||
if appNode.child(i).text(0) == docItem.Label), None)
|
||||
self.assertTrue(not docNode is None, "No test Document node")
|
||||
treeView.setCurrentItem(docNode)
|
||||
else:
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection(docItem)
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
def trySwapOuterTreeViewItems(self, docItem, transposable):
|
||||
|
||||
self.selectDocItem(docItem)
|
||||
treeView = self.getTreeWidget()
|
||||
|
||||
selected = treeView.selectedItems()
|
||||
self.assertTrue(len(selected) == 1,
|
||||
"Unexpected count of selected items: " + str(len(selected)))
|
||||
selected = selected[0]
|
||||
|
||||
originalState = [ selected.child(i).text(0) for i in range(selected.childCount()) ]
|
||||
self.assertTrue(len(originalState) >= 1,
|
||||
"No children found in item " + selected.text(0))
|
||||
|
||||
targetState = originalState.copy()
|
||||
if transposable:
|
||||
targetState[0], targetState[-1] = targetState[-1], targetState[0]
|
||||
|
||||
treeView.setCurrentItem(selected.child(0))
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
# One move down attempt more to test boundary behaviour
|
||||
for i in range(len(originalState)):
|
||||
FreeCADGui.runCommand("Std_GroupMoveDown")
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
treeView.setCurrentItem(selected.child(len(originalState) - 2 if len(originalState) > 1 else 0))
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
# One move up attempt more to test boundary behaviour
|
||||
for i in range(len(originalState) - 1):
|
||||
FreeCADGui.runCommand("Std_GroupMoveUp")
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
finalState = [ selected.child(i).text(0) for i in range(selected.childCount()) ]
|
||||
self.assertTrue(targetState == finalState,
|
||||
"Unexpected final state: %s\nExpected: %s" % (finalState, targetState))
|
||||
|
||||
def getChildrenOf(self, docItem):
|
||||
|
||||
self.selectDocItem(docItem)
|
||||
treeView = self.getTreeWidget()
|
||||
|
||||
selected = treeView.selectedItems()
|
||||
self.assertTrue(len(selected) == 1,
|
||||
"Unexpected count of selected items: " + str(len(selected)))
|
||||
selected = selected[0]
|
||||
|
||||
return [ selected.child(i).text(0) for i in range(selected.childCount()) ]
|
||||
|
||||
|
||||
def testMoveTransposableItems(self):
|
||||
# Makes sense only if Gui is shown
|
||||
if not FreeCAD.GuiUp:
|
||||
return
|
||||
|
||||
FreeCAD.TestEnvironment = True
|
||||
|
||||
doc = FreeCAD.newDocument("TreeViewTest1")
|
||||
FreeCAD.setActiveDocument(doc.Name)
|
||||
|
||||
box = doc.addObject("Part::Box", "Box")
|
||||
cyl = doc.addObject("Part::Cylinder", "Cylinder")
|
||||
sph = doc.addObject("Part::Sphere", "Sphere")
|
||||
con = doc.addObject("Part::Cone", "Cone")
|
||||
doc.recompute()
|
||||
|
||||
self.trySwapOuterTreeViewItems(doc, True)
|
||||
|
||||
grp = doc.addObject("App::DocumentObjectGroup", "Group")
|
||||
grp.addObjects([ box, cyl, sph, con ])
|
||||
doc.recompute()
|
||||
|
||||
self.trySwapOuterTreeViewItems(grp, True)
|
||||
|
||||
del FreeCAD.TestEnvironment
|
||||
|
||||
|
||||
def testMoveUnmovableItems(self):
|
||||
# Makes sense only if Gui is shown
|
||||
if not FreeCAD.GuiUp:
|
||||
return
|
||||
|
||||
FreeCAD.TestEnvironment = True
|
||||
|
||||
doc = FreeCAD.newDocument("TreeViewTest2")
|
||||
FreeCAD.setActiveDocument(doc.Name)
|
||||
|
||||
sph = doc.addObject("Part::Sphere", "Sphere")
|
||||
con = doc.addObject("Part::Cone", "Cone")
|
||||
doc.recompute()
|
||||
|
||||
cut = doc.addObject("Part::Cut", "Cut")
|
||||
cut.Base = sph
|
||||
cut.Tool = con
|
||||
doc.recompute()
|
||||
|
||||
self.trySwapOuterTreeViewItems(cut, False)
|
||||
|
||||
bdy = doc.addObject("PartDesign::Body", "Body")
|
||||
box = doc.addObject("PartDesign::AdditiveBox", "Box")
|
||||
bdy.addObject(box)
|
||||
doc.recompute()
|
||||
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection(bdy)
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
treeView = self.getTreeWidget()
|
||||
treeView.selectedItems()[0].setExpanded(True)
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection(doc.Name, bdy.Name, box.Name + ".Face6")
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
cha = bdy.newObject("PartDesign::Chamfer", "Chamfer")
|
||||
cha.Base = (box, ["Face6"])
|
||||
doc.recompute()
|
||||
|
||||
cyl = doc.addObject("PartDesign::SubtractiveCylinder", "Cylinder")
|
||||
bdy.addObject(cyl)
|
||||
doc.recompute()
|
||||
|
||||
self.trySwapOuterTreeViewItems(bdy, False)
|
||||
|
||||
del FreeCAD.TestEnvironment
|
||||
|
||||
|
||||
def testItemOrderSaveAndRestore(self):
|
||||
# Makes sense only if Gui is shown
|
||||
if not FreeCAD.GuiUp:
|
||||
return
|
||||
|
||||
FreeCAD.TestEnvironment = True
|
||||
|
||||
doc = FreeCAD.newDocument("TreeViewTest3")
|
||||
FreeCAD.setActiveDocument(doc.Name)
|
||||
|
||||
grp = doc.addObject("App::DocumentObjectGroup", "Group")
|
||||
box = doc.addObject("Part::Box", "Box")
|
||||
cyl = doc.addObject("Part::Cylinder", "Cylinder")
|
||||
sph = doc.addObject("Part::Sphere", "Sphere")
|
||||
con = doc.addObject("Part::Cone", "Cone")
|
||||
doc.recompute()
|
||||
|
||||
origOrder = self.getChildrenOf(doc)
|
||||
self.assertTrue(origOrder == ["Group", "Box", "Cylinder", "Sphere", "Cone"])
|
||||
|
||||
origOrderFile = tempfile.gettempdir() + os.sep + "TreeViewTest3_1.fcstd"
|
||||
doc.saveAs(origOrderFile)
|
||||
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection(con)
|
||||
FreeCADGui.Selection.addSelection(cyl)
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
FreeCADGui.runCommand("Std_GroupMoveUp")
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection(grp)
|
||||
FreeCADGui.Selection.addSelection(box)
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
FreeCADGui.runCommand("Std_GroupMoveDown")
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
newOrder = self.getChildrenOf(doc)
|
||||
self.assertTrue(newOrder == ["Cylinder", "Cone", "Sphere", "Group", "Box"])
|
||||
|
||||
newOrderFile = tempfile.gettempdir() + os.sep + "TreeViewTest3_2.fcstd"
|
||||
doc.saveAs(newOrderFile)
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
self.waitForTreeViewSync()
|
||||
|
||||
doc = FreeCAD.open(origOrderFile)
|
||||
order = self.getChildrenOf(doc)
|
||||
self.assertTrue(order == origOrder)
|
||||
|
||||
doc = FreeCAD.open(newOrderFile)
|
||||
order = self.getChildrenOf(doc)
|
||||
self.assertTrue(order == newOrder)
|
||||
|
||||
del FreeCAD.TestEnvironment
|
||||
Reference in New Issue
Block a user