diff --git a/src/Mod/Path/Gui/Resources/Path.qrc b/src/Mod/Path/Gui/Resources/Path.qrc
index 2921825c45..a8af95e4a4 100644
--- a/src/Mod/Path/Gui/Resources/Path.qrc
+++ b/src/Mod/Path/Gui/Resources/Path.qrc
@@ -105,6 +105,7 @@
panels/PageDepthsEdit.ui
panels/PageDiametersEdit.ui
panels/PageHeightsEdit.ui
+ panels/PageOpAdaptiveEdit.ui
panels/PageOpCustomEdit.ui
panels/PageOpDeburrEdit.ui
panels/PageOpDrillingEdit.ui
diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpAdaptiveEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpAdaptiveEdit.ui
new file mode 100644
index 0000000000..dde5b650e4
--- /dev/null
+++ b/src/Mod/Path/Gui/Resources/panels/PageOpAdaptiveEdit.ui
@@ -0,0 +1,276 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 437
+ 764
+
+
+
+ Form
+
+
+ -
+
+
+
-
+
+
+ Tool Controller
+
+
+
+ -
+
+
+ -
+
+
+ Coolant
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ <html><head/><body><p>How much to lift the tool up during the rapid linking moves over cleared regions.</p><p>If linking path is not clear tool is raised to clearence height.</p></body></html>
+
+
+
+ -
+
+
+ Lift Distance
+
+
+
+ -
+
+
+ <html><head/><body><p>If >0 it limits the helix ramp diameter</p><p>otherwise the 75 percent of tool diameter is used</p></body></html>
+
+
+
+ -
+
+
+ Helix Ramp Angle
+
+
+
+ -
+
+
+ <html><head/><body><p>Angle of the helix entry cone</p></body></html>
+
+
+
+ -
+
+
+ Stock to Leave
+
+
+
+ -
+
+
+ Cut Region
+
+
+
+ -
+
+
+ <html><head/><body><p>Cut inside or outside of the selected shapes</p></body></html>
+
+
+
+ -
+
+
+ Step Over Percent
+
+
+
+ -
+
+
+ Use Outline
+
+
+
+ -
+
+
+ <html><head/><body><p>Max length of keep-tool-down linking path compared to direct distance between points.</p><p>If exceeded link will be done by raising the tool to clearence height.</p></body></html>
+
+
+
+ -
+
+
+ Helix Max Diameter
+
+
+
+ -
+
+
+ Helix Cone Angle
+
+
+
+ -
+
+
+ Keep Tool Down Ratio
+
+
+
+ -
+
+
+ <html><head/><body><p>How much material to leave (i.e. for finishing operation)</p></body></html>
+
+
+
+ -
+
+
+ Force Clearing Inside-out
+
+
+
+ -
+
+
+ Operation Type
+
+
+
+ -
+
+
+ <html><head/><body><p>Angle of the helix ramp entry</p></body></html>
+
+
+
+ -
+
+
+ Finishing Profile
+
+
+
+ -
+
+
+ <html><head/><body><p>Type of adaptive operation</p></body></html>
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ Accuracy vs Performance
+
+
+
+ -
+
+
+ <html><head/><body><p>Influences calculation performance vs stability and accuracy</p></body></html>
+
+
+ 5
+
+
+ 15
+
+
+ 10
+
+
+ 10
+
+
+ Qt::Horizontal
+
+
+ 1
+
+
+
+
+
+
+ -
+
+
+ <html><head/><body><p>Optimal value for tool stepover</p></body></html>
+
+
+ 1
+
+
+ 100
+
+
+
+
+
+
+ -
+
+
+ Stop
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpThreadMillingEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpThreadMillingEdit.ui
index 8de86b656a..cd24476351 100644
--- a/src/Mod/Path/Gui/Resources/panels/PageOpThreadMillingEdit.ui
+++ b/src/Mod/Path/Gui/Resources/panels/PageOpThreadMillingEdit.ui
@@ -30,18 +30,8 @@
-
- 1
+ -1
-
-
-
- Left Hand
-
-
- -
-
- Right Hand
-
-
-
@@ -52,23 +42,7 @@
-
-
-
-
-
- Custom
-
-
- -
-
- Metric - internal
-
-
- -
-
- SAE - internal
-
-
-
+
-
@@ -208,18 +182,7 @@
-
-
-
-
-
- Climb
-
-
- -
-
- Conventional
-
-
-
+
-
@@ -236,7 +199,7 @@
Gui::QuantitySpinBox
- QDoubleSpinBox
+ QWidget
diff --git a/src/Mod/Path/InitGui.py b/src/Mod/Path/InitGui.py
index 820133a723..32f44f5dfb 100644
--- a/src/Mod/Path/InitGui.py
+++ b/src/Mod/Path/InitGui.py
@@ -150,7 +150,7 @@ class PathWorkbench(Workbench):
projcmdlist.append("Path_Sanity")
prepcmdlist.append("Path_Shape")
extracmdlist.extend(["Path_Area", "Path_Area_Workplane"])
- specialcmdlist.append("Path_Thread_Milling")
+ specialcmdlist.append("Path_ThreadMilling")
twodopcmdlist.append("Path_Slot")
if PathPreferences.advancedOCLFeaturesEnabled():
diff --git a/src/Mod/Path/PathScripts/PathAdaptive.py b/src/Mod/Path/PathScripts/PathAdaptive.py
index 42a6a9dbee..f7241105d0 100644
--- a/src/Mod/Path/PathScripts/PathAdaptive.py
+++ b/src/Mod/Path/PathScripts/PathAdaptive.py
@@ -32,17 +32,7 @@ import time
import json
import math
import area
-
-from PySide import QtCore
-
-# lazily loaded modules
-from lazy_loader.lazy_loader import LazyLoader
-Part = LazyLoader('Part', globals(), 'Part')
-# TechDraw = LazyLoader('TechDraw', globals(), 'TechDraw')
-FeatureExtensions = LazyLoader('PathScripts.PathFeatureExtensions',
- globals(),
- 'PathScripts.PathFeatureExtensions')
-DraftGeomUtils = LazyLoader('DraftGeomUtils', globals(), 'DraftGeomUtils')
+from PySide.QtCore import QT_TRANSLATE_NOOP
if FreeCAD.GuiUp:
from pivy import coin
@@ -50,14 +40,25 @@ if FreeCAD.GuiUp:
__doc__ = "Class and implementation of the Adaptive path operation."
+# lazily loaded modules
+from lazy_loader.lazy_loader import LazyLoader
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-# PathLog.trackModule(PathLog.thisModule())
+Part = LazyLoader("Part", globals(), "Part")
+# TechDraw = LazyLoader('TechDraw', globals(), 'TechDraw')
+FeatureExtensions = LazyLoader(
+ "PathScripts.PathFeatureExtensions", globals(), "PathScripts.PathFeatureExtensions"
+)
+DraftGeomUtils = LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils")
-# Qt translation handling
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
+
+
+translate = FreeCAD.Qt.translate
def convertTo2d(pathArray):
@@ -112,11 +113,11 @@ def discretize(edge, flipDirection=False):
def CalcHelixConePoint(height, cur_z, radius, angle):
- x = ((height - cur_z) / height) * radius * math.cos(math.radians(angle)*cur_z)
- y = ((height - cur_z) / height) * radius * math.sin(math.radians(angle)*cur_z)
+ x = ((height - cur_z) / height) * radius * math.cos(math.radians(angle) * cur_z)
+ y = ((height - cur_z) / height) * radius * math.sin(math.radians(angle) * cur_z)
z = cur_z
- return {'X': x, 'Y': y, 'Z': z}
+ return {"X": x, "Y": y, "Z": z}
def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
@@ -129,7 +130,9 @@ def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
for region in adaptiveResults:
p1 = region["HelixCenterPoint"]
p2 = region["StartPoint"]
- r = math.sqrt((p1[0]-p2[0]) * (p1[0]-p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]))
+ r = math.sqrt(
+ (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])
+ )
if r > helixRadius:
helixRadius = r
@@ -139,7 +142,7 @@ def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
if stepDown < 0.1:
stepDown = 0.1
- length = 2*math.pi * helixRadius
+ length = 2 * math.pi * helixRadius
if float(obj.HelixAngle) < 1:
obj.HelixAngle = 1
@@ -162,13 +165,14 @@ def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
finish_step = stepDown
depth_params = PathUtils.depth_params(
- clearance_height=obj.ClearanceHeight.Value,
- safe_height=obj.SafeHeight.Value,
- start_depth=obj.StartDepth.Value,
- step_down=stepDown,
- z_finish_step=finish_step,
- final_depth=obj.FinalDepth.Value,
- user_depths=None)
+ clearance_height=obj.ClearanceHeight.Value,
+ safe_height=obj.SafeHeight.Value,
+ start_depth=obj.StartDepth.Value,
+ step_down=stepDown,
+ z_finish_step=finish_step,
+ final_depth=obj.FinalDepth.Value,
+ user_depths=None,
+ )
# ml: this is dangerous because it'll hide all unused variables hence forward
# however, I don't know what lx and ly signify so I'll leave them for now
@@ -182,16 +186,21 @@ def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
step = step + 1
for region in adaptiveResults:
- startAngle = math.atan2(region["StartPoint"][1] - region["HelixCenterPoint"][1], region["StartPoint"][0] - region["HelixCenterPoint"][0])
+ startAngle = math.atan2(
+ region["StartPoint"][1] - region["HelixCenterPoint"][1],
+ region["StartPoint"][0] - region["HelixCenterPoint"][0],
+ )
# lx = region["HelixCenterPoint"][0]
# ly = region["HelixCenterPoint"][1]
- passDepth = (passStartDepth - passEndDepth)
+ passDepth = passStartDepth - passEndDepth
p1 = region["HelixCenterPoint"]
p2 = region["StartPoint"]
- helixRadius = math.sqrt((p1[0]-p2[0]) * (p1[0]-p2[0]) + (p1[1]-p2[1]) * (p1[1]-p2[1]))
+ helixRadius = math.sqrt(
+ (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])
+ )
# Helix ramp
if helixRadius > 0.01:
@@ -199,43 +208,96 @@ def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
maxfi = passDepth / depthPerOneCircle * 2 * math.pi
fi = 0
- offsetFi = -maxfi + startAngle-math.pi/16
+ offsetFi = -maxfi + startAngle - math.pi / 16
- helixStart = [region["HelixCenterPoint"][0] + r * math.cos(offsetFi), region["HelixCenterPoint"][1] + r * math.sin(offsetFi)]
+ helixStart = [
+ region["HelixCenterPoint"][0] + r * math.cos(offsetFi),
+ region["HelixCenterPoint"][1] + r * math.sin(offsetFi),
+ ]
- op.commandlist.append(Path.Command("(Helix to depth: %f)" % passEndDepth))
+ op.commandlist.append(
+ Path.Command("(Helix to depth: %f)" % passEndDepth)
+ )
if obj.UseHelixArcs is False:
# rapid move to start point
- op.commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value}))
- op.commandlist.append(Path.Command("G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.ClearanceHeight.Value}))
+ op.commandlist.append(
+ Path.Command("G0", {"Z": obj.ClearanceHeight.Value})
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G0",
+ {
+ "X": helixStart[0],
+ "Y": helixStart[1],
+ "Z": obj.ClearanceHeight.Value,
+ },
+ )
+ )
# rapid move to safe height
- op.commandlist.append(Path.Command("G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.SafeHeight.Value}))
+ op.commandlist.append(
+ Path.Command(
+ "G0",
+ {
+ "X": helixStart[0],
+ "Y": helixStart[1],
+ "Z": obj.SafeHeight.Value,
+ },
+ )
+ )
# move to start depth
- op.commandlist.append(Path.Command("G1", {"X": helixStart[0], "Y": helixStart[1], "Z": passStartDepth, "F": op.vertFeed}))
+ op.commandlist.append(
+ Path.Command(
+ "G1",
+ {
+ "X": helixStart[0],
+ "Y": helixStart[1],
+ "Z": passStartDepth,
+ "F": op.vertFeed,
+ },
+ )
+ )
if obj.HelixConeAngle == 0:
while fi < maxfi:
- x = region["HelixCenterPoint"][0] + r * math.cos(fi+offsetFi)
- y = region["HelixCenterPoint"][1] + r * math.sin(fi+offsetFi)
- z = passStartDepth - fi / maxfi * (passStartDepth - passEndDepth)
- op.commandlist.append(Path.Command("G1", {"X": x, "Y": y, "Z": z, "F": op.vertFeed}))
+ x = region["HelixCenterPoint"][0] + r * math.cos(
+ fi + offsetFi
+ )
+ y = region["HelixCenterPoint"][1] + r * math.sin(
+ fi + offsetFi
+ )
+ z = passStartDepth - fi / maxfi * (
+ passStartDepth - passEndDepth
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G1", {"X": x, "Y": y, "Z": z, "F": op.vertFeed}
+ )
+ )
# lx = x
# ly = y
fi = fi + math.pi / 16
# one more circle at target depth to make sure center is cleared
- maxfi = maxfi + 2*math.pi
+ maxfi = maxfi + 2 * math.pi
while fi < maxfi:
- x = region["HelixCenterPoint"][0] + r * math.cos(fi+offsetFi)
- y = region["HelixCenterPoint"][1] + r * math.sin(fi+offsetFi)
+ x = region["HelixCenterPoint"][0] + r * math.cos(
+ fi + offsetFi
+ )
+ y = region["HelixCenterPoint"][1] + r * math.sin(
+ fi + offsetFi
+ )
z = passEndDepth
- op.commandlist.append(Path.Command("G1", {"X": x, "Y": y, "Z": z, "F": op.horizFeed}))
+ op.commandlist.append(
+ Path.Command(
+ "G1", {"X": x, "Y": y, "Z": z, "F": op.horizFeed}
+ )
+ )
# lx = x
# ly = y
- fi = fi + math.pi/16
+ fi = fi + math.pi / 16
else:
# Cone
@@ -248,9 +310,14 @@ def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
# Calculate everything
helix_height = passStartDepth - passEndDepth
- r_extra = helix_height * math.tan(math.radians(obj.HelixConeAngle))
+ r_extra = helix_height * math.tan(
+ math.radians(obj.HelixConeAngle)
+ )
HelixTopRadius = helixRadius + r_extra
- helix_full_height = HelixTopRadius * (math.cos(math.radians(obj.HelixConeAngle)) / math.sin(math.radians(obj.HelixConeAngle)))
+ helix_full_height = HelixTopRadius * (
+ math.cos(math.radians(obj.HelixConeAngle))
+ / math.sin(math.radians(obj.HelixConeAngle))
+ )
# Start height
z = passStartDepth
@@ -267,70 +334,250 @@ def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
p = None
# Calculate conical helix
- while(z >= passEndDepth):
+ while z >= passEndDepth:
if z < passEndDepth:
z = passEndDepth
- p = CalcHelixConePoint(helix_full_height, i, HelixTopRadius, _HelixAngle)
- op.commandlist.append(Path.Command("G1", {"X": p['X'] + region["HelixCenterPoint"][0], "Y": p['Y'] + region["HelixCenterPoint"][1], "Z": z, "F": op.vertFeed}))
+ p = CalcHelixConePoint(
+ helix_full_height, i, HelixTopRadius, _HelixAngle
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G1",
+ {
+ "X": p["X"] + region["HelixCenterPoint"][0],
+ "Y": p["Y"] + region["HelixCenterPoint"][1],
+ "Z": z,
+ "F": op.vertFeed,
+ },
+ )
+ )
z = z - z_step
i = i + z_step
# Calculate some stuff for arcs at bottom
- p['X'] = p['X'] + region["HelixCenterPoint"][0]
- p['Y'] = p['Y'] + region["HelixCenterPoint"][1]
- x_m = region["HelixCenterPoint"][0] - p['X'] + region["HelixCenterPoint"][0]
- y_m = region["HelixCenterPoint"][1] - p['Y'] + region["HelixCenterPoint"][1]
- i_off = (x_m - p['X']) / 2
- j_off = (y_m - p['Y']) / 2
+ p["X"] = p["X"] + region["HelixCenterPoint"][0]
+ p["Y"] = p["Y"] + region["HelixCenterPoint"][1]
+ x_m = (
+ region["HelixCenterPoint"][0]
+ - p["X"]
+ + region["HelixCenterPoint"][0]
+ )
+ y_m = (
+ region["HelixCenterPoint"][1]
+ - p["Y"]
+ + region["HelixCenterPoint"][1]
+ )
+ i_off = (x_m - p["X"]) / 2
+ j_off = (y_m - p["Y"]) / 2
# One more circle at target depth to make sure center is cleared
- op.commandlist.append(Path.Command("G3", {"X": x_m, "Y": y_m, "Z": passEndDepth, "I": i_off, "J": j_off, "F": op.horizFeed}))
- op.commandlist.append(Path.Command("G3", {"X": p['X'], "Y": p['Y'], "Z": passEndDepth, "I": -i_off, "J": -j_off, "F": op.horizFeed}))
+ op.commandlist.append(
+ Path.Command(
+ "G3",
+ {
+ "X": x_m,
+ "Y": y_m,
+ "Z": passEndDepth,
+ "I": i_off,
+ "J": j_off,
+ "F": op.horizFeed,
+ },
+ )
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G3",
+ {
+ "X": p["X"],
+ "Y": p["Y"],
+ "Z": passEndDepth,
+ "I": -i_off,
+ "J": -j_off,
+ "F": op.horizFeed,
+ },
+ )
+ )
else:
# Use arcs for helix - no conical shape support
- helixStart = [region["HelixCenterPoint"][0] + r, region["HelixCenterPoint"][1]]
+ helixStart = [
+ region["HelixCenterPoint"][0] + r,
+ region["HelixCenterPoint"][1],
+ ]
# rapid move to start point
- op.commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value}))
- op.commandlist.append(Path.Command("G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.ClearanceHeight.Value}))
+ op.commandlist.append(
+ Path.Command("G0", {"Z": obj.ClearanceHeight.Value})
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G0",
+ {
+ "X": helixStart[0],
+ "Y": helixStart[1],
+ "Z": obj.ClearanceHeight.Value,
+ },
+ )
+ )
# rapid move to safe height
- op.commandlist.append(Path.Command("G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.SafeHeight.Value}))
+ op.commandlist.append(
+ Path.Command(
+ "G0",
+ {
+ "X": helixStart[0],
+ "Y": helixStart[1],
+ "Z": obj.SafeHeight.Value,
+ },
+ )
+ )
# move to start depth
- op.commandlist.append(Path.Command("G1", {"X": helixStart[0], "Y": helixStart[1], "Z": passStartDepth, "F": op.vertFeed}))
+ op.commandlist.append(
+ Path.Command(
+ "G1",
+ {
+ "X": helixStart[0],
+ "Y": helixStart[1],
+ "Z": passStartDepth,
+ "F": op.vertFeed,
+ },
+ )
+ )
x = region["HelixCenterPoint"][0] + r
y = region["HelixCenterPoint"][1]
curDep = passStartDepth
while curDep > (passEndDepth + depthPerOneCircle):
- op.commandlist.append(Path.Command("G2", {"X": x - (2*r), "Y": y, "Z": curDep - (depthPerOneCircle/2), "I": -r, "F": op.vertFeed}))
- op.commandlist.append(Path.Command("G2", {"X": x, "Y": y, "Z": curDep - depthPerOneCircle, "I": r, "F": op.vertFeed}))
+ op.commandlist.append(
+ Path.Command(
+ "G2",
+ {
+ "X": x - (2 * r),
+ "Y": y,
+ "Z": curDep - (depthPerOneCircle / 2),
+ "I": -r,
+ "F": op.vertFeed,
+ },
+ )
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G2",
+ {
+ "X": x,
+ "Y": y,
+ "Z": curDep - depthPerOneCircle,
+ "I": r,
+ "F": op.vertFeed,
+ },
+ )
+ )
curDep = curDep - depthPerOneCircle
lastStep = curDep - passEndDepth
- if lastStep > (depthPerOneCircle/2):
- op.commandlist.append(Path.Command("G2", {"X": x - (2*r), "Y": y, "Z": curDep - (lastStep/2), "I": -r, "F": op.vertFeed}))
- op.commandlist.append(Path.Command("G2", {"X": x, "Y": y, "Z": passEndDepth, "I": r, "F": op.vertFeed}))
+ if lastStep > (depthPerOneCircle / 2):
+ op.commandlist.append(
+ Path.Command(
+ "G2",
+ {
+ "X": x - (2 * r),
+ "Y": y,
+ "Z": curDep - (lastStep / 2),
+ "I": -r,
+ "F": op.vertFeed,
+ },
+ )
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G2",
+ {
+ "X": x,
+ "Y": y,
+ "Z": passEndDepth,
+ "I": r,
+ "F": op.vertFeed,
+ },
+ )
+ )
else:
- op.commandlist.append(Path.Command("G2", {"X": x - (2*r), "Y": y, "Z": passEndDepth, "I": -r, "F": op.vertFeed}))
- op.commandlist.append(Path.Command("G1", {"X": x, "Y": y, "Z": passEndDepth, "F": op.vertFeed}))
+ op.commandlist.append(
+ Path.Command(
+ "G2",
+ {
+ "X": x - (2 * r),
+ "Y": y,
+ "Z": passEndDepth,
+ "I": -r,
+ "F": op.vertFeed,
+ },
+ )
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G1",
+ {"X": x, "Y": y, "Z": passEndDepth, "F": op.vertFeed},
+ )
+ )
# one more circle at target depth to make sure center is cleared
- op.commandlist.append(Path.Command("G2", {"X": x - (2*r), "Y": y, "Z": passEndDepth, "I": -r, "F": op.horizFeed}))
- op.commandlist.append(Path.Command("G2", {"X": x, "Y": y, "Z": passEndDepth, "I": r, "F": op.horizFeed}))
+ op.commandlist.append(
+ Path.Command(
+ "G2",
+ {
+ "X": x - (2 * r),
+ "Y": y,
+ "Z": passEndDepth,
+ "I": -r,
+ "F": op.horizFeed,
+ },
+ )
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G2",
+ {
+ "X": x,
+ "Y": y,
+ "Z": passEndDepth,
+ "I": r,
+ "F": op.horizFeed,
+ },
+ )
+ )
# lx = x
# ly = y
else: # no helix entry
# rapid move to clearance height
- op.commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value}))
- op.commandlist.append(Path.Command("G0", {"X": region["StartPoint"][0], "Y": region["StartPoint"][1], "Z": obj.ClearanceHeight.Value}))
+ op.commandlist.append(
+ Path.Command("G0", {"Z": obj.ClearanceHeight.Value})
+ )
+ op.commandlist.append(
+ Path.Command(
+ "G0",
+ {
+ "X": region["StartPoint"][0],
+ "Y": region["StartPoint"][1],
+ "Z": obj.ClearanceHeight.Value,
+ },
+ )
+ )
# straight plunge to target depth
- op.commandlist.append(Path.Command("G1", {"X": region["StartPoint"][0], "Y": region["StartPoint"][1], "Z": passEndDepth, "F": op.vertFeed}))
+ op.commandlist.append(
+ Path.Command(
+ "G1",
+ {
+ "X": region["StartPoint"][0],
+ "Y": region["StartPoint"][1],
+ "Z": passEndDepth,
+ "F": op.vertFeed,
+ },
+ )
+ )
lz = passEndDepth
z = obj.ClearanceHeight.Value
@@ -349,9 +596,13 @@ def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
if motionType == area.AdaptiveMotionType.Cutting:
z = passEndDepth
if z != lz:
- op.commandlist.append(Path.Command("G1", {"Z": z, "F": op.vertFeed}))
+ op.commandlist.append(
+ Path.Command("G1", {"Z": z, "F": op.vertFeed})
+ )
- op.commandlist.append(Path.Command("G1", {"X": x, "Y": y, "F": op.horizFeed}))
+ op.commandlist.append(
+ Path.Command("G1", {"X": x, "Y": y, "F": op.horizFeed})
+ )
elif motionType == area.AdaptiveMotionType.LinkClear:
z = passEndDepth + stepUp
@@ -411,7 +662,7 @@ def Execute(op, obj):
obj.Path = Path.Path("(Calculating...)")
if FreeCAD.GuiUp:
- #store old visibility state
+ # store old visibility state
job = op.getJob(obj)
oldObjVisibility = obj.ViewObject.Visibility
oldJobVisibility = job.ViewObject.Visibility
@@ -469,7 +720,7 @@ def Execute(op, obj):
opType = area.AdaptiveOperationType.ProfilingInside
keepToolDownRatio = 3.0
- if hasattr(obj, 'KeepToolDownRatio'):
+ if hasattr(obj, "KeepToolDownRatio"):
keepToolDownRatio = float(obj.KeepToolDownRatio)
# put here all properties that influence calculation of adaptive base paths,
@@ -486,7 +737,7 @@ def Execute(op, obj):
"forceInsideOut": obj.ForceInsideOut,
"finishingProfile": obj.FinishingProfile,
"keepToolDownRatio": keepToolDownRatio,
- "stockToLeave": float(obj.StockToLeave)
+ "stockToLeave": float(obj.StockToLeave),
}
inputStateChanged = False
@@ -502,12 +753,16 @@ def Execute(op, obj):
# progress callback fn, if return true it will stop processing
def progressFn(tpaths):
if FreeCAD.GuiUp:
- for path in tpaths: #path[0] contains the MotionType, #path[1] contains list of points
+ for (
+ path
+ ) in (
+ tpaths
+ ): # path[0] contains the MotionType, #path[1] contains list of points
if path[0] == area.AdaptiveMotionType.Cutting:
- sceneDrawPath(path[1],(0,0,1))
+ sceneDrawPath(path[1], (0, 0, 1))
else:
- sceneDrawPath(path[1],(1,0,1))
+ sceneDrawPath(path[1], (1, 0, 1))
FreeCADGui.updateGui()
@@ -533,22 +788,27 @@ def Execute(op, obj):
# need to convert results to python object to be JSON serializable
adaptiveResults = []
for result in results:
- adaptiveResults.append({
- "HelixCenterPoint": result.HelixCenterPoint,
- "StartPoint": result.StartPoint,
- "AdaptivePaths": result.AdaptivePaths,
- "ReturnMotionType": result.ReturnMotionType})
+ adaptiveResults.append(
+ {
+ "HelixCenterPoint": result.HelixCenterPoint,
+ "StartPoint": result.StartPoint,
+ "AdaptivePaths": result.AdaptivePaths,
+ "ReturnMotionType": result.ReturnMotionType,
+ }
+ )
# GENERATE
GenerateGCode(op, obj, adaptiveResults, helixDiameter)
if not obj.StopProcessing:
- PathLog.info("*** Done. Elapsed time: %f sec\n\n" % (time.time()-start))
+ PathLog.info("*** Done. Elapsed time: %f sec\n\n" % (time.time() - start))
obj.AdaptiveOutputState = adaptiveResults
obj.AdaptiveInputState = inputStateObject
else:
- PathLog.info("*** Processing cancelled (after: %f sec).\n\n" % (time.time()-start))
+ PathLog.info(
+ "*** Processing cancelled (after: %f sec).\n\n" % (time.time() - start)
+ )
finally:
if FreeCAD.GuiUp:
@@ -558,12 +818,12 @@ def Execute(op, obj):
def _get_working_edges(op, obj):
- '''_get_working_edges(op, obj)...
+ """_get_working_edges(op, obj)...
Compile all working edges from the Base Geometry selection (obj.Base)
for the current operation.
Additional modifications to selected region(face), such as extensions,
should be placed within this function.
- '''
+ """
all_regions = list()
edge_list = list()
avoidFeatures = list()
@@ -603,7 +863,7 @@ def _get_working_edges(op, obj):
edge_list.append([discretize(e)])
# Apply regular Extensions
- op.exts = [] # pylint: disable=attribute-defined-outside-init
+ op.exts = [] # pylint: disable=attribute-defined-outside-init
for ext in extensions:
if not ext.avoid:
wire = ext.getWire()
@@ -626,55 +886,250 @@ def _get_working_edges(op, obj):
class PathAdaptive(PathOp.ObjectOp):
def opFeatures(self, obj):
- '''opFeatures(obj) ... returns the OR'ed list of features used and supported by the operation.
+ """opFeatures(obj) ... returns the OR'ed list of features used and supported by the operation.
The default implementation returns "FeatureTool | FeatureDepths | FeatureHeights | FeatureStartPoint"
- Should be overwritten by subclasses.'''
- return PathOp.FeatureTool | PathOp.FeatureBaseEdges | PathOp.FeatureDepths \
- | PathOp.FeatureFinishDepth | PathOp.FeatureStepDown | PathOp.FeatureHeights \
- | PathOp.FeatureBaseGeometry | PathOp.FeatureCoolant | PathOp.FeatureLocations
+ Should be overwritten by subclasses."""
+ return (
+ PathOp.FeatureTool
+ | PathOp.FeatureBaseEdges
+ | PathOp.FeatureDepths
+ | PathOp.FeatureFinishDepth
+ | PathOp.FeatureStepDown
+ | PathOp.FeatureHeights
+ | PathOp.FeatureBaseGeometry
+ | PathOp.FeatureCoolant
+ | PathOp.FeatureLocations
+ )
+
+ @classmethod
+ def propertyEnumerations(self, dataType="data"):
+ """helixOpPropertyEnumerations(dataType="data")... return property enumeration lists of specified dataType.
+ Args:
+ dataType = 'data', 'raw', 'translated'
+ Notes:
+ 'data' is list of internal string literals used in code
+ 'raw' is list of (translated_text, data_string) tuples
+ 'translated' is list of translated string literals
+ """
+
+ # Enumeration lists for App::PropertyEnumeration properties
+ enums = {
+ "Side": [
+ (translate("Path_Adaptive", "Outside"), "Outside"),
+ (translate("Path_Adaptive", "Inside"), "Inside"),
+ ], # this is the direction that the profile runs
+ "OperationType": [
+ (translate("Path_Adaptive", "Clearing"), "Clearing"),
+ (translate("Path_Adaptive", "Profiling"), "Profiling"),
+ ], # side of profile that cutter is on in relation to direction of profile
+ }
+
+ if dataType == "raw":
+ return enums
+
+ data = list()
+ idx = 0 if dataType == "translated" else 1
+
+ PathLog.debug(enums)
+
+ for k, v in enumerate(enums):
+ data.append((v, [tup[idx] for tup in enums[v]]))
+ PathLog.debug(data)
+
+ return data
def initOperation(self, obj):
- '''initOperation(obj) ... implement to create additional properties.
- Should be overwritten by subclasses.'''
- obj.addProperty("App::PropertyEnumeration", "Side", "Adaptive", "Side of selected faces that tool should cut")
- obj.Side = ['Outside', 'Inside'] # side of profile that cutter is on in relation to direction of profile
+ """initOperation(obj) ... implement to create additional properties.
+ Should be overwritten by subclasses."""
+ obj.addProperty(
+ "App::PropertyEnumeration",
+ "Side",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Side of selected faces that tool should cut",
+ ),
+ )
+ # obj.Side = [
+ # "Outside",
+ # "Inside",
+ # ] # side of profile that cutter is on in relation to direction of profile
- obj.addProperty("App::PropertyEnumeration", "OperationType", "Adaptive", "Type of adaptive operation")
- obj.OperationType = ['Clearing', 'Profiling'] # side of profile that cutter is on in relation to direction of profile
+ obj.addProperty(
+ "App::PropertyEnumeration",
+ "OperationType",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Type of adaptive operation",
+ ),
+ )
+ # obj.OperationType = [
+ # "Clearing",
+ # "Profiling",
+ # ] # side of profile that cutter is on in relation to direction of profile
- obj.addProperty("App::PropertyFloat", "Tolerance", "Adaptive", "Influences accuracy and performance")
- obj.addProperty("App::PropertyPercent", "StepOver", "Adaptive", "Percent of cutter diameter to step over on each pass")
- obj.addProperty("App::PropertyDistance", "LiftDistance", "Adaptive", "Lift distance for rapid moves")
- obj.addProperty("App::PropertyDistance", "KeepToolDownRatio", "Adaptive", "Max length of keep tool down path compared to direct distance between points")
- obj.addProperty("App::PropertyDistance", "StockToLeave", "Adaptive", "How much stock to leave (i.e. for finishing operation)")
- # obj.addProperty("App::PropertyBool", "ProcessHoles", "Adaptive","Process holes as well as the face outline")
+ obj.addProperty(
+ "App::PropertyFloat",
+ "Tolerance",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Influences accuracy and performance",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyPercent",
+ "StepOver",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Percent of cutter diameter to step over on each pass",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyDistance",
+ "LiftDistance",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Lift distance for rapid moves",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyDistance",
+ "KeepToolDownRatio",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Max length of keep tool down path compared to direct distance between points",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyDistance",
+ "StockToLeave",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "How much stock to leave (i.e. for finishing operation)",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "ForceInsideOut",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Force plunging into material inside and clearing towards the edges",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "FinishingProfile",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "To take a finishing profile path at the end",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "Stopped",
+ "Adaptive",
+ QT_TRANSLATE_NOOP("App::Property", "Stop processing"),
+ )
+ obj.setEditorMode("Stopped", 2) # hide this property
- obj.addProperty("App::PropertyBool", "ForceInsideOut", "Adaptive", "Force plunging into material inside and clearing towards the edges")
- obj.addProperty("App::PropertyBool", "FinishingProfile", "Adaptive", "To take a finishing profile path at the end")
- obj.addProperty("App::PropertyBool", "Stopped",
- "Adaptive", "Stop processing")
- obj.setEditorMode('Stopped', 2) # hide this property
+ obj.addProperty(
+ "App::PropertyBool",
+ "StopProcessing",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Stop processing",
+ ),
+ )
+ obj.setEditorMode("StopProcessing", 2) # hide this property
- obj.addProperty("App::PropertyBool", "StopProcessing",
- "Adaptive", "Stop processing")
- obj.setEditorMode('StopProcessing', 2) # hide this property
+ obj.addProperty(
+ "App::PropertyBool",
+ "UseHelixArcs",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Use Arcs (G2) for helix ramp",
+ ),
+ )
- obj.addProperty("App::PropertyBool", "UseHelixArcs", "Adaptive", "Use Arcs (G2) for helix ramp")
+ obj.addProperty(
+ "App::PropertyPythonObject",
+ "AdaptiveInputState",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Internal input state",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyPythonObject",
+ "AdaptiveOutputState",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Internal output state",
+ ),
+ )
+ obj.setEditorMode("AdaptiveInputState", 2) # hide this property
+ obj.setEditorMode("AdaptiveOutputState", 2) # hide this property
+ obj.addProperty(
+ "App::PropertyAngle",
+ "HelixAngle",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Helix ramp entry angle (degrees)",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyAngle",
+ "HelixConeAngle",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Helix cone angle (degrees)",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "HelixDiameterLimit",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Limit helix entry diameter, if limit larger than tool diameter or 0, tool diameter is used",
+ ),
+ )
- obj.addProperty("App::PropertyPythonObject", "AdaptiveInputState",
- "Adaptive", "Internal input state")
- obj.addProperty("App::PropertyPythonObject", "AdaptiveOutputState",
- "Adaptive", "Internal output state")
- obj.setEditorMode('AdaptiveInputState', 2) # hide this property
- obj.setEditorMode('AdaptiveOutputState', 2) # hide this property
- obj.addProperty("App::PropertyAngle", "HelixAngle", "Adaptive", "Helix ramp entry angle (degrees)")
- obj.addProperty("App::PropertyAngle", "HelixConeAngle", "Adaptive", "Helix cone angle (degrees)")
- obj.addProperty("App::PropertyLength", "HelixDiameterLimit", "Adaptive", "Limit helix entry diameter, if limit larger than tool diameter or 0, tool diameter is used")
+ obj.addProperty(
+ "App::PropertyBool",
+ "UseOutline",
+ "Adaptive",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Uses the outline of the base geometry.",
+ ),
+ )
- obj.addProperty("App::PropertyBool", "UseOutline", "Adaptive", "Uses the outline of the base geometry.")
+ obj.addProperty(
+ "Part::PropertyPartShape",
+ "removalshape",
+ "Path",
+ QT_TRANSLATE_NOOP("App::Property", ""),
+ )
- obj.addProperty("Part::PropertyPartShape", "removalshape", "Path", "")
- obj.setEditorMode('removalshape', 2) # hide
+ for n in self.propertyEnumerations():
+ setattr(obj, n[0], n[1])
+
+ obj.setEditorMode("removalshape", 2) # hide
FeatureExtensions.initialize_properties(obj)
@@ -701,43 +1156,66 @@ class PathAdaptive(PathOp.ObjectOp):
FeatureExtensions.set_default_property_values(obj, job)
def opExecute(self, obj):
- '''opExecute(obj) ... called whenever the receiver needs to be recalculated.
+ """opExecute(obj) ... called whenever the receiver needs to be recalculated.
See documentation of execute() for a list of base functionality provided.
- Should be overwritten by subclasses.'''
+ Should be overwritten by subclasses."""
self.pathArray = _get_working_edges(self, obj)
Execute(self, obj)
def opOnDocumentRestored(self, obj):
- if not hasattr(obj, 'HelixConeAngle'):
- obj.addProperty("App::PropertyAngle", "HelixConeAngle", "Adaptive", "Helix cone angle (degrees)")
+ if not hasattr(obj, "HelixConeAngle"):
+ obj.addProperty(
+ "App::PropertyAngle",
+ "HelixConeAngle",
+ "Adaptive",
+ "Helix cone angle (degrees)",
+ )
if not hasattr(obj, "UseOutline"):
- obj.addProperty("App::PropertyBool",
- "UseOutline",
- "Adaptive",
- "Uses the outline of the base geometry.")
+ obj.addProperty(
+ "App::PropertyBool",
+ "UseOutline",
+ "Adaptive",
+ "Uses the outline of the base geometry.",
+ )
if not hasattr(obj, "removalshape"):
obj.addProperty("Part::PropertyPartShape", "removalshape", "Path", "")
- obj.setEditorMode('removalshape', 2) # hide
+ obj.setEditorMode("removalshape", 2) # hide
FeatureExtensions.initialize_properties(obj)
+
+
# Eclass
def SetupProperties():
- setup = ["Side", "OperationType", "Tolerance", "StepOver",
- "LiftDistance", "KeepToolDownRatio", "StockToLeave",
- "ForceInsideOut", "FinishingProfile", "Stopped",
- "StopProcessing", "UseHelixArcs", "AdaptiveInputState",
- "AdaptiveOutputState", "HelixAngle", "HelixConeAngle",
- "HelixDiameterLimit", "UseOutline"]
+ setup = [
+ "Side",
+ "OperationType",
+ "Tolerance",
+ "StepOver",
+ "LiftDistance",
+ "KeepToolDownRatio",
+ "StockToLeave",
+ "ForceInsideOut",
+ "FinishingProfile",
+ "Stopped",
+ "StopProcessing",
+ "UseHelixArcs",
+ "AdaptiveInputState",
+ "AdaptiveOutputState",
+ "HelixAngle",
+ "HelixConeAngle",
+ "HelixDiameterLimit",
+ "UseOutline",
+ ]
return setup
def Create(name, obj=None, parentJob=None):
- '''Create(name) ... Creates and returns a Adaptive operation.'''
+ """Create(name) ... Creates and returns a Adaptive operation."""
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = PathAdaptive(obj, name, parentJob)
diff --git a/src/Mod/Path/PathScripts/PathAdaptiveGui.py b/src/Mod/Path/PathScripts/PathAdaptiveGui.py
index daa2335926..113fc1d91d 100644
--- a/src/Mod/Path/PathScripts/PathAdaptiveGui.py
+++ b/src/Mod/Path/PathScripts/PathAdaptiveGui.py
@@ -22,142 +22,41 @@
# ***************************************************************************
import PathScripts.PathOpGui as PathOpGui
-from PySide import QtCore, QtGui
+from PySide import QtCore
import PathScripts.PathAdaptive as PathAdaptive
import PathScripts.PathFeatureExtensionsGui as PathFeatureExtensionsGui
+import FreeCADGui
class TaskPanelOpPage(PathOpGui.TaskPanelPage):
- def initPage(self, obj):
- self.setTitle("Adaptive path operation")
-
def getForm(self):
- form = QtGui.QWidget()
- layout = QtGui.QVBoxLayout()
- formLayout = QtGui.QFormLayout()
+ """getForm() ... return UI"""
- # tool controller
- form.ToolController = QtGui.QComboBox()
- formLayout.addRow(QtGui.QLabel("Tool Controller"), form.ToolController)
+ form = FreeCADGui.PySideUic.loadUi(":/panels/PageOpAdaptiveEdit.ui")
+ comboToPropertyMap = [("Side", "Side"), ("OperationType", "OperationType")]
- # Coolant controller
- form.coolantController = QtGui.QComboBox()
- formLayout.addRow(QtGui.QLabel("Coolant Mode"), form.coolantController)
+ enumTups = PathAdaptive.PathAdaptive.propertyEnumerations(dataType="raw")
- # cut region
- form.Side = QtGui.QComboBox()
- form.Side.addItem("Inside")
- form.Side.addItem("Outside")
- form.Side.setToolTip("Cut inside or outside of the selected shapes")
- formLayout.addRow(QtGui.QLabel("Cut Region"), form.Side)
-
- # operation type
- form.OperationType = QtGui.QComboBox()
- form.OperationType.addItem("Clearing")
- form.OperationType.addItem("Profiling")
- form.OperationType.setToolTip("Type of adaptive operation")
- formLayout.addRow(QtGui.QLabel("Operation Type"), form.OperationType)
-
- # step over
- form.StepOver = QtGui.QSpinBox()
- form.StepOver.setMinimum(15)
- form.StepOver.setMaximum(75)
- form.StepOver.setSingleStep(1)
- form.StepOver.setValue(25)
- form.StepOver.setToolTip("Optimal value for tool stepover")
- formLayout.addRow(QtGui.QLabel("Step Over Percent"), form.StepOver)
-
- # tolerance
- form.Tolerance = QtGui.QSlider(QtCore.Qt.Horizontal)
- form.Tolerance.setMinimum(5)
- form.Tolerance.setMaximum(15)
- form.Tolerance.setTickInterval(1)
- form.Tolerance.setValue(10)
- form.Tolerance.setTickPosition(QtGui.QSlider.TicksBelow)
- form.Tolerance.setToolTip("Influences calculation performance vs stability and accuracy.")
- formLayout.addRow(QtGui.QLabel("Accuracy vs Performance"), form.Tolerance)
-
- # helix angle
- form.HelixAngle = QtGui.QDoubleSpinBox()
- form.HelixAngle.setMinimum(1)
- form.HelixAngle.setMaximum(89)
- form.HelixAngle.setSingleStep(1)
- form.HelixAngle.setValue(5)
- form.HelixAngle.setToolTip("Angle of the helix ramp entry")
- formLayout.addRow(QtGui.QLabel("Helix Ramp Angle"), form.HelixAngle)
-
- # helix cone angle
- form.HelixConeAngle = QtGui.QDoubleSpinBox()
- form.HelixConeAngle.setMinimum(0)
- form.HelixConeAngle.setMaximum(6)
- form.HelixConeAngle.setSingleStep(1)
- form.HelixConeAngle.setValue(0)
- form.HelixConeAngle.setToolTip("Angle of the helix entry cone")
- formLayout.addRow(QtGui.QLabel("Helix Cone Angle"), form.HelixConeAngle)
-
- # helix diam. limit
- form.HelixDiameterLimit = QtGui.QDoubleSpinBox()
- form.HelixDiameterLimit.setMinimum(0.0)
- form.HelixDiameterLimit.setMaximum(90)
- form.HelixDiameterLimit.setSingleStep(0.1)
- form.HelixDiameterLimit.setValue(0)
- form.HelixDiameterLimit.setToolTip("If >0 it limits the helix ramp diameter\notherwise the 75 percent of tool diameter is used as helix diameter")
- formLayout.addRow(QtGui.QLabel("Helix Max Diameter"), form.HelixDiameterLimit)
-
- # lift distance
- form.LiftDistance = QtGui.QDoubleSpinBox()
- form.LiftDistance.setMinimum(0.0)
- form.LiftDistance.setMaximum(1000)
- form.LiftDistance.setSingleStep(0.1)
- form.LiftDistance.setValue(1.0)
- form.LiftDistance.setToolTip("How much to lift the tool up during the rapid linking moves over cleared regions.\nIf linking path is not clear tool is raised to clearence height.")
- formLayout.addRow(QtGui.QLabel("Lift Distance"), form.LiftDistance)
-
- # KeepToolDownRatio
- form.KeepToolDownRatio = QtGui.QDoubleSpinBox()
- form.KeepToolDownRatio.setMinimum(1.0)
- form.KeepToolDownRatio.setMaximum(10)
- form.KeepToolDownRatio.setSingleStep(1)
- form.KeepToolDownRatio.setValue(3.0)
- form.KeepToolDownRatio.setToolTip("Max length of keep-tool-down linking path compared to direct distance between points.\nIf exceeded link will be done by raising the tool to clearence height.")
- formLayout.addRow(QtGui.QLabel("Keep Tool Down Ratio"), form.KeepToolDownRatio)
-
- # stock to leave
- form.StockToLeave = QtGui.QDoubleSpinBox()
- form.StockToLeave.setMinimum(0.0)
- form.StockToLeave.setMaximum(1000)
- form.StockToLeave.setSingleStep(0.1)
- form.StockToLeave.setValue(0)
- form.StockToLeave.setToolTip("How much material to leave (i.e. for finishing operation)")
- formLayout.addRow(QtGui.QLabel("Stock to Leave"), form.StockToLeave)
-
- # Force inside out
- form.ForceInsideOut = QtGui.QCheckBox()
- form.ForceInsideOut.setChecked(True)
- formLayout.addRow(QtGui.QLabel("Force Clearing Inside-Out"), form.ForceInsideOut)
-
- # Finishing profile
- form.FinishingProfile = QtGui.QCheckBox()
- form.FinishingProfile.setChecked(True)
- formLayout.addRow(QtGui.QLabel("Finishing Profile"), form.FinishingProfile)
-
- # Use outline checkbox
- form.useOutline = QtGui.QCheckBox()
- form.useOutline.setChecked(False)
- formLayout.addRow(QtGui.QLabel("Use outline"), form.useOutline)
-
- layout.addLayout(formLayout)
-
- # stop button
- form.StopButton = QtGui.QPushButton("Stop")
- form.StopButton.setCheckable(True)
- layout.addWidget(form.StopButton)
-
- form.setLayout(layout)
+ self.populateCombobox(form, enumTups, comboToPropertyMap)
return form
+ def populateCombobox(self, form, enumTups, comboBoxesPropertyMap):
+ """fillComboboxes(form, comboBoxesPropertyMap) ... populate comboboxes with translated enumerations
+ ** comboBoxesPropertyMap will be unnecessary if UI files use strict combobox naming protocol.
+ Args:
+ form = UI form
+ enumTups = list of (translated_text, data_string) tuples
+ comboBoxesPropertyMap = list of (translated_text, data_string) tuples
+ """
+ # Load appropriate enumerations in each combobox
+ for cb, prop in comboBoxesPropertyMap:
+ box = getattr(form, cb) # Get the combobox
+ box.clear() # clear the combobox
+ for text, data in enumTups[prop]: # load enumerations
+ box.addItem(text, data)
+
def getSignalsForUpdate(self, obj):
- '''getSignalsForUpdate(obj) ... return list of signals for updating obj'''
+ """getSignalsForUpdate(obj) ... return list of signals for updating obj"""
signals = []
# signals.append(self.form.button.clicked)
signals.append(self.form.Side.currentIndexChanged)
@@ -189,10 +88,10 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.form.HelixConeAngle.setValue(obj.HelixConeAngle)
self.form.HelixDiameterLimit.setValue(obj.HelixDiameterLimit)
self.form.LiftDistance.setValue(obj.LiftDistance)
- if hasattr(obj, 'KeepToolDownRatio'):
+ if hasattr(obj, "KeepToolDownRatio"):
self.form.KeepToolDownRatio.setValue(obj.KeepToolDownRatio)
- if hasattr(obj, 'StockToLeave'):
+ if hasattr(obj, "StockToLeave"):
self.form.StockToLeave.setValue(obj.StockToLeave)
# self.form.ProcessHoles.setChecked(obj.ProcessHoles)
@@ -202,17 +101,17 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.setupToolController(obj, self.form.ToolController)
self.setupCoolant(obj, self.form.coolantController)
self.form.StopButton.setChecked(obj.Stopped)
- obj.setEditorMode('AdaptiveInputState', 2) # hide this property
- obj.setEditorMode('AdaptiveOutputState', 2) # hide this property
- obj.setEditorMode('StopProcessing', 2) # hide this property
- obj.setEditorMode('Stopped', 2) # hide this property
+ obj.setEditorMode("AdaptiveInputState", 2) # hide this property
+ obj.setEditorMode("AdaptiveOutputState", 2) # hide this property
+ obj.setEditorMode("StopProcessing", 2) # hide this property
+ obj.setEditorMode("Stopped", 2) # hide this property
def getFields(self, obj):
- if obj.Side != str(self.form.Side.currentText()):
- obj.Side = str(self.form.Side.currentText())
+ if obj.Side != str(self.form.Side.currentData()):
+ obj.Side = str(self.form.Side.currentData())
- if obj.OperationType != str(self.form.OperationType.currentText()):
- obj.OperationType = str(self.form.OperationType.currentText())
+ if obj.OperationType != str(self.form.OperationType.currentData()):
+ obj.OperationType = str(self.form.OperationType.currentData())
obj.StepOver = self.form.StepOver.value()
obj.Tolerance = 1.0 * self.form.Tolerance.value() / 100.0
@@ -221,37 +120,41 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
obj.HelixDiameterLimit = self.form.HelixDiameterLimit.value()
obj.LiftDistance = self.form.LiftDistance.value()
- if hasattr(obj, 'KeepToolDownRatio'):
+ if hasattr(obj, "KeepToolDownRatio"):
obj.KeepToolDownRatio = self.form.KeepToolDownRatio.value()
- if hasattr(obj, 'StockToLeave'):
+ if hasattr(obj, "StockToLeave"):
obj.StockToLeave = self.form.StockToLeave.value()
obj.ForceInsideOut = self.form.ForceInsideOut.isChecked()
obj.FinishingProfile = self.form.FinishingProfile.isChecked()
obj.UseOutline = self.form.useOutline.isChecked()
obj.Stopped = self.form.StopButton.isChecked()
- if(obj.Stopped):
+ if obj.Stopped:
self.form.StopButton.setChecked(False) # reset the button
obj.StopProcessing = True
self.updateToolController(obj, self.form.ToolController)
self.updateCoolant(obj, self.form.coolantController)
- obj.setEditorMode('AdaptiveInputState', 2) # hide this property
- obj.setEditorMode('AdaptiveOutputState', 2) # hide this property
- obj.setEditorMode('StopProcessing', 2) # hide this property
- obj.setEditorMode('Stopped', 2) # hide this property
+ obj.setEditorMode("AdaptiveInputState", 2) # hide this property
+ obj.setEditorMode("AdaptiveOutputState", 2) # hide this property
+ obj.setEditorMode("StopProcessing", 2) # hide this property
+ obj.setEditorMode("Stopped", 2) # hide this property
def taskPanelBaseLocationPage(self, obj, features):
- if not hasattr(self, 'extensionsPanel'):
- self.extensionsPanel = PathFeatureExtensionsGui.TaskPanelExtensionPage(obj, features) # pylint: disable=attribute-defined-outside-init
+ if not hasattr(self, "extensionsPanel"):
+ self.extensionsPanel = PathFeatureExtensionsGui.TaskPanelExtensionPage(
+ obj, features
+ ) # pylint: disable=attribute-defined-outside-init
return self.extensionsPanel
-Command = PathOpGui.SetupOperation('Adaptive',
- PathAdaptive.Create,
- TaskPanelOpPage,
- 'Path_Adaptive',
- QtCore.QT_TRANSLATE_NOOP("Path_Adaptive", "Adaptive"),
- QtCore.QT_TRANSLATE_NOOP("Path_Adaptive", "Adaptive clearing and profiling"),
- PathAdaptive.SetupProperties)
+Command = PathOpGui.SetupOperation(
+ "Adaptive",
+ PathAdaptive.Create,
+ TaskPanelOpPage,
+ "Path_Adaptive",
+ QtCore.QT_TRANSLATE_NOOP("Path_Adaptive", "Adaptive"),
+ QtCore.QT_TRANSLATE_NOOP("Path_Adaptive", "Adaptive clearing and profiling"),
+ PathAdaptive.SetupProperties,
+)
diff --git a/src/Mod/Path/PathScripts/PathPreferencesAdvanced.py b/src/Mod/Path/PathScripts/PathPreferencesAdvanced.py
index 5b9151587b..4a9b3903dc 100644
--- a/src/Mod/Path/PathScripts/PathPreferencesAdvanced.py
+++ b/src/Mod/Path/PathScripts/PathPreferencesAdvanced.py
@@ -24,37 +24,46 @@ import FreeCADGui
import PathScripts.PathPreferences as PathPreferences
import PySide
-# Qt translation handling
-def translate(context, text, disambig=None):
- return PySide.QtCore.QCoreApplication.translate(context, text, disambig)
class AdvancedPreferencesPage:
def __init__(self, parent=None):
- self.form = FreeCADGui.PySideUic.loadUi(':preferences/Advanced.ui')
+ self.form = FreeCADGui.PySideUic.loadUi(":preferences/Advanced.ui")
self.form.WarningSuppressAllSpeeds.stateChanged.connect(self.updateSelection)
self.form.EnableAdvancedOCLFeatures.stateChanged.connect(self.updateSelection)
def saveSettings(self):
PathPreferences.setPreferencesAdvanced(
- self.form.EnableAdvancedOCLFeatures.isChecked(),
- self.form.WarningSuppressAllSpeeds.isChecked(),
- self.form.WarningSuppressRapidSpeeds.isChecked(),
- self.form.WarningSuppressSelectionMode.isChecked(),
- self.form.WarningSuppressOpenCamLib.isChecked())
+ self.form.EnableAdvancedOCLFeatures.isChecked(),
+ self.form.WarningSuppressAllSpeeds.isChecked(),
+ self.form.WarningSuppressRapidSpeeds.isChecked(),
+ self.form.WarningSuppressSelectionMode.isChecked(),
+ self.form.WarningSuppressOpenCamLib.isChecked(),
+ )
def loadSettings(self):
- self.form.WarningSuppressAllSpeeds.setChecked(PathPreferences.suppressAllSpeedsWarning())
- self.form.WarningSuppressRapidSpeeds.setChecked(PathPreferences.suppressRapidSpeedsWarning(False))
- self.form.WarningSuppressSelectionMode.setChecked(PathPreferences.suppressSelectionModeWarning())
- self.form.EnableAdvancedOCLFeatures.setChecked(PathPreferences.advancedOCLFeaturesEnabled())
- self.form.WarningSuppressOpenCamLib.setChecked(PathPreferences.suppressOpenCamLibWarning())
+ self.form.WarningSuppressAllSpeeds.setChecked(
+ PathPreferences.suppressAllSpeedsWarning()
+ )
+ self.form.WarningSuppressRapidSpeeds.setChecked(
+ PathPreferences.suppressRapidSpeedsWarning(False)
+ )
+ self.form.WarningSuppressSelectionMode.setChecked(
+ PathPreferences.suppressSelectionModeWarning()
+ )
+ self.form.EnableAdvancedOCLFeatures.setChecked(
+ PathPreferences.advancedOCLFeaturesEnabled()
+ )
+ self.form.WarningSuppressOpenCamLib.setChecked(
+ PathPreferences.suppressOpenCamLibWarning()
+ )
self.updateSelection()
def updateSelection(self, state=None):
- self.form.WarningSuppressOpenCamLib.setEnabled(self.form.EnableAdvancedOCLFeatures.isChecked())
+ self.form.WarningSuppressOpenCamLib.setEnabled(
+ self.form.EnableAdvancedOCLFeatures.isChecked()
+ )
if self.form.WarningSuppressAllSpeeds.isChecked():
self.form.WarningSuppressRapidSpeeds.setChecked(True)
self.form.WarningSuppressRapidSpeeds.setEnabled(False)
else:
self.form.WarningSuppressRapidSpeeds.setEnabled(True)
-
diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py
index 2c640aaca2..ef561f6361 100644
--- a/src/Mod/Path/PathScripts/PathSelection.py
+++ b/src/Mod/Path/PathScripts/PathSelection.py
@@ -402,7 +402,7 @@ def select(op):
opsel["Vcarve"] = vcarveselect
opsel["Probe"] = probeselect
opsel["Custom"] = customselect
- opsel["Thread Milling"] = drillselect
+ opsel["ThreadMilling"] = drillselect
opsel["TurnFace"] = turnselect
opsel["TurnProfile"] = turnselect
opsel["TurnPartoff"] = turnselect
diff --git a/src/Mod/Path/PathScripts/PathThreadMilling.py b/src/Mod/Path/PathScripts/PathThreadMilling.py
index 5d89c285b2..3dc5eb02c3 100644
--- a/src/Mod/Path/PathScripts/PathThreadMilling.py
+++ b/src/Mod/Path/PathScripts/PathThreadMilling.py
@@ -28,26 +28,25 @@ import PathScripts.PathCircularHoleBase as PathCircularHoleBase
import PathScripts.PathGeom as PathGeom
import PathScripts.PathLog as PathLog
import PathScripts.PathOp as PathOp
-import PathScripts.PathUtils as PathUtils
import math
-
-from PySide import QtCore
+from PySide.QtCore import QT_TRANSLATE_NOOP
__title__ = "Path Thread Milling Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Path thread milling operation."
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-#PathLog.trackModule(PathLog.thisModule())
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-# Qt translation handling
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
+translate = FreeCAD.Qt.translate
-def radiiInternal(majorDia, minorDia, toolDia, toolCrest = None):
- '''internlThreadRadius(majorDia, minorDia, toolDia, toolCrest) ... returns the maximum radius for thread.'''
+def radiiInternal(majorDia, minorDia, toolDia, toolCrest=None):
+ """internlThreadRadius(majorDia, minorDia, toolDia, toolCrest) ... returns the maximum radius for thread."""
PathLog.track(majorDia, minorDia, toolDia, toolCrest)
if toolCrest is None:
toolCrest = 0.0
@@ -57,20 +56,25 @@ def radiiInternal(majorDia, minorDia, toolDia, toolCrest = None):
# - The major diameter is 3/8 * H bigger than the pitch diameter
# Since we already have the outer diameter it's simpler to just add 1/8 * H
# to get the outer tip of the thread.
- H = ((majorDia - minorDia) / 2.0 ) * 1.6 # (D - d)/2 = 5/8 * H
+ H = ((majorDia - minorDia) / 2.0) * 1.6 # (D - d)/2 = 5/8 * H
outerTip = majorDia / 2.0 + H / 8.0
# Compensate for the crest of the tool
- toolTip = outerTip - toolCrest * 0.8660254037844386 # math.sqrt(3)/2 ... 60deg triangle height
+ toolTip = (
+ outerTip - toolCrest * 0.8660254037844386
+ ) # math.sqrt(3)/2 ... 60deg triangle height
return ((minorDia - toolDia) / 2.0, toolTip - toolDia / 2.0)
-def threadPasses(count, radii, majorDia, minorDia, toolDia, toolCrest = None):
+
+def threadPasses(count, radii, majorDia, minorDia, toolDia, toolCrest=None):
PathLog.track(count, radii, majorDia, minorDia, toolDia, toolCrest)
minor, major = radii(majorDia, minorDia, toolDia, toolCrest)
- dr = float(major - minor) / count
+ dr = float(major - minor) / count
return [major - dr * (count - (i + 1)) for i in range(count)]
+
class _InternalThread(object):
- '''Helper class for dealing with different thread types'''
+ """Helper class for dealing with different thread types"""
+
def __init__(self, cmd, zStart, zFinal, pitch):
self.cmd = cmd
if zStart < zFinal:
@@ -82,33 +86,34 @@ class _InternalThread(object):
self.zFinal = zFinal
def overshoots(self, z):
- '''overshoots(z) ... returns true if adding another half helix goes beyond the thread bounds'''
+ """overshoots(z) ... returns true if adding another half helix goes beyond the thread bounds"""
if self.pitch < 0:
return z + self.hPitch < self.zFinal
return z + self.hPitch > self.zFinal
def adjustX(self, x, dx):
- '''adjustX(x, dx) ... move x by dx, the direction depends on the thread settings'''
+ """adjustX(x, dx) ... move x by dx, the direction depends on the thread settings"""
if self.isG3() == (self.pitch > 0):
return x + dx
return x - dx
def adjustY(self, y, dy):
- '''adjustY(y, dy) ... move y by dy, the direction depends on the thread settings'''
+ """adjustY(y, dy) ... move y by dy, the direction depends on the thread settings"""
if self.isG3():
return y - dy
return y - dy
def isG3(self):
- '''isG3() ... returns True if this is a G3 command'''
- return self.cmd in ['G3', 'G03', 'g3', 'g03']
+ """isG3() ... returns True if this is a G3 command"""
+ return self.cmd in ["G3", "G03", "g3", "g03"]
def isUp(self):
- '''isUp() ... returns True if the thread goes from the bottom up'''
+ """isUp() ... returns True if the thread goes from the bottom up"""
return self.pitch > 0
+
def internalThreadCommands(loc, cmd, zStart, zFinal, pitch, radius, leadInOut):
- '''internalThreadCommands(loc, cmd, zStart, zFinal, pitch, radius) ... returns the g-code to mill the given internal thread'''
+ """internalThreadCommands(loc, cmd, zStart, zFinal, pitch, radius) ... returns the g-code to mill the given internal thread"""
thread = _InternalThread(cmd, zStart, zFinal, pitch)
yMin = loc.y - radius
@@ -118,30 +123,29 @@ def internalThreadCommands(loc, cmd, zStart, zFinal, pitch, radius, leadInOut):
# at this point the tool is at a safe height (depending on the previous thread), so we can move
# into position first, and then drop to the start height. If there is any material in the way this
# op hasn't been setup properly.
- path.append(Path.Command('G0', {'X': loc.x, 'Y': loc.y}))
- path.append(Path.Command('G0', {'Z': thread.zStart}))
+ path.append(Path.Command("G0", {"X": loc.x, "Y": loc.y}))
+ path.append(Path.Command("G0", {"Z": thread.zStart}))
if leadInOut:
- path.append(Path.Command(thread.cmd, {'Y': yMax, 'J': (yMax - loc.y) / 2}))
+ path.append(Path.Command(thread.cmd, {"Y": yMax, "J": (yMax - loc.y) / 2}))
else:
- path.append(Path.Command('G1', {'Y': yMax}))
+ path.append(Path.Command("G1", {"Y": yMax}))
z = thread.zStart
r = -radius
i = 0
while True:
- z = thread.zStart + i*thread.hPitch
+ z = thread.zStart + i * thread.hPitch
if thread.overshoots(z):
break
if 0 == (i & 0x01):
y = yMin
else:
y = yMax
- path.append(Path.Command(thread.cmd, {'Y': y, 'Z': z + thread.hPitch, 'J': r}))
+ path.append(Path.Command(thread.cmd, {"Y": y, "Z": z + thread.hPitch, "J": r}))
r = -r
i = i + 1
-
- z = thread.zStart + i*thread.hPitch
+ z = thread.zStart + i * thread.hPitch
if PathGeom.isRoughly(z, thread.zFinal):
x = loc.x
else:
@@ -151,48 +155,183 @@ def internalThreadCommands(loc, cmd, zStart, zFinal, pitch, radius, leadInOut):
dx = math.sin(k * math.pi)
y = thread.adjustY(loc.y, r * dy)
x = thread.adjustX(loc.x, r * dx)
- path.append(Path.Command(thread.cmd, {'X': x, 'Y': y, 'Z': thread.zFinal, 'J': r}))
+ path.append(
+ Path.Command(thread.cmd, {"X": x, "Y": y, "Z": thread.zFinal, "J": r})
+ )
if leadInOut:
- path.append(Path.Command(thread.cmd, {'X': loc.x, 'Y': loc.y, 'I': (loc.x - x) / 2, 'J': (loc.y - y) / 2}))
+ path.append(
+ Path.Command(
+ thread.cmd,
+ {"X": loc.x, "Y": loc.y, "I": (loc.x - x) / 2, "J": (loc.y - y) / 2},
+ )
+ )
else:
- path.append(Path.Command('G1', {'X': loc.x, 'Y': loc.y}))
+ path.append(Path.Command("G1", {"X": loc.x, "Y": loc.y}))
return path
-class ObjectThreadMilling(PathCircularHoleBase.ObjectOp):
- '''Proxy object for thread milling operation.'''
- LeftHand = 'LeftHand'
- RightHand = 'RightHand'
- ThreadTypeCustom = 'Custom'
- ThreadTypeMetricInternal = 'Metric - internal'
- ThreadTypeImperialInternal = 'Imperial - internal'
- DirectionClimb = 'Climb'
- DirectionConventional = 'Conventional'
+class ObjectThreadMilling(PathCircularHoleBase.ObjectOp):
+ """Proxy object for thread milling operation."""
+
+ LeftHand = "LeftHand"
+ RightHand = "RightHand"
+ ThreadTypeCustom = "Custom"
+ ThreadTypeMetricInternal = "MetricInternal"
+ ThreadTypeImperialInternal = "ImperialInternal"
+ DirectionClimb = "Climb"
+ DirectionConventional = "Conventional"
ThreadOrientations = [LeftHand, RightHand]
- ThreadTypes = [ThreadTypeCustom, ThreadTypeMetricInternal, ThreadTypeImperialInternal]
- Directions = [DirectionClimb, DirectionConventional]
+ ThreadTypes = [
+ ThreadTypeCustom,
+ ThreadTypeMetricInternal,
+ ThreadTypeImperialInternal,
+ ]
+ Directions = [DirectionClimb, DirectionConventional]
+
+ @classmethod
+ def propertyEnumerations(self, dataType="data"):
+ """helixOpPropertyEnumerations(dataType="data")... return property enumeration lists of specified dataType.
+ Args:
+ dataType = 'data', 'raw', 'translated'
+ Notes:
+ 'data' is list of internal string literals used in code
+ 'raw' is list of (translated_text, data_string) tuples
+ 'translated' is list of translated string literals
+ """
+
+ # Enumeration lists for App::PropertyEnumeration properties
+ enums = {
+ "ThreadType": [
+ (translate("Path_ThreadMilling", "Custom"), "Custom"),
+ (translate("Path_ThreadMilling", "Metric Internal"), "MetricInternal"),
+ (
+ translate("Path_ThreadMilling", "Imperial Internal"),
+ "ImperialInternal",
+ ),
+ ], # this is the direction that the profile runs
+ "ThreadOrientation": [
+ (translate("Path_ThreadMilling", "LeftHand"), "LeftHand"),
+ (translate("Path_ThreadMilling", "RightHand"), "RightHand"),
+ ], # side of profile that cutter is on in relation to direction of profile
+ "Direction": [
+ (translate("Path_ThreadMilling", "Climb"), "Climb"),
+ (translate("Path_ThreadMilling", "Conventional"), "Conventional"),
+ ], # side of profile that cutter is on in relation to direction of profile
+ }
+
+ if dataType == "raw":
+ return enums
+
+ data = list()
+ idx = 0 if dataType == "translated" else 1
+
+ PathLog.debug(enums)
+
+ for k, v in enumerate(enums):
+ data.append((v, [tup[idx] for tup in enums[v]]))
+ PathLog.debug(data)
+
+ return data
def circularHoleFeatures(self, obj):
return PathOp.FeatureBaseGeometry
def initCircularHoleOperation(self, obj):
- obj.addProperty("App::PropertyEnumeration", "ThreadOrientation", "Thread", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Set thread orientation"))
- obj.ThreadOrientation = self.ThreadOrientations
- obj.addProperty("App::PropertyEnumeration", "ThreadType", "Thread", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Currently only internal"))
- obj.ThreadType = self.ThreadTypes
- obj.addProperty("App::PropertyString", "ThreadName", "Thread", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Defines which standard thread was chosen"))
- obj.addProperty("App::PropertyLength", "MajorDiameter", "Thread", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Set thread's major diameter"))
- obj.addProperty("App::PropertyLength", "MinorDiameter", "Thread", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Set thread's minor diameter"))
- obj.addProperty("App::PropertyLength", "Pitch", "Thread", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Set thread's pitch - used for metric threads"))
- obj.addProperty("App::PropertyInteger", "TPI", "Thread", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Set thread's TPI (turns per inch) - used for imperial threads"))
- obj.addProperty("App::PropertyInteger", "ThreadFit", "Thread", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Set how many passes are used to cut the thread"))
- obj.addProperty("App::PropertyInteger", "Passes", "Operation", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Set how many passes are used to cut the thread"))
- obj.addProperty("App::PropertyEnumeration", "Direction", "Operation", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Direction of thread cutting operation"))
- obj.addProperty("App::PropertyBool", "LeadInOut", "Operation", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Set to True to get lead in and lead out arcs at the start and end of the thread cut"))
- obj.addProperty("App::PropertyLink", "ClearanceOp", "Operation", QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Operation to clear the inside of the thread"))
- obj.Direction = self.Directions
+ obj.addProperty(
+ "App::PropertyEnumeration",
+ "ThreadOrientation",
+ "Thread",
+ QT_TRANSLATE_NOOP("App::Property", "Set thread orientation"),
+ )
+ # obj.ThreadOrientation = self.ThreadOrientations
+ obj.addProperty(
+ "App::PropertyEnumeration",
+ "ThreadType",
+ "Thread",
+ QT_TRANSLATE_NOOP("App::Property", "Currently only internal"),
+ )
+ # obj.ThreadType = self.ThreadTypes
+ obj.addProperty(
+ "App::PropertyString",
+ "ThreadName",
+ "Thread",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "Defines which standard thread was chosen"
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "MajorDiameter",
+ "Thread",
+ QT_TRANSLATE_NOOP("App::Property", "Set thread's major diameter"),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "MinorDiameter",
+ "Thread",
+ QT_TRANSLATE_NOOP("App::Property", "Set thread's minor diameter"),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "Pitch",
+ "Thread",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "Set thread's pitch - used for metric threads"
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyInteger",
+ "TPI",
+ "Thread",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Set thread's TPI (turns per inch) - used for imperial threads",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyInteger",
+ "ThreadFit",
+ "Thread",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "Set how many passes are used to cut the thread"
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyInteger",
+ "Passes",
+ "Operation",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "Set how many passes are used to cut the thread"
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyEnumeration",
+ "Direction",
+ "Operation",
+ QT_TRANSLATE_NOOP("App::Property", "Direction of thread cutting operation"),
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "LeadInOut",
+ "Operation",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Set to True to get lead in and lead out arcs at the start and end of the thread cut",
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyLink",
+ "ClearanceOp",
+ "Operation",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "Operation to clear the inside of the thread"
+ ),
+ )
+
+ for n in self.propertyEnumerations():
+ setattr(obj, n[0], n[1])
def threadStartDepth(self, obj):
if obj.ThreadOrientation == self.RightHand:
@@ -225,25 +364,25 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp):
PathLog.track(obj.Label)
if obj.ThreadOrientation == self.RightHand:
if obj.Direction == self.DirectionClimb:
- PathLog.track(obj.Label, 'G2')
- return 'G2'
- PathLog.track(obj.Label, 'G3')
- return 'G3'
+ PathLog.track(obj.Label, "G2")
+ return "G2"
+ PathLog.track(obj.Label, "G3")
+ return "G3"
if obj.Direction == self.DirectionClimb:
- PathLog.track(obj.Label, 'G3')
- return 'G3'
- PathLog.track(obj.Label, 'G2')
- return 'G2'
+ PathLog.track(obj.Label, "G3")
+ return "G3"
+ PathLog.track(obj.Label, "G2")
+ return "G2"
def threadSetup(self, obj):
# the thing to remember is that Climb, for an internal thread must always be G3
if obj.Direction == self.DirectionClimb:
if obj.ThreadOrientation == self.RightHand:
- return ('G3', obj.FinalDepth.Value, obj.StartDepth.Value)
- return ('G3', obj.StartDepth.Value, obj.FinalDepth.Value)
+ return ("G3", obj.FinalDepth.Value, obj.StartDepth.Value)
+ return ("G3", obj.StartDepth.Value, obj.FinalDepth.Value)
if obj.ThreadOrientation == self.RightHand:
- return ('G2', obj.StartDepth.Value, obj.FinalDepth.Value)
- return ('G2', obj.FinalDepth.Value, obj.StartDepth.Value)
+ return ("G2", obj.StartDepth.Value, obj.FinalDepth.Value)
+ return ("G2", obj.FinalDepth.Value, obj.StartDepth.Value)
def threadPassRadii(self, obj):
PathLog.track(obj.Label)
@@ -251,7 +390,7 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp):
rMinor = (obj.MinorDiameter.Value - self.tool.Diameter) / 2.0
if obj.Passes < 1:
obj.Passes = 1
- rPass = (rMajor - rMinor) / obj.Passes
+ rPass = (rMajor - rMinor) / obj.Passes
passes = [rMajor]
for i in range(1, obj.Passes):
passes.append(rMajor - rPass * i)
@@ -260,20 +399,33 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp):
def executeThreadMill(self, obj, loc, gcode, zStart, zFinal, pitch):
PathLog.track(obj.Label, loc, gcode, zStart, zFinal, pitch)
- self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
+ self.commandlist.append(
+ Path.Command("G0", {"Z": obj.ClearanceHeight.Value, "F": self.vertRapid})
+ )
- for radius in threadPasses(obj.Passes, radiiInternal, obj.MajorDiameter.Value, obj.MinorDiameter.Value, float(self.tool.Diameter), float(self.tool.Crest)):
- commands = internalThreadCommands(loc, gcode, zStart, zFinal, pitch, radius, obj.LeadInOut)
+ for radius in threadPasses(
+ obj.Passes,
+ radiiInternal,
+ obj.MajorDiameter.Value,
+ obj.MinorDiameter.Value,
+ float(self.tool.Diameter),
+ float(self.tool.Crest),
+ ):
+ commands = internalThreadCommands(
+ loc, gcode, zStart, zFinal, pitch, radius, obj.LeadInOut
+ )
for cmd in commands:
p = cmd.Parameters
- if cmd.Name in ['G0']:
- p.update({'F': self.vertRapid})
- if cmd.Name in ['G1', 'G2', 'G3']:
- p.update({'F': self.horizFeed})
+ if cmd.Name in ["G0"]:
+ p.update({"F": self.vertRapid})
+ if cmd.Name in ["G1", "G2", "G3"]:
+ p.update({"F": self.horizFeed})
cmd.Parameters = p
self.commandlist.extend(commands)
- self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
+ self.commandlist.append(
+ Path.Command("G0", {"Z": obj.ClearanceHeight.Value, "F": self.vertRapid})
+ )
def circularHoleExecute(self, obj, holes):
PathLog.track()
@@ -290,11 +442,17 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp):
# rapid to clearance height
for loc in holes:
- self.executeThreadMill(obj, FreeCAD.Vector(loc['x'], loc['y'], 0), cmd, zStart, zFinal, pitch)
+ self.executeThreadMill(
+ obj,
+ FreeCAD.Vector(loc["x"], loc["y"], 0),
+ cmd,
+ zStart,
+ zFinal,
+ pitch,
+ )
else:
PathLog.error("No suitable Tool found for thread milling operation")
-
def opSetDefaultValues(self, obj, job):
obj.ThreadOrientation = self.RightHand
obj.ThreadType = self.ThreadTypeMetricInternal
@@ -306,8 +464,8 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp):
obj.LeadInOut = True
def isToolSupported(self, obj, tool):
- '''Thread milling only supports thread milling cutters.'''
- return hasattr(tool, 'Diameter') and hasattr(tool, 'Crest')
+ """Thread milling only supports thread milling cutters."""
+ return hasattr(tool, "Diameter") and hasattr(tool, "Crest")
def SetupProperties():
@@ -327,11 +485,10 @@ def SetupProperties():
def Create(name, obj=None, parentJob=None):
- '''Create(name) ... Creates and returns a thread milling operation.'''
+ """Create(name) ... Creates and returns a thread milling operation."""
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectThreadMilling(obj, name, parentJob)
if obj.Proxy:
obj.Proxy.findAllHoles(obj)
return obj
-
diff --git a/src/Mod/Path/PathScripts/PathThreadMillingGui.py b/src/Mod/Path/PathScripts/PathThreadMillingGui.py
index ff3bcd904f..1514f951e1 100644
--- a/src/Mod/Path/PathScripts/PathThreadMillingGui.py
+++ b/src/Mod/Path/PathScripts/PathThreadMillingGui.py
@@ -22,7 +22,7 @@
import FreeCAD
import FreeCADGui
-import PathGui as PGui # ensure Path/Gui/Resources are loaded
+import PathGui as PGui # ensure Path/Gui/Resources are loaded
import PathScripts.PathCircularHoleBaseGui as PathCircularHoleBaseGui
import PathScripts.PathThreadMilling as PathThreadMilling
import PathScripts.PathGui as PathGui
@@ -30,6 +30,9 @@ import PathScripts.PathLog as PathLog
import PathScripts.PathOpGui as PathOpGui
import csv
+from PySide.QtCore import QT_TRANSLATE_NOOP
+
+
from PySide import QtCore
__title__ = "Path Thread Milling Operation UI."
@@ -37,52 +40,88 @@ __author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "UI and Command for Path Thread Milling Operation."
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-#PathLog.trackModule(PathLog.thisModule())
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
+
+translate = FreeCAD.Qt.translate
-def setupCombo(combo, selections):
- combo.clear()
- for item in selections:
- combo.addItem(item)
def fillThreads(combo, dataFile):
combo.blockSignals(True)
combo.clear()
- with open("{}Mod/Path/Data/Threads/{}.csv".format(FreeCAD.getHomePath(), dataFile)) as fp:
+ with open(
+ "{}Mod/Path/Data/Threads/{}.csv".format(FreeCAD.getHomePath(), dataFile)
+ ) as fp:
reader = csv.DictReader(fp)
for row in reader:
- combo.addItem(row['name'], row)
+ combo.addItem(row["name"], row)
combo.setEnabled(True)
combo.blockSignals(False)
+
class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
- '''Controller for the thread milling operation's page'''
+ """Controller for the thread milling operation's page"""
def initPage(self, obj):
- self.majorDia = PathGui.QuantitySpinBox(self.form.threadMajor, obj, 'MajorDiameter') # pylint: disable=attribute-defined-outside-init
- self.minorDia = PathGui.QuantitySpinBox(self.form.threadMinor, obj, 'MinorDiameter') # pylint: disable=attribute-defined-outside-init
- self.pitch = PathGui.QuantitySpinBox(self.form.threadPitch, obj, 'Pitch') # pylint: disable=attribute-defined-outside-init
+ self.majorDia = PathGui.QuantitySpinBox(
+ self.form.threadMajor, obj, "MajorDiameter"
+ ) # pylint: disable=attribute-defined-outside-init
+ self.minorDia = PathGui.QuantitySpinBox(
+ self.form.threadMinor, obj, "MinorDiameter"
+ ) # pylint: disable=attribute-defined-outside-init
+ self.pitch = PathGui.QuantitySpinBox(
+ self.form.threadPitch, obj, "Pitch"
+ ) # pylint: disable=attribute-defined-outside-init
- setupCombo(self.form.threadOrientation, obj.Proxy.ThreadOrientations)
- setupCombo(self.form.threadType, obj.Proxy.ThreadTypes)
- setupCombo(self.form.opDirection, obj.Proxy.Directions)
+ # setupCombo(self.form.threadOrientation, obj.Proxy.ThreadOrientations)
+ # setupCombo(self.form.threadType, obj.Proxy.ThreadTypes)
+ # setupCombo(self.form.opDirection, obj.Proxy.Directions)
def getForm(self):
- '''getForm() ... return UI'''
- return FreeCADGui.PySideUic.loadUi(":/panels/PageOpThreadMillingEdit.ui")
+ """getForm() ... return UI"""
+ form = FreeCADGui.PySideUic.loadUi(":/panels/PageOpThreadMillingEdit.ui")
+ comboToPropertyMap = [
+ ("threadOrientation", "ThreadOrientation"),
+ ("threadType", "ThreadType"),
+ ("opDirection", "Direction"),
+ ]
+ enumTups = PathThreadMilling.ObjectThreadMilling.propertyEnumerations(
+ dataType="raw"
+ )
+ self.populateCombobox(form, enumTups, comboToPropertyMap)
+
+ return form
+
+ def populateCombobox(self, form, enumTups, comboBoxesPropertyMap):
+ """fillComboboxes(form, comboBoxesPropertyMap) ... populate comboboxes with translated enumerations
+ ** comboBoxesPropertyMap will be unnecessary if UI files use strict combobox naming protocol.
+ Args:
+ form = UI form
+ enumTups = list of (translated_text, data_string) tuples
+ comboBoxesPropertyMap = list of (translated_text, data_string) tuples
+ """
+ # Load appropriate enumerations in each combobox
+ for cb, prop in comboBoxesPropertyMap:
+ box = getattr(form, cb) # Get the combobox
+ box.clear() # clear the combobox
+ for text, data in enumTups[prop]: # load enumerations
+ box.addItem(text, data)
def getFields(self, obj):
- '''getFields(obj) ... update obj's properties with values from the UI'''
+ """getFields(obj) ... update obj's properties with values from the UI"""
PathLog.track()
self.majorDia.updateProperty()
self.minorDia.updateProperty()
self.pitch.updateProperty()
- obj.ThreadOrientation = self.form.threadOrientation.currentText()
- obj.ThreadType = self.form.threadType.currentText()
+ obj.ThreadOrientation = self.form.threadOrientation.currentData()
+ obj.ThreadType = self.form.threadType.currentData()
obj.ThreadName = self.form.threadName.currentText()
- obj.Direction = self.form.opDirection.currentText()
+ obj.Direction = self.form.opDirection.currentData()
obj.Passes = self.form.opPasses.value()
obj.LeadInOut = self.form.leadInOut.checkState() == QtCore.Qt.Checked
obj.TPI = self.form.threadTPI.value()
@@ -90,23 +129,22 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
self.updateToolController(obj, self.form.toolController)
def setFields(self, obj):
- '''setFields(obj) ... update UI with obj properties' values'''
+ """setFields(obj) ... update UI with obj properties' values"""
PathLog.track()
- self.form.threadOrientation.setCurrentText(obj.ThreadOrientation)
+ self.selectInComboBox(obj.ThreadOrientation, self.form.threadOrientation)
+ self.selectInComboBox(obj.ThreadType, self.form.threadType)
+ self.selectInComboBox(obj.Direction, self.form.opDirection)
- self.form.threadType.blockSignals(True)
self.form.threadName.blockSignals(True)
- self.form.threadType.setCurrentText(obj.ThreadType)
- self._updateFromThreadType()
self.form.threadName.setCurrentText(obj.ThreadName)
- self.form.threadType.blockSignals(False)
self.form.threadName.blockSignals(False)
self.form.threadTPI.setValue(obj.TPI)
self.form.opPasses.setValue(obj.Passes)
- self.form.opDirection.setCurrentText(obj.Direction)
- self.form.leadInOut.setCheckState(QtCore.Qt.Checked if obj.LeadInOut else QtCore.Qt.Unchecked)
+ self.form.leadInOut.setCheckState(
+ QtCore.Qt.Checked if obj.LeadInOut else QtCore.Qt.Unchecked
+ )
self.majorDia.updateSpinBox()
self.minorDia.updateSpinBox()
@@ -114,16 +152,24 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
self.setupToolController(obj, self.form.toolController)
-
def _isThreadMetric(self):
- return self.form.threadType.currentText() == PathThreadMilling.ObjectThreadMilling.ThreadTypeMetricInternal
+ return (
+ self.form.threadType.currentData()
+ == PathThreadMilling.ObjectThreadMilling.ThreadTypeMetricInternal
+ )
def _isThreadImperial(self):
- return self.form.threadType.currentText() == PathThreadMilling.ObjectThreadMilling.ThreadTypeImperialInternal
+ return (
+ self.form.threadType.currentData()
+ == PathThreadMilling.ObjectThreadMilling.ThreadTypeImperialInternal
+ )
def _updateFromThreadType(self):
- if self.form.threadType.currentText() == PathThreadMilling.ObjectThreadMilling.ThreadTypeCustom:
+ if (
+ self.form.threadType.currentData()
+ == PathThreadMilling.ObjectThreadMilling.ThreadTypeCustom
+ ):
self.form.threadName.setEnabled(False)
self.form.threadFit.setEnabled(False)
self.form.threadFitLabel.setEnabled(False)
@@ -140,7 +186,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
self.form.threadTPI.setEnabled(False)
self.form.threadTPILabel.setEnabled(False)
self.form.threadTPI.setValue(0)
- fillThreads(self.form.threadName, 'metric-internal')
+ fillThreads(self.form.threadName, "metric-internal")
if self._isThreadImperial():
self.form.threadFit.setEnabled(True)
@@ -150,24 +196,24 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
self.form.threadTPI.setEnabled(True)
self.form.threadTPILabel.setEnabled(True)
self.pitch.updateSpinBox(0)
- fillThreads(self.form.threadName, 'imperial-internal')
+ fillThreads(self.form.threadName, "imperial-internal")
def _updateFromThreadName(self):
thread = self.form.threadName.currentData()
fit = float(self.form.threadFit.value()) / 100
- mamin = float(thread['dMajorMin'])
- mamax = float(thread['dMajorMax'])
+ mamin = float(thread["dMajorMin"])
+ mamax = float(thread["dMajorMax"])
major = mamin + (mamax - mamin) * fit
- mimin = float(thread['dMinorMin'])
- mimax = float(thread['dMinorMax'])
+ mimin = float(thread["dMinorMin"])
+ mimax = float(thread["dMinorMax"])
minor = mimin + (mimax - mimin) * fit
if self._isThreadMetric():
- pitch = float(thread['pitch'])
+ pitch = float(thread["pitch"])
self.pitch.updateSpinBox(pitch)
if self._isThreadImperial():
- tpi = int(thread['tpi'])
+ tpi = int(thread["tpi"])
self.form.threadTPI.setValue(tpi)
minor = minor * 25.4
major = major * 25.4
@@ -178,7 +224,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
self.setDirty()
def getSignalsForUpdate(self, obj):
- '''getSignalsForUpdate(obj) ... return list of signals which cause the receiver to update the model'''
+ """getSignalsForUpdate(obj) ... return list of signals which cause the receiver to update the model"""
signals = []
signals.append(self.form.threadMajor.editingFinished)
@@ -200,12 +246,17 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
self.form.threadFit.valueChanged.connect(self._updateFromThreadName)
-Command = PathOpGui.SetupOperation('Thread Milling',
- PathThreadMilling.Create,
- TaskPanelOpPage,
- 'Path_ThreadMilling',
- QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Thread Milling"),
- QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Creates a Path Thread Milling operation from features of a base object"),
- PathThreadMilling.SetupProperties)
+Command = PathOpGui.SetupOperation(
+ "ThreadMilling",
+ PathThreadMilling.Create,
+ TaskPanelOpPage,
+ "Path_ThreadMilling",
+ QT_TRANSLATE_NOOP("Path_ThreadMilling", "Thread Milling"),
+ QT_TRANSLATE_NOOP(
+ "Path_ThreadMilling",
+ "Creates a Path Thread Milling operation from features of a base object",
+ ),
+ PathThreadMilling.SetupProperties,
+)
FreeCAD.Console.PrintLog("Loading PathThreadMillingGui ... done\n")
diff --git a/src/Mod/Path/PathScripts/PathToolBit.py b/src/Mod/Path/PathScripts/PathToolBit.py
index 6d6032abfd..f4adde8fbb 100644
--- a/src/Mod/Path/PathScripts/PathToolBit.py
+++ b/src/Mod/Path/PathScripts/PathToolBit.py
@@ -25,30 +25,32 @@ import PathScripts.PathLog as PathLog
import PathScripts.PathPreferences as PathPreferences
import PathScripts.PathPropertyBag as PathPropertyBag
import PathScripts.PathUtil as PathUtil
-import PySide
import json
import os
import zipfile
+from PySide.QtCore import QT_TRANSLATE_NOOP
# lazily loaded modules
from lazy_loader.lazy_loader import LazyLoader
-Part = LazyLoader('Part', globals(), 'Part')
+
+Part = LazyLoader("Part", globals(), "Part")
__title__ = "Tool bits."
__author__ = "sliptonic (Brad Collette)"
__url__ = "https://www.freecadweb.org"
__doc__ = "Class to deal with and represent a tool bit."
-PropertyGroupShape = 'Shape'
+PropertyGroupShape = "Shape"
_DebugFindTool = False
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-#PathLog.trackModule()
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-def translate(context, text, disambig=None):
- return PySide.QtCore.QCoreApplication.translate(context, text, disambig)
def _findToolFile(name, containerFile, typ):
PathLog.track(name)
@@ -74,7 +76,6 @@ def _findToolFile(name, containerFile, typ):
return (True, fullPath)
return (False, None)
-
for p in paths:
found, path = _findFile(p, name)
if found:
@@ -83,26 +84,26 @@ def _findToolFile(name, containerFile, typ):
def findToolShape(name, path=None):
- '''findToolShape(name, path) ... search for name, if relative path look in path'''
+ """findToolShape(name, path) ... search for name, if relative path look in path"""
PathLog.track(name, path)
- return _findToolFile(name, path, 'Shape')
+ return _findToolFile(name, path, "Shape")
def findToolBit(name, path=None):
- '''findToolBit(name, path) ... search for name, if relative path look in path'''
+ """findToolBit(name, path) ... search for name, if relative path look in path"""
PathLog.track(name, path)
- if name.endswith('.fctb'):
- return _findToolFile(name, path, 'Bit')
- return _findToolFile("{}.fctb".format(name), path, 'Bit')
+ if name.endswith(".fctb"):
+ return _findToolFile(name, path, "Bit")
+ return _findToolFile("{}.fctb".format(name), path, "Bit")
# Only used in ToolBit unit test module: TestPathToolBit.py
def findToolLibrary(name, path=None):
- '''findToolLibrary(name, path) ... search for name, if relative path look in path'''
+ """findToolLibrary(name, path) ... search for name, if relative path look in path"""
PathLog.track(name, path)
- if name.endswith('.fctl'):
- return _findToolFile(name, path, 'Library')
- return _findToolFile("{}.fctl".format(name), path, 'Library')
+ if name.endswith(".fctl"):
+ return _findToolFile(name, path, "Library")
+ return _findToolFile("{}.fctl".format(name), path, "Library")
def _findRelativePath(path, typ):
@@ -110,7 +111,7 @@ def _findRelativePath(path, typ):
relative = path
for p in PathPreferences.searchPathsTool(typ):
if path.startswith(p):
- p = path[len(p):]
+ p = path[len(p) :]
if os.path.sep == p[0]:
p = p[1:]
if len(p) < len(relative):
@@ -130,23 +131,52 @@ def findRelativePathTool(path):
def findRelativePathLibrary(path):
- return _findRelativePath(path, 'Library')
+ return _findRelativePath(path, "Library")
+
class ToolBit(object):
-
def __init__(self, obj, shapeFile, path=None):
PathLog.track(obj.Label, shapeFile, path)
self.obj = obj
- obj.addProperty('App::PropertyFile', 'BitShape', 'Base', translate('PathToolBit', 'Shape for bit shape'))
- obj.addProperty('App::PropertyLink', 'BitBody', 'Base', translate('PathToolBit', 'The parametrized body representing the tool bit'))
- obj.addProperty('App::PropertyFile', 'File', 'Base', translate('PathToolBit', 'The file of the tool'))
- obj.addProperty('App::PropertyString', 'ShapeName', 'Base', translate('PathToolBit', 'The name of the shape file'))
- obj.addProperty('App::PropertyStringList', 'BitPropertyNames', 'Base', translate('PathToolBit', 'List of all properties inherited from the bit'))
+ obj.addProperty(
+ "App::PropertyFile",
+ "BitShape",
+ "Base",
+ QT_TRANSLATE_NOOP("App::Property", "Shape for bit shape"),
+ )
+ obj.addProperty(
+ "App::PropertyLink",
+ "BitBody",
+ "Base",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "The parametrized body representing the tool bit"
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyFile",
+ "File",
+ "Base",
+ QT_TRANSLATE_NOOP("App::Property", "The file of the tool"),
+ )
+ obj.addProperty(
+ "App::PropertyString",
+ "ShapeName",
+ "Base",
+ QT_TRANSLATE_NOOP("App::Property", "The name of the shape file"),
+ )
+ obj.addProperty(
+ "App::PropertyStringList",
+ "BitPropertyNames",
+ "Base",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "List of all properties inherited from the bit"
+ ),
+ )
if path:
obj.File = path
if shapeFile is None:
- obj.BitShape = 'endmill.fcstd'
+ obj.BitShape = "endmill.fcstd"
self._setupBitShape(obj)
self.unloadBitBody(obj)
else:
@@ -159,7 +189,7 @@ class ToolBit(object):
def __setstate__(self, state):
for obj in FreeCAD.ActiveDocument.Objects:
- if hasattr(obj, 'Proxy') and obj.Proxy == self:
+ if hasattr(obj, "Proxy") and obj.Proxy == self:
self.obj = obj
break
return None
@@ -168,14 +198,21 @@ class ToolBit(object):
# when files are shared it is essential to be able to change/set the shape file,
# otherwise the file is hard to use
# obj.setEditorMode('BitShape', 1)
- obj.setEditorMode('BitBody', 2)
- obj.setEditorMode('File', 1)
- obj.setEditorMode('Shape', 2)
- if not hasattr(obj, 'BitPropertyNames'):
- obj.addProperty('App::PropertyStringList', 'BitPropertyNames', 'Base', translate('PathToolBit', 'List of all properties inherited from the bit'))
+ obj.setEditorMode("BitBody", 2)
+ obj.setEditorMode("File", 1)
+ obj.setEditorMode("Shape", 2)
+ if not hasattr(obj, "BitPropertyNames"):
+ obj.addProperty(
+ "App::PropertyStringList",
+ "BitPropertyNames",
+ "Base",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "List of all properties inherited from the bit"
+ ),
+ )
propNames = []
for prop in obj.PropertiesList:
- if obj.getGroupOfProperty(prop) == 'Bit':
+ if obj.getGroupOfProperty(prop) == "Bit":
val = obj.getPropertyByName(prop)
typ = obj.getTypeIdOfProperty(prop)
dsc = obj.getDocumentationOfProperty(prop)
@@ -185,10 +222,10 @@ class ToolBit(object):
PathUtil.setProperty(obj, prop, val)
propNames.append(prop)
- elif obj.getGroupOfProperty(prop) == 'Attribute':
+ elif obj.getGroupOfProperty(prop) == "Attribute":
propNames.append(prop)
obj.BitPropertyNames = propNames
- obj.setEditorMode('BitPropertyNames', 2)
+ obj.setEditorMode("BitPropertyNames", 2)
for prop in obj.BitPropertyNames:
if obj.getGroupOfProperty(prop) == PropertyGroupShape:
@@ -202,7 +239,7 @@ class ToolBit(object):
def onChanged(self, obj, prop):
PathLog.track(obj.Label, prop)
- if prop == 'BitShape' and 'Restore' not in obj.State:
+ if prop == "BitShape" and "Restore" not in obj.State:
self._setupBitShape(obj)
def onDelete(self, obj, arg2=None):
@@ -212,7 +249,11 @@ class ToolBit(object):
def _updateBitShape(self, obj, properties=None):
if obj.BitBody is not None:
- for attributes in [o for o in obj.BitBody.Group if hasattr(o, 'Proxy') and hasattr(o.Proxy, 'getCustomProperties')]:
+ for attributes in [
+ o
+ for o in obj.BitBody.Group
+ if hasattr(o, "Proxy") and hasattr(o.Proxy, "getCustomProperties")
+ ]:
for prop in attributes.Proxy.getCustomProperties():
# the property might not exist in our local object (new attribute in shape)
# for such attributes we just keep the default
@@ -291,7 +332,7 @@ class ToolBit(object):
dsc = orig.getDocumentationOfProperty(prop)
obj.addProperty(typ, prop, grp, dsc)
- if 'App::PropertyEnumeration' == typ:
+ if "App::PropertyEnumeration" == typ:
setattr(obj, prop, orig.getEnumerationsOfProperty(prop))
obj.setEditorMode(prop, 1)
@@ -315,16 +356,21 @@ class ToolBit(object):
if bitBody.ViewObject:
bitBody.ViewObject.Visibility = False
- PathLog.debug("bitBody.{} ({}): {}".format(bitBody.Label, bitBody.Name, type(bitBody)))
+ PathLog.debug(
+ "bitBody.{} ({}): {}".format(bitBody.Label, bitBody.Name, type(bitBody))
+ )
propNames = []
- for attributes in [o for o in bitBody.Group if PathPropertyBag.IsPropertyBag(o)]:
+ for attributes in [
+ o for o in bitBody.Group if PathPropertyBag.IsPropertyBag(o)
+ ]:
PathLog.debug("Process properties from {}".format(attributes.Label))
for prop in attributes.Proxy.getCustomProperties():
self._setupProperty(obj, prop, attributes)
propNames.append(prop)
if not propNames:
- PathLog.error(translate('PathToolBit', 'Did not find a PropertyBag in {} - not a ToolBit shape?'.format(docName)))
+ PathLog.error("Did not find a PropertyBag in {} - not a ToolBit shape?".format(
+ docName))
# has to happen last because it could trigger op.execute evaluations
obj.BitPropertyNames = propNames
@@ -332,20 +378,32 @@ class ToolBit(object):
self._copyBitShape(obj)
def toolShapeProperties(self, obj):
- '''toolShapeProperties(obj) ... return all properties defining it's shape'''
- return sorted([prop for prop in obj.BitPropertyNames if obj.getGroupOfProperty(prop) == PropertyGroupShape])
+ """toolShapeProperties(obj) ... return all properties defining it's shape"""
+ return sorted(
+ [
+ prop
+ for prop in obj.BitPropertyNames
+ if obj.getGroupOfProperty(prop) == PropertyGroupShape
+ ]
+ )
def toolAdditionalProperties(self, obj):
- '''toolShapeProperties(obj) ... return all properties unrelated to it's shape'''
- return sorted([prop for prop in obj.BitPropertyNames if obj.getGroupOfProperty(prop) != PropertyGroupShape])
+ """toolShapeProperties(obj) ... return all properties unrelated to it's shape"""
+ return sorted(
+ [
+ prop
+ for prop in obj.BitPropertyNames
+ if obj.getGroupOfProperty(prop) != PropertyGroupShape
+ ]
+ )
def toolGroupsAndProperties(self, obj, includeShape=True):
- '''toolGroupsAndProperties(obj) ... returns a dictionary of group names with a list of property names.'''
+ """toolGroupsAndProperties(obj) ... returns a dictionary of group names with a list of property names."""
category = {}
for prop in obj.BitPropertyNames:
group = obj.getGroupOfProperty(prop)
if includeShape or group != PropertyGroupShape:
- properties = category.get(group, [])
+ properties = category.get(group, [])
properties.append(prop)
category[group] = properties
return category
@@ -354,10 +412,10 @@ class ToolBit(object):
if obj.BitShape:
path = findToolShape(obj.BitShape)
if path:
- with open(path, 'rb') as fd:
+ with open(path, "rb") as fd:
try:
zf = zipfile.ZipFile(fd)
- pf = zf.open('thumbnails/Thumbnail.png', 'r')
+ pf = zf.open("thumbnails/Thumbnail.png", "r")
data = pf.read()
pf.close()
return data
@@ -368,55 +426,58 @@ class ToolBit(object):
def saveToFile(self, obj, path, setFile=True):
PathLog.track(path)
try:
- with open(path, 'w') as fp:
- json.dump(self.templateAttrs(obj), fp, indent=' ')
+ with open(path, "w") as fp:
+ json.dump(self.templateAttrs(obj), fp, indent=" ")
if setFile:
obj.File = path
return True
except (OSError, IOError) as e:
- PathLog.error("Could not save tool {} to {} ({})".format(obj.Label, path, e))
+ PathLog.error(
+ "Could not save tool {} to {} ({})".format(obj.Label, path, e)
+ )
raise
def templateAttrs(self, obj):
attrs = {}
- attrs['version'] = 2 # Path.Tool is version 1
- attrs['name'] = obj.Label
+ attrs["version"] = 2 # Path.Tool is version 1
+ attrs["name"] = obj.Label
if PathPreferences.toolsStoreAbsolutePaths():
- attrs['shape'] = obj.BitShape
+ attrs["shape"] = obj.BitShape
else:
# attrs['shape'] = findRelativePathShape(obj.BitShape)
# Extract the name of the shape file
- __, filShp = os.path.split(obj.BitShape) # __ is an ignored placeholder acknowledged by LGTM
- attrs['shape'] = str(filShp)
+ __, filShp = os.path.split(
+ obj.BitShape
+ ) # __ is an ignored placeholder acknowledged by LGTM
+ attrs["shape"] = str(filShp)
params = {}
for name in obj.BitPropertyNames:
params[name] = PathUtil.getPropertyValueString(obj, name)
- attrs['parameter'] = params
+ attrs["parameter"] = params
params = {}
- attrs['attribute'] = params
+ attrs["attribute"] = params
return attrs
def Declaration(path):
PathLog.track(path)
- with open(path, 'r') as fp:
+ with open(path, "r") as fp:
return json.load(fp)
class ToolBitFactory(object):
-
- def CreateFromAttrs(self, attrs, name='ToolBit', path=None):
+ def CreateFromAttrs(self, attrs, name="ToolBit", path=None):
PathLog.track(attrs, path)
- obj = Factory.Create(name, attrs['shape'], path)
- obj.Label = attrs['name']
- params = attrs['parameter']
+ obj = Factory.Create(name, attrs["shape"], path)
+ obj.Label = attrs["name"]
+ params = attrs["parameter"]
for prop in params:
PathUtil.setProperty(obj, prop, params[prop])
obj.Proxy._updateBitShape(obj)
obj.Proxy.unloadBitBody(obj)
return obj
- def CreateFrom(self, path, name='ToolBit'):
+ def CreateFrom(self, path, name="ToolBit"):
PathLog.track(name, path)
try:
data = Declaration(path)
@@ -426,9 +487,9 @@ class ToolBitFactory(object):
PathLog.error("%s not a valid tool file (%s)" % (path, e))
raise
- def Create(self, name='ToolBit', shapeFile=None, path=None):
+ def Create(self, name="ToolBit", shapeFile=None, path=None):
PathLog.track(name, shapeFile, path)
- obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', name)
+ obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
obj.Proxy = ToolBit(obj, shapeFile, path)
return obj
diff --git a/src/Mod/Path/PathScripts/PathToolBitCmd.py b/src/Mod/Path/PathScripts/PathToolBitCmd.py
index 31df9d5ba2..8a388b3552 100644
--- a/src/Mod/Path/PathScripts/PathToolBitCmd.py
+++ b/src/Mod/Path/PathScripts/PathToolBitCmd.py
@@ -20,25 +20,37 @@
# * *
# ***************************************************************************
+from PySide import QtCore
+from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD
import FreeCADGui
import PathScripts
+import PathScripts.PathLog as PathLog
import os
-from PySide import QtCore
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
+
class CommandToolBitCreate:
- '''
+ """
Command used to create a new Tool.
- '''
+ """
def __init__(self):
pass
def GetResources(self):
- return {'Pixmap': 'Path_ToolBit',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBit", "Create Tool"),
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBit", "Creates a new ToolBit object")}
+ return {
+ "Pixmap": "Path_ToolBit",
+ "MenuText": QT_TRANSLATE_NOOP("Path_ToolBitCreate", "Create Tool"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "Path_ToolBitCreate", "Creates a new ToolBit object"
+ ),
+ }
def IsActive(self):
return FreeCAD.ActiveDocument is not None
@@ -47,26 +59,33 @@ class CommandToolBitCreate:
obj = PathScripts.PathToolBit.Factory.Create()
obj.ViewObject.Proxy.setCreate(obj.ViewObject)
+
class CommandToolBitSave:
- '''
+ """
Command used to save an existing Tool to a file.
- '''
+ """
def __init__(self, saveAs):
self.saveAs = saveAs
def GetResources(self):
if self.saveAs:
- menuTxt = QtCore.QT_TRANSLATE_NOOP("PathToolBit", "Save Tool as...")
+ menuTxt = QT_TRANSLATE_NOOP("Path_ToolBitSaveAs", "Save Tool as...")
else:
- menuTxt = QtCore.QT_TRANSLATE_NOOP("PathToolBit", "Save Tool")
- return {'Pixmap': 'Path_ToolBit',
- 'MenuText': menuTxt,
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBit", "Save an existing ToolBit object to a file")}
+ menuTxt = QT_TRANSLATE_NOOP("Path_ToolBitSave", "Save Tool")
+ return {
+ "Pixmap": "Path_ToolBit",
+ "MenuText": menuTxt,
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "Path_ToolBitSave", "Save an existing ToolBit object to a file"
+ ),
+ }
def selectedTool(self):
sel = FreeCADGui.Selection.getSelectionEx()
- if 1 == len(sel) and isinstance(sel[0].Object.Proxy, PathScripts.PathToolBit.ToolBit):
+ if 1 == len(sel) and isinstance(
+ sel[0].Object.Proxy, PathScripts.PathToolBit.ToolBit
+ ):
return sel[0].Object
return None
@@ -80,6 +99,7 @@ class CommandToolBitSave:
def Activated(self):
from PySide import QtGui
+
tool = self.selectedTool()
if tool:
path = None
@@ -87,35 +107,47 @@ class CommandToolBitSave:
if tool.File:
fname = tool.File
else:
- fname = os.path.join(PathScripts.PathPreferences.lastPathToolBit(), tool.Label + '.fctb')
- foo = QtGui.QFileDialog.getSaveFileName(QtGui.QApplication.activeWindow(), "Tool", fname, "*.fctb")
+ fname = os.path.join(
+ PathScripts.PathPreferences.lastPathToolBit(),
+ tool.Label + ".fctb",
+ )
+ foo = QtGui.QFileDialog.getSaveFileName(
+ QtGui.QApplication.activeWindow(), "Tool", fname, "*.fctb"
+ )
if foo:
path = foo[0]
else:
path = tool.File
if path:
- if not path.endswith('.fctb'):
- path += '.fctb'
+ if not path.endswith(".fctb"):
+ path += ".fctb"
tool.Proxy.saveToFile(tool, path)
PathScripts.PathPreferences.setLastPathToolBit(os.path.dirname(path))
+
class CommandToolBitLoad:
- '''
+ """
Command used to load an existing Tool from a file into the current document.
- '''
+ """
def __init__(self):
pass
def GetResources(self):
- return {'Pixmap': 'Path_ToolBit',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBit", "Load Tool"),
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBit", "Load an existing ToolBit object from a file")}
+ return {
+ "Pixmap": "Path_ToolBit",
+ "MenuText": QT_TRANSLATE_NOOP("Path_ToolBitLoad", "Load Tool"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "Path_ToolBitLoad", "Load an existing ToolBit object from a file"
+ ),
+ }
def selectedTool(self):
sel = FreeCADGui.Selection.getSelectionEx()
- if 1 == len(sel) and isinstance(sel[0].Object.Proxy, PathScripts.PathToolBit.ToolBit):
+ if 1 == len(sel) and isinstance(
+ sel[0].Object.Proxy, PathScripts.PathToolBit.ToolBit
+ ):
return sel[0].Object
return None
@@ -126,12 +158,18 @@ class CommandToolBitLoad:
if PathScripts.PathToolBitGui.LoadTools():
FreeCAD.ActiveDocument.recompute()
-if FreeCAD.GuiUp:
- FreeCADGui.addCommand('Path_ToolBitCreate', CommandToolBitCreate())
- FreeCADGui.addCommand('Path_ToolBitLoad', CommandToolBitLoad())
- FreeCADGui.addCommand('Path_ToolBitSave', CommandToolBitSave(False))
- FreeCADGui.addCommand('Path_ToolBitSaveAs', CommandToolBitSave(True))
-CommandList = ['Path_ToolBitCreate', 'Path_ToolBitLoad', 'Path_ToolBitSave', 'Path_ToolBitSaveAs']
+if FreeCAD.GuiUp:
+ FreeCADGui.addCommand("Path_ToolBitCreate", CommandToolBitCreate())
+ FreeCADGui.addCommand("Path_ToolBitLoad", CommandToolBitLoad())
+ FreeCADGui.addCommand("Path_ToolBitSave", CommandToolBitSave(False))
+ FreeCADGui.addCommand("Path_ToolBitSaveAs", CommandToolBitSave(True))
+
+CommandList = [
+ "Path_ToolBitCreate",
+ "Path_ToolBitLoad",
+ "Path_ToolBitSave",
+ "Path_ToolBitSaveAs",
+]
FreeCAD.Console.PrintLog("Loading PathToolBitCmd... done\n")
diff --git a/src/Mod/Path/PathScripts/PathToolBitEdit.py b/src/Mod/Path/PathScripts/PathToolBitEdit.py
index 3028bd7bb1..9746f0e3bb 100644
--- a/src/Mod/Path/PathScripts/PathToolBitEdit.py
+++ b/src/Mod/Path/PathScripts/PathToolBitEdit.py
@@ -20,32 +20,30 @@
# * *
# ***************************************************************************
-import FreeCAD
+from PySide import QtCore, QtGui
import FreeCADGui
import PathScripts.PathGui as PathGui
import PathScripts.PathLog as PathLog
import PathScripts.PathPreferences as PathPreferences
import PathScripts.PathPropertyEditor as PathPropertyEditor
-import PathScripts.PathToolBit as PathToolBit
import PathScripts.PathUtil as PathUtil
import os
import re
-from PySide import QtCore, QtGui
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-# PathLog.trackModule(PathLog.thisModule())
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-# Qt translation handling
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
-
class _Delegate(QtGui.QStyledItemDelegate):
- '''Handles the creation of an appropriate editing widget for a given property.'''
- ObjectRole = QtCore.Qt.UserRole + 1
+ """Handles the creation of an appropriate editing widget for a given property."""
+
+ ObjectRole = QtCore.Qt.UserRole + 1
PropertyRole = QtCore.Qt.UserRole + 2
- EditorRole = QtCore.Qt.UserRole + 3
+ EditorRole = QtCore.Qt.UserRole + 3
def createEditor(self, parent, option, index):
editor = index.data(self.EditorRole)
@@ -64,14 +62,18 @@ class _Delegate(QtGui.QStyledItemDelegate):
# called to update the model with the data from the widget
editor = index.data(self.EditorRole)
editor.setModelData(widget)
- index.model().setData(index, PathUtil.getPropertyValueString(editor.obj, editor.prop), QtCore.Qt.DisplayRole)
+ index.model().setData(
+ index,
+ PathUtil.getPropertyValueString(editor.obj, editor.prop),
+ QtCore.Qt.DisplayRole,
+ )
class ToolBitEditor(object):
- '''UI and controller for editing a ToolBit.
+ """UI and controller for editing a ToolBit.
The controller embeds the UI to the parentWidget which has to have a
layout attached to it.
- '''
+ """
def __init__(self, tool, parentWidget=None, loadBitBody=True):
PathLog.track()
@@ -84,7 +86,7 @@ class ToolBitEditor(object):
self.tool = tool
self.loadbitbody = loadBitBody
if not tool.BitShape:
- self.tool.BitShape = 'endmill.fcstd'
+ self.tool.BitShape = "endmill.fcstd"
if self.loadbitbody:
self.tool.Proxy.loadBitBody(self.tool)
@@ -107,7 +109,7 @@ class ToolBitEditor(object):
# which aren't being needed anymore.
def labelText(name):
- return re.sub('([A-Z][a-z]+)', r' \1', re.sub('([A-Z]+)', r' \1', name))
+ return re.sub("([A-Z][a-z]+)", r" \1", re.sub("([A-Z]+)", r" \1", name))
layout = self.form.bitParams.layout()
ui = FreeCADGui.UiLoader()
@@ -125,12 +127,12 @@ class ToolBitEditor(object):
label.show()
qsb.show()
else:
- qsb = ui.createWidget('Gui::QuantitySpinBox')
+ qsb = ui.createWidget("Gui::QuantitySpinBox")
editor = PathGui.QuantitySpinBox(qsb, tool, name)
- label = QtGui.QLabel(labelText(name))
+ label = QtGui.QLabel(labelText(name))
self.widgets.append((label, qsb, editor))
PathLog.debug("create row: {} [{}] {}".format(nr, name, type(qsb)))
- if hasattr(qsb, 'editingFinished'):
+ if hasattr(qsb, "editingFinished"):
qsb.editingFinished.connect(self.updateTool)
if nr >= layout.rowCount():
@@ -156,10 +158,10 @@ class ToolBitEditor(object):
PathLog.track()
setup = True
- if not hasattr(self, 'delegate'):
+ if not hasattr(self, "delegate"):
self.delegate = _Delegate(self.form.attrTree)
self.model = QtGui.QStandardItemModel(self.form.attrTree)
- self.model.setHorizontalHeaderLabels(['Property', 'Value'])
+ self.model.setHorizontalHeaderLabels(["Property", "Value"])
else:
self.model.removeRows(0, self.model.rowCount())
setup = False
@@ -175,21 +177,22 @@ class ToolBitEditor(object):
label.setEditable(False)
value = QtGui.QStandardItem()
- value.setData(PathUtil.getPropertyValueString(tool, prop), QtCore.Qt.DisplayRole)
+ value.setData(
+ PathUtil.getPropertyValueString(tool, prop), QtCore.Qt.DisplayRole
+ )
value.setData(tool, _Delegate.ObjectRole)
value.setData(prop, _Delegate.PropertyRole)
group.appendRow([label, value])
self.model.appendRow(group)
-
if setup:
self.form.attrTree.setModel(self.model)
self.form.attrTree.setItemDelegateForColumn(1, self.delegate)
self.form.attrTree.expandAll()
self.form.attrTree.resizeColumnToContents(0)
self.form.attrTree.resizeColumnToContents(1)
- #self.form.attrTree.collapseAll()
+ # self.form.attrTree.collapseAll()
def accept(self):
PathLog.track()
@@ -215,7 +218,7 @@ class ToolBitEditor(object):
# editors fires an event and tries to access its old property, which
# might not exist anymore.
for lbl, qsb, editor in self.widgets:
- editor.attachTo(self.tool, 'File')
+ editor.attachTo(self.tool, "File")
self.tool.BitShape = shapePath
self.setupTool(self.tool)
self.form.toolName.setText(self.tool.Label)
@@ -260,7 +263,9 @@ class ToolBitEditor(object):
path = self.tool.BitShape
if not path:
path = PathPreferences.lastPathToolShape()
- foo = QtGui.QFileDialog.getOpenFileName(self.form, "Path - Tool Shape", path, "*.fcstd")
+ foo = QtGui.QFileDialog.getOpenFileName(
+ self.form, "Path - Tool Shape", path, "*.fcstd"
+ )
if foo and foo[0]:
PathPreferences.setLastPathToolShape(os.path.dirname(foo[0]))
self.form.shapePath.setText(foo[0])
diff --git a/src/Mod/Path/PathScripts/PathToolBitGui.py b/src/Mod/Path/PathScripts/PathToolBitGui.py
index 62e8e0bfc1..bedb532070 100644
--- a/src/Mod/Path/PathScripts/PathToolBitGui.py
+++ b/src/Mod/Path/PathScripts/PathToolBitGui.py
@@ -20,6 +20,8 @@
# * *
# ***************************************************************************
+from PySide import QtCore, QtGui
+from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD
import FreeCADGui
import PathScripts.PathIconViewProvider as PathIconViewProvider
@@ -29,26 +31,24 @@ import PathScripts.PathToolBit as PathToolBit
import PathScripts.PathToolBitEdit as PathToolBitEdit
import os
-from PySide import QtCore, QtGui
-
__title__ = "Tool Bit UI"
__author__ = "sliptonic (Brad Collette)"
__url__ = "https://www.freecadweb.org"
__doc__ = "Task panel editor for a ToolBit"
-# Qt translation handling
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-# PathLog.trackModule(PathLog.thisModule())
+translate = FreeCAD.Qt.translate
class ViewProvider(object):
- '''ViewProvider for a ToolBit.
- It's sole job is to provide an icon and invoke the TaskPanel on edit.'''
+ """ViewProvider for a ToolBit.
+ It's sole job is to provide an icon and invoke the TaskPanel on edit."""
def __init__(self, vobj, name):
PathLog.track(name, vobj.Object)
@@ -67,9 +67,9 @@ class ViewProvider(object):
png = self.obj.Proxy.getBitThumbnail(self.obj)
if png:
pixmap = QtGui.QPixmap()
- pixmap.loadFromData(png, 'PNG')
+ pixmap.loadFromData(png, "PNG")
return QtGui.QIcon(pixmap)
- return ':/icons/Path_ToolBit.svg'
+ return ":/icons/Path_ToolBit.svg"
def __getstate__(self):
return None
@@ -84,7 +84,7 @@ class ViewProvider(object):
def getDisplayMode(self, mode):
# pylint: disable=unused-argument
- return 'Default'
+ return "Default"
def _openTaskPanel(self, vobj, deleteOnReject):
PathLog.track()
@@ -117,15 +117,16 @@ class ViewProvider(object):
if os.path.exists(vobj.Object.BitShape):
self.setEdit(vobj)
else:
- msg = translate('PathToolBit',
- 'Toolbit cannot be edited: Shapefile not found')
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Warning, 'Error', msg)
+ msg = translate(
+ "PathToolBit", "Toolbit cannot be edited: Shapefile not found"
+ )
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Warning, "Error", msg)
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
class TaskPanel:
- '''TaskPanel for the SetupSheet - if it is being edited directly.'''
+ """TaskPanel for the SetupSheet - if it is being edited directly."""
def __init__(self, vobj, deleteOnReject):
PathLog.track(vobj.Object.Label)
@@ -134,15 +135,14 @@ class TaskPanel:
self.editor = PathToolBitEdit.ToolBitEditor(self.obj)
self.form = self.editor.form
self.deleteOnReject = deleteOnReject
- FreeCAD.ActiveDocument.openTransaction(translate('PathToolBit',
- 'Edit ToolBit'))
+ FreeCAD.ActiveDocument.openTransaction("Edit ToolBit")
def reject(self):
FreeCAD.ActiveDocument.abortTransaction()
self.editor.reject()
FreeCADGui.Control.closeDialog()
if self.deleteOnReject:
- FreeCAD.ActiveDocument.openTransaction(translate('PathToolBit', 'Uncreate ToolBit'))
+ FreeCAD.ActiveDocument.openTransaction("Uncreate ToolBit")
self.editor.reject()
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
FreeCAD.ActiveDocument.commitTransaction()
@@ -169,18 +169,18 @@ class TaskPanel:
class ToolBitGuiFactory(PathToolBit.ToolBitFactory):
-
- def Create(self, name='ToolBit', shapeFile=None, path=None):
- '''Create(name = 'ToolBit') ... creates a new tool bit.
- It is assumed the tool will be edited immediately so the internal bit body is still attached.'''
+ def Create(self, name="ToolBit", shapeFile=None, path=None):
+ """Create(name = 'ToolBit') ... creates a new tool bit.
+ It is assumed the tool will be edited immediately so the internal bit body is still attached."""
PathLog.track(name, shapeFile, path)
- FreeCAD.ActiveDocument.openTransaction(translate('PathToolBit', 'Create ToolBit'))
+ FreeCAD.ActiveDocument.openTransaction("Create ToolBit")
tool = PathToolBit.ToolBitFactory.Create(self, name, shapeFile, path)
PathIconViewProvider.Attach(tool.ViewObject, name)
FreeCAD.ActiveDocument.commitTransaction()
return tool
+
def isValidFileName(filename):
print(filename)
try:
@@ -194,9 +194,9 @@ def GetNewToolFile(parent=None):
if parent is None:
parent = QtGui.QApplication.activeWindow()
- foo = QtGui.QFileDialog.getSaveFileName(parent, 'Tool',
- PathPreferences.lastPathToolBit(),
- '*.fctb')
+ foo = QtGui.QFileDialog.getSaveFileName(
+ parent, "Tool", PathPreferences.lastPathToolBit(), "*.fctb"
+ )
if foo and foo[0]:
if not isValidFileName(foo[0]):
msgBox = QtGui.QMessageBox()
@@ -212,9 +212,9 @@ def GetNewToolFile(parent=None):
def GetToolFile(parent=None):
if parent is None:
parent = QtGui.QApplication.activeWindow()
- foo = QtGui.QFileDialog.getOpenFileName(parent, 'Tool',
- PathPreferences.lastPathToolBit(),
- '*.fctb')
+ foo = QtGui.QFileDialog.getOpenFileName(
+ parent, "Tool", PathPreferences.lastPathToolBit(), "*.fctb"
+ )
if foo and foo[0]:
PathPreferences.setLastPathToolBit(os.path.dirname(foo[0]))
return foo[0]
@@ -224,9 +224,9 @@ def GetToolFile(parent=None):
def GetToolFiles(parent=None):
if parent is None:
parent = QtGui.QApplication.activeWindow()
- foo = QtGui.QFileDialog.getOpenFileNames(parent, 'Tool',
- PathPreferences.lastPathToolBit(),
- '*.fctb')
+ foo = QtGui.QFileDialog.getOpenFileNames(
+ parent, "Tool", PathPreferences.lastPathToolBit(), "*.fctb"
+ )
if foo and foo[0]:
PathPreferences.setLastPathToolBit(os.path.dirname(foo[0][0]))
return foo[0]
@@ -243,8 +243,9 @@ def GetToolShapeFile(parent=None):
elif not os.path.isdir(location):
location = PathPreferences.filePath()
- fname = QtGui.QFileDialog.getOpenFileName(parent, 'Select Tool Shape',
- location, '*.fcstd')
+ fname = QtGui.QFileDialog.getOpenFileName(
+ parent, "Select Tool Shape", location, "*.fcstd"
+ )
if fname and fname[0]:
if fname != location:
newloc = os.path.dirname(fname[0])
@@ -255,21 +256,21 @@ def GetToolShapeFile(parent=None):
def LoadTool(parent=None):
- '''
+ """
LoadTool(parent=None) ... Open a file dialog to load a tool from a file.
- '''
+ """
foo = GetToolFile(parent)
return PathToolBit.Factory.CreateFrom(foo) if foo else foo
def LoadTools(parent=None):
- '''
+ """
LoadTool(parent=None) ... Open a file dialog to load a tool from a file.
- '''
+ """
return [PathToolBit.Factory.CreateFrom(foo) for foo in GetToolFiles(parent)]
# Set the factory so all tools are created with UI
PathToolBit.Factory = ToolBitGuiFactory()
-PathIconViewProvider.RegisterViewProvider('ToolBit', ViewProvider)
+PathIconViewProvider.RegisterViewProvider("ToolBit", ViewProvider)
diff --git a/src/Mod/Path/PathScripts/PathToolBitLibraryCmd.py b/src/Mod/Path/PathScripts/PathToolBitLibraryCmd.py
index 5d03f72fe0..309f77d5e9 100644
--- a/src/Mod/Path/PathScripts/PathToolBitLibraryCmd.py
+++ b/src/Mod/Path/PathScripts/PathToolBitLibraryCmd.py
@@ -20,65 +20,83 @@
# * *
# ***************************************************************************
+from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD
import FreeCADGui
-import PySide.QtCore as QtCore
-import PathScripts.PathPreferences as PathPreferences
+import PathScripts.PathLog as PathLog
+
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
+
+translate = FreeCAD.Qt.translate
class CommandToolBitSelectorOpen:
- '''
+ """
Command to toggle the ToolBitSelector Dock
- '''
+ """
def __init__(self):
pass
def GetResources(self):
- return {'Pixmap': 'Path_ToolTable',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "ToolBit Dock"),
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Toggle the Toolbit Dock"),
- 'Accel': "P, T",
- 'CmdType': "ForEdit"}
+ return {
+ "Pixmap": "Path_ToolTable",
+ "MenuText": QT_TRANSLATE_NOOP("Path_ToolBitDock", "ToolBit Dock"),
+ "ToolTip": QT_TRANSLATE_NOOP("Path_ToolBitDock", "Toggle the Toolbit Dock"),
+ "Accel": "P, T",
+ "CmdType": "ForEdit",
+ }
def IsActive(self):
return FreeCAD.ActiveDocument is not None
def Activated(self):
import PathScripts.PathToolBitLibraryGui as PathToolBitLibraryGui
+
dock = PathToolBitLibraryGui.ToolBitSelector()
dock.open()
class CommandToolBitLibraryOpen:
- '''
+ """
Command to open ToolBitLibrary editor.
- '''
+ """
def __init__(self):
pass
def GetResources(self):
- return {'Pixmap': 'Path_ToolTable',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "ToolBit Library editor"),
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Open an editor to manage ToolBit libraries"),
- 'CmdType': "ForEdit"}
+ return {
+ "Pixmap": "Path_ToolTable",
+ "MenuText": QT_TRANSLATE_NOOP(
+ "Path_ToolBitLibraryOpen", "ToolBit Library editor"
+ ),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "Path_ToolBitLibraryOpen", "Open an editor to manage ToolBit libraries"
+ ),
+ "CmdType": "ForEdit",
+ }
def IsActive(self):
return FreeCAD.ActiveDocument is not None
def Activated(self):
import PathScripts.PathToolBitLibraryGui as PathToolBitLibraryGui
+
library = PathToolBitLibraryGui.ToolBitLibrary()
library.open()
if FreeCAD.GuiUp:
- FreeCADGui.addCommand('Path_ToolBitLibraryOpen', CommandToolBitLibraryOpen())
- FreeCADGui.addCommand('Path_ToolBitDock', CommandToolBitSelectorOpen())
+ FreeCADGui.addCommand("Path_ToolBitLibraryOpen", CommandToolBitLibraryOpen())
+ FreeCADGui.addCommand("Path_ToolBitDock", CommandToolBitSelectorOpen())
-BarList = ['Path_ToolBitDock']
-MenuList = ['Path_ToolBitLibraryOpen', 'Path_ToolBitDock']
+BarList = ["Path_ToolBitDock"]
+MenuList = ["Path_ToolBitLibraryOpen", "Path_ToolBitDock"]
FreeCAD.Console.PrintLog("Loading PathToolBitLibraryCmd... done\n")
diff --git a/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py b/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py
index 693d954c0c..0ab4308b21 100644
--- a/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py
+++ b/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py
@@ -24,7 +24,7 @@
import FreeCAD
import FreeCADGui
-import PathGui as PGui # ensure Path/Gui/Resources are loaded
+import PathGui as PGui # ensure Path/Gui/Resources are loaded
import PathScripts.PathLog as PathLog
import PathScripts.PathPreferences as PathPreferences
import PathScripts.PathToolBit as PathToolBit
@@ -42,15 +42,19 @@ import uuid as UUID
from functools import partial
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-# PathLog.trackModule(PathLog.thisModule())
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
+
_UuidRole = PySide.QtCore.Qt.UserRole + 1
_PathRole = PySide.QtCore.Qt.UserRole + 2
-def translate(context, text, disambig=None):
- return PySide.QtCore.QCoreApplication.translate(context, text, disambig)
+translate = FreeCAD.Qt.translate
+
def checkWorkingDir():
# users shouldn't use the example toolbits and libraries.
@@ -60,30 +64,37 @@ def checkWorkingDir():
workingdir = os.path.dirname(PathPreferences.lastPathToolLibrary())
defaultdir = os.path.dirname(PathPreferences.pathDefaultToolsPath())
- PathLog.debug('workingdir: {} defaultdir: {}'.format(workingdir, defaultdir))
+ PathLog.debug("workingdir: {} defaultdir: {}".format(workingdir, defaultdir))
- dirOK = lambda : workingdir != defaultdir and (os.access(workingdir, os.W_OK))
+ dirOK = lambda: workingdir != defaultdir and (os.access(workingdir, os.W_OK))
if dirOK():
return True
qm = PySide.QtGui.QMessageBox
- ret = qm.question(None,'', "Toolbit working directory not set up. Do that now?", qm.Yes | qm.No)
+ ret = qm.question(
+ None, "", "Toolbit working directory not set up. Do that now?", qm.Yes | qm.No
+ )
if ret == qm.No:
return False
- msg = translate("Path", "Choose a writable location for your toolbits", None)
+ msg = translate(
+ "Path_ToolBit", "Choose a writable location for your toolbits", None
+ )
while not dirOK():
- workingdir = PySide.QtGui.QFileDialog.getExistingDirectory(None, msg,
- PathPreferences.filePath())
+ workingdir = PySide.QtGui.QFileDialog.getExistingDirectory(
+ None, msg, PathPreferences.filePath()
+ )
- if workingdir[-8:] == os.path.sep + 'Library':
+ if workingdir[-8:] == os.path.sep + "Library":
workingdir = workingdir[:-8] # trim off trailing /Library if user chose it
- PathPreferences.setLastPathToolLibrary("{}{}Library".format(workingdir, os.path.sep))
+ PathPreferences.setLastPathToolLibrary(
+ "{}{}Library".format(workingdir, os.path.sep)
+ )
PathPreferences.setLastPathToolBit("{}{}Bit".format(workingdir, os.path.sep))
- PathLog.debug('setting workingdir to: {}'.format(workingdir))
+ PathLog.debug("setting workingdir to: {}".format(workingdir))
# Copy only files of default Path\Tools folder to working directory (targeting the README.md help file)
src_toolfiles = os.listdir(defaultdir)
@@ -94,7 +105,7 @@ def checkWorkingDir():
shutil.copy(full_file_name, workingdir)
# Determine which subdirectories are missing
- subdirlist = ['Bit', 'Library', 'Shape']
+ subdirlist = ["Bit", "Library", "Shape"]
mode = 0o777
for dir in subdirlist.copy():
subdir = "{}{}{}".format(workingdir, os.path.sep, dir)
@@ -103,9 +114,16 @@ def checkWorkingDir():
# Query user for creation permission of any missing subdirectories
if len(subdirlist) >= 1:
- needed = ', '.join([str(d) for d in subdirlist])
+ needed = ", ".join([str(d) for d in subdirlist])
qm = PySide.QtGui.QMessageBox
- ret = qm.question(None,'', "Toolbit Working directory {} needs these sudirectories:\n {} \n Create them?".format(workingdir, needed), qm.Yes | qm.No)
+ ret = qm.question(
+ None,
+ "",
+ "Toolbit Working directory {} needs these sudirectories:\n {} \n Create them?".format(
+ workingdir, needed
+ ),
+ qm.Yes | qm.No,
+ )
if ret == qm.No:
return False
@@ -115,27 +133,37 @@ def checkWorkingDir():
subdir = "{}{}{}".format(workingdir, os.path.sep, dir)
os.mkdir(subdir, mode)
# Query user to copy example files into subdirectories created
- if dir != 'Shape':
+ if dir != "Shape":
qm = PySide.QtGui.QMessageBox
- ret = qm.question(None,'', "Copy example files to new {} directory?".format(dir), qm.Yes | qm.No)
+ ret = qm.question(
+ None,
+ "",
+ "Copy example files to new {} directory?".format(dir),
+ qm.Yes | qm.No,
+ )
if ret == qm.Yes:
- src="{}{}{}".format(defaultdir, os.path.sep, dir)
+ src = "{}{}{}".format(defaultdir, os.path.sep, dir)
src_files = os.listdir(src)
for file_name in src_files:
full_file_name = os.path.join(src, file_name)
if os.path.isfile(full_file_name):
shutil.copy(full_file_name, subdir)
-
# if no library is set, choose the first one in the Library directory
if PathPreferences.lastFileToolLibrary() is None:
- libFiles = [f for f in glob.glob(PathPreferences.lastPathToolLibrary() + os.path.sep + '*.fctl')]
+ libFiles = [
+ f
+ for f in glob.glob(
+ PathPreferences.lastPathToolLibrary() + os.path.sep + "*.fctl"
+ )
+ ]
PathPreferences.setLastFileToolLibrary(libFiles[0])
return True
+
class _TableView(PySide.QtGui.QTableView):
- '''Subclass of QTableView to support rearrange and copying of ToolBits'''
+ """Subclass of QTableView to support rearrange and copying of ToolBits"""
def __init__(self, parent):
PySide.QtGui.QTableView.__init__(self, parent)
@@ -169,9 +197,15 @@ class _TableView(PySide.QtGui.QTableView):
for col in range(model.columnCount()):
srcItem = model.item(srcRow, col)
- model.setData(model.index(dstRow, col), srcItem.data(PySide.QtCore.Qt.EditRole), PySide.QtCore.Qt.EditRole)
+ model.setData(
+ model.index(dstRow, col),
+ srcItem.data(PySide.QtCore.Qt.EditRole),
+ PySide.QtCore.Qt.EditRole,
+ )
if col == 0:
- model.setData(model.index(dstRow, col), srcItem.data(_PathRole), _PathRole)
+ model.setData(
+ model.index(dstRow, col), srcItem.data(_PathRole), _PathRole
+ )
# Even a clone of a tool gets its own uuid so it can be identified when
# rearranging the order or inserting/deleting rows
model.setData(model.index(dstRow, col), UUID.uuid4(), _UuidRole)
@@ -185,7 +219,7 @@ class _TableView(PySide.QtGui.QTableView):
def dropEvent(self, event):
PathLog.track()
mime = event.mimeData()
- data = mime.data('application/x-qstandarditemmodeldatalist')
+ data = mime.data("application/x-qstandarditemmodeldatalist")
stream = PySide.QtCore.QDataStream(data)
srcRows = []
while not stream.atEnd():
@@ -205,8 +239,7 @@ class _TableView(PySide.QtGui.QTableView):
class ModelFactory(object):
- ''' Helper class to generate qtdata models for toolbit libraries
- '''
+ """Helper class to generate qtdata models for toolbit libraries"""
def __init__(self, path=None):
PathLog.track()
@@ -221,35 +254,37 @@ class ModelFactory(object):
with open(path) as fp:
library = json.load(fp)
- for toolBit in library['tools']:
+ for toolBit in library["tools"]:
try:
- nr = toolBit['nr']
- bit = PathToolBit.findToolBit(toolBit['path'], path)
+ nr = toolBit["nr"]
+ bit = PathToolBit.findToolBit(toolBit["path"], path)
if bit:
PathLog.track(bit)
tool = PathToolBit.Declaration(bit)
datamodel.appendRow(self._toolAdd(nr, tool, bit))
else:
- PathLog.error("Could not find tool #{}: {}".format(nr, toolBit['path']))
+ PathLog.error(
+ "Could not find tool #{}: {}".format(nr, toolBit["path"])
+ )
except Exception as e:
- msg = "Error loading tool: {} : {}".format(toolBit['path'], e)
+ msg = "Error loading tool: {} : {}".format(toolBit["path"], e)
FreeCAD.Console.PrintError(msg)
def _toolAdd(self, nr, tool, path):
- strShape = os.path.splitext(os.path.basename(tool['shape']))[0]
+ strShape = os.path.splitext(os.path.basename(tool["shape"]))[0]
# strDiam = tool['parameter']['Diameter']
tooltip = "{}".format(strShape)
toolNr = PySide.QtGui.QStandardItem()
toolNr.setData(nr, PySide.QtCore.Qt.EditRole)
- toolNr.setToolTip(tool['shape'])
+ toolNr.setToolTip(tool["shape"])
toolNr.setData(path, _PathRole)
toolNr.setData(UUID.uuid4(), _UuidRole)
toolNr.setToolTip(tooltip)
toolName = PySide.QtGui.QStandardItem()
- toolName.setData(tool['name'], PySide.QtCore.Qt.EditRole)
+ toolName.setData(tool["name"], PySide.QtCore.Qt.EditRole)
toolName.setEditable(False)
toolName.setToolTip(tooltip)
@@ -260,9 +295,9 @@ class ModelFactory(object):
return [toolNr, toolName, toolShape]
def newTool(self, datamodel, path):
- '''
+ """
Adds a toolbit item to a model
- '''
+ """
PathLog.track()
try:
@@ -278,15 +313,15 @@ class ModelFactory(object):
datamodel.appendRow(self._toolAdd(nr, tool, path))
def findLibraries(self, model):
- '''
+ """
Finds all the fctl files in a location
Returns a QStandardItemModel
- '''
+ """
PathLog.track()
path = PathPreferences.lastPathToolLibrary()
if os.path.isdir(path): # opening all tables in a directory
- libFiles = [f for f in glob.glob(path + os.path.sep + '*.fctl')]
+ libFiles = [f for f in glob.glob(path + os.path.sep + "*.fctl")]
libFiles.sort()
for libFile in libFiles:
loc, fnlong = os.path.split(libFile)
@@ -294,17 +329,17 @@ class ModelFactory(object):
libItem = PySide.QtGui.QStandardItem(fn)
libItem.setToolTip(loc)
libItem.setData(libFile, _PathRole)
- libItem.setIcon(PySide.QtGui.QPixmap(':/icons/Path_ToolTable.svg'))
+ libItem.setIcon(PySide.QtGui.QPixmap(":/icons/Path_ToolTable.svg"))
model.appendRow(libItem)
- PathLog.debug('model rows: {}'.format(model.rowCount()))
+ PathLog.debug("model rows: {}".format(model.rowCount()))
return model
def libraryOpen(self, model, lib=""):
- '''
+ """
opens the tools in library
Returns a QStandardItemModel
- '''
+ """
PathLog.track(lib)
if lib == "":
@@ -316,23 +351,23 @@ class ModelFactory(object):
if os.path.isfile(lib): # An individual library is wanted
self.__libraryLoad(lib, model)
- PathLog.debug('model rows: {}'.format(model.rowCount()))
+ PathLog.debug("model rows: {}".format(model.rowCount()))
return model
class ToolBitSelector(object):
- '''Controller for displaying a library and creating ToolControllers'''
+ """Controller for displaying a library and creating ToolControllers"""
def __init__(self):
checkWorkingDir()
- self.form = FreeCADGui.PySideUic.loadUi(':/panels/ToolBitSelector.ui')
+ self.form = FreeCADGui.PySideUic.loadUi(":/panels/ToolBitSelector.ui")
self.factory = ModelFactory()
self.toolModel = PySide.QtGui.QStandardItemModel(0, len(self.columnNames()))
self.setupUI()
self.title = self.form.windowTitle()
def columnNames(self):
- return ['#', 'Tool']
+ return ["#", "Tool"]
def currentLibrary(self, shortNameOnly):
libfile = PathPreferences.lastFileToolLibrary()
@@ -357,14 +392,19 @@ class ToolBitSelector(object):
self.loadData()
self.form.tools.setModel(self.toolModel)
self.form.tools.selectionModel().selectionChanged.connect(self.enableButtons)
- self.form.tools.doubleClicked.connect(partial(self.selectedOrAllToolControllers))
+ self.form.tools.doubleClicked.connect(
+ partial(self.selectedOrAllToolControllers)
+ )
self.form.libraryEditorOpen.clicked.connect(self.libraryEditorOpen)
self.form.addToolController.clicked.connect(self.selectedOrAllToolControllers)
def enableButtons(self):
- selected = (len(self.form.tools.selectedIndexes()) >= 1)
+ selected = len(self.form.tools.selectedIndexes()) >= 1
if selected:
- jobs = len([1 for j in FreeCAD.ActiveDocument.Objects if j.Name[:3] == "Job"]) >= 1
+ jobs = (
+ len([1 for j in FreeCAD.ActiveDocument.Objects if j.Name[:3] == "Job"])
+ >= 1
+ )
self.form.addToolController.setEnabled(selected and jobs)
def libraryEditorOpen(self):
@@ -373,17 +413,17 @@ class ToolBitSelector(object):
self.loadData()
def selectedOrAllTools(self):
- '''
+ """
Iterate the selection and add individual tools
If a group is selected, iterate and add children
- '''
+ """
itemsToProcess = []
for index in self.form.tools.selectedIndexes():
item = index.model().itemFromIndex(index)
if item.hasChildren():
- for i in range(item.rowCount()-1):
+ for i in range(item.rowCount() - 1):
if item.child(i).column() == 0:
itemsToProcess.append(item.child(i))
@@ -398,10 +438,10 @@ class ToolBitSelector(object):
return tools
def selectedOrAllToolControllers(self, index=None):
- '''
+ """
if no jobs, don't do anything, otherwise all TCs for all
selected toolbits
- '''
+ """
jobs = PathUtilsGui.PathUtils.GetJobs()
if len(jobs) == 0:
return
@@ -417,12 +457,14 @@ class ToolBitSelector(object):
tools = self.selectedOrAllTools()
for tool in tools:
- tc = PathToolControllerGui.Create("TC: {}".format(tool[1].Label), tool[1], tool[0])
+ tc = PathToolControllerGui.Create(
+ "TC: {}".format(tool[1].Label), tool[1], tool[0]
+ )
job.Proxy.addToolController(tc)
FreeCAD.ActiveDocument.recompute()
def open(self, path=None):
- ''' load library stored in path and bring up ui'''
+ """load library stored in path and bring up ui"""
docs = FreeCADGui.getMainWindow().findChildren(PySide.QtGui.QDockWidget)
for doc in docs:
if doc.objectName() == "ToolSelector":
@@ -434,13 +476,16 @@ class ToolBitSelector(object):
return
mw = FreeCADGui.getMainWindow()
- mw.addDockWidget(PySide.QtCore.Qt.RightDockWidgetArea, self.form,
- PySide.QtCore.Qt.Orientation.Vertical)
+ mw.addDockWidget(
+ PySide.QtCore.Qt.RightDockWidgetArea,
+ self.form,
+ PySide.QtCore.Qt.Orientation.Vertical,
+ )
class ToolBitLibrary(object):
- '''ToolBitLibrary is the controller for
- displaying/selecting/creating/editing a collection of ToolBits.'''
+ """ToolBitLibrary is the controller for
+ displaying/selecting/creating/editing a collection of ToolBits."""
def __init__(self):
PathLog.track()
@@ -449,9 +494,11 @@ class ToolBitLibrary(object):
self.temptool = None
self.toolModel = PySide.QtGui.QStandardItemModel(0, len(self.columnNames()))
self.listModel = PySide.QtGui.QStandardItemModel()
- self.form = FreeCADGui.PySideUic.loadUi(':/panels/ToolBitLibraryEdit.ui')
+ self.form = FreeCADGui.PySideUic.loadUi(":/panels/ToolBitLibraryEdit.ui")
self.toolTableView = _TableView(self.form.toolTableGroup)
- self.form.toolTableGroup.layout().replaceWidget(self.form.toolTable, self.toolTableView)
+ self.form.toolTableGroup.layout().replaceWidget(
+ self.form.toolTable, self.toolTableView
+ )
self.form.toolTable.hide()
self.setupUI()
self.title = self.form.windowTitle()
@@ -503,7 +550,9 @@ class ToolBitLibrary(object):
def toolDelete(self):
PathLog.track()
- selectedRows = set([index.row() for index in self.toolTableView.selectedIndexes()])
+ selectedRows = set(
+ [index.row() for index in self.toolTableView.selectedIndexes()]
+ )
for row in sorted(list(selectedRows), key=lambda r: -r):
self.toolModel.removeRows(row, 1)
@@ -512,7 +561,7 @@ class ToolBitLibrary(object):
self.form.toolDelete.setEnabled(sel)
def tableSelected(self, index):
- ''' loads the tools for the selected tool table '''
+ """loads the tools for the selected tool table"""
PathLog.track()
item = index.model().itemFromIndex(index)
libpath = item.data(_PathRole)
@@ -525,7 +574,9 @@ class ToolBitLibrary(object):
def libraryPath(self):
PathLog.track()
- path = PySide.QtGui.QFileDialog.getExistingDirectory(self.form, 'Tool Library Path', PathPreferences.lastPathToolLibrary())
+ path = PySide.QtGui.QFileDialog.getExistingDirectory(
+ self.form, "Tool Library Path", PathPreferences.lastPathToolLibrary()
+ )
if len(path) == 0:
return
@@ -588,10 +639,14 @@ class ToolBitLibrary(object):
pass
else:
tbpath = item.data(_PathRole)
- self.temptool = PathToolBit.ToolBitFactory().CreateFrom(tbpath, 'temptool')
- self.editor = PathToolBitEdit.ToolBitEditor(self.temptool, self.form.toolTableGroup, loadBitBody=False)
+ self.temptool = PathToolBit.ToolBitFactory().CreateFrom(tbpath, "temptool")
+ self.editor = PathToolBitEdit.ToolBitEditor(
+ self.temptool, self.form.toolTableGroup, loadBitBody=False
+ )
- QBtn = PySide.QtGui.QDialogButtonBox.Ok | PySide.QtGui.QDialogButtonBox.Cancel
+ QBtn = (
+ PySide.QtGui.QDialogButtonBox.Ok | PySide.QtGui.QDialogButtonBox.Cancel
+ )
buttonBox = PySide.QtGui.QDialogButtonBox(QBtn)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
@@ -603,24 +658,31 @@ class ToolBitLibrary(object):
def toolEditDone(self, success=True):
FreeCAD.ActiveDocument.removeObject("temptool")
- print('all done')
+ print("all done")
def libraryNew(self):
- TooltableTypeJSON = translate("PathToolLibraryManager", "Tooltable JSON (*.fctl)")
+ TooltableTypeJSON = translate("Path_ToolBit", "Tooltable JSON (*.fctl)")
- filename = PySide.QtGui.QFileDialog.getSaveFileName(self.form,
- translate("TooltableEditor", "Save toolbit library", None),
- PathPreferences.lastPathToolLibrary(), "{}".format(TooltableTypeJSON))
+ filename = PySide.QtGui.QFileDialog.getSaveFileName(
+ self.form,
+ translate("Path_ToolBit", "Save toolbit library", None),
+ PathPreferences.lastPathToolLibrary(),
+ "{}".format(TooltableTypeJSON),
+ )
if not (filename and filename[0]):
self.loadData()
- path = filename[0] if filename[0].endswith('.fctl') else "{}.fctl".format(filename[0])
+ path = (
+ filename[0]
+ if filename[0].endswith(".fctl")
+ else "{}.fctl".format(filename[0])
+ )
library = {}
tools = []
- library['version'] = 1
- library['tools'] = tools
- with open(path, 'w') as fp:
+ library["version"] = 1
+ library["tools"] = tools
+ with open(path, "w") as fp:
json.dump(library, fp, sort_keys=True, indent=2)
self.loadData()
@@ -628,22 +690,26 @@ class ToolBitLibrary(object):
def librarySave(self):
library = {}
tools = []
- library['version'] = 1
- library['tools'] = tools
+ library["version"] = 1
+ library["tools"] = tools
for row in range(self.toolModel.rowCount()):
- toolNr = self.toolModel.data(self.toolModel.index(row, 0), PySide.QtCore.Qt.EditRole)
+ toolNr = self.toolModel.data(
+ self.toolModel.index(row, 0), PySide.QtCore.Qt.EditRole
+ )
toolPath = self.toolModel.data(self.toolModel.index(row, 0), _PathRole)
if PathPreferences.toolsStoreAbsolutePaths():
bitPath = toolPath
else:
# bitPath = PathToolBit.findRelativePathTool(toolPath)
# Extract the name of the shape file
- __, filShp = os.path.split(toolPath) # __ is an ignored placeholder acknowledged by LGTM
+ __, filShp = os.path.split(
+ toolPath
+ ) # __ is an ignored placeholder acknowledged by LGTM
bitPath = str(filShp)
- tools.append({'nr': toolNr, 'path': bitPath})
+ tools.append({"nr": toolNr, "path": bitPath})
if self.path is not None:
- with open(self.path, 'w') as fp:
+ with open(self.path, "w") as fp:
json.dump(library, fp, sort_keys=True, indent=2)
def libraryOk(self):
@@ -658,7 +724,7 @@ class ToolBitLibrary(object):
return lib, loc
def columnNames(self):
- return ['Nr', 'Tool', 'Shape']
+ return ["Nr", "Tool", "Shape"]
def loadData(self, path=None):
PathLog.track(path)
@@ -680,7 +746,7 @@ class ToolBitLibrary(object):
self.path = path
self.form.setWindowTitle("{}".format(PathPreferences.lastPathToolLibrary()))
self.toolModel.setHorizontalHeaderLabels(self.columnNames())
- self.listModel.setHorizontalHeaderLabels(['Library'])
+ self.listModel.setHorizontalHeaderLabels(["Library"])
# Select the current library in the list of tables
curIndex = None
@@ -723,19 +789,29 @@ class ToolBitLibrary(object):
def librarySaveAs(self, path):
- TooltableTypeJSON = translate("PathToolLibraryManager", "Tooltable JSON (*.fctl)")
- TooltableTypeLinuxCNC = translate("PathToolLibraryManager", "LinuxCNC tooltable (*.tbl)")
+ TooltableTypeJSON = translate("Path_ToolBit", "Tooltable JSON (*.fctl)")
+ TooltableTypeLinuxCNC = translate("Path_ToolBit", "LinuxCNC tooltable (*.tbl)")
- filename = PySide.QtGui.QFileDialog.getSaveFileName(self.form,
- translate("TooltableEditor", "Save toolbit library", None),
- PathPreferences.lastPathToolLibrary(), "{};;{}".format(TooltableTypeJSON,
- TooltableTypeLinuxCNC))
+ filename = PySide.QtGui.QFileDialog.getSaveFileName(
+ self.form,
+ translate("Path_ToolBit", "Save toolbit library", None),
+ PathPreferences.lastPathToolLibrary(),
+ "{};;{}".format(TooltableTypeJSON, TooltableTypeLinuxCNC),
+ )
if filename and filename[0]:
if filename[1] == TooltableTypeLinuxCNC:
- path = filename[0] if filename[0].endswith('.tbl') else "{}.tbl".format(filename[0])
+ path = (
+ filename[0]
+ if filename[0].endswith(".tbl")
+ else "{}.tbl".format(filename[0])
+ )
self.libararySaveLinuxCNC(path)
else:
- path = filename[0] if filename[0].endswith('.fctl') else "{}.fctl".format(filename[0])
+ path = (
+ filename[0]
+ if filename[0].endswith(".fctl")
+ else "{}.fctl".format(filename[0])
+ )
self.path = path
self.librarySave()
self.updateToolbar()
@@ -743,11 +819,13 @@ class ToolBitLibrary(object):
def libararySaveLinuxCNC(self, path):
# linuxcnc line template
LIN = "T{} P{} X{} Y{} Z{} A{} B{} C{} U{} V{} W{} D{} I{} J{} Q{}; {}"
- with open(path, 'w') as fp:
+ with open(path, "w") as fp:
fp.write(";\n")
for row in range(self.toolModel.rowCount()):
- toolNr = self.toolModel.data(self.toolModel.index(row, 0), PySide.QtCore.Qt.EditRole)
+ toolNr = self.toolModel.data(
+ self.toolModel.index(row, 0), PySide.QtCore.Qt.EditRole
+ )
toolPath = self.toolModel.data(self.toolModel.index(row, 0), _PathRole)
bit = PathToolBit.Factory.CreateFrom(toolPath)
@@ -765,16 +843,39 @@ class ToolBitLibrary(object):
voffset = bit.Voffset if hasattr(bit, "Voffset") else "0"
woffset = bit.Woffset if hasattr(bit, "Woffset") else "0"
- diameter = bit.Diameter.getUserPreferred()[0].split()[0] if hasattr(bit, "Diameter") else "0"
+ diameter = (
+ bit.Diameter.getUserPreferred()[0].split()[0]
+ if hasattr(bit, "Diameter")
+ else "0"
+ )
frontangle = bit.FrontAngle if hasattr(bit, "FrontAngle") else "0"
backangle = bit.BackAngle if hasattr(bit, "BackAngle") else "0"
- orientation = bit.Orientation if hasattr(bit, "Orientation") else "0"
+ orientation = (
+ bit.Orientation if hasattr(bit, "Orientation") else "0"
+ )
remark = bit.Label
- fp.write(LIN.format(toolNr, pocket, xoffset, yoffset,
- zoffset, aoffset, boffset, coffset, uoffset,
- voffset, woffset, diameter, frontangle, backangle,
- orientation, remark) + "\n")
+ fp.write(
+ LIN.format(
+ toolNr,
+ pocket,
+ xoffset,
+ yoffset,
+ zoffset,
+ aoffset,
+ boffset,
+ coffset,
+ uoffset,
+ voffset,
+ woffset,
+ diameter,
+ frontangle,
+ backangle,
+ orientation,
+ remark,
+ )
+ + "\n"
+ )
FreeCAD.ActiveDocument.removeObject(bit.Name)
diff --git a/src/Mod/Path/PathScripts/PathToolController.py b/src/Mod/Path/PathScripts/PathToolController.py
index 0a7633208d..5704fcfb87 100644
--- a/src/Mod/Path/PathScripts/PathToolController.py
+++ b/src/Mod/Path/PathScripts/PathToolController.py
@@ -20,78 +20,149 @@
# * *
# ***************************************************************************
-'''Tool Controller defines tool, spindle speed and feed rates for Path Operations'''
+"""Tool Controller defines tool, spindle speed and feed rates for Path Operations"""
+from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD
import Path
import PathScripts.PathLog as PathLog
import PathScripts.PathPreferences as PathPreferences
import PathScripts.PathToolBit as PathToolBit
-from PySide import QtCore
-# PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
-# PathLog.trackModule(PathLog.thisModule())
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-
-# Qt translation handling
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
+translate = FreeCAD.Qt.translate
class ToolControllerTemplate:
- '''Attribute and sub element strings for template export/import.'''
+ """Attribute and sub element strings for template export/import."""
- Expressions = 'xengine'
- ExprExpr = 'expr'
- ExprProp = 'prop'
- HorizFeed = 'hfeed'
- HorizRapid = 'hrapid'
- Label = 'label'
- Name = 'name'
- SpindleDir = 'dir'
- SpindleSpeed = 'speed'
- ToolNumber = 'nr'
- Tool = 'tool'
- Version = 'version'
- VertFeed = 'vfeed'
- VertRapid = 'vrapid'
+ Expressions = "xengine"
+ ExprExpr = "expr"
+ ExprProp = "prop"
+ HorizFeed = "hfeed"
+ HorizRapid = "hrapid"
+ Label = "label"
+ Name = "name"
+ SpindleDir = "dir"
+ SpindleSpeed = "speed"
+ ToolNumber = "nr"
+ Tool = "tool"
+ Version = "version"
+ VertFeed = "vfeed"
+ VertRapid = "vrapid"
class ToolController:
-
def __init__(self, obj, legacyTool=False, createTool=True):
- PathLog.track('tool: {}'.format(legacyTool))
+ PathLog.track("tool: {}".format(legacyTool))
- obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", QtCore.QT_TRANSLATE_NOOP("PathToolController", "The active tool"))
+ obj.addProperty(
+ "App::PropertyIntegerConstraint",
+ "ToolNumber",
+ "Tool",
+ QT_TRANSLATE_NOOP("App::Property", "The active tool"),
+ )
obj.ToolNumber = (0, 0, 10000, 1)
- obj.addProperty("App::PropertyFloat", "SpindleSpeed", "Tool", QtCore.QT_TRANSLATE_NOOP("PathToolController", "The speed of the cutting spindle in RPM"))
- obj.addProperty("App::PropertyEnumeration", "SpindleDir", "Tool", QtCore.QT_TRANSLATE_NOOP("PathToolController", "Direction of spindle rotation"))
- obj.SpindleDir = ['Forward', 'Reverse']
- obj.addProperty("App::PropertySpeed", "VertFeed", "Feed", QtCore.QT_TRANSLATE_NOOP("PathToolController", "Feed rate for vertical moves in Z"))
- obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed", QtCore.QT_TRANSLATE_NOOP("PathToolController", "Feed rate for horizontal moves"))
- obj.addProperty("App::PropertySpeed", "VertRapid", "Rapid", QtCore.QT_TRANSLATE_NOOP("PathToolController", "Rapid rate for vertical moves in Z"))
- obj.addProperty("App::PropertySpeed", "HorizRapid", "Rapid", QtCore.QT_TRANSLATE_NOOP("PathToolController", "Rapid rate for horizontal moves"))
- obj.setEditorMode('Placement', 2)
+ obj.addProperty(
+ "App::PropertyFloat",
+ "SpindleSpeed",
+ "Tool",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "The speed of the cutting spindle in RPM"
+ ),
+ )
+ obj.addProperty(
+ "App::PropertyEnumeration",
+ "SpindleDir",
+ "Tool",
+ QT_TRANSLATE_NOOP("App::Property", "Direction of spindle rotation"),
+ )
+ obj.addProperty(
+ "App::PropertySpeed",
+ "VertFeed",
+ "Feed",
+ QT_TRANSLATE_NOOP("App::Property", "Feed rate for vertical moves in Z"),
+ )
+ obj.addProperty(
+ "App::PropertySpeed",
+ "HorizFeed",
+ "Feed",
+ QT_TRANSLATE_NOOP("App::Property", "Feed rate for horizontal moves"),
+ )
+ obj.addProperty(
+ "App::PropertySpeed",
+ "VertRapid",
+ "Rapid",
+ QT_TRANSLATE_NOOP("App::Property", "Rapid rate for vertical moves in Z"),
+ )
+ obj.addProperty(
+ "App::PropertySpeed",
+ "HorizRapid",
+ "Rapid",
+ QT_TRANSLATE_NOOP("App::Property", "Rapid rate for horizontal moves"),
+ )
+ obj.setEditorMode("Placement", 2)
+
+ for n in self.propertyEnumerations():
+ setattr(obj, n[0], n[1])
if createTool:
self.ensureUseLegacyTool(obj, legacyTool)
+ @classmethod
+ def propertyEnumerations(self, dataType="data"):
+ """helixOpPropertyEnumerations(dataType="data")... return property enumeration lists of specified dataType.
+ Args:
+ dataType = 'data', 'raw', 'translated'
+ Notes:
+ 'data' is list of internal string literals used in code
+ 'raw' is list of (translated_text, data_string) tuples
+ 'translated' is list of translated string literals
+ """
+
+ # Enumeration lists for App::PropertyEnumeration properties
+ enums = {
+ "SpindleDir": [
+ (translate("Path_ToolController", "Forward"), "Forward"),
+ (translate("Path_ToolController", "Reverse"), "Reverse"),
+ ], # this is the direction that the profile runs
+ }
+
+ if dataType == "raw":
+ return enums
+
+ data = list()
+ idx = 0 if dataType == "translated" else 1
+
+ PathLog.debug(enums)
+
+ for k, v in enumerate(enums):
+ data.append((v, [tup[idx] for tup in enums[v]]))
+ PathLog.debug(data)
+
+ return data
+
def onDocumentRestored(self, obj):
- obj.setEditorMode('Placement', 2)
+ obj.setEditorMode("Placement", 2)
def onDelete(self, obj, arg2=None):
# pylint: disable=unused-argument
if not self.usesLegacyTool(obj):
- if hasattr(obj.Tool, 'InList') and len(obj.Tool.InList) == 1:
- if hasattr(obj.Tool.Proxy, 'onDelete'):
+ if hasattr(obj.Tool, "InList") and len(obj.Tool.InList) == 1:
+ if hasattr(obj.Tool.Proxy, "onDelete"):
obj.Tool.Proxy.onDelete(obj.Tool)
def setFromTemplate(self, obj, template):
- '''
+ """
setFromTemplate(obj, xmlItem) ... extract properties from xmlItem
and assign to receiver.
- '''
+ """
PathLog.track(obj.Name, template)
version = 0
if template.get(ToolControllerTemplate.Version):
@@ -108,51 +179,79 @@ class ToolController:
if template.get(ToolControllerTemplate.HorizRapid):
obj.HorizRapid = template.get(ToolControllerTemplate.HorizRapid)
if template.get(ToolControllerTemplate.SpindleSpeed):
- obj.SpindleSpeed = float(template.get(ToolControllerTemplate.SpindleSpeed))
+ obj.SpindleSpeed = float(
+ template.get(ToolControllerTemplate.SpindleSpeed)
+ )
if template.get(ToolControllerTemplate.SpindleDir):
obj.SpindleDir = template.get(ToolControllerTemplate.SpindleDir)
if template.get(ToolControllerTemplate.ToolNumber):
- obj.ToolNumber = int(template.get(ToolControllerTemplate.ToolNumber))
+ obj.ToolNumber = int(
+ template.get(ToolControllerTemplate.ToolNumber)
+ )
if template.get(ToolControllerTemplate.Tool):
- toolVersion = template.get(ToolControllerTemplate.Tool).get(ToolControllerTemplate.Version)
+ toolVersion = template.get(ToolControllerTemplate.Tool).get(
+ ToolControllerTemplate.Version
+ )
if toolVersion == 1:
self.ensureUseLegacyTool(obj, True)
- obj.Tool.setFromTemplate(template.get(ToolControllerTemplate.Tool))
+ obj.Tool.setFromTemplate(
+ template.get(ToolControllerTemplate.Tool)
+ )
else:
self.ensureUseLegacyTool(obj, False)
- obj.Tool = PathToolBit.Factory.CreateFromAttrs(template.get(ToolControllerTemplate.Tool))
- if obj.Tool and obj.Tool.ViewObject and obj.Tool.ViewObject.Visibility:
+ obj.Tool = PathToolBit.Factory.CreateFromAttrs(
+ template.get(ToolControllerTemplate.Tool)
+ )
+ if (
+ obj.Tool
+ and obj.Tool.ViewObject
+ and obj.Tool.ViewObject.Visibility
+ ):
obj.Tool.ViewObject.Visibility = False
if template.get(ToolControllerTemplate.Expressions):
for exprDef in template.get(ToolControllerTemplate.Expressions):
if exprDef[ToolControllerTemplate.ExprExpr]:
- obj.setExpression(exprDef[ToolControllerTemplate.ExprProp], exprDef[ToolControllerTemplate.ExprExpr])
+ obj.setExpression(
+ exprDef[ToolControllerTemplate.ExprProp],
+ exprDef[ToolControllerTemplate.ExprExpr],
+ )
else:
- PathLog.error(translate('PathToolController', "Unsupported PathToolController template version %s") % template.get(ToolControllerTemplate.Version))
+ PathLog.error(
+ "Unsupported PathToolController template version {}".format(
+ template.get(ToolControllerTemplate.Version)
+ )
+ )
else:
- PathLog.error(translate('PathToolController', 'PathToolController template has no version - corrupted template file?'))
+ PathLog.error(
+ "PathToolController template has no version - corrupted template file?"
+ )
def templateAttrs(self, obj):
- '''templateAttrs(obj) ... answer a dictionary with all properties that should be stored for a template.'''
+ """templateAttrs(obj) ... answer a dictionary with all properties that should be stored for a template."""
attrs = {}
- attrs[ToolControllerTemplate.Version] = 1
- attrs[ToolControllerTemplate.Name] = obj.Name
- attrs[ToolControllerTemplate.Label] = obj.Label
- attrs[ToolControllerTemplate.ToolNumber] = obj.ToolNumber
- attrs[ToolControllerTemplate.VertFeed] = ("%s" % (obj.VertFeed))
- attrs[ToolControllerTemplate.HorizFeed] = ("%s" % (obj.HorizFeed))
- attrs[ToolControllerTemplate.VertRapid] = ("%s" % (obj.VertRapid))
- attrs[ToolControllerTemplate.HorizRapid] = ("%s" % (obj.HorizRapid))
+ attrs[ToolControllerTemplate.Version] = 1
+ attrs[ToolControllerTemplate.Name] = obj.Name
+ attrs[ToolControllerTemplate.Label] = obj.Label
+ attrs[ToolControllerTemplate.ToolNumber] = obj.ToolNumber
+ attrs[ToolControllerTemplate.VertFeed] = "%s" % (obj.VertFeed)
+ attrs[ToolControllerTemplate.HorizFeed] = "%s" % (obj.HorizFeed)
+ attrs[ToolControllerTemplate.VertRapid] = "%s" % (obj.VertRapid)
+ attrs[ToolControllerTemplate.HorizRapid] = "%s" % (obj.HorizRapid)
attrs[ToolControllerTemplate.SpindleSpeed] = obj.SpindleSpeed
- attrs[ToolControllerTemplate.SpindleDir] = obj.SpindleDir
+ attrs[ToolControllerTemplate.SpindleDir] = obj.SpindleDir
if self.usesLegacyTool(obj):
- attrs[ToolControllerTemplate.Tool] = obj.Tool.templateAttrs()
+ attrs[ToolControllerTemplate.Tool] = obj.Tool.templateAttrs()
else:
- attrs[ToolControllerTemplate.Tool] = obj.Tool.Proxy.templateAttrs(obj.Tool)
+ attrs[ToolControllerTemplate.Tool] = obj.Tool.Proxy.templateAttrs(obj.Tool)
expressions = []
for expr in obj.ExpressionEngine:
- PathLog.debug('%s: %s' % (expr[0], expr[1]))
- expressions.append({ToolControllerTemplate.ExprProp: expr[0], ToolControllerTemplate.ExprExpr: expr[1]})
+ PathLog.debug("%s: %s" % (expr[0], expr[1]))
+ expressions.append(
+ {
+ ToolControllerTemplate.ExprProp: expr[0],
+ ToolControllerTemplate.ExprExpr: expr[1],
+ }
+ )
if expressions:
attrs[ToolControllerTemplate.Expressions] = expressions
return attrs
@@ -161,24 +260,23 @@ class ToolController:
PathLog.track()
commands = ""
- commands += "(" + obj.Label + ")"+'\n'
- commands += 'M6 T'+str(obj.ToolNumber)+'\n'
+ commands += "(" + obj.Label + ")" + "\n"
+ commands += "M6 T" + str(obj.ToolNumber) + "\n"
# If a toolbit is used, check to see if spindlepower is allowed.
# This is to prevent accidentally spinning the spindle with an
# unpowered tool like probe or dragknife
allowSpindlePower = True
- if (not isinstance(obj.Tool, Path.Tool) and
- hasattr(obj.Tool, "SpindlePower")):
- allowSpindlePower = obj.Tool.SpindlePower
+ if not isinstance(obj.Tool, Path.Tool) and hasattr(obj.Tool, "SpindlePower"):
+ allowSpindlePower = obj.Tool.SpindlePower
if allowSpindlePower:
- PathLog.debug('selected tool preventing spindle power')
- if obj.SpindleDir == 'Forward':
- commands += 'M3 S' + str(obj.SpindleSpeed) + '\n'
+ PathLog.debug("selected tool preventing spindle power")
+ if obj.SpindleDir == "Forward":
+ commands += "M3 S" + str(obj.SpindleSpeed) + "\n"
else:
- commands += 'M4 S' + str(obj.SpindleSpeed) + '\n'
+ commands += "M4 S" + str(obj.SpindleSpeed) + "\n"
if commands == "":
commands += "(No commands processed)"
@@ -189,32 +287,56 @@ class ToolController:
obj.ViewObject.Visibility = True
def getTool(self, obj):
- '''returns the tool associated with this tool controller'''
+ """returns the tool associated with this tool controller"""
PathLog.track()
return obj.Tool
def usesLegacyTool(self, obj):
- '''returns True if the tool being controlled is a legacy tool'''
+ """returns True if the tool being controlled is a legacy tool"""
return isinstance(obj.Tool, Path.Tool)
def ensureUseLegacyTool(self, obj, legacy):
- if not hasattr(obj, 'Tool') or (legacy != self.usesLegacyTool(obj)):
- if legacy and hasattr(obj, 'Tool') and len(obj.Tool.InList) == 1:
- if hasattr(obj.Tool.Proxy, 'onDelete'):
+ if not hasattr(obj, "Tool") or (legacy != self.usesLegacyTool(obj)):
+ if legacy and hasattr(obj, "Tool") and len(obj.Tool.InList) == 1:
+ if hasattr(obj.Tool.Proxy, "onDelete"):
obj.Tool.Proxy.onDelete(obj.Tool)
obj.Document.removeObject(obj.Tool.Name)
- if hasattr(obj, 'Tool'):
- obj.removeProperty('Tool')
+ if hasattr(obj, "Tool"):
+ obj.removeProperty("Tool")
if legacy:
- obj.addProperty("Path::PropertyTool", "Tool", "Base", QtCore.QT_TRANSLATE_NOOP("PathToolController", "The tool used by this controller"))
+ obj.addProperty(
+ "Path::PropertyTool",
+ "Tool",
+ "Base",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "The tool used by this controller"
+ ),
+ )
else:
- obj.addProperty("App::PropertyLink", "Tool", "Base", QtCore.QT_TRANSLATE_NOOP("PathToolController", "The tool used by this controller"))
+ obj.addProperty(
+ "App::PropertyLink",
+ "Tool",
+ "Base",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "The tool used by this controller"
+ ),
+ )
-def Create(name='TC: Default Tool', tool=None, toolNumber=1, assignViewProvider=True, assignTool=True):
- legacyTool = PathPreferences.toolsUseLegacyTools() if tool is None else isinstance(tool, Path.Tool)
+def Create(
+ name="TC: Default Tool",
+ tool=None,
+ toolNumber=1,
+ assignViewProvider=True,
+ assignTool=True,
+):
+ legacyTool = (
+ PathPreferences.toolsUseLegacyTools()
+ if tool is None
+ else isinstance(tool, Path.Tool)
+ )
PathLog.track(tool, toolNumber, legacyTool)
diff --git a/src/Mod/Path/PathScripts/PathToolControllerGui.py b/src/Mod/Path/PathScripts/PathToolControllerGui.py
index 905888026e..91595b9168 100644
--- a/src/Mod/Path/PathScripts/PathToolControllerGui.py
+++ b/src/Mod/Path/PathScripts/PathToolControllerGui.py
@@ -20,45 +20,50 @@
# * *
# ***************************************************************************
+from PySide import QtCore, QtGui
+from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD
import FreeCADGui
-import PathGui as PGui # ensure Path/Gui/Resources are loaded
+import PathGui as PGui # ensure Path/Gui/Resources are loaded
import PathScripts
import PathScripts.PathGui as PathGui
import PathScripts.PathLog as PathLog
import PathScripts.PathToolBitGui as PathToolBitGui
import PathScripts.PathToolEdit as PathToolEdit
import PathScripts.PathUtil as PathUtil
-
-from PySide import QtCore, QtGui
+import PathScripts.PathToolController as PathToolController
# lazily loaded modules
from lazy_loader.lazy_loader import LazyLoader
-Part = LazyLoader('Part', globals(), 'Part')
+
+Part = LazyLoader("Part", globals(), "Part")
-# Qt translation handling
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
+
+translate = FreeCAD.Qt.translate
class ViewProvider:
-
def __init__(self, vobj):
vobj.Proxy = self
self.vobj = vobj
def attach(self, vobj):
mode = 2
- vobj.setEditorMode('LineWidth', mode)
- vobj.setEditorMode('MarkerColor', mode)
- vobj.setEditorMode('NormalColor', mode)
- vobj.setEditorMode('DisplayMode', mode)
- vobj.setEditorMode('BoundingBox', mode)
- vobj.setEditorMode('Selectable', mode)
- vobj.setEditorMode('ShapeColor', mode)
- vobj.setEditorMode('Transparency', mode)
- vobj.setEditorMode('Visibility', mode)
+ vobj.setEditorMode("LineWidth", mode)
+ vobj.setEditorMode("MarkerColor", mode)
+ vobj.setEditorMode("NormalColor", mode)
+ vobj.setEditorMode("DisplayMode", mode)
+ vobj.setEditorMode("BoundingBox", mode)
+ vobj.setEditorMode("Selectable", mode)
+ vobj.setEditorMode("ShapeColor", mode)
+ vobj.setEditorMode("Transparency", mode)
+ vobj.setEditorMode("Visibility", mode)
self.vobj = vobj
def __getstate__(self):
@@ -73,12 +78,12 @@ class ViewProvider:
def onChanged(self, vobj, prop):
# pylint: disable=unused-argument
mode = 2
- vobj.setEditorMode('LineWidth', mode)
- vobj.setEditorMode('MarkerColor', mode)
- vobj.setEditorMode('NormalColor', mode)
- vobj.setEditorMode('DisplayMode', mode)
- vobj.setEditorMode('BoundingBox', mode)
- vobj.setEditorMode('Selectable', mode)
+ vobj.setEditorMode("LineWidth", mode)
+ vobj.setEditorMode("MarkerColor", mode)
+ vobj.setEditorMode("NormalColor", mode)
+ vobj.setEditorMode("DisplayMode", mode)
+ vobj.setEditorMode("BoundingBox", mode)
+ vobj.setEditorMode("Selectable", mode)
def onDelete(self, vobj, args=None):
# pylint: disable=unused-argument
@@ -115,7 +120,7 @@ class ViewProvider:
PathLog.track()
for action in menu.actions():
menu.removeAction(action)
- action = QtGui.QAction(translate('Path', 'Edit'), menu)
+ action = QtGui.QAction(translate("Path", "Edit"), menu)
action.triggered.connect(self.setEdit)
menu.addAction(action)
@@ -126,7 +131,7 @@ class ViewProvider:
return []
-def Create(name='Default Tool', tool=None, toolNumber=1):
+def Create(name="Default Tool", tool=None, toolNumber=1):
PathLog.track(tool, toolNumber)
obj = PathScripts.PathToolController.Create(name, tool, toolNumber)
@@ -142,16 +147,20 @@ class CommandPathToolController(object):
# pylint: disable=no-init
def GetResources(self):
- return {'Pixmap': 'Path_LengthOffset',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_ToolController", "Add Tool Controller to the Job"),
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_ToolController", "Add Tool Controller")}
+ return {
+ "Pixmap": "Path_LengthOffset",
+ "MenuText": QT_TRANSLATE_NOOP(
+ "Path_ToolController", "Add Tool Controller to the Job"
+ ),
+ "ToolTip": QT_TRANSLATE_NOOP("Path_ToolController", "Add Tool Controller"),
+ }
def selectedJob(self):
if FreeCAD.ActiveDocument:
sel = FreeCADGui.Selection.getSelectionEx()
- if sel and sel[0].Object.Name[:3] == 'Job':
+ if sel and sel[0].Object.Name[:3] == "Job":
return sel[0].Object
- jobs = [o for o in FreeCAD.ActiveDocument.Objects if o.Name[:3] == 'Job']
+ jobs = [o for o in FreeCAD.ActiveDocument.Objects if o.Name[:3] == "Job"]
if 1 == len(jobs):
return jobs[0]
return None
@@ -178,30 +187,69 @@ class CommandPathToolController(object):
class ToolControllerEditor(object):
-
def __init__(self, obj, asDialog):
self.form = FreeCADGui.PySideUic.loadUi(":/panels/DlgToolControllerEdit.ui")
if not asDialog:
self.form.buttonBox.hide()
self.obj = obj
- self.vertFeed = PathGui.QuantitySpinBox(self.form.vertFeed, obj,
- 'VertFeed')
- self.horizFeed = PathGui.QuantitySpinBox(self.form.horizFeed, obj,
- 'HorizFeed')
- self.vertRapid = PathGui.QuantitySpinBox(self.form.vertRapid, obj,
- 'VertRapid')
- self.horizRapid = PathGui.QuantitySpinBox(self.form.horizRapid, obj,
- 'HorizRapid')
+ comboToPropertyMap = [("spindleDirection", "SpindleDir")]
+ enumTups = PathToolController.ToolController.propertyEnumerations(
+ dataType="raw"
+ )
+
+ self.populateCombobox(self.form, enumTups, comboToPropertyMap)
+ self.vertFeed = PathGui.QuantitySpinBox(self.form.vertFeed, obj, "VertFeed")
+ self.horizFeed = PathGui.QuantitySpinBox(self.form.horizFeed, obj, "HorizFeed")
+ self.vertRapid = PathGui.QuantitySpinBox(self.form.vertRapid, obj, "VertRapid")
+ self.horizRapid = PathGui.QuantitySpinBox(
+ self.form.horizRapid, obj, "HorizRapid"
+ )
if obj.Proxy.usesLegacyTool(obj):
- self.editor = PathToolEdit.ToolEditor(obj.Tool,
- self.form.toolEditor)
+ self.editor = PathToolEdit.ToolEditor(obj.Tool, self.form.toolEditor)
else:
self.editor = None
self.form.toolBox.widget(1).hide()
self.form.toolBox.removeItem(1)
+ def selectInComboBox(self, name, combo):
+ """selectInComboBox(name, combo) ...
+ helper function to select a specific value in a combo box."""
+ blocker = QtCore.QSignalBlocker(combo)
+ index = combo.currentIndex() # Save initial index
+
+ # Search using currentData and return if found
+ newindex = combo.findData(name)
+ if newindex >= 0:
+ combo.setCurrentIndex(newindex)
+ return
+
+ # if not found, search using current text
+ newindex = combo.findText(name, QtCore.Qt.MatchFixedString)
+ if newindex >= 0:
+ combo.setCurrentIndex(newindex)
+ return
+
+ # not found, return unchanged
+ combo.setCurrentIndex(index)
+ return
+
+ def populateCombobox(self, form, enumTups, comboBoxesPropertyMap):
+ """fillComboboxes(form, comboBoxesPropertyMap) ... populate comboboxes with translated enumerations
+ ** comboBoxesPropertyMap will be unnecessary if UI files use strict combobox naming protocol.
+ Args:
+ form = UI form
+ enumTups = list of (translated_text, data_string) tuples
+ comboBoxesPropertyMap = list of (translated_text, data_string) tuples
+ """
+ # Load appropriate enumerations in each combobox
+ for cb, prop in comboBoxesPropertyMap:
+ box = getattr(form, cb) # Get the combobox
+ box.clear() # clear the combobox
+ for text, data in enumTups[prop]: # load enumerations
+ box.addItem(text, data)
+
def updateUi(self):
tc = self.obj
self.form.tcName.setText(tc.Label)
@@ -211,10 +259,14 @@ class ToolControllerEditor(object):
self.vertFeed.updateSpinBox()
self.vertRapid.updateSpinBox()
self.form.spindleSpeed.setValue(tc.SpindleSpeed)
- index = self.form.spindleDirection.findText(tc.SpindleDir,
- QtCore.Qt.MatchFixedString)
- if index >= 0:
- self.form.spindleDirection.setCurrentIndex(index)
+
+ self.selectInComboBox(tc.SpindleDir, self.form.spindleDirection)
+
+ # index = self.form.spindleDirection.findText(
+ # tc.SpindleDir, QtCore.Qt.MatchFixedString
+ # )
+ # if index >= 0:
+ # self.form.spindleDirection.setCurrentIndex(index)
if self.editor:
self.editor.updateUI()
@@ -229,15 +281,14 @@ class ToolControllerEditor(object):
self.horizRapid.updateProperty()
self.vertRapid.updateProperty()
tc.SpindleSpeed = self.form.spindleSpeed.value()
- tc.SpindleDir = self.form.spindleDirection.currentText()
+ tc.SpindleDir = self.form.spindleDirection.currentData()
if self.editor:
self.editor.updateTool()
tc.Tool = self.editor.tool
except Exception as e:
- PathLog.error(translate("PathToolController",
- "Error updating TC: %s") % e)
+ PathLog.error("Error updating TC: {}".format(e))
def refresh(self):
self.form.blockSignals(True)
@@ -259,7 +310,6 @@ class ToolControllerEditor(object):
class TaskPanel:
-
def __init__(self, obj):
self.editor = ToolControllerEditor(obj, False)
self.form = self.editor.form
@@ -309,8 +359,7 @@ class TaskPanel:
def setupUi(self):
if self.editor.editor:
t = Part.makeCylinder(1, 1)
- self.toolrep = FreeCAD.ActiveDocument.addObject("Part::Feature",
- "tool")
+ self.toolrep = FreeCAD.ActiveDocument.addObject("Part::Feature", "tool")
self.toolrep.Shape = t
self.setFields()
@@ -337,6 +386,6 @@ class DlgToolControllerEdit:
if FreeCAD.GuiUp:
# register the FreeCAD command
- FreeCADGui.addCommand('Path_ToolController', CommandPathToolController())
+ FreeCADGui.addCommand("Path_ToolController", CommandPathToolController())
FreeCAD.Console.PrintLog("Loading PathToolControllerGui... done\n")
diff --git a/src/Mod/Path/PathScripts/PathToolLibraryEditor.py b/src/Mod/Path/PathScripts/PathToolLibraryEditor.py
index da2bae994e..5294b1d54e 100644
--- a/src/Mod/Path/PathScripts/PathToolLibraryEditor.py
+++ b/src/Mod/Path/PathScripts/PathToolLibraryEditor.py
@@ -21,7 +21,8 @@
# ***************************************************************************
from __future__ import print_function
-
+from PySide import QtCore, QtGui
+from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD
import FreeCADGui
import Path
@@ -30,19 +31,20 @@ import PathScripts.PathLog as PathLog
import PathScripts.PathPreferences as PathPreferences
import PathScripts.PathToolBitLibraryCmd as PathToolBitLibraryCmd
import PathScripts.PathToolEdit as PathToolEdit
-import PathScripts.PathUtils as PathUtils
import PathScripts.PathToolLibraryManager as ToolLibraryManager
+import PathScripts.PathUtils as PathUtils
-from PySide import QtCore, QtGui
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-#PathLog.trackModule(PathLog.thisModule())
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
+translate = FreeCAD.Qt.translate
-class EditorPanel():
+class EditorPanel:
def __init__(self, job, cb):
self.form = FreeCADGui.PySideUic.loadUi(":/panels/ToolLibraryEditor.ui")
self.TLM = ToolLibraryManager.ToolLibraryManager()
@@ -88,7 +90,7 @@ class EditorPanel():
return toolslist[tooltype]
def getMaterial(self, material):
- '''gets a combobox index number for a given material or vice versa'''
+ """gets a combobox index number for a given material or vice versa"""
matslist = Path.Tool.getToolMaterials(Path.Tool())
if isinstance(material, str):
if material in matslist:
@@ -99,7 +101,7 @@ class EditorPanel():
return matslist[material]
def addTool(self):
- '''adds new tool to the current tool table'''
+ """adds new tool to the current tool table"""
tool = Path.Tool()
editor = self.toolEditor(tool)
@@ -111,19 +113,19 @@ class EditorPanel():
self.loadTable(listname)
def delete(self):
- '''deletes the selected tool'''
+ """deletes the selected tool"""
listname = self.TLM.getCurrentTableName()
model = self.form.ToolsList.model()
for i in range(model.rowCount()):
item = model.item(i, 0)
if item.checkState():
t = model.index(i, 1)
- self.TLM.delete(int(t.data()) ,listname)
+ self.TLM.delete(int(t.data()), listname)
self.loadTable(listname)
self.toolSelectionChanged()
def editTool(self, currItem):
- '''load the tool edit dialog'''
+ """load the tool edit dialog"""
if not currItem:
currItem = self.form.ToolsList.selectedIndexes()[1]
@@ -141,7 +143,7 @@ class EditorPanel():
self.loadTable(listname)
def moveUp(self):
- '''moves a tool to a lower number, if possible'''
+ """moves a tool to a lower number, if possible"""
item = self.form.ToolsList.selectedIndexes()[1].data()
if item:
number = int(item)
@@ -152,7 +154,7 @@ class EditorPanel():
self.updateSelection(newNum)
def moveDown(self):
- '''moves a tool to a higher number, if possible'''
+ """moves a tool to a higher number, if possible"""
item = self.form.ToolsList.selectedIndexes()[1].data()
if item:
number = int(item)
@@ -163,7 +165,7 @@ class EditorPanel():
self.updateSelection(newNum)
def duplicate(self):
- '''duplicated the selected tool in the current tool table'''
+ """duplicated the selected tool in the current tool table"""
item = self.form.ToolsList.selectedIndexes()[1].data()
if item:
number = int(item)
@@ -174,7 +176,7 @@ class EditorPanel():
self.updateSelection(newNum)
def updateSelection(self, number):
- '''update the tool list selection to track moves'''
+ """update the tool list selection to track moves"""
model = self.form.ToolsList.model()
for i in range(model.rowCount()):
if int(model.index(i, 1).data()) == number:
@@ -182,24 +184,41 @@ class EditorPanel():
self.form.ToolsList.model().item(i, 0).setCheckState(QtCore.Qt.Checked)
return
-
def importFile(self):
- '''imports a tooltable from a file'''
- filename = QtGui.QFileDialog.getOpenFileName(self.form, translate( "TooltableEditor", "Open tooltable", None), None, "{};;{};;{}".format(self.TLM.TooltableTypeJSON, self.TLM.TooltableTypeXML, self.TLM.TooltableTypeHeekscad))
+ """imports a tooltable from a file"""
+ filename = QtGui.QFileDialog.getOpenFileName(
+ self.form,
+ translate("Path_ToolTable", "Open tooltable", None),
+ None,
+ "{};;{};;{}".format(
+ self.TLM.TooltableTypeJSON,
+ self.TLM.TooltableTypeXML,
+ self.TLM.TooltableTypeHeekscad,
+ ),
+ )
if filename[0]:
listname = self.TLM.getNextToolTableName()
if self.TLM.read(filename, listname):
self.loadToolTables()
def exportFile(self):
- '''export a tooltable to a file'''
- filename = QtGui.QFileDialog.getSaveFileName(self.form, translate("TooltableEditor", "Save tooltable", None), None, "{};;{};;{}".format(self.TLM.TooltableTypeJSON, self.TLM.TooltableTypeXML, self.TLM.TooltableTypeLinuxCNC))
+ """export a tooltable to a file"""
+ filename = QtGui.QFileDialog.getSaveFileName(
+ self.form,
+ translate("Path_ToolTable", "Save tooltable", None),
+ None,
+ "{};;{};;{}".format(
+ self.TLM.TooltableTypeJSON,
+ self.TLM.TooltableTypeXML,
+ self.TLM.TooltableTypeLinuxCNC,
+ ),
+ )
if filename[0]:
listname = self.TLM.getCurrentTableName()
self.TLM.write(filename, listname)
def toolSelectionChanged(self, index=None):
- ''' updates the ui when tools are selected'''
+ """updates the ui when tools are selected"""
if index:
self.form.ToolsList.selectRow(index.row())
@@ -222,7 +241,7 @@ class EditorPanel():
# only allow moving or deleting a single tool at a time.
if checkCount == 1:
- #make sure the row is highlighted when the check box gets ticked
+ # make sure the row is highlighted when the check box gets ticked
self.form.ToolsList.selectRow(checkList[0])
self.form.ButtonDelete.setEnabled(True)
self.form.ButtonUp.setEnabled(True)
@@ -234,7 +253,7 @@ class EditorPanel():
self.form.btnCopyTools.setEnabled(False)
def copyTools(self):
- ''' copy selected tool '''
+ """copy selected tool"""
tools = []
model = self.form.ToolsList.model()
for i in range(model.rowCount()):
@@ -268,43 +287,54 @@ class EditorPanel():
for toolnum in tools:
tool = self.TLM.getTool(currList, int(toolnum))
- PathLog.debug('tool: {}, toolnum: {}'.format(tool, toolnum))
+ PathLog.debug("tool: {}, toolnum: {}".format(tool, toolnum))
if self.job:
label = "T{}: {}".format(toolnum, tool.Name)
- tc = PathScripts.PathToolController.Create(label, tool=tool, toolNumber=int(toolnum))
+ tc = PathScripts.PathToolController.Create(
+ label, tool=tool, toolNumber=int(toolnum)
+ )
self.job.Proxy.addToolController(tc)
else:
for job in FreeCAD.ActiveDocument.findObjects("Path::Feature"):
- if isinstance(job.Proxy, PathScripts.PathJob.ObjectJob) and job.Label == targetlist:
+ if (
+ isinstance(job.Proxy, PathScripts.PathJob.ObjectJob)
+ and job.Label == targetlist
+ ):
label = "T{}: {}".format(toolnum, tool.Name)
- tc = PathScripts.PathToolController.Create(label, tool=tool, toolNumber=int(toolnum))
+ tc = PathScripts.PathToolController.Create(
+ label, tool=tool, toolNumber=int(toolnum)
+ )
job.Proxy.addToolController(tc)
if self.cb:
self.cb()
FreeCAD.ActiveDocument.recompute()
def tableSelected(self, index):
- ''' loads the tools for the selected tool table '''
- name = self.form.TableList.itemWidget(self.form.TableList.itemFromIndex(index)).getTableName()
+ """loads the tools for the selected tool table"""
+ name = self.form.TableList.itemWidget(
+ self.form.TableList.itemFromIndex(index)
+ ).getTableName()
self.loadTable(name)
def loadTable(self, name):
- ''' loads the tools for the selected tool table '''
+ """loads the tools for the selected tool table"""
tooldata = self.TLM.getTools(name)
if tooldata:
self.form.ToolsList.setModel(tooldata)
self.form.ToolsList.resizeColumnsToContents()
- self.form.ToolsList.horizontalHeader().setResizeMode(self.form.ToolsList.model().columnCount() - 1, QtGui.QHeaderView.Stretch)
+ self.form.ToolsList.horizontalHeader().setResizeMode(
+ self.form.ToolsList.model().columnCount() - 1, QtGui.QHeaderView.Stretch
+ )
self.setCurrentToolTableByName(name)
def addNewToolTable(self):
- ''' adds new tool to selected tool table '''
+ """adds new tool to selected tool table"""
name = self.TLM.addNewToolTable()
self.loadToolTables()
self.loadTable(name)
def loadToolTables(self):
- ''' Load list of available tool tables '''
+ """Load list of available tool tables"""
self.form.TableList.clear()
model = self.form.ToolsList.model()
if model:
@@ -314,44 +344,54 @@ class EditorPanel():
listWidgetItem = QtGui.QListWidgetItem()
listItem = ToolTableListWidgetItem(self.TLM)
listItem.setTableName(table.Name)
- listItem.setIcon(QtGui.QPixmap(':/icons/Path_ToolTable.svg'))
+ listItem.setIcon(QtGui.QPixmap(":/icons/Path_ToolTable.svg"))
listItem.toolMoved.connect(self.reloadReset)
- listWidgetItem.setSizeHint(QtCore.QSize(0,40))
+ listWidgetItem.setSizeHint(QtCore.QSize(0, 40))
self.form.TableList.addItem(listWidgetItem)
self.form.TableList.setItemWidget(listWidgetItem, listItem)
- #Load the first tooltable
+ # Load the first tooltable
self.loadTable(self.TLM.getCurrentTableName())
def reloadReset(self):
- ''' reloads the current tooltable'''
+ """reloads the current tooltable"""
name = self.TLM.getCurrentTableName()
self.loadTable(name)
def setCurrentToolTableByName(self, name):
- ''' get the current tool table '''
+ """get the current tool table"""
item = self.getToolTableByName(name)
if item:
self.form.TableList.setCurrentItem(item)
def getToolTableByName(self, name):
- ''' returns the listWidgetItem for the selected name'''
+ """returns the listWidgetItem for the selected name"""
for i in range(self.form.TableList.count()):
- tableName = self.form.TableList.itemWidget(self.form.TableList.item(i)).getTableName()
+ tableName = self.form.TableList.itemWidget(
+ self.form.TableList.item(i)
+ ).getTableName()
if tableName == name:
return self.form.TableList.item(i)
return False
def removeToolTable(self):
- ''' delete the selected tool table '''
+ """delete the selected tool table"""
self.TLM.deleteToolTable()
self.loadToolTables()
def renameTable(self):
- ''' provides dialog for new tablename and renames the selected tool table'''
+ """provides dialog for new tablename and renames the selected tool table"""
name = self.TLM.getCurrentTableName()
- newName, ok = QtGui.QInputDialog.getText(None, translate("TooltableEditor","Rename Tooltable"),translate("TooltableEditor","Enter Name:"),QtGui.QLineEdit.Normal,name)
+ newName, ok = QtGui.QInputDialog.getText(
+ None,
+ translate("Path_ToolTable", "Rename Tooltable"),
+ translate("Path_ToolTable", "Enter Name:"),
+ QtGui.QLineEdit.Normal,
+ name,
+ )
if ok and newName:
- index = self.form.TableList.indexFromItem(self.getToolTableByName(name)).row()
+ index = self.form.TableList.indexFromItem(
+ self.getToolTableByName(name)
+ ).row()
reloadTables = self.TLM.renameToolTable(newName, index)
if reloadTables:
self.loadToolTables()
@@ -380,14 +420,21 @@ class EditorPanel():
self.form.TableList.itemChanged.connect(self.renameTable)
self.form.ButtonAddToolTable.clicked.connect(self.addNewToolTable)
- self.form.ButtonAddToolTable.setToolTip(translate("TooltableEditor","Add New Tool Table"))
+ self.form.ButtonAddToolTable.setToolTip(
+ translate("Path_ToolTable", "Add New Tool Table")
+ )
self.form.ButtonRemoveToolTable.clicked.connect(self.removeToolTable)
- self.form.ButtonRemoveToolTable.setToolTip(translate("TooltableEditor","Delete Selected Tool Table"))
+ self.form.ButtonRemoveToolTable.setToolTip(
+ translate("Path_ToolTable", "Delete Selected Tool Table")
+ )
self.form.ButtonRenameToolTable.clicked.connect(self.renameTable)
- self.form.ButtonRenameToolTable.setToolTip(translate("TooltableEditor","Rename Selected Tool Table"))
+ self.form.ButtonRenameToolTable.setToolTip(
+ translate("Path_ToolTable", "Rename Selected Tool Table")
+ )
self.setFields()
+
class ToolTableListWidgetItem(QtGui.QWidget):
toolMoved = QtCore.Signal()
@@ -405,13 +452,13 @@ class ToolTableListWidgetItem(QtGui.QWidget):
self.mainLayout.addWidget(self.tableNameLabel, 1)
self.setLayout(self.mainLayout)
- def setTableName (self, text):
+ def setTableName(self, text):
self.tableNameLabel.setText(text)
def getTableName(self):
return self.tableNameLabel.text()
- def setIcon (self, icon):
+ def setIcon(self, icon):
icon = icon.scaled(24, 24)
self.iconQLabel.setPixmap(icon)
@@ -434,7 +481,7 @@ class ToolTableListWidgetItem(QtGui.QWidget):
self.toolMoved.emit()
-class CommandToolLibraryEdit():
+class CommandToolLibraryEdit:
def __init__(self):
pass
@@ -449,10 +496,12 @@ class CommandToolLibraryEdit():
cb()
def GetResources(self):
- return {'Pixmap' : 'Path_ToolTable',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_ToolTable","Tool Manager"),
- 'Accel': "P, T",
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_ToolTable","Tool Manager")}
+ return {
+ "Pixmap": "Path_ToolTable",
+ "MenuText": QT_TRANSLATE_NOOP("Path_ToolTable", "Tool Manager"),
+ "Accel": "P, T",
+ "ToolTip": QT_TRANSLATE_NOOP("Path_ToolTable", "Tool Manager"),
+ }
def IsActive(self):
return not FreeCAD.ActiveDocument is None
@@ -460,6 +509,7 @@ class CommandToolLibraryEdit():
def Activated(self):
self.edit()
+
if FreeCAD.GuiUp:
# register the FreeCAD command
- FreeCADGui.addCommand('Path_ToolLibraryEdit',CommandToolLibraryEdit())
+ FreeCADGui.addCommand("Path_ToolLibraryEdit", CommandToolLibraryEdit())
diff --git a/src/Mod/Path/PathScripts/PathToolLibraryManager.py b/src/Mod/Path/PathScripts/PathToolLibraryManager.py
index a352840597..cd5320a5c0 100644
--- a/src/Mod/Path/PathScripts/PathToolLibraryManager.py
+++ b/src/Mod/Path/PathScripts/PathToolLibraryManager.py
@@ -23,7 +23,6 @@
from __future__ import print_function
import FreeCAD
-import FreeCADGui
import Path
import PathScripts
import PathScripts.PathLog as PathLog
@@ -31,14 +30,15 @@ import PathScripts.PathUtil as PathUtil
import json
import os
import xml.sax
+from PySide import QtGui
-from PySide import QtCore, QtGui
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-#PathLog.trackModule(PathLog.thisModule())
-
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
+translate = FreeCAD.Qt.translate
# Tooltable XML readers
class FreeCADTooltableHandler(xml.sax.ContentHandler):
@@ -62,7 +62,7 @@ class FreeCADTooltableHandler(xml.sax.ContentHandler):
self.tool.ToolType = str(attrs["type"])
self.tool.Material = str(attrs["mat"])
# for some reason without the following line I get an error
- #print attrs["diameter"]
+ # print attrs["diameter"]
self.tool.Diameter = float(attrs["diameter"])
self.tool.LengthOffset = float(attrs["length"])
self.tool.FlatRadius = float(attrs["flat"])
@@ -80,7 +80,6 @@ class FreeCADTooltableHandler(xml.sax.ContentHandler):
class HeeksTooltableHandler(xml.sax.ContentHandler):
-
def __init__(self):
xml.sax.ContentHandler.__init__(self)
self.tooltable = Path.Tooltable()
@@ -115,15 +114,13 @@ class HeeksTooltableHandler(xml.sax.ContentHandler):
elif m == "1":
self.tool.Material = "Carbide"
# for some reason without the following line I get an error
- #print attrs["diameter"]
+ # print attrs["diameter"]
self.tool.Diameter = float(attrs["diameter"])
self.tool.LengthOffset = float(attrs["tool_length_offset"])
self.tool.FlatRadius = float(attrs["flat_radius"])
self.tool.CornerRadius = float(attrs["corner_radius"])
- self.tool.CuttingEdgeAngle = float(
- attrs["cutting_edge_angle"])
- self.tool.CuttingEdgeHeight = float(
- attrs["cutting_edge_height"])
+ self.tool.CuttingEdgeAngle = float(attrs["cutting_edge_angle"])
+ self.tool.CuttingEdgeHeight = float(attrs["cutting_edge_height"])
# Call when an elements ends
def endElement(self, name):
@@ -134,17 +131,21 @@ class HeeksTooltableHandler(xml.sax.ContentHandler):
self.tool = None
-class ToolLibraryManager():
- '''
+class ToolLibraryManager:
+ """
The Tool Library is a list of individual tool tables. Each
Tool Table can contain n tools. The tool library will be persisted to user
preferences and all or part of the library can be exported to other formats
- '''
+ """
- TooltableTypeJSON = translate("PathToolLibraryManager", "Tooltable JSON (*.json)")
- TooltableTypeXML = translate("PathToolLibraryManager", "Tooltable XML (*.xml)")
- TooltableTypeHeekscad = translate("PathToolLibraryManager", "HeeksCAD tooltable (*.tooltable)")
- TooltableTypeLinuxCNC = translate("PathToolLibraryManager", "LinuxCNC tooltable (*.tbl)")
+ TooltableTypeJSON = translate("PathToolLibraryManager", "Tooltable JSON (*.json)")
+ TooltableTypeXML = translate("PathToolLibraryManager", "Tooltable XML (*.xml)")
+ TooltableTypeHeekscad = translate(
+ "PathToolLibraryManager", "HeeksCAD tooltable (*.tooltable)"
+ )
+ TooltableTypeLinuxCNC = translate(
+ "PathToolLibraryManager", "LinuxCNC tooltable (*.tbl)"
+ )
PreferenceMainLibraryXML = "ToolLibrary"
PreferenceMainLibraryJSON = "ToolLibrary-Main"
@@ -156,38 +157,40 @@ class ToolLibraryManager():
self.loadToolTables()
def getToolTables(self):
- ''' Return tool table list '''
+ """Return tool table list"""
return self.toolTables
def getCurrentTableName(self):
- ''' return the name of the currently loaded tool table '''
+ """return the name of the currently loaded tool table"""
return self.currentTableName
def getCurrentTable(self):
- ''' returns an object of the current tool table '''
+ """returns an object of the current tool table"""
return self.getTableFromName(self.currentTableName)
def getTableFromName(self, name):
- ''' get the tool table object from the name '''
+ """get the tool table object from the name"""
for table in self.toolTables:
if table.Name == name:
return table
- def getNextToolTableName(self, tableName='Tool Table'):
- ''' get a unique name for a new tool table '''
+ def getNextToolTableName(self, tableName="Tool Table"):
+ """get a unique name for a new tool table"""
iter = 1
tempName = tableName[-2:]
- if tempName[0] == '-' and tempName[-1].isdigit():
+ if tempName[0] == "-" and tempName[-1].isdigit():
tableName = tableName[:-2]
- while any(table.Name == tableName + '-' + str(iter) for table in self.toolTables):
+ while any(
+ table.Name == tableName + "-" + str(iter) for table in self.toolTables
+ ):
iter += 1
- return tableName + '-' + str(iter)
+ return tableName + "-" + str(iter)
def addNewToolTable(self):
- ''' creates a new tool table '''
+ """creates a new tool table"""
tt = Path.Tooltable()
tt.Version = 1
name = self.getNextToolTableName()
@@ -197,20 +200,27 @@ class ToolLibraryManager():
return name
def deleteToolTable(self):
- ''' deletes the selected tool table '''
+ """deletes the selected tool table"""
if len(self.toolTables):
- index = next((index for (index, d) in enumerate(self.toolTables) if d.Name == self.currentTableName), None)
+ index = next(
+ (
+ index
+ for (index, d) in enumerate(self.toolTables)
+ if d.Name == self.currentTableName
+ ),
+ None,
+ )
self.toolTables.pop(index)
self.saveMainLibrary()
def renameToolTable(self, newName, index):
- ''' renames a tool table with the new name'''
+ """renames a tool table with the new name"""
currentTableName = self.toolTables[index].Name
if newName == currentTableName:
- PathLog.error(translate('PathToolLibraryManager', "Tool Table Same Name"))
+ PathLog.error(translate("PathToolLibraryManager", "Tool Table Same Name"))
return False
if newName in self.toolTables:
- PathLog.error(translate('PathToolLibraryManager', "Tool Table Name Exists"))
+ PathLog.error(translate("PathToolLibraryManager", "Tool Table Name Exists"))
return False
tt = self.getTableFromName(currentTableName)
if tt:
@@ -218,67 +228,74 @@ class ToolLibraryManager():
self.saveMainLibrary()
return True
-
def templateAttrs(self):
- ''' gets the tool table arributes '''
+ """gets the tool table arributes"""
toolTables = []
for tt in self.toolTables:
tableData = {}
- tableData['Version'] = 1
- tableData['TableName'] = tt.Name
+ tableData["Version"] = 1
+ tableData["TableName"] = tt.Name
toolData = {}
for tool in tt.Tools:
toolData[tool] = tt.Tools[tool].templateAttrs()
- tableData['Tools'] = toolData
+ tableData["Tools"] = toolData
toolTables.append(tableData)
return toolTables
def tooltableFromAttrs(self, stringattrs):
- if stringattrs.get('Version') and 1 == int(stringattrs['Version']):
+ if stringattrs.get("Version") and 1 == int(stringattrs["Version"]):
tt = Path.Tooltable()
tt.Version = 1
tt.Name = self.getNextToolTableName()
- if stringattrs.get('Version'):
- tt.Version = stringattrs.get('Version')
+ if stringattrs.get("Version"):
+ tt.Version = stringattrs.get("Version")
- if stringattrs.get('TableName'):
- tt.Name = stringattrs.get('TableName')
+ if stringattrs.get("TableName"):
+ tt.Name = stringattrs.get("TableName")
if any(table.Name == tt.Name for table in self.toolTables):
tt.Name = self.getNextToolTableName(tt.Name)
- for key, attrs in PathUtil.keyValueIter(stringattrs['Tools']):
- tool = Path.Tool()
- tool.Name = str(attrs["name"])
- tool.ToolType = str(attrs["tooltype"])
- tool.Material = str(attrs["material"])
- tool.Diameter = float(attrs["diameter"])
- tool.LengthOffset = float(attrs["lengthOffset"])
- tool.FlatRadius = float(attrs["flatRadius"])
- tool.CornerRadius = float(attrs["cornerRadius"])
- tool.CuttingEdgeAngle = float(attrs["cuttingEdgeAngle"])
- tool.CuttingEdgeHeight = float(attrs["cuttingEdgeHeight"])
- tt.setTool(int(key), tool)
+ for key, attrs in PathUtil.keyValueIter(stringattrs["Tools"]):
+ tool = Path.Tool()
+ tool.Name = str(attrs["name"])
+ tool.ToolType = str(attrs["tooltype"])
+ tool.Material = str(attrs["material"])
+ tool.Diameter = float(attrs["diameter"])
+ tool.LengthOffset = float(attrs["lengthOffset"])
+ tool.FlatRadius = float(attrs["flatRadius"])
+ tool.CornerRadius = float(attrs["cornerRadius"])
+ tool.CuttingEdgeAngle = float(attrs["cuttingEdgeAngle"])
+ tool.CuttingEdgeHeight = float(attrs["cuttingEdgeHeight"])
+ tt.setTool(int(key), tool)
return tt
else:
- PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable template version %s") % stringattrs.get('Version'))
+ PathLog.error(
+ translate(
+ "PathToolLibraryManager",
+ "Unsupported Path tooltable template version %s",
+ )
+ % stringattrs.get("Version")
+ )
return None
def loadToolTables(self):
- ''' loads the tool tables from the stored data '''
+ """loads the tool tables from the stored data"""
self.toolTables = []
- self.currentTableName = ''
+ self.currentTableName = ""
def addTable(tt):
if tt:
self.toolTables.append(tt)
else:
- PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable"))
+ PathLog.error(
+ translate("PathToolLibraryManager", "Unsupported Path tooltable")
+ )
prefString = self.prefs.GetString(self.PreferenceMainLibraryJSON, "")
@@ -300,14 +317,14 @@ class ToolLibraryManager():
self.currentTableName = self.toolTables[0].Name
def saveMainLibrary(self):
- '''Persists the permanent library to FreeCAD user preferences'''
+ """Persists the permanent library to FreeCAD user preferences"""
tmpstring = json.dumps(self.templateAttrs())
self.prefs.SetString(self.PreferenceMainLibraryJSON, tmpstring)
self.loadToolTables()
return True
def getJobList(self):
- '''Builds the list of all Tool Table lists'''
+ """Builds the list of all Tool Table lists"""
tablelist = []
for o in FreeCAD.ActiveDocument.Objects:
@@ -318,27 +335,29 @@ class ToolLibraryManager():
return tablelist
def getTool(self, listname, toolnum):
- ''' gets the tool object '''
+ """gets the tool object"""
tt = self.getTableFromName(listname)
return tt.getTool(toolnum)
def getTools(self, tablename):
- '''returns the tool data for a given table'''
+ """returns the tool data for a given table"""
tooldata = []
- tableExists = any(table.Name == tablename for table in self.toolTables)
+ tableExists = any(table.Name == tablename for table in self.toolTables)
if tableExists:
self.currentTableName = tablename
else:
return None
tt = self.getTableFromName(tablename)
- headers = ["","Tool Num.","Name","Tool Type","Diameter"]
+ headers = ["", "Tool Num.", "Name", "Tool Type", "Diameter"]
model = QtGui.QStandardItemModel()
model.setHorizontalHeaderLabels(headers)
def unitconv(ivalue):
val = FreeCAD.Units.Quantity(ivalue, FreeCAD.Units.Length)
- displayed_val = val.UserString #just the displayed value-not the internal one
+ displayed_val = (
+ val.UserString
+ ) # just the displayed value-not the internal one
return displayed_val
if tt:
@@ -348,10 +367,10 @@ class ToolLibraryManager():
itemcheck = QtGui.QStandardItem()
itemcheck.setCheckable(True)
- itemNumber = QtGui.QStandardItem(str(number))
- itemName = QtGui.QStandardItem(t.Name)
- itemToolType = QtGui.QStandardItem(t.ToolType)
- itemDiameter = QtGui.QStandardItem(unitconv(t.Diameter))
+ itemNumber = QtGui.QStandardItem(str(number))
+ itemName = QtGui.QStandardItem(t.Name)
+ itemToolType = QtGui.QStandardItem(t.ToolType)
+ itemDiameter = QtGui.QStandardItem(unitconv(t.Diameter))
row = [itemcheck, itemNumber, itemName, itemToolType, itemDiameter]
model.appendRow(row)
@@ -367,9 +386,9 @@ class ToolLibraryManager():
try:
fileExtension = os.path.splitext(filename[0])[1].lower()
xmlHandler = None
- if fileExtension == '.tooltable':
+ if fileExtension == ".tooltable":
xmlHandler = HeeksTooltableHandler()
- if fileExtension == '.xml':
+ if fileExtension == ".xml":
xmlHandler = FreeCADTooltableHandler()
if xmlHandler:
@@ -405,41 +424,58 @@ class ToolLibraryManager():
else:
return False
- except Exception as e: # pylint: disable=broad-except
+ except Exception as e: # pylint: disable=broad-except
print("could not parse file", e)
-
def write(self, filename, listname):
"exports the tooltable to a file"
tt = self.getTableFromName(listname)
if tt:
try:
+
def openFileWithExtension(name, ext):
fext = os.path.splitext(name)[1].lower()
if fext != ext:
name = "{}{}".format(name, ext)
- return (open(PathUtil.toUnicode(name), 'w'), name)
+ return (open(PathUtil.toUnicode(name), "w"), name)
if filename[1] == self.TooltableTypeXML:
- fp,fname = openFileWithExtension(filename[0], '.xml')
+ fp, fname = openFileWithExtension(filename[0], ".xml")
fp.write('\n')
fp.write(tt.Content)
elif filename[1] == self.TooltableTypeLinuxCNC:
- fp,fname = openFileWithExtension(filename[0], '.tbl')
+ fp, fname = openFileWithExtension(filename[0], ".tbl")
for key in tt.Tools:
t = tt.Tools[key]
- fp.write("T{0} P{0} Y{1} Z{2} A{3} B{4} C{5} U{6} V{7} W{8} D{9} I{10} J{11} Q{12} ;{13}\n".format(key,0,t.LengthOffset,0,0,0,0,0,0,t.Diameter,0,0,0,t.Name))
+ fp.write(
+ "T{0} P{0} Y{1} Z{2} A{3} B{4} C{5} U{6} V{7} W{8} D{9} I{10} J{11} Q{12} ;{13}\n".format(
+ key,
+ 0,
+ t.LengthOffset,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ t.Diameter,
+ 0,
+ 0,
+ 0,
+ t.Name,
+ )
+ )
else:
- fp,fname = openFileWithExtension(filename[0], '.json')
+ fp, fname = openFileWithExtension(filename[0], ".json")
json.dump(self.templateAttrs(), fp, sort_keys=True, indent=2)
fp.close()
print("Written ", PathUtil.toUnicode(fname))
- except Exception as e: # pylint: disable=broad-except
+ except Exception as e: # pylint: disable=broad-except
print("Could not write file:", e)
- def addnew(self, listname, tool, position = None):
+ def addnew(self, listname, tool, position=None):
"adds a new tool at the end of the table"
tt = self.getTableFromName(listname)
if not tt:
@@ -456,7 +492,7 @@ class ToolLibraryManager():
return newID
def updateTool(self, listname, toolnum, tool):
- '''updates tool data'''
+ """updates tool data"""
tt = self.getTableFromName(listname)
tt.deleteTool(toolnum)
tt.setTool(toolnum, tool)
@@ -498,7 +534,7 @@ class ToolLibraryManager():
return True, target
def duplicate(self, number, listname):
- ''' duplicates the selected tool in the selected tool table '''
+ """duplicates the selected tool in the selected tool table"""
tt = self.getTableFromName(listname)
tool = tt.getTool(number).copy()
tt.addTools(tool)
@@ -510,7 +546,7 @@ class ToolLibraryManager():
return True, newID
def moveToTable(self, number, listname):
- ''' Moves the tool to selected tool table '''
+ """Moves the tool to selected tool table"""
fromTable = self.getTableFromName(self.getCurrentTableName())
toTable = self.getTableFromName(listname)
tool = fromTable.getTool(number).copy()
@@ -518,9 +554,9 @@ class ToolLibraryManager():
fromTable.deleteTool(number)
def delete(self, number, listname):
- '''deletes a tool from the current list'''
+ """deletes a tool from the current list"""
tt = self.getTableFromName(listname)
tt.deleteTool(number)
if listname == self.getCurrentTableName():
self.saveMainLibrary()
- return True
\ No newline at end of file
+ return True