diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt
index 5b88d574de..7046290c7b 100644
--- a/src/Mod/Path/CMakeLists.txt
+++ b/src/Mod/Path/CMakeLists.txt
@@ -154,26 +154,28 @@ SET(PathScripts_post_SRCS
)
SET(Tools_Bit_SRCS
- Tools/Bit/t1.fctb
- Tools/Bit/t2.fctb
- Tools/Bit/t3.fctb
- Tools/Bit/t4.fctb
- Tools/Bit/t5.fctb
- Tools/Bit/t6.fctb
- Tools/Bit/t7.fctb
- Tools/Bit/t8.fctb
- Tools/Bit/t9.fctb
+ Tools/Bit/45degree_chamfer.fctb
+ Tools/Bit/5mm_Drill.fctb
+ Tools/Bit/5mm_Endmill.fctb
+ Tools/Bit/60degree_Vbit.fctb
+ Tools/Bit/6mm_Ball_End.fctb
+ Tools/Bit/6mm_Bullnose.fctb
+ Tools/Bit/slittingsaw.fctb
+ Tools/Bit/probe.fctb
)
SET(Tools_Library_SRCS
- Tools/Library/endmills.fctl
+ Tools/Library/Default.fctl
)
SET(Tools_Shape_SRCS
Tools/Shape/ballend.fcstd
Tools/Shape/bullnose.fcstd
Tools/Shape/drill.fcstd
+ Tools/Shape/chamfer.fcstd
Tools/Shape/endmill.fcstd
+ Tools/Shape/probe.fcstd
+ Tools/Shape/slittingsaw.fcstd
Tools/Shape/v-bit.fcstd
)
diff --git a/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui b/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui
index 42a5e98364..1342da5649 100644
--- a/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui
+++ b/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui
@@ -1,21 +1,27 @@
- Form
-
+ ToolBitAttributes
+
0
0
- 587
- 744
+ 401
+ 715
- Form
+ Tool Bit Attributes
-
+
+
+ 0
+ 0
+
+
0
@@ -114,7 +120,7 @@
-
- 180°
+ 0 °
°
@@ -131,7 +137,7 @@
-
- 0.00
+ 0 mm
mm
diff --git a/src/Mod/Path/Gui/Resources/panels/ToolBitLibraryEdit.ui b/src/Mod/Path/Gui/Resources/panels/ToolBitLibraryEdit.ui
index 83301b6b0d..f97deb479e 100644
--- a/src/Mod/Path/Gui/Resources/panels/ToolBitLibraryEdit.ui
+++ b/src/Mod/Path/Gui/Resources/panels/ToolBitLibraryEdit.ui
@@ -11,297 +11,11 @@
- ToolBit Library
+ Library Manager
-
-
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
-
- 226
- 16777215
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- Tool Libraries
-
-
-
- -
-
-
-
- 32
- 32
-
-
-
- <html><head/><body><p>Rename Tool Table</p></body></html>
-
-
-
-
-
-
- :/icons/edit-edit.svg:/icons/edit-edit.svg
-
-
-
- -
-
-
-
- 32
- 32
-
-
-
- <html><head/><body><p>Add New Tool Table</p></body></html>
-
-
-
-
-
-
- :/icons/list-add.svg:/icons/list-add.svg
-
-
-
- -
-
-
-
- 32
- 32
-
-
-
- <html><head/><body><p>Remove Tool Table from Disc</p></body></html>
-
-
-
-
-
-
- :/icons/list-remove.svg:/icons/list-remove.svg
-
-
-
-
-
- -
-
-
- QFrame::Box
-
-
-
-
-
-
- -
-
-
- 0
-
-
- 0
-
-
-
-
-
- true
-
-
- <html><head/><body><p>Table of Tool Bits of the library.</p></body></html>
-
-
- QFrame::Box
-
-
- QFrame::Sunken
-
-
- 1
-
-
- 0
-
-
- true
-
-
- QAbstractItemView::InternalMove
-
-
- Qt::MoveAction
-
-
- QAbstractItemView::SelectRows
-
-
- true
-
-
- false
-
-
-
- -
-
-
-
-
-
- Add Tool Controller(s) to Job
-
-
-
- :/icons/edit_OK.svg:/icons/edit_OK.svg
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 140
- 20
-
-
-
-
- -
-
-
- <html><head/><body><p>Close the Tool Bit Library Editor</p></body></html>
-
-
- Cancel
-
-
-
- :/icons/button_invalid.svg:/icons/button_invalid.svg
-
-
-
- -
-
-
- <html><head/><body><p>Save the current Library</p></body></html>
-
-
- Save Table
-
-
-
- :/icons/document-save.svg:/icons/document-save.svg
-
-
-
- -
-
-
- <html><head/><body><p>Save the library to a new file</p></body></html>
-
-
- Save Table As...
-
-
-
- :/icons/document-save-as.svg:/icons/document-save-as.svg
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 420
- 0
-
-
-
- true
-
-
-
- -
-
-
- <html><head/><body><p>Select the folder with the tool libraries to load.</p></body></html>
-
-
-
-
-
-
- :/icons/document-open.svg:/icons/document-open.svg
-
-
-
+
+ -
+
-
@@ -315,22 +29,45 @@
+ -
+
+
+ Create Toolbit
+
+
+
+ :/icons/Path-ToolBit.svg:/icons/Path-ToolBit.svg
+
+
+
-
+
+
+ 16777215
+ 16777215
+
+
<html><head/><body><p>Add existing Tool Bit to this library.</p><p><br/></p></body></html>
- Add Toolbit
+ Add Existing
-
- :/icons/list-add.svg:/icons/list-add.svg
+
+ :/icons/Path-ToolDuplicate.svg:/icons/Path-ToolDuplicate.svg
-
+
+
+ 16777215
+ 16777215
+
+
<html><head/><body><p>Delete selected Tool Bit(s) from the library.</p><p><br/></p></body></html>
@@ -343,17 +80,194 @@
+
+
+ -
+
+
+
-
+
+
-
+
+
+
+ 16777215
+ 16777215
+
+
+
+ <html><head/><body><p>Select a working path for the tool library editor.</p></body></html>
+
+
+
+
+
+
+ :/icons/document-open.svg:/icons/document-open.svg
+
+
+
+ -
+
+
+
+ 16777215
+ 16777215
+
+
+
+ <html><head/><body><p>Add New Tool Table</p></body></html>
+
+
+
+
+
+
+ :/icons/document-new.svg:/icons/document-new.svg
+
+
+
+ 24
+ 24
+
+
+
+
+ -
+
+
+ <html><head/><body><p>Save the selected library with a new name or export to another format</p></body></html>
+
+
+
+
+
+
+ :/icons/document-save.svg:/icons/document-save.svg
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::Box
+
+
+
+ -
+
+
+ true
+
+
+ <html><head/><body><p>Table of Tool Bits of the library.</p></body></html>
+
+
+ QFrame::Box
+
+
+ QFrame::Sunken
+
+
+ 1
+
+
+ 0
+
+
+ false
+
+
+ false
+
+
+ QAbstractItemView::DragOnly
+
+
+ Qt::IgnoreAction
+
+
+ QAbstractItemView::SingleSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+
+ -
+
-
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Preferred
+
+
+
+ 65555555
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
- <html><head/><body><p>Assign numbers to each Tool Bit according to its current position in the library. The first Tool Bit is assigned the ID 1.</p></body></html>
+ <html><head/><body><p>Save the current Library</p></body></html>
- Enumerate
+ Close
- :/icons/button_sort.svg:/icons/button_sort.svg
+ :/icons/edit_OK.svg:/icons/edit_OK.svg
@@ -363,6 +277,7 @@
+
diff --git a/src/Mod/Path/Gui/Resources/panels/ToolBitSelector.ui b/src/Mod/Path/Gui/Resources/panels/ToolBitSelector.ui
index 4dde97be5a..32e87cb8fb 100644
--- a/src/Mod/Path/Gui/Resources/panels/ToolBitSelector.ui
+++ b/src/Mod/Path/Gui/Resources/panels/ToolBitSelector.ui
@@ -1,119 +1,135 @@
- Dialog
-
+ ToolSelector
+
0
0
- 588
- 396
+ 350
+ 542
-
- Dialog
+
+
+ 0
+ 0
+
-
- -
-
-
+
+ Tool Selector
+
+
+
+
-
+
+
+
-
+
+
+ TextLabel
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ :/icons/Path-ToolTable.svg:/icons/Path-ToolTable.svg
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+
+ -
+
-
-
+
<html><head/><body><p>Available Tool Bits to choose from.</p></body></html>
QAbstractItemView::NoEditTriggers
-
-
- -
-
-
-
-
-
-
- <html><head/><body><p>Load an existing Tool Bit from a file.</p></body></html>
-
-
- Load...
-
-
-
- -
-
-
- <html><head/><body><p>Create a new Tool Bit based on an existing shape.</p></body></html>
-
-
- New
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
+
+ QAbstractItemView::ExtendedSelection
+
+
+ false
+
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
+
+ -
+
+
-
+
+
+ false
+
+
+ <html><head/><body><p>Create ToolControllers for the selected toolbits and add them to the Job</p></body></html>
+
+
+ Add To Job
+
+
+
+ :/icons/edit_OK.svg:/icons/edit_OK.svg
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
-
-
-
- buttonBox
- accepted()
- Dialog
- accept()
-
-
- 248
- 254
-
-
- 157
- 274
-
-
-
-
- buttonBox
- rejected()
- Dialog
- reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
-
-
+
+
+
+
+
diff --git a/src/Mod/Path/InitGui.py b/src/Mod/Path/InitGui.py
index f40ff06ee6..7580f38862 100644
--- a/src/Mod/Path/InitGui.py
+++ b/src/Mod/Path/InitGui.py
@@ -76,20 +76,13 @@ class PathWorkbench (Workbench):
from PathScripts import PathToolBitCmd
from PathScripts import PathToolBitLibraryCmd
- if PathPreferences.experimentalFeaturesEnabled():
- toolbitcmdlist = PathToolBitCmd.CommandList + ["Separator"] + PathToolBitLibraryCmd.CommandList + ["Path_ToolController", "Separator"]
- self.toolbitctxmenu = ["Path_ToolBitLibraryLoad", "Path_ToolController"]
- else:
- toolbitcmdlist = []
- self.toolbitctxmenu = []
import PathCommands
PathGuiInit.Startup()
# build commands list
projcmdlist = ["Path_Job", "Path_Post"]
- toolcmdlist = ["Path_Inspect", "Path_Simulator",
- "Path_ToolLibraryEdit", "Path_SelectLoop",
+ toolcmdlist = ["Path_Inspect", "Path_Simulator", "Path_SelectLoop",
"Path_OpActiveToggle"]
prepcmdlist = ["Path_Fixture", "Path_Comment", "Path_Stop",
"Path_Custom", "Path_Probe"]
@@ -107,6 +100,16 @@ class PathWorkbench (Workbench):
# modcmdmore = ["Path_Hop",]
# remotecmdlist = ["Path_Remote"]
+
+ if PathPreferences.toolsReallyUseLegacyTools():
+ toolcmdlist.append("Path_ToolLibraryEdit")
+ toolbitcmdlist = []
+ else:
+ toolcmdlist.extend(PathToolBitLibraryCmd.BarList)
+ toolbitcmdlist = PathToolBitLibraryCmd.MenuList
+
+
+
engravecmdgroup = ['Path_EngraveTools']
FreeCADGui.addCommand('Path_EngraveTools', PathCommandGroup(engravecmdlist, QtCore.QT_TRANSLATE_NOOP("Path", 'Engraving Operations')))
@@ -134,7 +137,7 @@ class PathWorkbench (Workbench):
self.appendToolbar(QtCore.QT_TRANSLATE_NOOP("Path", "Helpful Tools"), extracmdlist)
self.appendMenu([QtCore.QT_TRANSLATE_NOOP("Path", "&Path")], projcmdlist + ["Path_ExportTemplate", "Separator"] +
- toolbitcmdlist + toolcmdlist + ["Separator"] + twodopcmdlist + engravecmdlist + ["Separator"] +
+ toolcmdlist + toolbitcmdlist + ["Separator"] + twodopcmdlist + engravecmdlist + ["Separator"] +
threedopcmdlist + ["Separator"])
self.appendMenu([QtCore.QT_TRANSLATE_NOOP("Path", "&Path"), QtCore.QT_TRANSLATE_NOOP(
"Path", "Path Dressup")], dressupcmdlist)
diff --git a/src/Mod/Path/PathScripts/PathJob.py b/src/Mod/Path/PathScripts/PathJob.py
index d17cf3e717..d68b24cdcb 100644
--- a/src/Mod/Path/PathScripts/PathJob.py
+++ b/src/Mod/Path/PathScripts/PathJob.py
@@ -94,6 +94,13 @@ def createModelResourceClone(obj, orig):
return createResourceClone(obj, orig, 'Model', 'BaseGeometry')
+class NotificationClass(QtCore.QObject):
+ updateTC = QtCore.Signal(object, object)
+
+
+Notification = NotificationClass()
+
+
class ObjectJob:
def __init__(self, obj, models, templateFile=None):
@@ -261,6 +268,7 @@ class ObjectJob:
self.setupBaseModel(obj)
self.fixupOperations(obj)
self.setupSetupSheet(obj)
+
obj.setEditorMode('Operations', 2) # hide
obj.setEditorMode('Placement', 2)
@@ -413,6 +421,7 @@ class ObjectJob:
tc.setExpression('HorizRapid', "%s.%s" % (self.setupSheet.expressionReference(), PathSetupSheet.Template.HorizRapid))
group.append(tc)
self.obj.ToolController = group
+ Notification.updateTC.emit(self.obj, tc)
def allOperations(self):
ops = []
diff --git a/src/Mod/Path/PathScripts/PathJobGui.py b/src/Mod/Path/PathScripts/PathJobGui.py
index 5c3d1daf9d..8e6781a2a2 100644
--- a/src/Mod/Path/PathScripts/PathJobGui.py
+++ b/src/Mod/Path/PathScripts/PathJobGui.py
@@ -25,7 +25,6 @@ from collections import Counter
from contextlib import contextmanager
import math
import traceback
-
from pivy import coin
from PySide import QtCore, QtGui
@@ -45,6 +44,7 @@ import PathScripts.PathToolControllerGui as PathToolControllerGui
import PathScripts.PathToolLibraryEditor as PathToolLibraryEditor
import PathScripts.PathUtil as PathUtil
import PathScripts.PathUtils as PathUtils
+import PathScripts.PathToolBitGui as PathToolBitGui
# lazily loaded modules
from lazy_loader.lazy_loader import LazyLoader
@@ -866,7 +866,15 @@ class TaskPanel:
self.toolControllerSelect()
def toolControllerAdd(self):
- PathToolLibraryEditor.CommandToolLibraryEdit().edit(self.obj, self.updateToolController)
+ if PathPreferences.toolsUseLegacyTools():
+ PathToolLibraryEditor.CommandToolLibraryEdit().edit(self.obj, self.updateToolController)
+ else:
+ tools = PathToolBitGui.LoadTools()
+ for tool in tools:
+ tc = PathToolControllerGui.Create(name=tool.Label, tool=tool)
+ self.obj.Proxy.addToolController(tc)
+ FreeCAD.ActiveDocument.recompute()
+ self.updateToolController()
def toolControllerDelete(self):
self.objectDelete(self.form.toolControllerList)
diff --git a/src/Mod/Path/PathScripts/PathOpGui.py b/src/Mod/Path/PathScripts/PathOpGui.py
index b84be08568..20e7dc678e 100644
--- a/src/Mod/Path/PathScripts/PathOpGui.py
+++ b/src/Mod/Path/PathScripts/PathOpGui.py
@@ -25,6 +25,7 @@ import FreeCADGui
import PathScripts.PathGeom as PathGeom
import PathScripts.PathGetPoint as PathGetPoint
import PathScripts.PathGui as PathGui
+import PathScripts.PathJob as PathJob
import PathScripts.PathLog as PathLog
import PathScripts.PathOp as PathOp
import PathScripts.PathPreferences as PathPreferences
@@ -211,6 +212,9 @@ class TaskPanelPage(object):
self.parent = None
self.panelTitle = 'Operation'
+ if hasattr(self.form, 'toolController'):
+ PathJob.Notification.updateTC.connect(self.resetToolController)
+
def setParent(self, parent):
'''setParent() ... used to transfer parent object link to child class.
Do not overwrite.'''
@@ -361,6 +365,12 @@ class TaskPanelPage(object):
combo.setCurrentIndex(index)
combo.blockSignals(False)
+ def resetToolController(self, job, tc):
+ if self.obj is not None:
+ self.obj.ToolController = tc
+ combo = self.form.toolController
+ self.setupToolController(self.obj, combo)
+
def setupToolController(self, obj, combo):
'''setupToolController(obj, combo) ...
helper function to setup obj's ToolController
@@ -535,7 +545,7 @@ class TaskPanelBaseGeometryPage(TaskPanelPage):
PathLog.error(translate("PathProject", "Faces are not supported"))
return False
else:
- if not self.supportsPanels() or not 'Panel' in sel.Object.Name:
+ if not self.supportsPanels() or 'Panel' not in sel.Object.Name:
if not ignoreErrors:
PathLog.error(translate("PathProject", "Please select %s of a solid" % self.featureName()))
return False
@@ -626,6 +636,7 @@ class TaskPanelBaseGeometryPage(TaskPanelPage):
row = (qList.count() + qList.frameWidth()) * 15
qList.setFixedSize(col, row)
+
class TaskPanelBaseLocationPage(TaskPanelPage):
'''Page controller for base locations. Uses PathGetPoint.'''
@@ -926,6 +937,7 @@ class TaskPanelDepthsPage(TaskPanelPage):
self.form.startDepthSet.setEnabled(False)
self.form.finalDepthSet.setEnabled(False)
+
class TaskPanelDiametersPage(TaskPanelPage):
'''Page controller for diameters.'''
@@ -950,7 +962,7 @@ class TaskPanelDiametersPage(TaskPanelPage):
self.minDiameter.updateProperty()
self.maxDiameter.updateProperty()
- def setFields(self, obj):
+ def setFields(self, obj):
self.minDiameter.updateSpinBox()
self.maxDiameter.updateSpinBox()
@@ -964,6 +976,7 @@ class TaskPanelDiametersPage(TaskPanelPage):
if prop in ['MinDiameter', 'MaxDiameter']:
self.setFields(obj)
+
class TaskPanel(object):
'''
Generic TaskPanel implementation handling the standard Path operation layout.
diff --git a/src/Mod/Path/PathScripts/PathPreferences.py b/src/Mod/Path/PathScripts/PathPreferences.py
index ad6d2d5585..6fe58570ef 100644
--- a/src/Mod/Path/PathScripts/PathPreferences.py
+++ b/src/Mod/Path/PathScripts/PathPreferences.py
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
+
# ***************************************************************************
+# * *
# * Copyright (c) 2014 Yorik van Havre *
# * *
# * This program is free software; you can redistribute it and/or modify *
@@ -25,8 +27,8 @@ import glob
import os
import PathScripts.PathLog as PathLog
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-#PathLog.trackModule()
+# PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
+# PathLog.trackModule()
DefaultFilePath = "DefaultFilePath"
DefaultJobTemplate = "DefaultJobTemplate"
@@ -42,15 +44,19 @@ PostProcessorOutputPolicy = "PostProcessorOutputPolicy"
LastPathToolBit = "LastPathToolBit"
LastPathToolLibrary = "LastPathToolLibrary"
LastPathToolShape = "LastPathToolShape"
-LastPathToolTable ="LastPathToolTable"
+LastPathToolTable = "LastPathToolTable"
+
+LastFileToolBit = "LastFileToolBit"
+LastFileToolLibrary = "LastFileToolLibrary"
+LastFileToolShape = "LastFileToolShape"
UseLegacyTools = "UseLegacyTools"
UseAbsoluteToolPaths = "UseAbsoluteToolPaths"
OpenLastLibrary = "OpenLastLibrary"
# Linear tolerance to use when generating Paths, eg when tessellating geometry
-GeometryTolerance = "GeometryTolerance"
-LibAreaCurveAccuracy = "LibAreaCurveAccuarcy"
+GeometryTolerance = "GeometryTolerance"
+LibAreaCurveAccuracy = "LibAreaCurveAccuarcy"
EnableExperimentalFeatures = "EnableExperimentalFeatures"
@@ -58,58 +64,70 @@ EnableExperimentalFeatures = "EnableExperimentalFeatures"
def preferences():
return FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
+
def pathScriptsSourcePath():
return os.path.join(FreeCAD.getHomePath(), "Mod/Path/PathScripts/")
+
def pathDefaultToolsPath(sub=None):
if sub:
return os.path.join(FreeCAD.getHomePath(), "Mod/Path/Tools/", sub)
return os.path.join(FreeCAD.getHomePath(), "Mod/Path/Tools/")
+
def allAvailablePostProcessors():
allposts = []
for path in searchPathsPost():
- posts = [ str(os.path.split(os.path.splitext(p)[0])[1][:-5]) for p in glob.glob(path + '/*_post.py')]
+ posts = [str(os.path.split(os.path.splitext(p)[0])[1][:-5]) for p in glob.glob(path + '/*_post.py')]
allposts.extend(posts)
allposts.sort()
return allposts
-def allEnabledPostProcessors(include = None):
+
+def allEnabledPostProcessors(include=None):
blacklist = postProcessorBlacklist()
- enabled = [processor for processor in allAvailablePostProcessors() if not processor in blacklist]
+ enabled = [processor for processor in allAvailablePostProcessors() if processor not in blacklist]
if include:
- l = list(set(include + enabled))
- l.sort()
- return l
+ postlist = list(set(include + enabled))
+ postlist.sort()
+ return postlist
return enabled
+
def defaultPostProcessor():
pref = preferences()
return pref.GetString(PostProcessorDefault, "")
+
def defaultPostProcessorArgs():
pref = preferences()
return pref.GetString(PostProcessorDefaultArgs, "")
+
def defaultGeometryTolerance():
return preferences().GetFloat(GeometryTolerance, 0.01)
+
def defaultLibAreaCurveAccuracy():
return preferences().GetFloat(LibAreaCurveAccuracy, 0.01)
+
def defaultFilePath():
return preferences().GetString(DefaultFilePath)
+
def filePath():
path = defaultFilePath()
if not path:
path = macroFilePath()
return path
+
def macroFilePath():
grp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macro")
return grp.GetString("MacroPath", FreeCAD.getUserMacroDir())
+
def searchPaths():
paths = []
p = defaultFilePath()
@@ -118,6 +136,7 @@ def searchPaths():
paths.append(macroFilePath())
return paths
+
def searchPathsPost():
paths = []
p = defaultFilePath()
@@ -128,11 +147,14 @@ def searchPathsPost():
paths.append(pathScriptsSourcePath())
return paths
+
def searchPathsTool(sub='Bit'):
paths = []
if 'Bit' == sub:
+ paths.append("{}/Bit".format(os.path.dirname(lastPathToolLibrary())))
paths.append(lastPathToolBit())
+
if 'Library' == sub:
paths.append(lastPathToolLibrary())
if 'Shape' == sub:
@@ -148,30 +170,37 @@ def searchPathsTool(sub='Bit'):
appendPath(os.path.join(FreeCAD.getHomePath(), "Mod/Path/"), sub)
return paths
+
def toolsUseLegacyTools():
- return preferences().GetBool(UseLegacyTools, True)
+ return preferences().GetBool(UseLegacyTools, False)
+
def toolsReallyUseLegacyTools():
- return toolsUseLegacyTools() or not experimentalFeaturesEnabled()
+ return toolsUseLegacyTools()
+
def toolsStoreAbsolutePaths():
return preferences().GetBool(UseAbsoluteToolPaths, False)
+
def toolsOpenLastLibrary():
return preferences().GetBool(OpenLastLibrary, False)
+
def setToolsSettings(legacy, relative, lastlibrary):
pref = preferences()
pref.SetBool(UseLegacyTools, legacy)
pref.SetBool(UseAbsoluteToolPaths, relative)
pref.SetBool(OpenLastLibrary, lastlibrary)
+
def defaultJobTemplate():
template = preferences().GetString(DefaultJobTemplate)
if 'xml' not in template:
return template
return ''
+
def setJobDefaults(fileName, jobTemplate, geometryTolerance, curveAccuracy):
PathLog.track("(%s='%s', %s, %s, %s)" % (DefaultFilePath, fileName, jobTemplate, geometryTolerance, curveAccuracy))
pref = preferences()
@@ -180,12 +209,14 @@ def setJobDefaults(fileName, jobTemplate, geometryTolerance, curveAccuracy):
pref.SetFloat(GeometryTolerance, geometryTolerance)
pref.SetFloat(LibAreaCurveAccuracy, curveAccuracy)
+
def postProcessorBlacklist():
pref = preferences()
blacklist = pref.GetString(PostProcessorBlacklist, "")
if not blacklist:
return []
- return eval(blacklist) # pylint: disable=eval-used
+ return eval(blacklist) # pylint: disable=eval-used
+
def setPostProcessorDefaults(processor, args, blacklist):
pref = preferences()
@@ -193,54 +224,99 @@ def setPostProcessorDefaults(processor, args, blacklist):
pref.SetString(PostProcessorDefaultArgs, args)
pref.SetString(PostProcessorBlacklist, "%s" % (blacklist))
+
def setOutputFileDefaults(fileName, policy):
pref = preferences()
pref.SetString(PostProcessorOutputFile, fileName)
pref.SetString(PostProcessorOutputPolicy, policy)
+
def defaultOutputFile():
pref = preferences()
return pref.GetString(PostProcessorOutputFile, "")
+
def defaultOutputPolicy():
pref = preferences()
return pref.GetString(PostProcessorOutputPolicy, "")
+
def defaultStockTemplate():
return preferences().GetString(DefaultStockTemplate, "")
+
def setDefaultStockTemplate(template):
preferences().SetString(DefaultStockTemplate, template)
+
def defaultTaskPanelLayout():
return preferences().GetInt(DefaultTaskPanelLayout, 0)
+
def setDefaultTaskPanelLayout(style):
preferences().SetInt(DefaultTaskPanelLayout, style)
+
def experimentalFeaturesEnabled():
return preferences().GetBool(EnableExperimentalFeatures, False)
+
+def lastFileToolLibrary():
+ filename = preferences().GetString(LastFileToolLibrary)
+ if filename.endswith('.fctl') and os.path.isfile(filename):
+ return filename
+
+ libpath = preferences().GetString(LastPathToolLibrary, pathDefaultToolsPath('Library'))
+ libFiles = [f for f in glob.glob(libpath + '/*.fctl')]
+ libFiles.sort()
+ if len(libFiles) >= 1:
+ filename = libFiles[0]
+ setLastFileToolLibrary(filename)
+ PathLog.track(filename)
+ return filename
+ else:
+ return None
+
+
+def setLastFileToolLibrary(path):
+ PathLog.track(path)
+ if os.path.isfile(path): # keep the path and file in sync
+ preferences().SetString(LastPathToolLibrary, os.path.split(path)[0])
+ return preferences().SetString(LastFileToolLibrary, path)
+
+
def lastPathToolBit():
return preferences().GetString(LastPathToolBit, pathDefaultToolsPath('Bit'))
+
def setLastPathToolBit(path):
return preferences().SetString(LastPathToolBit, path)
+
def lastPathToolLibrary():
+ PathLog.track()
return preferences().GetString(LastPathToolLibrary, pathDefaultToolsPath('Library'))
+
def setLastPathToolLibrary(path):
+ PathLog.track(path)
+ curLib = lastFileToolLibrary()
+ if os.path.split(curLib)[0] != path:
+ setLastFileToolLibrary('') # a path is known but not specific file
return preferences().SetString(LastPathToolLibrary, path)
+
def lastPathToolShape():
return preferences().GetString(LastPathToolShape, pathDefaultToolsPath('Shape'))
+
def setLastPathToolShape(path):
return preferences().SetString(LastPathToolShape, path)
+
def lastPathToolTable():
return preferences().GetString(LastPathToolTable, "")
+
def setLastPathToolTable(table):
return preferences().SetString(LastPathToolTable, table)
diff --git a/src/Mod/Path/PathScripts/PathProfileGui.py b/src/Mod/Path/PathScripts/PathProfileGui.py
index 3d398fec6f..ff7b6d807f 100644
--- a/src/Mod/Path/PathScripts/PathProfileGui.py
+++ b/src/Mod/Path/PathScripts/PathProfileGui.py
@@ -38,6 +38,7 @@ __doc__ = "Profile operation page controller and command implementation."
FeatureSide = 0x01
FeatureProcessing = 0x02
+
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
@@ -127,8 +128,6 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
def updateVisibility(self):
hasFace = False
- hasGeom = False
- fullModel = False
objBase = list()
if hasattr(self.obj, 'Base'):
@@ -140,8 +139,6 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
if sub[:4] == 'Face':
hasFace = True
break
- else:
- fullModel = True
if hasFace:
self.form.processCircles.show()
diff --git a/src/Mod/Path/PathScripts/PathSanity.py b/src/Mod/Path/PathScripts/PathSanity.py
index f602579a49..57230465e7 100644
--- a/src/Mod/Path/PathScripts/PathSanity.py
+++ b/src/Mod/Path/PathScripts/PathSanity.py
@@ -47,21 +47,54 @@ def translate(context, text, disambig=None):
LOG_MODULE = 'PathSanity'
-PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
+# PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
# PathLog.trackModule('PathSanity')
class CommandPathSanity:
- baseobj = None
- outputpath = PathPreferences.defaultOutputFile()
- if outputpath == "":
- outputpath = PathPreferences.macroFilePath()
- if outputpath[-1] != os.sep:
- outputpath += os.sep
- if not os.path.exists(outputpath):
- os.makedirs(outputpath)
- squawkData = {"items": []}
+ def resolveOutputPath(self, job):
+ if job.PostProcessorOutputFile != "":
+ filepath = job.PostProcessorOutputFile
+ elif PathPreferences.defaultOutputFile() != "":
+ filepath = PathPreferences.defaultOutputFile()
+ else:
+ filepath = PathPreferences.macroFilePath()
+
+ if '%D' in filepath:
+ D = FreeCAD.ActiveDocument.FileName
+ if D:
+ D = os.path.dirname(D)
+ # in case the document is in the current working directory
+ if not D:
+ D = '.'
+ else:
+ FreeCAD.Console.PrintError("Please save document in order to resolve output path!\n")
+ return None
+ filepath = filepath.replace('%D', D)
+
+ if '%d' in filepath:
+ d = FreeCAD.ActiveDocument.Label
+ filepath = filepath.replace('%d', d)
+
+ if '%j' in filepath:
+ j = job.Label
+ filepath = filepath.replace('%j', j)
+
+ if '%M' in filepath:
+ pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macro")
+ M = pref.GetString("MacroPath", FreeCAD.getUserAppDataDir())
+ filepath = filepath.replace('%M', M)
+
+ PathLog.debug('filepath: {}'.format(filepath))
+
+ # starting at the derived filename, iterate up until we have a valid
+ # directory to write to
+ while not os.path.isdir(filepath):
+ filepath = os.path.dirname(filepath)
+
+ PathLog.debug('filepath: {}'.format(filepath))
+ return filepath + os.sep
def GetResources(self):
return {'Pixmap': 'Path-Sanity',
@@ -77,9 +110,10 @@ class CommandPathSanity:
def Activated(self):
# if everything is ok, execute
- self.squawkData["items"] = []
+ self.squawkData = {"items": []}
obj = FreeCADGui.Selection.getSelectionEx()[0].Object
+ self.outputpath = self.resolveOutputPath(obj)
data = self.__summarize(obj)
html = self.__report(data)
if html is not None:
@@ -369,8 +403,8 @@ class CommandPathSanity:
# Save the report
- reportraw = self.outputpath + '/setupreport.asciidoc'
- reporthtml = self.outputpath + '/setupreport.html'
+ reportraw = self.outputpath + 'setupreport.asciidoc'
+ reporthtml = self.outputpath + 'setupreport.html'
with open(reportraw, 'w') as fd:
fd.write(report)
fd.close()
@@ -505,7 +539,7 @@ class CommandPathSanity:
tooldata['partNumber'] = ""
imagedata = TC.Tool.Proxy.getBitThumbnail(TC.Tool)
- imagepath = '{}/T{}.png'.format(self.outputpath, TC.ToolNumber)
+ imagepath = '{}T{}.png'.format(self.outputpath, TC.ToolNumber)
tooldata['feedrate'] = str(TC.HorizFeed)
if TC.HorizFeed.Value == 0.0:
self.squawk("PathSanity",
@@ -646,7 +680,7 @@ class CommandPathSanity:
view.showNormal()
view.resize(320, 320)
- imagepath = '{}/origin'.format(self.outputpath)
+ imagepath = '{}origin'.format(self.outputpath)
FreeCADGui.Selection.clearSelection()
FreeCADGui.SendMsgToActiveView("PerspectiveCamera")
diff --git a/src/Mod/Path/PathScripts/PathToolBit.py b/src/Mod/Path/PathScripts/PathToolBit.py
index d04473923d..a76150b597 100644
--- a/src/Mod/Path/PathScripts/PathToolBit.py
+++ b/src/Mod/Path/PathScripts/PathToolBit.py
@@ -45,29 +45,32 @@ __doc__ = "Class to deal with and represent a tool bit."
# PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
# PathLog.trackModule()
+
def translate(context, text, disambig=None):
return PySide.QtCore.QCoreApplication.translate(context, text, disambig)
+
ParameterTypeConstraint = {
'Angle': 'App::PropertyAngle',
'Distance': 'App::PropertyLength',
'DistanceX': 'App::PropertyLength',
'DistanceY': 'App::PropertyLength',
- 'Radius': 'App::PropertyLength'
- }
+ 'Radius': 'App::PropertyLength'}
def _findTool(path, typ, dbg=False):
- if os.path.exists(path):
+ if os.path.exists(path): # absolute reference
if dbg:
PathLog.debug("Found {} at {}".format(typ, path))
return path
def searchFor(pname, fname):
+ # PathLog.debug("pname: {} fname: {}".format(pname, fname))
if dbg:
PathLog.debug("Looking for {}".format(pname))
if fname:
for p in PathPreferences.searchPathsTool(typ):
+ PathLog.track(p)
f = os.path.join(p, fname)
if dbg:
PathLog.debug(" Checking {}".format(f))
@@ -76,6 +79,7 @@ def _findTool(path, typ, dbg=False):
PathLog.debug(" Found {} at {}".format(typ, f))
return f
if pname and os.path.sep != pname:
+ PathLog.track(pname)
ppname, pfname = os.path.split(pname)
ffname = os.path.join(pfname, fname) if fname else pfname
return searchFor(ppname, ffname)
@@ -83,20 +87,28 @@ def _findTool(path, typ, dbg=False):
return searchFor(path, '')
+
def findShape(path):
- '''findShape(path) ... search for path, full and partially in all known shape directories.'''
+ '''
+ findShape(path) ... search for path, full and partially
+ in all known shape directories.
+ '''
return _findTool(path, 'Shape')
+
def findBit(path):
+ PathLog.track(path)
if path.endswith('.fctb'):
return _findTool(path, 'Bit')
return _findTool("{}.fctb".format(path), 'Bit')
+
def findLibrary(path, dbg=False):
if path.endswith('.fctl'):
return _findTool(path, 'Library', dbg)
return _findTool("{}.fctl".format(path), 'Library', dbg)
+
def _findRelativePath(path, typ):
relative = path
for p in PathPreferences.searchPathsTool(typ):
@@ -108,15 +120,19 @@ def _findRelativePath(path, typ):
relative = p
return relative
+
def findRelativePathShape(path):
return _findRelativePath(path, 'Shape')
+
def findRelativePathTool(path):
return _findRelativePath(path, 'Bit')
+
def findRelativePathLibrary(path):
return _findRelativePath(path, 'Library')
+
def updateConstraint(sketch, name, value):
for i, constraint in enumerate(sketch.Constraints):
if constraint.Name.split(';')[0] == name:
@@ -128,7 +144,9 @@ def updateConstraint(sketch, name, value):
if constr is not None:
if not PathGeom.isRoughly(constraint.Value, value.Value):
- PathLog.track(name, constraint.Type, 'update', i, "(%.2f -> %.2f)" % (constraint.Value, value.Value))
+ PathLog.track(name, constraint.Type,
+ 'update', i, "(%.2f -> %.2f)"
+ % (constraint.Value, value.Value))
sketch.delConstraint(i)
sketch.recompute()
n = sketch.addConstraint(constr)
@@ -141,15 +159,21 @@ def updateConstraint(sketch, name, value):
PropertyGroupBit = 'Bit'
PropertyGroupAttribute = 'Attribute'
+
class ToolBit(object):
def __init__(self, obj, shapeFile):
PathLog.track(obj.Label, shapeFile)
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::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'))
if shapeFile is None:
obj.BitShape = 'endmill.fcstd'
self._setupBitShape(obj)
@@ -184,14 +208,14 @@ class ToolBit(object):
for prop in self.propertyNamesBit(obj):
obj.setEditorMode(prop, 1)
# I currently don't see why these need to be read-only
- #for prop in self.propertyNamesAttribute(obj):
+ # for prop in self.propertyNamesAttribute(obj):
# obj.setEditorMode(prop, 1)
def onChanged(self, obj, prop):
PathLog.track(obj.Label, prop)
- if prop == 'BitShape' and not 'Restore' in obj.State:
+ if prop == 'BitShape' and 'Restore' not in obj.State:
self._setupBitShape(obj)
- #elif obj.getGroupOfProperty(prop) == PropertyGroupBit:
+ # elif obj.getGroupOfProperty(prop) == PropertyGroupBit:
# self._updateBitShape(obj, [prop])
def onDelete(self, obj, arg2=None):
@@ -200,7 +224,7 @@ class ToolBit(object):
obj.Document.removeObject(obj.Name)
def _updateBitShape(self, obj, properties=None):
- if not obj.BitBody is None:
+ if obj.BitBody is not None:
if not properties:
properties = self.propertyNamesBit(obj)
for prop in properties:
@@ -234,7 +258,6 @@ class ToolBit(object):
return (doc, docOpened)
def _removeBitBody(self, obj):
- print('in _removebitbody')
if obj.BitBody:
obj.BitBody.removeObjectsFromDocument()
obj.Document.removeObject(obj.BitBody.Name)
@@ -286,7 +309,7 @@ class ToolBit(object):
prop = parts[0]
desc = ''
if len(parts) > 1:
- desc = parts[1]
+ desc = parts[1]
obj.addProperty(typ, prop, PropertyGroupBit, desc)
obj.setEditorMode(prop, 1)
value = constraint.Value
@@ -307,7 +330,7 @@ class ToolBit(object):
return None
def saveToFile(self, obj, path, setFile=True):
- print('were saving now')
+ PathLog.track(path)
try:
with open(path, 'w') as fp:
json.dump(self.templateAttrs(obj), fp, indent=' ')
@@ -315,12 +338,13 @@ class ToolBit(object):
obj.File = path
return True
except (OSError, IOError) as e:
- PathLog.error("Could not save tool %s to %s (%s)" % (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['version'] = 2 # Path.Tool is version 1
attrs['name'] = obj.Label
if PathPreferences.toolsStoreAbsolutePaths():
attrs['shape'] = obj.BitShape
@@ -332,7 +356,6 @@ class ToolBit(object):
attrs['parameter'] = params
params = {}
for name in self.propertyNamesAttribute(obj):
- #print(f"shapeattr {name}")
if name == "UserAttributes":
for key, value in obj.UserAttributes.items():
params[key] = value
@@ -341,26 +364,43 @@ class ToolBit(object):
attrs['attribute'] = params
return attrs
+
def Declaration(path):
+ PathLog.track(path)
with open(path, 'r') as fp:
return json.load(fp)
+
class AttributePrototype(PathSetupSheetOpPrototype.OpPrototype):
def __init__(self):
PathSetupSheetOpPrototype.OpPrototype.__init__(self, 'ToolBitAttribute')
- self.addProperty('App::PropertyEnumeration', 'Material', PropertyGroupAttribute, translate('PathToolBit', 'Tool bit material'))
- self.Material = ['Carbide', 'CastAlloy', 'Ceramics', 'Diamond', 'HighCarbonToolSteel', 'HighSpeedSteel', 'Sialon']
- self.addProperty('App::PropertyDistance', 'LengthOffset', PropertyGroupAttribute, translate('PathToolBit', 'Length offset in Z direction'))
- self.addProperty('App::PropertyInteger', 'Flutes', PropertyGroupAttribute, translate('PathToolBit', 'The number of flutes'))
- self.addProperty('App::PropertyDistance', 'ChipLoad', PropertyGroupAttribute, translate('PathToolBit', 'Chipload as per manufacturer'))
- self.addProperty('App::PropertyMap', 'UserAttributes', PropertyGroupAttribute, translate('PathTooolBit', 'User Defined Values'))
+ self.addProperty('App::PropertyEnumeration', 'Material',
+ PropertyGroupAttribute,
+ translate('PathToolBit', 'Tool bit material'))
+ self.Material = ['Carbide', 'CastAlloy', 'Ceramics', 'Diamond',
+ 'HighCarbonToolSteel', 'HighSpeedSteel', 'Sialon']
+ self.addProperty('App::PropertyDistance', 'LengthOffset',
+ PropertyGroupAttribute, translate('PathToolBit',
+ 'Length offset in Z direction'))
+ self.addProperty('App::PropertyInteger', 'Flutes',
+ PropertyGroupAttribute, translate('PathToolBit',
+ 'The number of flutes'))
+ self.addProperty('App::PropertyDistance', 'ChipLoad',
+ PropertyGroupAttribute, translate('PathToolBit',
+ 'Chipload as per manufacturer'))
+ self.addProperty('App::PropertyMap', 'UserAttributes',
+ PropertyGroupAttribute, translate('PathToolBit',
+ 'User Defined Values'))
+ self.addProperty('App::PropertyBool', 'SpindlePower',
+ PropertyGroupAttribute, translate('PathToolBit',
+ 'Whether Spindle Power should be allowed'))
class ToolBitFactory(object):
def CreateFromAttrs(self, attrs, name='ToolBit'):
- # pylint: disable=protected-access
+ PathLog.debug(attrs)
obj = Factory.Create(name, attrs['shape'])
obj.Label = attrs['name']
params = attrs['parameter']
@@ -372,23 +412,17 @@ class ToolBitFactory(object):
proto = AttributePrototype()
uservals = {}
for pname in params:
- #print(f"pname: {pname}")
try:
prop = proto.getProperty(pname)
- val = prop.valueFromString(params[pname])
prop.setupProperty(obj, pname, PropertyGroupAttribute, prop.valueFromString(params[pname]))
- except:
- # prop = obj.addProperty('App::PropertyString', pname, "Attribute", translate('PathTooolBit', 'User Defined Value'))
- # setattr(obj, pname, params[pname])
+ except Exception:
prop = proto.getProperty("UserAttributes")
uservals.update({pname: params[pname]})
- #prop.setupProperty(obj, pname, "UserAttributes", prop.valueFromString(params[pname]))
if len(uservals.items()) > 0:
- prop.setupProperty(obj, "UserAttributes", PropertyGroupAttribute, uservals)
+ prop.setupProperty(obj, "UserAttributes",
+ PropertyGroupAttribute, uservals)
- # print("prop[%s] = %s (%s)" % (pname, params[pname], type(val)))
- #prop.setupProperty(obj, pname, PropertyGroupAttribute, prop.valueFromString(params[pname]))
return obj
def CreateFrom(self, path, name='ToolBit'):
@@ -406,4 +440,5 @@ class ToolBitFactory(object):
obj.Proxy = ToolBit(obj, shapeFile)
return obj
+
Factory = ToolBitFactory()
diff --git a/src/Mod/Path/PathScripts/PathToolBitEdit.py b/src/Mod/Path/PathScripts/PathToolBitEdit.py
index a8e76cf20e..0ee54747bb 100644
--- a/src/Mod/Path/PathScripts/PathToolBitEdit.py
+++ b/src/Mod/Path/PathScripts/PathToolBitEdit.py
@@ -31,7 +31,7 @@ import re
from PySide import QtCore, QtGui
-# PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# PathLog.trackModule(PathLog.thisModule())
@@ -42,10 +42,12 @@ def translate(context, text, disambig=None):
class ToolBitEditor(object):
'''UI and controller for editing a ToolBit.
- The controller embeds the UI to the parentWidget which has to have a layout attached to it.
+ The controller embeds the UI to the parentWidget which has to have a
+ layout attached to it.
'''
- def __init__(self, tool, parentWidget=None):
+ def __init__(self, tool, parentWidget=None, loadBitBody=True):
+ PathLog.track()
self.form = FreeCADGui.PySideUic.loadUi(":/panels/ToolBitEditor.ui")
if parentWidget:
@@ -53,13 +55,18 @@ class ToolBitEditor(object):
parentWidget.layout().addWidget(self.form)
self.tool = tool
+ self.loadbitbody = loadBitBody
if not tool.BitShape:
self.tool.BitShape = 'endmill.fcstd'
- self.tool.Proxy.loadBitBody(self.tool)
+
+ if self.loadbitbody:
+ self.tool.Proxy.loadBitBody(self.tool)
+
self.setupTool(self.tool)
self.setupAttributes(self.tool)
def setupTool(self, tool):
+ PathLog.track()
layout = self.form.bitParams.layout()
for i in range(layout.rowCount() - 1, -1, -1):
layout.removeRow(i)
@@ -69,7 +76,8 @@ class ToolBitEditor(object):
if tool.getGroupOfProperty(name) == PathToolBit.PropertyGroupBit:
qsb = ui.createWidget('Gui::QuantitySpinBox')
editor[name] = PathGui.QuantitySpinBox(qsb, tool, name)
- label = QtGui.QLabel(re.sub('([A-Z][a-z]+)', r' \1', re.sub('([A-Z]+)', r' \1', name)))
+ label = QtGui.QLabel(re.sub('([A-Z][a-z]+)', r' \1',
+ re.sub('([A-Z]+)', r' \1', name)))
layout.addRow(label, qsb)
self.bitEditor = editor
img = tool.Proxy.getBitThumbnail(tool)
@@ -79,6 +87,7 @@ class ToolBitEditor(object):
self.form.image.setPixmap(QtGui.QPixmap())
def setupAttributes(self, tool):
+ PathLog.track()
self.proto = PathToolBit.AttributePrototype()
self.props = sorted(self.proto.properties)
self.delegate = PathSetupSheetGui.Delegate(self.form)
@@ -86,7 +95,7 @@ class ToolBitEditor(object):
self.model.setHorizontalHeaderLabels(['Set', 'Property', 'Value'])
for i, name in enumerate(self.props):
- print("propname: %s " % name)
+ PathLog.debug("propname: %s " % name)
prop = self.proto.getProperty(name)
isset = hasattr(tool, name)
@@ -99,10 +108,15 @@ class ToolBitEditor(object):
else:
- self.model.setData(self.model.index(i, 0), isset, QtCore.Qt.EditRole)
- self.model.setData(self.model.index(i, 1), name, QtCore.Qt.EditRole)
- self.model.setData(self.model.index(i, 2), prop, PathSetupSheetGui.Delegate.PropertyRole)
- self.model.setData(self.model.index(i, 2), prop.displayString(), QtCore.Qt.DisplayRole)
+ self.model.setData(self.model.index(i, 0), isset,
+ QtCore.Qt.EditRole)
+ self.model.setData(self.model.index(i, 1), name,
+ QtCore.Qt.EditRole)
+ self.model.setData(self.model.index(i, 2), prop,
+ PathSetupSheetGui.Delegate.PropertyRole)
+ self.model.setData(self.model.index(i, 2),
+ prop.displayString(),
+ QtCore.Qt.DisplayRole)
self.model.item(i, 0).setCheckable(True)
self.model.item(i, 0).setText('')
@@ -119,7 +133,7 @@ class ToolBitEditor(object):
if hasattr(tool, "UserAttributes"):
for key, value in tool.UserAttributes.items():
- print(key, value)
+ PathLog.debug(key, value)
c1 = QtGui.QStandardItem()
c1.setCheckable(False)
c1.setEditable(False)
@@ -141,26 +155,33 @@ class ToolBitEditor(object):
self.model.dataChanged.connect(self.updateData)
def updateData(self, topLeft, bottomRight):
- # pylint: disable=unused-argument
+ PathLog.track()
if 0 == topLeft.column():
- isset = self.model.item(topLeft.row(), 0).checkState() == QtCore.Qt.Checked
+ isset = self.model.item(topLeft.row(),
+ 0).checkState() == QtCore.Qt.Checked
self.model.item(topLeft.row(), 1).setEnabled(isset)
self.model.item(topLeft.row(), 2).setEnabled(isset)
def accept(self):
+ PathLog.track()
self.refresh()
self.tool.Proxy.unloadBitBody(self.tool)
# get the attributes
for i, name in enumerate(self.props):
+ PathLog.debug('in accept: {}'.format(name))
prop = self.proto.getProperty(name)
- enabled = self.model.item(i, 0).checkState() == QtCore.Qt.Checked
- if enabled and not prop.getValue() is None:
- prop.setupProperty(self.tool, name, PathToolBit.PropertyGroupAttribute, prop.getValue())
- elif hasattr(self.tool, name):
- self.tool.removeProperty(name)
+ if self.model.item(i, 0) is not None:
+ enabled = self.model.item(i, 0).checkState() == QtCore.Qt.Checked
+ if enabled and not prop.getValue() is None:
+ prop.setupProperty(self.tool, name,
+ PathToolBit.PropertyGroupAttribute,
+ prop.getValue())
+ elif hasattr(self.tool, name):
+ self.tool.removeProperty(name)
def reject(self):
+ PathLog.track()
self.tool.Proxy.unloadBitBody(self.tool)
def updateUI(self):
@@ -172,6 +193,7 @@ class ToolBitEditor(object):
self.bitEditor[editor].updateSpinBox()
def updateShape(self):
+ PathLog.track()
self.tool.BitShape = str(self.form.shapePath.text())
self.setupTool(self.tool)
self.form.toolName.setText(self.tool.Label)
@@ -180,7 +202,6 @@ class ToolBitEditor(object):
self.bitEditor[editor].updateSpinBox()
def updateTool(self):
- # pylint: disable=protected-access
PathLog.track()
self.tool.Label = str(self.form.toolName.text())
self.tool.BitShape = str(self.form.shapePath.text())
@@ -188,7 +209,7 @@ class ToolBitEditor(object):
for editor in self.bitEditor:
self.bitEditor[editor].updateProperty()
- self.tool.Proxy._updateBitShape(self.tool)
+ # self.tool.Proxy._updateBitShape(self.tool)
def refresh(self):
PathLog.track()
@@ -198,13 +219,14 @@ class ToolBitEditor(object):
self.form.blockSignals(False)
def selectShape(self):
+ PathLog.track()
path = self.tool.BitShape
if not path:
path = PathPreferences.lastPathToolShape()
foo = QtGui.QFileDialog.getOpenFileName(self.form,
- "Path - Tool Shape",
- path,
- "*.fcstd")
+ "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 9702dfe469..21a755f2ce 100644
--- a/src/Mod/Path/PathScripts/PathToolBitGui.py
+++ b/src/Mod/Path/PathScripts/PathToolBitGui.py
@@ -36,12 +36,15 @@ __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)
-#PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
-#PathLog.trackModule(PathLog.thisModule())
+
+PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
+# PathLog.trackModule(PathLog.thisModule())
+
class ViewProvider(object):
'''ViewProvider for a ToolBit.
@@ -58,7 +61,7 @@ class ViewProvider(object):
def attach(self, vobj):
PathLog.track(vobj.Object)
self.vobj = vobj
- self.obj = vobj.Object
+ self.obj = vobj.Object
def getIcon(self):
png = self.obj.Proxy.getBitThumbnail(self.obj)
@@ -111,7 +114,15 @@ class ViewProvider(object):
return []
def doubleClicked(self, vobj):
- self.setEdit(vobj)
+ 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)
+ diag.setWindowModality(QtCore.Qt.ApplicationModal)
+ diag.exec_()
+
class TaskPanel:
'''TaskPanel for the SetupSheet - if it is being edited directly.'''
@@ -123,7 +134,8 @@ 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(translate('PathToolBit',
+ 'Edit ToolBit'))
def reject(self):
FreeCAD.ActiveDocument.abortTransaction()
@@ -145,6 +157,7 @@ class TaskPanel:
FreeCAD.ActiveDocument.recompute()
def updateUI(self):
+ PathLog.track()
self.editor.updateUI()
def updateModel(self):
@@ -155,141 +168,91 @@ class TaskPanel:
self.editor.setupUI()
-class ToolBitSelector(object):
- ToolRole = QtCore.Qt.UserRole + 1
-
- def __init__(self):
- self.buttons = None
- self.editor = None
- self.dialog = None
- self.form = FreeCADGui.PySideUic.loadUi(':/panels/ToolBitSelector.ui')
- self.setupUI()
-
- def updateTools(self, selected=None):
- PathLog.track()
- selItem = None
- self.form.tools.setUpdatesEnabled(False)
- if selected is None and self.form.tools.currentItem():
- selected = self.form.tools.currentItem().text()
- self.form.tools.clear()
- for tool in sorted(self.loadedTools(), key=lambda t: t.Label):
- icon = None
- if tool.ViewObject and tool.ViewObject.Proxy:
- icon = tool.ViewObject.Proxy.getIcon()
- if icon and isinstance(icon, QtGui.QIcon):
- item = QtGui.QListWidgetItem(icon, tool.Label)
- else:
- item = QtGui.QListWidgetItem(tool.Label)
- item.setData(self.ToolRole, tool)
- if selected == tool.Label:
- selItem = item
- self.form.tools.addItem(item)
- if selItem:
- self.form.tools.setCurrentItem(selItem)
- self.updateSelection()
- self.form.tools.setUpdatesEnabled(True)
-
- def getTool(self):
- PathLog.track()
- self.updateTools()
- res = self.form.exec_()
- if 1 == res and self.form.tools.currentItem():
- return self.form.tools.currentItem().data(self.ToolRole)
- return None
-
- def loadedTools(self):
- PathLog.track()
- if FreeCAD.ActiveDocument:
- return [o for o in FreeCAD.ActiveDocument.Objects if hasattr(o, 'Proxy') and isinstance(o.Proxy, PathToolBit.ToolBit)]
- return []
-
- def loadTool(self):
- PathLog.track()
- tool = LoadTool(self.form)
- if tool:
- self.updateTools(tool.Label)
-
- def createTool(self):
- PathLog.track()
- tool = PathToolBit.Factory.Create()
-
- def accept():
- self.editor.accept()
- self.dialog.done(1)
- self.updateTools(tool.Label)
-
- def reject():
- FreeCAD.ActiveDocument.openTransaction(translate('PathToolBit', 'Uncreate ToolBit'))
- self.editor.reject()
- self.dialog.done(0)
- FreeCAD.ActiveDocument.removeObject(tool.Name)
- FreeCAD.ActiveDocument.commitTransaction()
-
- self.dialog = QtGui.QDialog(self.form)
- layout = QtGui.QVBoxLayout(self.dialog)
- self.editor = PathToolBitEdit.ToolBitEditor(tool, self.dialog)
- self.editor.setupUI()
- self.buttons = QtGui.QDialogButtonBox(
- QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel,
- QtCore.Qt.Horizontal, self.dialog)
- layout.addWidget(self.buttons)
- self.buttons.accepted.connect(accept)
- self.buttons.rejected.connect(reject)
- print(self.dialog.exec_())
-
- def updateSelection(self):
- PathLog.track()
- if self.form.tools.selectedItems():
- self.form.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
- else:
- self.form.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False)
-
- def setupUI(self):
- PathLog.track()
- self.form.toolCreate.clicked.connect(self.createTool)
- self.form.toolLoad.clicked.connect(self.loadTool)
- self.form.tools.itemSelectionChanged.connect(self.updateSelection)
- self.form.tools.doubleClicked.connect(self.form.accept)
-
class ToolBitGuiFactory(PathToolBit.ToolBitFactory):
def Create(self, name='ToolBit', shapeFile=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.'''
- FreeCAD.ActiveDocument.openTransaction(translate('PathToolBit', 'Create ToolBit'))
+
+ FreeCAD.ActiveDocument.openTransaction(translate('PathToolBit',
+ 'Create ToolBit'))
tool = PathToolBit.ToolBitFactory.Create(self, name, shapeFile)
PathIconViewProvider.Attach(tool.ViewObject, name)
FreeCAD.ActiveDocument.commitTransaction()
return tool
-def GetToolFile(parent = None):
+
+def GetNewToolFile(parent=None):
if parent is None:
parent = QtGui.QApplication.activeWindow()
- foo = QtGui.QFileDialog.getOpenFileName(parent, 'Tool', PathPreferences.lastPathToolBit(), '*.fctb')
+ foo = QtGui.QFileDialog.getSaveFileName(parent, 'Tool',
+ PathPreferences.lastPathToolBit(),
+ '*.fctb')
if foo and foo[0]:
PathPreferences.setLastPathToolBit(os.path.dirname(foo[0]))
return foo[0]
return None
-def GetToolFiles(parent = None):
+
+def GetToolFile(parent=None):
if parent is None:
parent = QtGui.QApplication.activeWindow()
- foo = QtGui.QFileDialog.getOpenFileNames(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]
+ return None
+
+
+def GetToolFiles(parent=None):
+ if parent is None:
+ parent = QtGui.QApplication.activeWindow()
+ 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]
return []
-def LoadTool(parent = None):
- '''LoadTool(parent=None) ... Open a file dialog to load a tool from a file.'''
+def GetToolShapeFile(parent=None):
+ if parent is None:
+ parent = QtGui.QApplication.activeWindow()
+
+ location = PathPreferences.lastPathToolShape()
+ if os.path.isfile(location):
+ location = os.path.split(location)[0]
+ elif not os.path.isdir(location):
+ location = PathPreferences.filePath()
+
+ fname = QtGui.QFileDialog.getOpenFileName(parent, 'Select Tool Shape',
+ location, '*.fcstd')
+ if fname and fname[0]:
+ if fname != location:
+ PathPreferences.setLastPathToolShape(location)
+ return fname[0]
+ else:
+ return 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.'''
+
+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()
diff --git a/src/Mod/Path/PathScripts/PathToolBitLibraryCmd.py b/src/Mod/Path/PathScripts/PathToolBitLibraryCmd.py
index 10ad578196..3d18989ee5 100644
--- a/src/Mod/Path/PathScripts/PathToolBitLibraryCmd.py
+++ b/src/Mod/Path/PathScripts/PathToolBitLibraryCmd.py
@@ -25,9 +25,10 @@ import FreeCADGui
import PySide.QtCore as QtCore
import PathScripts.PathPreferences as PathPreferences
-class CommandToolBitLibraryOpen:
+
+class CommandToolBitSelectorOpen:
'''
- Command to ToolBitLibrary editor.
+ Command to toggle the ToolBitSelector Dock
'''
def __init__(self):
@@ -35,11 +36,42 @@ class CommandToolBitLibraryOpen:
def GetResources(self):
return {'Pixmap': 'Path-ToolTable',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Open ToolBit Library editor"),
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Open an editor to manage ToolBit libraries")}
+ 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "ToolBit Dock"),
+ 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Toggle the Toolbit Dock"),
+ 'Accel': "P, T",
+ 'CmdType': "ForEdit"}
def IsActive(self):
- return True
+ return FreeCAD.ActiveDocument is not None
+
+ def Activated(self):
+ import PathScripts.PathToolBitLibraryGui as PathToolBitLibraryGui
+ dock = PathToolBitLibraryGui.ToolBitSelector()
+
+ lastlib = PathPreferences.lastPathToolLibrary()
+
+ if PathPreferences.toolsOpenLastLibrary():
+ dock.open(lastlib)
+ else:
+ 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"}
+
+ def IsActive(self):
+ return FreeCAD.ActiveDocument is not None
def Activated(self):
import PathScripts.PathToolBitLibraryGui as PathToolBitLibraryGui
@@ -52,55 +84,57 @@ class CommandToolBitLibraryOpen:
else:
library.open()
-class CommandToolBitLibraryLoad:
- '''
- Command used to load an entire ToolBitLibrary (or part of it) from a file into a job.
- '''
+# class CommandToolBitLibraryLoad:
+# '''
+# Command used to load an entire ToolBitLibrary (or part of it) from a file into a job.
+# '''
- def __init__(self):
- pass
+# def __init__(self):
+# pass
- def GetResources(self):
- return {'Pixmap': 'Path-ToolTable',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Load ToolBit Library"),
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Load an entire ToolBit library or part of it into a job")}
+# def GetResources(self):
+# return {'Pixmap': 'Path-ToolTable',
+# 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Load ToolBit Library"),
+# 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Load an entire ToolBit library or part of it into a job")}
- def selectedJob(self):
- if FreeCAD.ActiveDocument:
- sel = FreeCADGui.Selection.getSelectionEx()
- 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']
- if 1 == len(jobs):
- return jobs[0]
- return None
+# def selectedJob(self):
+# if FreeCAD.ActiveDocument:
+# sel = FreeCADGui.Selection.getSelectionEx()
+# 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']
+# if 1 == len(jobs):
+# return jobs[0]
+# return None
- def IsActive(self):
- return not self.selectedJob() is None
+# def IsActive(self):
+# return not self.selectedJob() is None
- def Activated(self):
- job = self.selectedJob()
- self.Execute(job)
+# def Activated(self):
+# job = self.selectedJob()
+# self.Execute(job)
- @classmethod
- def Execute(cls, job):
- import PathScripts.PathToolBitLibraryGui as PathToolBitLibraryGui
- import PathScripts.PathToolControllerGui as PathToolControllerGui
+# @classmethod
+# def Execute(cls, job):
+# import PathScripts.PathToolBitLibraryGui as PathToolBitLibraryGui
+# import PathScripts.PathToolControllerGui as PathToolControllerGui
- library = PathToolBitLibraryGui.ToolBitLibrary()
+# library = PathToolBitLibraryGui.ToolBitLibrary()
+
+# if 1 == library.open() and job:
+# for nr, tool in library.selectedOrAllTools():
+# tc = PathToolControllerGui.Create("TC: {}".format(tool.Label), tool, nr)
+# job.Proxy.addToolController(tc)
+# FreeCAD.ActiveDocument.recompute()
+# return True
+# return False
- if 1 == library.open() and job:
- for nr, tool in library.selectedOrAllTools():
- tc = PathToolControllerGui.Create("TC: {}".format(tool.Label), tool, nr)
- job.Proxy.addToolController(tc)
- FreeCAD.ActiveDocument.recompute()
- return True
- return False
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Path_ToolBitLibraryOpen', CommandToolBitLibraryOpen())
- FreeCADGui.addCommand('Path_ToolBitLibraryLoad', CommandToolBitLibraryLoad())
+ FreeCADGui.addCommand('Path_ToolBitDock', CommandToolBitSelectorOpen())
-CommandList = ['Path_ToolBitLibraryOpen', 'Path_ToolBitLibraryLoad']
+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 2dbb4c0ce9..a0a52f0de3 100644
--- a/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py
+++ b/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py
@@ -35,7 +35,7 @@ from PySide import QtCore, QtGui
import PySide
import json
import os
-import traceback
+import glob
import uuid as UUID
from functools import partial
@@ -55,11 +55,11 @@ class _TableView(PySide.QtGui.QTableView):
def __init__(self, parent):
PySide.QtGui.QTableView.__init__(self, parent)
- self.setDragEnabled(True)
- self.setAcceptDrops(True)
- self.setDropIndicatorShown(True)
- self.setDragDropMode(PySide.QtGui.QAbstractItemView.InternalMove)
- self.setDefaultDropAction(PySide.QtCore.Qt.MoveAction)
+ self.setDragEnabled(False)
+ self.setAcceptDrops(False)
+ self.setDropIndicatorShown(False)
+ self.setDragDropMode(PySide.QtGui.QAbstractItemView.DragOnly)
+ self.setDefaultDropAction(PySide.QtCore.Qt.IgnoreAction)
self.setSortingEnabled(True)
self.setSelectionBehavior(PySide.QtGui.QAbstractItemView.SelectRows)
self.verticalHeader().hide()
@@ -68,18 +68,18 @@ class _TableView(PySide.QtGui.QTableView):
return [PySide.QtCore.Qt.CopyAction, PySide.QtCore.Qt.MoveAction]
def _uuidOfRow(self, row):
- model = self.model()
+ model = self.toolModel()
return model.data(model.index(row, 0), _UuidRole)
def _rowWithUuid(self, uuid):
- model = self.model()
+ model = self.toolModel()
for row in range(model.rowCount()):
if self._uuidOfRow(row) == uuid:
return row
return None
def _copyTool(self, uuid_, dstRow):
- model = self.model()
+ model = self.toolModel()
model.insertRow(dstRow)
srcRow = self._rowWithUuid(uuid_)
for col in range(model.columnCount()):
@@ -108,23 +108,9 @@ class _TableView(PySide.QtGui.QTableView):
# pylint: disable=unused-variable
row = stream.readInt32()
srcRows.append(row)
- # col = stream.readInt32()
- # PathLog.track(row, col)
- # cnt = stream.readInt32()
- # for i in range(cnt):
- # key = stream.readInt32()
- # val = stream.readQVariant()
- # PathLog.track(' ', i, key, val, type(val))
- # I have no idea what these three integers are,
- # or if they even are three integers,
- # but it seems to work out this way.
- # i0 = stream.readInt32()
- # i1 = stream.readInt32()
- # i2 = stream.readInt32()
- # PathLog.track(' ', i0, i1, i2)
# get the uuids of all srcRows
- model = self.model()
+ model = self.toolModel()
srcUuids = [self._uuidOfRow(row) for row in set(srcRows)]
destRow = self.rowAt(event.pos().y())
@@ -134,264 +120,432 @@ class _TableView(PySide.QtGui.QTableView):
model.removeRow(self._rowWithUuid(uuid))
-class ToolBitLibrary(object):
- '''ToolBitLibrary is the controller for displaying/selecting/creating/editing a collection of ToolBits.'''
+class ModelFactory(object):
+ ''' Helper class to generate qtdata models for toolbit libraries
+ '''
def __init__(self, path=None):
- self.path = path
+ PathLog.track()
+ self.path = ""
+ # self.currentLib = ""
+
+ def __libraryLoad(self, path, datamodel):
+ PathLog.track(path)
+ PathPreferences.setLastFileToolLibrary(path)
+ # self.currenLib = path
+
+ with open(path) as fp:
+ library = json.load(fp)
+
+ for toolBit in library['tools']:
+ try:
+ nr = toolBit['nr']
+ bit = PathToolBit.findBit(toolBit['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']))
+ except Exception as 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]
+ # strDiam = tool['parameter']['Diameter']
+ tooltip = "{}".format(strShape)
+
+ toolNr = PySide.QtGui.QStandardItem()
+ toolNr.setData(nr, PySide.QtCore.Qt.EditRole)
+ 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.setEditable(False)
+ toolName.setToolTip(tooltip)
+
+ toolShape = PySide.QtGui.QStandardItem()
+ toolShape.setData(strShape, PySide.QtCore.Qt.EditRole)
+ toolShape.setEditable(False)
+
+ return [toolNr, toolName, toolShape]
+
+ def newTool(self, datamodel, path):
+ '''
+ Adds a toolbit item to a model
+ '''
+ PathLog.track()
+
+ try:
+ nr = 0
+ for row in range(datamodel.rowCount()):
+ itemNr = int(datamodel.item(row, 0).data(PySide.QtCore.Qt.EditRole))
+ nr = max(nr, itemNr)
+ nr += 1
+ tool = PathToolBit.Declaration(path)
+ except Exception as e:
+ PathLog.error(e)
+
+ 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 + '/*.fctl')]
+ libFiles.sort()
+ for libFile in libFiles:
+ loc, fnlong = os.path.split(libFile)
+ fn, ext = os.path.splitext(fnlong)
+ libItem = QtGui.QStandardItem(fn)
+ libItem.setToolTip(loc)
+ libItem.setData(libFile, _PathRole)
+ libItem.setIcon(QtGui.QPixmap(':/icons/Path-ToolTable.svg'))
+ model.appendRow(libItem)
+
+ 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 == "":
+ lib = PathPreferences.lastFileToolLibrary()
+
+ if lib == "" or lib is None:
+ return model
+
+ if os.path.isfile(lib): # An individual library is wanted
+ self.__libraryLoad(lib, model)
+
+ PathLog.debug('model rows: {}'.format(model.rowCount()))
+ return model
+
+
+class ToolBitSelector(object):
+ '''Controller for displaying a library and creating ToolControllers'''
+
+ def __init__(self):
+ 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']
+
+ def curLib(self):
+ libfile = PathPreferences.lastFileToolLibrary()
+ if libfile is None or libfile == "":
+ return ""
+ else:
+ libfile = os.path.split(PathPreferences.lastFileToolLibrary())[1]
+ libfile = os.path.splitext(libfile)[0]
+ return libfile
+
+ def loadData(self):
+ PathLog.track()
+ self.toolModel.clear()
+ self.toolModel.setHorizontalHeaderLabels(self.columnNames())
+ self.form.lblLibrary.setText(self.curLib())
+ self.factory.libraryOpen(self.toolModel)
+ self.toolModel.takeColumn(3)
+ self.toolModel.takeColumn(2)
+
+ def setupUI(self):
+ PathLog.track()
+ 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.libraryEditorOpen.clicked.connect(self.libraryEditorOpen)
+ self.form.addToolController.clicked.connect(self.selectedOrAllToolControllers)
+
+ def enableButtons(self):
+ selected = (len(self.form.tools.selectedIndexes()) >= 1)
+ if selected:
+ 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):
+ library = ToolBitLibrary()
+ library.open()
+ 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):
+ if item.child(i).column() == 0:
+ itemsToProcess.append(item.child(i))
+
+ elif item.column() == 0:
+ itemsToProcess.append(item)
+
+ tools = []
+ for item in itemsToProcess:
+ toolNr = int(item.data(PySide.QtCore.Qt.EditRole))
+ toolPath = item.data(_PathRole)
+ tools.append((toolNr, PathToolBit.Factory.CreateFrom(toolPath)))
+ 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
+ elif len(jobs) == 1:
+ job = jobs[0]
+ else:
+ userinput = PathUtilsGui.PathUtilsUserInput()
+ job = userinput.chooseJob(jobs)
+
+ if job is None: # user may have canceled
+ return
+
+ tools = self.selectedOrAllTools()
+
+ for tool in tools:
+ tc = PathToolControllerGui.Create(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'''
+ docs = FreeCADGui.getMainWindow().findChildren(QtGui.QDockWidget)
+ for doc in docs:
+ if doc.objectName() == "ToolSelector":
+ if doc.isVisible():
+ doc.deleteLater()
+ return
+ else:
+ doc.setVisible(True)
+ return
+
+ mw = FreeCADGui.getMainWindow()
+ mw.addDockWidget(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.'''
+
+ def __init__(self):
+ PathLog.track()
+ self.factory = ModelFactory()
+ 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.toolTableView = _TableView(self.form.toolTableGroup)
self.form.toolTableGroup.layout().replaceWidget(self.form.toolTable, self.toolTableView)
self.form.toolTable.hide()
self.setupUI()
self.title = self.form.windowTitle()
- self.LibFiles = []
- if path:
- self.libraryLoad(path)
- self.form.addToolController.setEnabled(False)
- self.form.ButtonRemoveToolTable.setEnabled(False)
- self.form.ButtonRenameToolTable.setEnabled(False)
-
- def _toolAdd(self, nr, tool, path):
- toolNr = PySide.QtGui.QStandardItem()
- toolNr.setData(nr, PySide.QtCore.Qt.EditRole)
- toolNr.setData(path, _PathRole)
- toolNr.setData(UUID.uuid4(), _UuidRole)
-
- toolName = PySide.QtGui.QStandardItem()
- toolName.setData(tool['name'], PySide.QtCore.Qt.EditRole)
- toolName.setEditable(False)
-
- toolShape = PySide.QtGui.QStandardItem()
- toolShape.setData(os.path.splitext(os.path.basename(tool['shape']))[0], PySide.QtCore.Qt.EditRole)
- toolShape.setEditable(False)
-
- toolDiameter = PySide.QtGui.QStandardItem()
- toolDiameter.setData(tool['parameter']['Diameter'], PySide.QtCore.Qt.EditRole)
- toolDiameter.setEditable(False)
-
- self.model.appendRow([toolNr, toolName, toolShape, toolDiameter])
-
- def toolAdd(self):
+ def toolBitNew(self):
PathLog.track()
- # pylint: disable=broad-except
- try:
- nr = 0
- for row in range(self.model.rowCount()):
- itemNr = int(self.model.item(row, 0).data(PySide.QtCore.Qt.EditRole))
- nr = max(nr, itemNr)
- nr += 1
- for i, foo in enumerate(PathToolBitGui.GetToolFiles(self.form)):
- tool = PathToolBit.Declaration(foo)
- self._toolAdd(nr + i, tool, foo)
- self.toolTableView.resizeColumnsToContents()
- except Exception:
- PathLog.error('something happened')
- PathLog.error(traceback.print_exc())
+ # select the shape file
+ shapefile = PathToolBitGui.GetToolShapeFile()
+ if shapefile is None: # user canceled
+ return
- def selectedOrAllTools(self):
- selectedRows = set([index.row() for index in self.toolTableView.selectedIndexes()])
- if not selectedRows:
- selectedRows = list(range(self.model.rowCount()))
- tools = []
- for row in selectedRows:
- item = self.model.item(row, 0)
- toolNr = int(item.data(PySide.QtCore.Qt.EditRole))
- toolPath = item.data(_PathRole)
- tools.append((toolNr, PathToolBit.Factory.CreateFrom(toolPath)))
- return tools
+ filename = PathToolBitGui.GetNewToolFile()
+ if filename is None:
+ return
- def selectedOrAllToolControllers(self):
- tools = self.selectedOrAllTools()
+ # Parse out the name of the file and write the structure
+ loc, fil = os.path.split(filename)
+ fname = os.path.splitext(fil)[0]
+ fullpath = "{}/{}.fctb".format(loc, fname)
+ PathLog.debug(fullpath)
- userinput = PathUtilsGui.PathUtilsUserInput()
- job = userinput.chooseJob(PathUtilsGui.PathUtils.GetJobs())
- for tool in tools:
- print(tool)
- tc = PathToolControllerGui.Create(tool[1].Label, tool[1], tool[0])
- job.Proxy.addToolController(tc)
- FreeCAD.ActiveDocument.recompute()
+ self.temptool = PathToolBit.ToolBitFactory().Create(name=fname)
+ self.temptool.BitShape = shapefile
+ self.temptool.Proxy.unloadBitBody(self.temptool)
+ self.temptool.Label = fname
+ self.temptool.Proxy.saveToFile(self.temptool, fullpath)
+ self.temptool.Document.removeObject(self.temptool.Name)
+ self.temptool = None
+
+ # add it to the model
+ self.factory.newTool(self.toolModel, fullpath)
+
+ def toolBitExisting(self):
+
+ filenames = PathToolBitGui.GetToolFiles()
+
+ if len(filenames) == 0:
+ return
+
+ for f in filenames:
+
+ loc, fil = os.path.split(f)
+ fname = os.path.splitext(fil)[0]
+ fullpath = "{}/{}.fctb".format(loc, fname)
+
+ self.factory.newTool(self.toolModel, fullpath)
def toolDelete(self):
PathLog.track()
selectedRows = set([index.row() for index in self.toolTableView.selectedIndexes()])
for row in sorted(list(selectedRows), key=lambda r: -r):
- self.model.removeRows(row, 1)
-
- def libraryDelete(self):
- PathLog.track()
- reply = QtGui.QMessageBox.question(self.form, 'Warning', "Delete " + os.path.basename(self.path) + "?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel)
- if reply == QtGui.QMessageBox.Yes and len(self.path) > 0:
- os.remove(self.path)
- PathPreferences.setLastPathToolTable("")
- self.libraryOpen(filedialog=False)
-
- def toolEnumerate(self):
- PathLog.track()
- for row in range(self.model.rowCount()):
- self.model.setData(self.model.index(row, 0), row + 1, PySide.QtCore.Qt.EditRole)
+ self.toolModel.removeRows(row, 1)
def toolSelect(self, selected, deselected):
- # pylint: disable=unused-argument
sel = len(self.toolTableView.selectedIndexes()) > 0
self.form.toolDelete.setEnabled(sel)
- if sel:
- self.form.addToolController.setEnabled(True)
- else:
- self.form.addToolController.setEnabled(False)
-
def tableSelected(self, index):
''' loads the tools for the selected tool table '''
- name = self.form.TableList.itemWidget(self.form.TableList.itemFromIndex(index)).getTableName()
- self.libraryLoad(PathPreferences.lastPathToolLibrary() + '/' + name)
- self.form.ButtonRemoveToolTable.setEnabled(True)
- self.form.ButtonRenameToolTable.setEnabled(True)
+ PathLog.track()
+ item = index.model().itemFromIndex(index)
+ libpath = item.data(_PathRole)
+ self.loadData(libpath)
+ self.path = libpath
- def open(self, path=None, dialog=False):
- '''open(path=None, dialog=False) ... load library stored in path and bring up ui.
- Returns 1 if user pressed OK, 0 otherwise.'''
- if path:
- self.libraryOpen(path, filedialog=False)
- elif dialog:
- self.libraryOpen(None, True)
- else:
- self.libraryOpen(None, False)
+ def open(self):
+ PathLog.track()
return self.form.exec_()
- def updateToolbar(self):
- if self.path:
- self.form.librarySave.setEnabled(True)
- else:
- self.form.librarySave.setEnabled(False)
-
- def libraryOpen(self, path=None, filedialog=True):
- import glob
+ def libraryPath(self):
PathLog.track()
+ path = PySide.QtGui.QFileDialog.getExistingDirectory(self.form, 'Tool Library Path', PathPreferences.lastPathToolLibrary())
+ if len(path) == 0:
+ return
- # Load default search path
- path = PathPreferences.lastPathToolLibrary()
+ PathPreferences.setLastPathToolLibrary(path)
+ self.loadData()
- if filedialog or len(path) == 0:
- path = PySide.QtGui.QFileDialog.getExistingDirectory(self.form, 'Tool Library Path', PathPreferences.lastPathToolLibrary())
- if len(path) > 0:
- PathPreferences.setLastPathToolLibrary(path)
- else:
- return
+ def cleanupDocument(self):
+ # This feels like a hack. Remove the toolbit object
+ # remove the editor from the dialog
+ # re-enable all the controls
+ self.temptool.Proxy.unloadBitBody(self.temptool)
+ self.temptool.Document.removeObject(self.temptool.Name)
+ self.temptool = None
+ widget = self.form.toolTableGroup.children()[-1]
+ widget.setParent(None)
+ self.editor = None
+ self.lockoff()
- # Clear view
- self.form.TableList.clear()
- self.LibFiles.clear()
- self.form.lineLibPath.clear()
- self.form.lineLibPath.insert(path)
+ def accept(self):
+ self.editor.accept()
+ self.temptool.Proxy.saveToFile(self.temptool, self.temptool.File)
+ self.librarySave()
+ self.loadData()
+ self.cleanupDocument()
- # Find all tool tables in directory
- for file in glob.glob(path + '/*.fctl'):
- self.LibFiles.append(file)
+ def reject(self):
+ self.cleanupDocument()
- self.LibFiles.sort()
+ def lockon(self):
+ self.toolTableView.setEnabled(False)
+ self.form.toolCreate.setEnabled(False)
+ self.form.toolDelete.setEnabled(False)
+ self.form.toolAdd.setEnabled(False)
+ self.form.TableList.setEnabled(False)
+ self.form.libraryOpen.setEnabled(False)
+ self.form.libraryExport.setEnabled(False)
+ self.form.addToolTable.setEnabled(False)
+ self.form.librarySave.setEnabled(False)
- # Add all tables to list
- for table in self.LibFiles:
- listWidgetItem = QtGui.QListWidgetItem()
- listItem = ToolTableListWidgetItem()
- listItem.setTableName(os.path.basename(table))
- listItem.setIcon(QtGui.QPixmap(':/icons/Path-ToolTable.svg'))
- listWidgetItem.setSizeHint(QtCore.QSize(0, 40))
- self.form.TableList.addItem(listWidgetItem)
- self.form.TableList.setItemWidget(listWidgetItem, listItem)
+ def lockoff(self):
+ self.toolTableView.setEnabled(True)
+ self.form.toolCreate.setEnabled(True)
+ self.form.toolDelete.setEnabled(True)
+ self.form.toolAdd.setEnabled(True)
+ self.form.toolTable.setEnabled(True)
+ self.form.TableList.setEnabled(True)
+ self.form.libraryOpen.setEnabled(True)
+ self.form.libraryExport.setEnabled(True)
+ self.form.addToolTable.setEnabled(True)
+ self.form.librarySave.setEnabled(True)
- self.path = []
- self.form.ButtonRemoveToolTable.setEnabled(False)
- self.form.ButtonRenameToolTable.setEnabled(False)
+ def toolEdit(self, selected):
+ item = self.toolModel.item(selected.row(), 0)
- self.toolTableView.setUpdatesEnabled(False)
- self.model.clear()
- self.model.setHorizontalHeaderLabels(self.columnNames())
- self.toolTableView.resizeColumnsToContents()
- self.toolTableView.setUpdatesEnabled(True)
+ if self.temptool is not None:
+ self.temptool.Document.removeObject(self.temptool.Name)
- # Search last selected table
- if len(self.LibFiles) > 0:
- for idx in range(len(self.LibFiles)):
- if PathPreferences.lastPathToolTable() == os.path.basename(self.LibFiles[idx]):
- break
- # Not found, select first entry
- if idx >= len(self.LibFiles):
- idx = 0
+ if selected.column() == 0: # editing Nr
+ pass
+ else:
+ tbpath = item.data(_PathRole)
+ self.temptool = PathToolBit.ToolBitFactory().CreateFrom(tbpath, 'temptool')
+ self.editor = PathToolBitEdit.ToolBitEditor(self.temptool, self.form.toolTableGroup, loadBitBody=False)
- # Load selected table
- self.libraryLoad(self.LibFiles[idx])
- self.form.TableList.setCurrentRow(idx)
- self.form.ButtonRemoveToolTable.setEnabled(True)
- self.form.ButtonRenameToolTable.setEnabled(True)
+ QBtn = QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel
+ buttonBox = QtGui.QDialogButtonBox(QBtn)
+ buttonBox.accepted.connect(self.accept)
+ buttonBox.rejected.connect(self.reject)
- def libraryLoad(self, path):
- self.toolTableView.setUpdatesEnabled(False)
- self.model.clear()
- self.model.setHorizontalHeaderLabels(self.columnNames())
+ layout = self.editor.form.layout()
+ layout.addWidget(buttonBox)
+ self.lockon()
+ self.editor.setupUI()
- if path:
- with open(path) as fp:
- PathPreferences.setLastPathToolTable(os.path.basename(path))
- library = json.load(fp)
-
- for toolBit in library['tools']:
- nr = toolBit['nr']
- bit = PathToolBit.findBit(toolBit['path'])
- if bit:
- PathLog.track(bit)
- tool = PathToolBit.Declaration(bit)
- self._toolAdd(nr, tool, bit)
- else:
- PathLog.error("Could not find tool #{}: {}".format(nr, library['tools'][nr]))
-
- self.toolTableView.resizeColumnsToContents()
-
- self.toolTableView.setUpdatesEnabled(True)
-
- self.form.setWindowTitle("{} - {}".format(self.title, os.path.basename(path) if path else ''))
- self.path = path
- self.updateToolbar()
+ def toolEditDone(self, success=True):
+ FreeCAD.ActiveDocument.removeObject("temptool")
+ print('all done')
def libraryNew(self):
- self.libraryLoad(None)
- self.librarySaveAs()
+ TooltableTypeJSON = translate("PathToolLibraryManager", "Tooltable JSON (*.fctl)")
- def renameLibrary(self):
- name = self.form.TableList.itemWidget(self.form.TableList.currentItem()).getTableName()
- newName, ok = QtGui.QInputDialog.getText(None, translate(
- "TooltableEditor", "Rename Tooltable"), translate(
- "TooltableEditor", "Enter Name:"), QtGui.QLineEdit.Normal, name)
- if ok and newName:
- os.rename(PathPreferences.lastPathToolLibrary() + '/' + name, PathPreferences.lastPathToolLibrary() + '/' + newName)
- self.libraryOpen(filedialog=False)
+ filename = PySide.QtGui.QFileDialog.getSaveFileName(self.form,
+ translate("TooltableEditor", "Save toolbit library", None),
+ PathPreferences.lastPathToolLibrary(), "{}".format(TooltableTypeJSON))
- # def createToolBit(self):
- # tool = PathToolBit.ToolBitFactory().Create()
+ if not (filename and filename[0]):
+ self.loadData()
- # #self.dialog = PySide.QtGui.QDialog(self.form)
- # #layout = PySide.QtGui.QVBoxLayout(self.dialog)
- # self.editor = PathToolBitEdit.ToolBitEditor(tool, self.form.toolTableGroup)
- # self.editor.setupUI()
- # self.buttons = PySide.QtGui.QDialogButtonBox(
- # PySide.QtGui.QDialogButtonBox.Ok | PySide.QtGui.QDialogButtonBox.Cancel,
- # PySide.QtCore.Qt.Horizontal, self.dialog)
- # layout.addWidget(self.buttons)
- # #self.buttons.accepted.connect(accept)
- # #self.buttons.rejected.connect(reject)
- # print(self.dialog.exec_())
+ 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:
+ json.dump(library, fp, sort_keys=True, indent=2)
+
+ self.loadData()
def librarySave(self):
library = {}
tools = []
library['version'] = 1
library['tools'] = tools
- for row in range(self.model.rowCount()):
- toolNr = self.model.data(self.model.index(row, 0), PySide.QtCore.Qt.EditRole)
- toolPath = self.model.data(self.model.index(row, 0), _PathRole)
+ for row in range(self.toolModel.rowCount()):
+ 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():
tools.append({'nr': toolNr, 'path': toolPath})
else:
@@ -400,13 +554,109 @@ class ToolBitLibrary(object):
with open(self.path, 'w') as fp:
json.dump(library, fp, sort_keys=True, indent=2)
+ def libraryOk(self):
+ self.librarySave()
+ self.form.close()
+
+ def libPaths(self):
+ lib = PathPreferences.lastFileToolLibrary()
+ loc = PathPreferences.lastPathToolLibrary()
+
+ PathLog.track("lib: {} loc: {}".format(lib, loc))
+ return lib, loc
+
+ def columnNames(self):
+ return ['Nr', 'Tool', 'Shape']
+
+ def loadData(self, path=None):
+ PathLog.track(path)
+ self.toolTableView.setUpdatesEnabled(False)
+ self.form.TableList.setUpdatesEnabled(False)
+
+ if path is None:
+ path, loc = self.libPaths()
+
+ self.toolModel.clear()
+ self.listModel.clear()
+ self.factory.libraryOpen(self.toolModel, lib=path)
+ self.factory.findLibraries(self.listModel)
+
+ else:
+ self.toolModel.clear()
+ self.factory.libraryOpen(self.toolModel, lib=path)
+
+ self.path = path
+ self.form.setWindowTitle("{}".format(PathPreferences.lastPathToolLibrary()))
+ self.toolModel.setHorizontalHeaderLabels(self.columnNames())
+ self.listModel.setHorizontalHeaderLabels(['Library'])
+
+ # Select the current library in the list of tables
+ curIndex = None
+ for i in range(self.listModel.rowCount()):
+ item = self.listModel.item(i)
+ if item.data(_PathRole) == path:
+ curIndex = self.listModel.indexFromItem(item)
+
+ if curIndex:
+ sm = self.form.TableList.selectionModel()
+ sm.select(curIndex, QtCore.QItemSelectionModel.Select)
+
+ self.toolTableView.setUpdatesEnabled(True)
+ self.form.TableList.setUpdatesEnabled(True)
+
+ def setupUI(self):
+ PathLog.track()
+ self.form.TableList.setModel(self.listModel)
+ self.toolTableView.setModel(self.toolModel)
+
+ self.loadData()
+
+ self.toolTableView.resizeColumnsToContents()
+ self.toolTableView.selectionModel().selectionChanged.connect(self.toolSelect)
+ self.toolTableView.doubleClicked.connect(self.toolEdit)
+
+ self.form.TableList.clicked.connect(self.tableSelected)
+
+ self.form.toolAdd.clicked.connect(self.toolBitExisting)
+ self.form.toolDelete.clicked.connect(self.toolDelete)
+ self.form.toolCreate.clicked.connect(self.toolBitNew)
+
+ self.form.addToolTable.clicked.connect(self.libraryNew)
+
+ self.form.libraryOpen.clicked.connect(self.libraryPath)
+ self.form.librarySave.clicked.connect(self.libraryOk)
+ self.form.libraryExport.clicked.connect(self.librarySaveAs)
+
+ self.toolSelect([], [])
+
+ def librarySaveAs(self, path):
+
+ TooltableTypeJSON = translate("PathToolLibraryManager", "Tooltable JSON (*.fctl)")
+ TooltableTypeLinuxCNC = translate("PathToolLibraryManager", "LinuxCNC tooltable (*.tbl)")
+
+ filename = PySide.QtGui.QFileDialog.getSaveFileName(self.form,
+ translate("TooltableEditor", "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])
+ self.libararySaveLinuxCNC(path)
+ else:
+ path = filename[0] if filename[0].endswith('.fctl') else "{}.fctl".format(filename[0])
+ self.path = path
+ self.librarySave()
+ self.updateToolbar()
+
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:
fp.write(";\n")
- for row in range(self.model.rowCount()):
- toolNr = self.model.data(self.model.index(row, 0), PySide.QtCore.Qt.EditRole)
- toolPath = self.model.data(self.model.index(row, 0), _PathRole)
+ for row in range(self.toolModel.rowCount()):
+ 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)
if bit:
@@ -429,129 +679,12 @@ class ToolBitLibrary(object):
orientation = bit.Orientation if hasattr(bit, "Orientation") else "0"
remark = bit.Label
- fp.write("T%s P%s X%s Y%s Z%s A%s B%s C%s U%s V%s W%s D%s I%s J%s Q%s ; %s\n" %
- (toolNr,
- pocket,
- xoffset,
- yoffset,
- zoffset,
- aoffset,
- boffset,
- coffset,
- uoffset,
- voffset,
- woffset,
- diameter,
- frontangle,
- backangle,
- orientation,
- remark))
+ 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)
else:
PathLog.error("Could not find tool #{} ".format(toolNr))
-
- def librarySaveAs(self):
- TooltableTypeJSON = translate("PathToolLibraryManager", "Tooltable JSON (*.fctl)")
- TooltableTypeLinuxCNC = translate("PathToolLibraryManager", "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, \
- # 'Tool Library', PathPreferences.lastPathToolLibrary(), '*.fctl')
- if filename and filename[0]:
- if filename[1] == TooltableTypeLinuxCNC:
- 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])
- PathPreferences.setLastPathToolLibrary(os.path.dirname(path))
- self.path = path
- self.librarySave()
- self.updateToolbar()
- PathPreferences.setLastPathToolTable(os.path.basename(path))
- self.libraryOpen(None, False)
-
- def libraryCancel(self):
- self.form.close()
-
- def columnNames(self):
- return ['Nr', 'Tool', 'Shape', 'Diameter']
-
- def toolEdit(self, selected):
- print('here')
- print(selected)
- if selected.column() == 0:
- print('nope')
- else:
- print('yep')
-
- def setupUI(self):
- PathLog.track('+')
- self.model = PySide.QtGui.QStandardItemModel(0, len(self.columnNames()), self.toolTableView)
- self.model.setHorizontalHeaderLabels(self.columnNames())
-
- self.toolTableView.setModel(self.model)
- self.toolTableView.resizeColumnsToContents()
- self.toolTableView.selectionModel().selectionChanged.connect(self.toolSelect)
- self.toolTableView.doubleClicked.connect(self.toolEdit)
-
- self.form.toolAdd.clicked.connect(self.toolAdd)
- self.form.toolDelete.clicked.connect(self.toolDelete)
- self.form.toolEnumerate.clicked.connect(self.toolEnumerate)
- # self.form.createToolBit.clicked.connect(self.createToolBit)
-
- self.form.ButtonAddToolTable.clicked.connect(self.libraryNew)
- self.form.ButtonRemoveToolTable.clicked.connect(self.libraryDelete)
- self.form.ButtonRenameToolTable.clicked.connect(self.renameLibrary)
-
- # self.form.libraryNew.clicked.connect(self.libraryNew)
- self.form.libraryOpen.clicked.connect(partial(self.libraryOpen, filedialog=True))
- self.form.librarySave.clicked.connect(self.librarySave)
- self.form.librarySaveAs.clicked.connect(self.librarySaveAs)
- self.form.libraryCancel.clicked.connect(self.libraryCancel)
-
- self.form.addToolController.clicked.connect(self.selectedOrAllToolControllers)
-
- self.form.TableList.clicked.connect(self.tableSelected)
-
- self.toolSelect([], [])
- self.updateToolbar()
- PathLog.track('-')
-
-
-class ToolTableListWidgetItem(QtGui.QWidget):
- toolMoved = QtCore.Signal()
-
- def __init__(self):
- super(ToolTableListWidgetItem, self).__init__()
-
- self.setAcceptDrops(True)
-
- self.mainLayout = QtGui.QHBoxLayout()
- self.iconQLabel = QtGui.QLabel()
- self.tableNameLabel = QtGui.QLabel()
- self.mainLayout.addWidget(self.iconQLabel, 0)
- self.mainLayout.addWidget(self.tableNameLabel, 1)
- self.setLayout(self.mainLayout)
-
- def setTableName(self, text):
- self.tableNameLabel.setText(text)
-
- def getTableName(self):
- return self.tableNameLabel.text()
-
- def setIcon(self, icon):
- icon = icon.scaled(22, 22)
- self.iconQLabel.setPixmap(icon)
-
- # def dragEnterEvent(self, e):
- # currentToolTable = self.tlm.getCurrentTableName()
- # thisToolTable = self.getTableName()
-
- def dropEvent(self, e):
- selectedTools = e.source().selectedIndexes()
- print("Drop: {}, {}".format(selectedTools, selectedTools[1].data()))
diff --git a/src/Mod/Path/PathScripts/PathToolController.py b/src/Mod/Path/PathScripts/PathToolController.py
index a3c315288e..45e468500f 100644
--- a/src/Mod/Path/PathScripts/PathToolController.py
+++ b/src/Mod/Path/PathScripts/PathToolController.py
@@ -30,16 +30,17 @@ import PathScripts.PathToolBit as PathToolBit
from PySide import QtCore
-#PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
-#PathLog.trackModule(PathLog.thisModule())
+# PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+# PathLog.trackModule(PathLog.thisModule())
+
# Qt translation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
+
class ToolControllerTemplate:
'''Attribute and sub element strings for template export/import.'''
- # pylint: disable=no-init
Expressions = 'xengine'
ExprExpr = 'expr'
@@ -56,21 +57,36 @@ class ToolControllerTemplate:
VertFeed = 'vfeed'
VertRapid = 'vrapid'
+
class ToolController:
def __init__(self, obj, cTool=False):
PathLog.track('tool: {}'.format(cTool))
- obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", QtCore.QT_TRANSLATE_NOOP("PathToolController", "The active tool"))
+ obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber",
+ "Tool", QtCore.QT_TRANSLATE_NOOP("PathToolController",
+ "The active tool"))
obj.ToolNumber = (0, 0, 10000, 1)
self.ensureUseLegacyTool(obj, cTool)
- 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.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.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)
def onDocumentRestored(self, obj):
@@ -82,10 +98,12 @@ class ToolController:
if hasattr(obj.Tool, 'InList') and len(obj.Tool.InList) == 1:
if hasattr(obj.Tool.Proxy, 'onDelete'):
obj.Tool.Proxy.onDelete(obj.Tool)
- obj.Document.removeObject(obj.Tool.Name)
def setFromTemplate(self, obj, template):
- '''setFromTemplate(obj, xmlItem) ... extract properties from xmlItem and assign to receiver.'''
+ '''
+ setFromTemplate(obj, xmlItem) ... extract properties from xmlItem
+ and assign to receiver.
+ '''
PathLog.track(obj.Name, template)
version = 0
if template.get(ToolControllerTemplate.Version):
@@ -158,10 +176,21 @@ class ToolController:
commands += "(" + obj.Label + ")"+'\n'
commands += 'M6 T'+str(obj.ToolNumber)+'\n'
- if obj.SpindleDir == 'Forward':
- commands += 'M3 S' + str(obj.SpindleSpeed) + '\n'
- else:
- commands += 'M4 S' + str(obj.SpindleSpeed) + '\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 allowSpindlePower:
+ 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'
if commands == "":
commands += "(No commands processed)"
@@ -195,13 +224,14 @@ class ToolController:
else:
obj.addProperty("App::PropertyLink", "Tool", "Base", QtCore.QT_TRANSLATE_NOOP("PathToolController", "The tool used by this controller"))
-def Create(name = 'Default Tool', tool=None, toolNumber=1, assignViewProvider=True):
+
+def Create(name='Default Tool', tool=None, toolNumber=1, assignViewProvider=True):
legacyTool = PathPreferences.toolsReallyUseLegacyTools() if tool is None else isinstance(tool, Path.Tool)
PathLog.track(tool, toolNumber, legacyTool)
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
- obj.Label = name
+ obj.Label = "TC: {}".format(name)
obj.Proxy = ToolController(obj, legacyTool)
if FreeCAD.GuiUp and assignViewProvider:
@@ -224,6 +254,7 @@ def Create(name = 'Default Tool', tool=None, toolNumber=1, assignViewProvider=Tr
obj.ToolNumber = toolNumber
return obj
+
def FromTemplate(template, assignViewProvider=True):
# pylint: disable=unused-argument
PathLog.track()
@@ -234,6 +265,7 @@ def FromTemplate(template, assignViewProvider=True):
return obj
+
if FreeCAD.GuiUp:
# need ViewProvider class in this file to support loading of old files
from PathScripts.PathToolControllerGui import ViewProvider
diff --git a/src/Mod/Path/PathScripts/PathToolControllerGui.py b/src/Mod/Path/PathScripts/PathToolControllerGui.py
index c290abb299..54daefa5ca 100644
--- a/src/Mod/Path/PathScripts/PathToolControllerGui.py
+++ b/src/Mod/Path/PathScripts/PathToolControllerGui.py
@@ -35,10 +35,12 @@ from PySide import QtCore, QtGui
from lazy_loader.lazy_loader import LazyLoader
Part = LazyLoader('Part', globals(), 'Part')
+
# Qt translation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
+
class ViewProvider:
def __init__(self, vobj):
@@ -122,7 +124,8 @@ class ViewProvider:
return [obj.Tool]
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)
@@ -172,6 +175,7 @@ class CommandPathToolController(object):
job.Proxy.addToolController(tc)
FreeCAD.ActiveDocument.recompute()
+
class ToolControllerEditor(object):
def __init__(self, obj, asDialog):
@@ -180,13 +184,18 @@ class ToolControllerEditor(object):
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')
+ 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()
@@ -201,7 +210,8 @@ 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)
+ index = self.form.spindleDirection.findText(tc.SpindleDir,
+ QtCore.Qt.MatchFixedString)
if index >= 0:
self.form.spindleDirection.setCurrentIndex(index)
@@ -224,9 +234,9 @@ class ToolControllerEditor(object):
self.editor.updateTool()
tc.Tool = self.editor.tool
- except Exception as e: # pylint: disable=broad-except
- PathLog.error(translate("PathToolController", "Error updating TC: %s") % e)
-
+ except Exception as e:
+ PathLog.error(translate("PathToolController",
+ "Error updating TC: %s") % e)
def refresh(self):
self.form.blockSignals(True)
@@ -296,7 +306,8 @@ 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()
@@ -311,7 +322,7 @@ class DlgToolControllerEdit:
self.obj = obj
def exec_(self):
- restoreTC = self.obj.Proxy.templateAttrs(self.obj)
+ restoreTC = self.obj.Proxy.templateAttrs(self.obj)
rc = False
if not self.editor.form.exec_():
@@ -320,6 +331,7 @@ class DlgToolControllerEdit:
rc = True
return rc
+
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_ToolController', CommandPathToolController())
diff --git a/src/Mod/Path/Tools/Bit/45degree_chamfer.fctb b/src/Mod/Path/Tools/Bit/45degree_chamfer.fctb
new file mode 100644
index 0000000000..6c1231ed0f
--- /dev/null
+++ b/src/Mod/Path/Tools/Bit/45degree_chamfer.fctb
@@ -0,0 +1,14 @@
+{
+ "version": 2,
+ "name": "45 Deg. Chamfer",
+ "shape": "chamfer.fcstd",
+ "parameter": {
+ "CuttingEdgeAngle": "45.0000 \u00b0",
+ "CuttingEdgeHeight": "6.3500 mm",
+ "Diameter": "12.3323 mm",
+ "FlatRadius": "5.0000 mm",
+ "Length": "30.0000 mm",
+ "ShankDiameter": "6.3500 mm"
+ },
+ "attribute": {}
+}
\ No newline at end of file
diff --git a/src/Mod/Path/Tools/Bit/5mm_Drill.fctb b/src/Mod/Path/Tools/Bit/5mm_Drill.fctb
new file mode 100644
index 0000000000..40243399a2
--- /dev/null
+++ b/src/Mod/Path/Tools/Bit/5mm_Drill.fctb
@@ -0,0 +1,11 @@
+{
+ "version": 2,
+ "name": "5mm Drill",
+ "shape": "drill.fcstd",
+ "parameter": {
+ "Diameter": "5.0000 mm",
+ "Length": "50.0000 mm",
+ "TipAngle": "119.0000 \u00b0"
+ },
+ "attribute": {}
+}
\ No newline at end of file
diff --git a/src/Mod/Path/Tools/Bit/5mm_Endmill.fctb b/src/Mod/Path/Tools/Bit/5mm_Endmill.fctb
new file mode 100644
index 0000000000..7cc72ba33c
--- /dev/null
+++ b/src/Mod/Path/Tools/Bit/5mm_Endmill.fctb
@@ -0,0 +1,12 @@
+{
+ "version": 2,
+ "name": "5mm Endmill",
+ "shape": "endmill.fcstd",
+ "parameter": {
+ "CuttingEdgeHeight": "30.0000 mm",
+ "Diameter": "5.0000 mm",
+ "Length": "50.0000 mm",
+ "ShankDiameter": "3.0000 mm"
+ },
+ "attribute": {}
+}
diff --git a/src/Mod/Path/Tools/Bit/60degree_Vbit.fctb b/src/Mod/Path/Tools/Bit/60degree_Vbit.fctb
new file mode 100644
index 0000000000..715361ec34
--- /dev/null
+++ b/src/Mod/Path/Tools/Bit/60degree_Vbit.fctb
@@ -0,0 +1,14 @@
+{
+ "version": 2,
+ "name": "60 Deg. V-Bit",
+ "shape": "v-bit.fcstd",
+ "parameter": {
+ "CuttingEdgeAngle": "60.0000 \u00b0",
+ "Diameter": "10.0000 mm",
+ "FlatHeight": "1.0000 mm",
+ "FlatRadius": "0.5000 mm",
+ "Length": "20.0000 mm",
+ "ShankDiameter": "5.0000 mm"
+ },
+ "attribute": {}
+}
\ No newline at end of file
diff --git a/src/Mod/Path/Tools/Bit/6mm_Ball_End.fctb b/src/Mod/Path/Tools/Bit/6mm_Ball_End.fctb
new file mode 100644
index 0000000000..9e9afbabc8
--- /dev/null
+++ b/src/Mod/Path/Tools/Bit/6mm_Ball_End.fctb
@@ -0,0 +1,12 @@
+{
+ "version": 2,
+ "name": "6mm Ball End",
+ "shape": "ballend.fcstd",
+ "parameter": {
+ "CuttingEdgeHeight": "40.0000 mm",
+ "Diameter": "6.0000 mm",
+ "Length": "50.0000 mm",
+ "ShankDiameter": "3.0000 mm"
+ },
+ "attribute": {}
+}
\ No newline at end of file
diff --git a/src/Mod/Path/Tools/Bit/6mm_Bullnose.fctb b/src/Mod/Path/Tools/Bit/6mm_Bullnose.fctb
new file mode 100644
index 0000000000..05d80b1d2a
--- /dev/null
+++ b/src/Mod/Path/Tools/Bit/6mm_Bullnose.fctb
@@ -0,0 +1,13 @@
+{
+ "version": 2,
+ "name": "6 mm Bull Nose",
+ "shape": "bullnose.fcstd",
+ "parameter": {
+ "CuttingEdgeHeight": "40.0000 mm",
+ "Diameter": "6.0000 mm",
+ "FlatRadius": "1.5000 mm",
+ "Length": "50.0000 mm",
+ "ShankDiameter": "3.0000 mm"
+ },
+ "attribute": {}
+}
\ No newline at end of file
diff --git a/src/Mod/Path/Tools/Bit/probe.fctb b/src/Mod/Path/Tools/Bit/probe.fctb
new file mode 100644
index 0000000000..b92828e7ac
--- /dev/null
+++ b/src/Mod/Path/Tools/Bit/probe.fctb
@@ -0,0 +1,11 @@
+{
+ "version": 2,
+ "name": "Probe004",
+ "shape": "probe.fcstd",
+ "parameter": {
+ "Diameter": "6.0000 mm",
+ "Length": "50.0000 mm",
+ "ShaftDiameter": "4.0000 mm"
+ },
+ "attribute": {}
+}
diff --git a/src/Mod/Path/Tools/Bit/slittingsaw.fctb b/src/Mod/Path/Tools/Bit/slittingsaw.fctb
new file mode 100644
index 0000000000..e9d33fe571
--- /dev/null
+++ b/src/Mod/Path/Tools/Bit/slittingsaw.fctb
@@ -0,0 +1,14 @@
+{
+ "version": 2,
+ "name": "Slitting Saw",
+ "shape": "slittingsaw.fcstd",
+ "parameter": {
+ "BladeThickness": "3.0000 mm",
+ "BoltHeight": "3.0000 mm",
+ "BoltWidth": "8.0000 mm",
+ "Diameter": "76.2000 mm",
+ "Length": "50.0000 mm",
+ "ShankDiameter": "19.0500 mm"
+ },
+ "attribute": {}
+}
diff --git a/src/Mod/Path/Tools/Bit/t1.fctb b/src/Mod/Path/Tools/Bit/t1.fctb
deleted file mode 100644
index 9221229563..0000000000
--- a/src/Mod/Path/Tools/Bit/t1.fctb
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": 2,
- "name": "T1",
- "shape": "endmill.fcstd",
- "attribute": {},
- "parameter": {
- "CuttingEdgeHeight": "30.000 mm",
- "Diameter": "1.000 mm",
- "Length": "50.000 mm",
- "ShankDiameter": "3.000 mm"
- }
-}
diff --git a/src/Mod/Path/Tools/Bit/t2.fctb b/src/Mod/Path/Tools/Bit/t2.fctb
deleted file mode 100644
index 1c70485e5c..0000000000
--- a/src/Mod/Path/Tools/Bit/t2.fctb
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": 1,
- "name": "T2",
- "shape": "endmill.fcstd",
- "attribute": {},
- "parameter": {
- "CuttingEdgeHeight": "30.000 mm",
- "Diameter": "2.000 mm",
- "Length": "50.000 mm",
- "ShankDiameter": "3.000 mm"
- }
-}
diff --git a/src/Mod/Path/Tools/Bit/t3.fctb b/src/Mod/Path/Tools/Bit/t3.fctb
deleted file mode 100644
index 86e6bf1110..0000000000
--- a/src/Mod/Path/Tools/Bit/t3.fctb
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": 2,
- "name": "T3",
- "shape": "endmill.fcstd",
- "attribute": {},
- "parameter": {
- "CuttingEdgeHeight": "30.000 mm",
- "Diameter": "3.000 mm",
- "Length": "50.000 mm",
- "ShankDiameter": "3.000 mm"
- }
-}
diff --git a/src/Mod/Path/Tools/Bit/t4.fctb b/src/Mod/Path/Tools/Bit/t4.fctb
deleted file mode 100644
index c97b20feed..0000000000
--- a/src/Mod/Path/Tools/Bit/t4.fctb
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": 1,
- "name": "T4",
- "shape": "endmill.fcstd",
- "attribute": {},
- "parameter": {
- "CuttingEdgeHeight": "30.000 mm",
- "Diameter": "4.000 mm",
- "Length": "50.000 mm",
- "ShankDiameter": "3.000 mm"
- }
-}
diff --git a/src/Mod/Path/Tools/Bit/t5.fctb b/src/Mod/Path/Tools/Bit/t5.fctb
deleted file mode 100644
index 014ebea50c..0000000000
--- a/src/Mod/Path/Tools/Bit/t5.fctb
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": 1,
- "name": "T5",
- "shape": "endmill.fcstd",
- "attribute": {},
- "parameter": {
- "CuttingEdgeHeight": "30.000 mm",
- "Diameter": "5.000 mm",
- "Length": "50.000 mm",
- "ShankDiameter": "3.000 mm"
- }
-}
diff --git a/src/Mod/Path/Tools/Bit/t6.fctb b/src/Mod/Path/Tools/Bit/t6.fctb
deleted file mode 100644
index 521b489554..0000000000
--- a/src/Mod/Path/Tools/Bit/t6.fctb
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": 1,
- "name": "T6",
- "shape": "endmill.fcstd",
- "attribute": {},
- "parameter": {
- "CuttingEdgeHeight": "30.000 mm",
- "Diameter": "6.000 mm",
- "Length": "50.000 mm",
- "ShankDiameter": "3.000 mm"
- }
-}
diff --git a/src/Mod/Path/Tools/Bit/t7.fctb b/src/Mod/Path/Tools/Bit/t7.fctb
deleted file mode 100644
index b10067d4aa..0000000000
--- a/src/Mod/Path/Tools/Bit/t7.fctb
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": 1,
- "name": "T7",
- "shape": "endmill.fcstd",
- "attribute": {},
- "parameter": {
- "CuttingEdgeHeight": "30.000 mm",
- "Diameter": "7.000 mm",
- "Length": "50.000 mm",
- "ShankDiameter": "3.000 mm"
- }
-}
diff --git a/src/Mod/Path/Tools/Bit/t8.fctb b/src/Mod/Path/Tools/Bit/t8.fctb
deleted file mode 100644
index 2ad54eb330..0000000000
--- a/src/Mod/Path/Tools/Bit/t8.fctb
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": 1,
- "name": "T8",
- "shape": "endmill.fcstd",
- "attribute": {},
- "parameter": {
- "CuttingEdgeHeight": "30.000 mm",
- "Diameter": "8.000 mm",
- "Length": "50.000 mm",
- "ShankDiameter": "3.000 mm"
- }
-}
diff --git a/src/Mod/Path/Tools/Bit/t9.fctb b/src/Mod/Path/Tools/Bit/t9.fctb
deleted file mode 100644
index 3a3dbc3f78..0000000000
--- a/src/Mod/Path/Tools/Bit/t9.fctb
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": 1,
- "name": "T9",
- "shape": "endmill.fcstd",
- "attribute": {},
- "parameter": {
- "CuttingEdgeHeight": "30.000 mm",
- "Diameter": "9.000 mm",
- "Length": "50.000 mm",
- "ShankDiameter": "3.000 mm"
- }
-}
diff --git a/src/Mod/Path/Tools/Library/Default.fctl b/src/Mod/Path/Tools/Library/Default.fctl
new file mode 100644
index 0000000000..b3b8ea23c4
--- /dev/null
+++ b/src/Mod/Path/Tools/Library/Default.fctl
@@ -0,0 +1,37 @@
+{
+ "tools": [
+ {
+ "nr": 1,
+ "path": "5mm_Endmill.fctb"
+ },
+ {
+ "nr": 2,
+ "path": "5mm_Drill.fctb"
+ },
+ {
+ "nr": 3,
+ "path": "6mm_Ball_End.fctb"
+ },
+ {
+ "nr": 4,
+ "path": "6mm_Bullnose.fctb"
+ },
+ {
+ "nr": 5,
+ "path": "60degree_Vbit.fctb"
+ },
+ {
+ "nr": 6,
+ "path": "45degree_chamfer.fctb"
+ },
+ {
+ "nr": 7,
+ "path": "slittingsaw.fctb"
+ },
+ {
+ "nr": 8,
+ "path": "probe.fctb"
+ }
+ ],
+ "version": 1
+}
diff --git a/src/Mod/Path/Tools/Library/endmills.fctl b/src/Mod/Path/Tools/Library/endmills.fctl
deleted file mode 100644
index c443e6cd10..0000000000
--- a/src/Mod/Path/Tools/Library/endmills.fctl
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "tools": [
- {
- "nr": 1,
- "path": "t1.fctb"
- },
- {
- "nr": 2,
- "path": "t2.fctb"
- },
- {
- "nr": 3,
- "path": "t3.fctb"
- },
- {
- "nr": 4,
- "path": "t4.fctb"
- },
- {
- "nr": 5,
- "path": "t5.fctb"
- },
- {
- "nr": 6,
- "path": "t6.fctb"
- },
- {
- "nr": 7,
- "path": "t7.fctb"
- },
- {
- "nr": 8,
- "path": "t8.fctb"
- },
- {
- "nr": 9,
- "path": "t9.fctb"
- }
- ],
- "version": 1
-}
diff --git a/src/Mod/Path/Tools/Shape/ballend.fcstd b/src/Mod/Path/Tools/Shape/ballend.fcstd
index 430a6f8160..79cbd68605 100644
Binary files a/src/Mod/Path/Tools/Shape/ballend.fcstd and b/src/Mod/Path/Tools/Shape/ballend.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/bullnose.fcstd b/src/Mod/Path/Tools/Shape/bullnose.fcstd
index a97cacde63..c2f7240b72 100644
Binary files a/src/Mod/Path/Tools/Shape/bullnose.fcstd and b/src/Mod/Path/Tools/Shape/bullnose.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/chamfer.fcstd b/src/Mod/Path/Tools/Shape/chamfer.fcstd
new file mode 100644
index 0000000000..e56a1359d4
Binary files /dev/null and b/src/Mod/Path/Tools/Shape/chamfer.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/drill.fcstd b/src/Mod/Path/Tools/Shape/drill.fcstd
index 75f7573829..aa2a626d02 100644
Binary files a/src/Mod/Path/Tools/Shape/drill.fcstd and b/src/Mod/Path/Tools/Shape/drill.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/endmill.fcstd b/src/Mod/Path/Tools/Shape/endmill.fcstd
index 79acaf72fc..8e258621ba 100644
Binary files a/src/Mod/Path/Tools/Shape/endmill.fcstd and b/src/Mod/Path/Tools/Shape/endmill.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/probe.fcstd b/src/Mod/Path/Tools/Shape/probe.fcstd
new file mode 100644
index 0000000000..5f853f415b
Binary files /dev/null and b/src/Mod/Path/Tools/Shape/probe.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/slittingsaw.fcstd b/src/Mod/Path/Tools/Shape/slittingsaw.fcstd
new file mode 100644
index 0000000000..81d3d7f3d9
Binary files /dev/null and b/src/Mod/Path/Tools/Shape/slittingsaw.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/v-bit.fcstd b/src/Mod/Path/Tools/Shape/v-bit.fcstd
index 6a333a871c..5d35188c81 100644
Binary files a/src/Mod/Path/Tools/Shape/v-bit.fcstd and b/src/Mod/Path/Tools/Shape/v-bit.fcstd differ