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