Removed deprecated and obsolete Path.Tool and Path.Tooltable
This commit is contained in:
@@ -74,8 +74,6 @@ def Startup():
|
||||
from PathScripts import PathSimpleCopy
|
||||
from PathScripts import PathSimulatorGui
|
||||
from PathScripts import PathStop
|
||||
from PathScripts import PathToolLibraryEditor
|
||||
from PathScripts import PathToolLibraryManager
|
||||
from PathScripts import PathUtilsGui
|
||||
|
||||
from packaging.version import Version, parse
|
||||
|
||||
@@ -549,14 +549,6 @@ class ObjectJob:
|
||||
for n in self.propertyEnumerations():
|
||||
setattr(obj, n[0], n[1])
|
||||
|
||||
if True in [isinstance(t.Tool, Path.Tool) for t in obj.Tools.Group]:
|
||||
FreeCAD.Console.PrintWarning(
|
||||
translate(
|
||||
"Path",
|
||||
"This job contains Legacy tools. Legacy tools are deprecated. They will be removed after version 0.20",
|
||||
)
|
||||
)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "PostProcessor" and obj.PostProcessor:
|
||||
processor = PostProcessor.load(obj.PostProcessor)
|
||||
|
||||
@@ -38,7 +38,6 @@ import PathScripts.PathJobDlg as PathJobDlg
|
||||
import PathScripts.PathPreferences as PathPreferences
|
||||
import PathScripts.PathSetupSheetGui as PathSetupSheetGui
|
||||
import PathScripts.PathStock as PathStock
|
||||
import PathScripts.PathToolLibraryEditor as PathToolLibraryEditor
|
||||
import PathScripts.PathUtil as PathUtil
|
||||
import PathScripts.PathUtils as PathUtils
|
||||
import json
|
||||
@@ -999,35 +998,30 @@ class TaskPanel:
|
||||
# Try to find a tool number from the currently selected lib. Otherwise
|
||||
# use next available number
|
||||
|
||||
if PathPreferences.toolsUseLegacyTools():
|
||||
PathToolLibraryEditor.CommandToolLibraryEdit().edit(
|
||||
self.obj, self.updateToolController
|
||||
tools = PathToolBitGui.LoadTools()
|
||||
|
||||
curLib = PathPreferences.lastFileToolLibrary()
|
||||
|
||||
library = None
|
||||
if curLib is not None:
|
||||
with open(curLib) as fp:
|
||||
library = json.load(fp)
|
||||
|
||||
for tool in tools:
|
||||
toolNum = self.obj.Proxy.nextToolNumber()
|
||||
if library is not None:
|
||||
for toolBit in library["tools"]:
|
||||
|
||||
if toolBit["path"] == tool.File:
|
||||
toolNum = toolBit["nr"]
|
||||
|
||||
tc = PathToolControllerGui.Create(
|
||||
name=tool.Label, tool=tool, toolNumber=toolNum
|
||||
)
|
||||
else:
|
||||
tools = PathToolBitGui.LoadTools()
|
||||
self.obj.Proxy.addToolController(tc)
|
||||
|
||||
curLib = PathPreferences.lastFileToolLibrary()
|
||||
|
||||
library = None
|
||||
if curLib is not None:
|
||||
with open(curLib) as fp:
|
||||
library = json.load(fp)
|
||||
|
||||
for tool in tools:
|
||||
toolNum = self.obj.Proxy.nextToolNumber()
|
||||
if library is not None:
|
||||
for toolBit in library["tools"]:
|
||||
|
||||
if toolBit["path"] == tool.File:
|
||||
toolNum = toolBit["nr"]
|
||||
|
||||
tc = PathToolControllerGui.Create(
|
||||
name=tool.Label, tool=tool, toolNumber=toolNum
|
||||
)
|
||||
self.obj.Proxy.addToolController(tc)
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
self.updateToolController()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
self.updateToolController()
|
||||
|
||||
def toolControllerDelete(self):
|
||||
self.objectDelete(self.form.toolControllerList)
|
||||
|
||||
@@ -54,7 +54,6 @@ LastFileToolBit = "LastFileToolBit"
|
||||
LastFileToolLibrary = "LastFileToolLibrary"
|
||||
LastFileToolShape = "LastFileToolShape"
|
||||
|
||||
UseLegacyTools = "UseLegacyTools"
|
||||
UseAbsoluteToolPaths = "UseAbsoluteToolPaths"
|
||||
# OpenLastLibrary = "OpenLastLibrary"
|
||||
|
||||
@@ -171,9 +170,6 @@ def searchPathsTool(sub):
|
||||
return paths
|
||||
|
||||
|
||||
def toolsUseLegacyTools():
|
||||
return preferences().GetBool(UseLegacyTools, False)
|
||||
|
||||
|
||||
def toolsStoreAbsolutePaths():
|
||||
return preferences().GetBool(UseAbsoluteToolPaths, False)
|
||||
@@ -183,19 +179,8 @@ def toolsStoreAbsolutePaths():
|
||||
# return preferences().GetBool(OpenLastLibrary, False)
|
||||
|
||||
|
||||
def setToolsSettings(legacy, relative):
|
||||
def setToolsSettings(relative):
|
||||
pref = preferences()
|
||||
if legacy:
|
||||
msgBox = QMessageBox()
|
||||
msgBox.setIcon(QMessageBox.Warning)
|
||||
msgBox.setText(
|
||||
translate(
|
||||
"Path",
|
||||
"Legacy tools are deprecated. They will be removed after version 0.20",
|
||||
)
|
||||
)
|
||||
msgBox.exec_()
|
||||
pref.SetBool(UseLegacyTools, legacy)
|
||||
pref.SetBool(UseAbsoluteToolPaths, relative)
|
||||
# pref.SetBool(OpenLastLibrary, lastlibrary)
|
||||
|
||||
|
||||
@@ -147,8 +147,7 @@ class JobPreferencesPage:
|
||||
|
||||
def saveToolsSettings(self):
|
||||
PathPreferences.setToolsSettings(
|
||||
self.form.toolsUseLegacy.isChecked(),
|
||||
self.form.toolsAbsolutePaths.isChecked(),
|
||||
self.form.toolsAbsolutePaths.isChecked()
|
||||
)
|
||||
|
||||
def selectComboEntry(self, widget, text):
|
||||
@@ -328,7 +327,6 @@ class JobPreferencesPage:
|
||||
self.form.stockCreateCylinder.hide()
|
||||
|
||||
def loadToolSettings(self):
|
||||
self.form.toolsUseLegacy.setChecked(PathPreferences.toolsUseLegacyTools())
|
||||
self.form.toolsAbsolutePaths.setChecked(
|
||||
PathPreferences.toolsStoreAbsolutePaths()
|
||||
)
|
||||
|
||||
@@ -188,20 +188,7 @@ class PathSimulation:
|
||||
self.tool = None
|
||||
|
||||
if self.tool is not None:
|
||||
if isinstance(self.tool, Path.Tool):
|
||||
# handle legacy tools
|
||||
toolProf = self.CreateToolProfile(
|
||||
self.tool,
|
||||
Vector(0, 1, 0),
|
||||
Vector(0, 0, 0),
|
||||
float(self.tool.Diameter) / 2.0,
|
||||
)
|
||||
self.cutTool.Shape = Part.makeSolid(
|
||||
toolProf.revolve(Vector(0, 0, 0), Vector(0, 0, 1))
|
||||
)
|
||||
else:
|
||||
# handle tool bits
|
||||
self.cutTool.Shape = self.tool.Shape
|
||||
self.cutTool.Shape = self.tool.Shape
|
||||
|
||||
if not self.cutTool.Shape.isValid() or self.cutTool.Shape.isNull():
|
||||
self.EndSimulation()
|
||||
|
||||
@@ -1,352 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2018 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
import Path
|
||||
import math
|
||||
|
||||
from PySide import QtGui
|
||||
|
||||
Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule())
|
||||
# Path.Log.trackModule(Path.Log.thisModule())
|
||||
|
||||
|
||||
class ToolEditorDefault:
|
||||
"""Generic Tool parameter editor for all Tools that don't have a customized edit function.
|
||||
Let's the user enter the raw internal data. Not the best approach but this is the starting point."""
|
||||
|
||||
def __init__(self, editor):
|
||||
self.editor = editor
|
||||
self.form = editor.form
|
||||
|
||||
def setupUI(self):
|
||||
self.form.paramImage.hide()
|
||||
self.form.paramGeneric.show()
|
||||
|
||||
def updateUI(self):
|
||||
self.form.toolDiameter.setText(
|
||||
FreeCAD.Units.Quantity(
|
||||
self.editor.tool.Diameter, FreeCAD.Units.Length
|
||||
).UserString
|
||||
)
|
||||
self.form.toolFlatRadius.setText(
|
||||
FreeCAD.Units.Quantity(
|
||||
self.editor.tool.FlatRadius, FreeCAD.Units.Length
|
||||
).UserString
|
||||
)
|
||||
self.form.toolCornerRadius.setText(
|
||||
FreeCAD.Units.Quantity(
|
||||
self.editor.tool.CornerRadius, FreeCAD.Units.Length
|
||||
).UserString
|
||||
)
|
||||
self.form.toolCuttingEdgeHeight.setText(
|
||||
FreeCAD.Units.Quantity(
|
||||
self.editor.tool.CuttingEdgeHeight, FreeCAD.Units.Length
|
||||
).UserString
|
||||
)
|
||||
self.form.toolCuttingEdgeAngle.setText(
|
||||
FreeCAD.Units.Quantity(
|
||||
self.editor.tool.CuttingEdgeAngle, FreeCAD.Units.Angle
|
||||
).UserString
|
||||
)
|
||||
|
||||
def updateTool(self):
|
||||
self.editor.tool.Diameter = FreeCAD.Units.parseQuantity(
|
||||
self.form.toolDiameter.text()
|
||||
)
|
||||
self.editor.tool.FlatRadius = FreeCAD.Units.parseQuantity(
|
||||
self.form.toolFlatRadius.text()
|
||||
)
|
||||
self.editor.tool.CornerRadius = FreeCAD.Units.parseQuantity(
|
||||
self.form.toolCornerRadius.text()
|
||||
)
|
||||
self.editor.tool.CuttingEdgeAngle = FreeCAD.Units.Quantity(
|
||||
self.form.toolCuttingEdgeAngle.text()
|
||||
)
|
||||
self.editor.tool.CuttingEdgeHeight = FreeCAD.Units.parseQuantity(
|
||||
self.form.toolCuttingEdgeHeight.text()
|
||||
)
|
||||
|
||||
|
||||
class ToolEditorImage(object):
|
||||
"""Base implementation for all customized Tool parameter editors.
|
||||
While not required it is simplest to subclass specific editors."""
|
||||
|
||||
def __init__(self, editor, imageFile, hide="", disable=""):
|
||||
self.editor = editor
|
||||
self.form = editor.form
|
||||
self.imagePath = "{}Mod/Path/Images/Tools/{}".format(
|
||||
FreeCAD.getHomePath(), imageFile
|
||||
)
|
||||
self.image = QtGui.QPixmap(self.imagePath)
|
||||
self.hide = hide
|
||||
self.disable = disable
|
||||
|
||||
form = editor.form
|
||||
self.widgets = {
|
||||
"D": (form.label_D, form.value_D),
|
||||
"d": (form.label_d, form.value_d),
|
||||
"H": (form.label_H, form.value_H),
|
||||
"a": (form.label_a, form.value_a),
|
||||
"S": (form.label_S, form.value_S),
|
||||
}
|
||||
|
||||
def setupUI(self):
|
||||
Path.Log.track()
|
||||
self.form.paramGeneric.hide()
|
||||
self.form.paramImage.show()
|
||||
|
||||
for key, widgets in self.widgets.items():
|
||||
hide = key in self.hide
|
||||
disable = key in self.disable
|
||||
for w in widgets:
|
||||
w.setHidden(hide)
|
||||
w.setDisabled(disable)
|
||||
if not hide and not disable:
|
||||
widgets[1].editingFinished.connect(self.editor.refresh)
|
||||
|
||||
self.form.image.setPixmap(self.image)
|
||||
|
||||
def updateUI(self):
|
||||
Path.Log.track()
|
||||
self.form.value_D.setText(self.quantityDiameter(True).UserString)
|
||||
self.form.value_d.setText(self.quantityFlatRadius(True).UserString)
|
||||
self.form.value_a.setText(self.quantityCuttingEdgeAngle(True).UserString)
|
||||
self.form.value_H.setText(self.quantityCuttingEdgeHeight(True).UserString)
|
||||
|
||||
def updateTool(self):
|
||||
Path.Log.track()
|
||||
toolDefault = Path.Tool()
|
||||
if "D" in self.hide:
|
||||
self.editor.tool.Diameter = toolDefault.Diameter
|
||||
else:
|
||||
self.editor.tool.Diameter = self.quantityDiameter(False)
|
||||
|
||||
if "d" in self.hide:
|
||||
self.editor.tool.FlatRadius = toolDefault.FlatRadius
|
||||
else:
|
||||
self.editor.tool.FlatRadius = self.quantityFlatRadius(False)
|
||||
|
||||
if "a" in self.hide:
|
||||
self.editor.tool.CuttingEdgeAngle = toolDefault.CuttingEdgeAngle
|
||||
else:
|
||||
self.editor.tool.CuttingEdgeAngle = self.quantityCuttingEdgeAngle(False)
|
||||
|
||||
if "H" in self.hide:
|
||||
self.editor.tool.CuttingEdgeHeight = toolDefault.CuttingEdgeHeight
|
||||
else:
|
||||
self.editor.tool.CuttingEdgeHeight = self.quantityCuttingEdgeHeight(False)
|
||||
|
||||
self.editor.tool.CornerRadius = toolDefault.CornerRadius
|
||||
|
||||
def quantityDiameter(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return FreeCAD.Units.Quantity(
|
||||
self.editor.tool.Diameter, FreeCAD.Units.Length
|
||||
)
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_D.text())
|
||||
|
||||
def quantityFlatRadius(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return (
|
||||
FreeCAD.Units.Quantity(
|
||||
self.editor.tool.FlatRadius, FreeCAD.Units.Length
|
||||
)
|
||||
* 2
|
||||
)
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_d.text()) / 2
|
||||
|
||||
def quantityCuttingEdgeAngle(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return FreeCAD.Units.Quantity(
|
||||
self.editor.tool.CuttingEdgeAngle, FreeCAD.Units.Angle
|
||||
)
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_a.text())
|
||||
|
||||
def quantityCuttingEdgeHeight(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return FreeCAD.Units.Quantity(
|
||||
self.editor.tool.CuttingEdgeHeight, FreeCAD.Units.Length
|
||||
)
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_H.text())
|
||||
|
||||
|
||||
class ToolEditorEndmill(ToolEditorImage):
|
||||
"""Tool parameter editor for endmills."""
|
||||
|
||||
def __init__(self, editor):
|
||||
super(ToolEditorEndmill, self).__init__(editor, "endmill.svg", "da", "S")
|
||||
|
||||
|
||||
class ToolEditorReamer(ToolEditorImage):
|
||||
"""Tool parameter editor for reamers."""
|
||||
|
||||
def __init__(self, editor):
|
||||
super(ToolEditorReamer, self).__init__(editor, "reamer.svg", "da", "S")
|
||||
|
||||
|
||||
class ToolEditorDrill(ToolEditorImage):
|
||||
"""Tool parameter editor for drills."""
|
||||
|
||||
def __init__(self, editor):
|
||||
super(ToolEditorDrill, self).__init__(editor, "drill.svg", "dS", "")
|
||||
|
||||
def quantityCuttingEdgeAngle(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return FreeCAD.Units.Quantity(
|
||||
self.editor.tool.CuttingEdgeAngle, FreeCAD.Units.Angle
|
||||
)
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_a.text())
|
||||
|
||||
|
||||
class ToolEditorEngrave(ToolEditorImage):
|
||||
"""Tool parameter editor for v-bits."""
|
||||
|
||||
def __init__(self, editor):
|
||||
super(ToolEditorEngrave, self).__init__(editor, "v-bit.svg", "", "dS")
|
||||
|
||||
def quantityCuttingEdgeHeight(self, propertyToDisplay):
|
||||
Path.Log.track()
|
||||
dr = (self.quantityDiameter(False) - self.quantityFlatRadius(False)) / 2
|
||||
da = self.quantityCuttingEdgeAngle(False).Value
|
||||
return dr / math.tan(math.radians(da) / 2)
|
||||
|
||||
|
||||
class ToolEditor:
|
||||
"""UI and controller for editing a Tool.
|
||||
The controller embeds the UI to the parentWidget which has to have a layout attached to it.
|
||||
The editor maintains two Tools, self.tool and self.Tool. The former is the one being edited
|
||||
and always reflects the current state. self.Tool on the other hand is the "official" Tool
|
||||
which should be used externally. The state is transferred between the two with accept and
|
||||
reject.
|
||||
|
||||
The editor uses instances of ToolEditorDefault and ToolEditorImage to deal with the changes
|
||||
of the actual parameters. For any ToolType not mapped in ToolTypeImage the editor uses
|
||||
an instance of ToolEditorDefault.
|
||||
"""
|
||||
|
||||
ToolTypeImage = {
|
||||
"EndMill": ToolEditorEndmill,
|
||||
"Drill": ToolEditorDrill,
|
||||
"Engraver": ToolEditorEngrave,
|
||||
"Reamer": ToolEditorReamer,
|
||||
}
|
||||
|
||||
def __init__(self, tool, parentWidget, parent=None):
|
||||
self.Parent = parent
|
||||
self.Tool = tool
|
||||
self.tool = tool.copy()
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/ToolEditor.ui")
|
||||
|
||||
self.form.setParent(parentWidget)
|
||||
parentWidget.layout().addWidget(self.form)
|
||||
|
||||
for tooltype in Path.Tool.getToolTypes(tool):
|
||||
self.form.toolType.addItem(tooltype)
|
||||
for material in Path.Tool.getToolMaterials(tool):
|
||||
self.form.toolMaterial.addItem(material)
|
||||
|
||||
self.setupToolType(self.tool.ToolType)
|
||||
|
||||
def accept(self):
|
||||
self.refresh()
|
||||
self.Tool = self.tool
|
||||
|
||||
def reject(self):
|
||||
self.tool = self.Tool
|
||||
|
||||
def getType(self, tooltype):
|
||||
"gets a combobox index number for a given type or vice versa"
|
||||
toolslist = Path.Tool.getToolTypes(Path.Tool())
|
||||
if isinstance(tooltype, str):
|
||||
if tooltype in toolslist:
|
||||
return toolslist.index(tooltype)
|
||||
else:
|
||||
return 0
|
||||
return toolslist[tooltype]
|
||||
|
||||
def getMaterial(self, material):
|
||||
"gets a combobox index number for a given material or vice versa"
|
||||
matslist = Path.Tool.getToolMaterials(Path.Tool())
|
||||
if isinstance(material, str):
|
||||
if material in matslist:
|
||||
return matslist.index(material)
|
||||
else:
|
||||
return 0
|
||||
return matslist[material]
|
||||
|
||||
def updateUI(self):
|
||||
Path.Log.track()
|
||||
self.form.toolName.setText(self.tool.Name)
|
||||
self.form.toolType.setCurrentIndex(self.getType(self.tool.ToolType))
|
||||
self.form.toolMaterial.setCurrentIndex(self.getMaterial(self.tool.Material))
|
||||
self.form.toolLengthOffset.setText(
|
||||
FreeCAD.Units.Quantity(
|
||||
self.tool.LengthOffset, FreeCAD.Units.Length
|
||||
).UserString
|
||||
)
|
||||
|
||||
self.editor.updateUI()
|
||||
|
||||
def updateToolType(self):
|
||||
Path.Log.track()
|
||||
self.form.blockSignals(True)
|
||||
self.tool.ToolType = self.getType(self.form.toolType.currentIndex())
|
||||
self.setupToolType(self.tool.ToolType)
|
||||
self.updateUI()
|
||||
self.form.blockSignals(False)
|
||||
|
||||
def setupToolType(self, tt):
|
||||
Path.Log.track()
|
||||
print("Tool type: %s" % (tt))
|
||||
if "Undefined" == tt:
|
||||
tt = Path.Tool.getToolTypes(Path.Tool())[0]
|
||||
if tt in self.ToolTypeImage:
|
||||
self.editor = self.ToolTypeImage[tt](self)
|
||||
else:
|
||||
Path.Log.debug("weak supported ToolType = %s" % (tt))
|
||||
self.editor = ToolEditorDefault(self)
|
||||
self.editor.setupUI()
|
||||
|
||||
def updateTool(self):
|
||||
Path.Log.track()
|
||||
self.tool.Name = str(self.form.toolName.text())
|
||||
self.tool.Material = self.getMaterial(self.form.toolMaterial.currentIndex())
|
||||
self.tool.LengthOffset = FreeCAD.Units.parseQuantity(
|
||||
self.form.toolLengthOffset.text()
|
||||
)
|
||||
self.editor.updateTool()
|
||||
|
||||
def refresh(self):
|
||||
Path.Log.track()
|
||||
self.form.blockSignals(True)
|
||||
self.updateTool()
|
||||
self.updateUI()
|
||||
self.form.blockSignals(False)
|
||||
|
||||
def setupUI(self):
|
||||
Path.Log.track()
|
||||
self.updateUI()
|
||||
|
||||
self.form.toolName.editingFinished.connect(self.refresh)
|
||||
self.form.toolType.currentIndexChanged.connect(self.updateToolType)
|
||||
@@ -1,515 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2014 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
from __future__ import print_function
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
import Path
|
||||
import Path.Tools.Controller as PathToolController
|
||||
import Path.Tools.Gui.BitLibraryCmd as PathToolBitLibraryCmd
|
||||
import PathScripts
|
||||
import PathScripts.PathPreferences as PathPreferences
|
||||
import PathScripts.PathToolEdit as PathToolEdit
|
||||
import PathScripts.PathToolLibraryManager as ToolLibraryManager
|
||||
import PathScripts.PathUtils as PathUtils
|
||||
|
||||
|
||||
if False:
|
||||
Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule())
|
||||
Path.Log.trackModule(Path.Log.thisModule())
|
||||
else:
|
||||
Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule())
|
||||
|
||||
translate = FreeCAD.Qt.translate
|
||||
|
||||
|
||||
class EditorPanel:
|
||||
def __init__(self, job, cb):
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/ToolLibraryEditor.ui")
|
||||
self.TLM = ToolLibraryManager.ToolLibraryManager()
|
||||
listname = self.TLM.getCurrentTableName()
|
||||
|
||||
if listname:
|
||||
self.loadToolTables()
|
||||
|
||||
self.job = job
|
||||
self.cb = cb
|
||||
|
||||
def toolEditor(self, tool):
|
||||
dialog = FreeCADGui.PySideUic.loadUi(":/panels/DlgToolEdit.ui")
|
||||
editor = PathToolEdit.ToolEditor(tool, dialog.toolEditor, dialog)
|
||||
editor.setupUI()
|
||||
return editor
|
||||
|
||||
def accept(self):
|
||||
pass
|
||||
|
||||
def reject(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def getFields(self):
|
||||
pass
|
||||
|
||||
def setFields(self):
|
||||
pass
|
||||
|
||||
def open(self):
|
||||
pass
|
||||
|
||||
def getType(self, tooltype):
|
||||
"gets a combobox index number for a given type or vice versa"
|
||||
toolslist = Path.Tool.getToolTypes(Path.Tool())
|
||||
if isinstance(tooltype, str):
|
||||
if tooltype in toolslist:
|
||||
return toolslist.index(tooltype)
|
||||
else:
|
||||
return 0
|
||||
else:
|
||||
return toolslist[tooltype]
|
||||
|
||||
def getMaterial(self, material):
|
||||
"""gets a combobox index number for a given material or vice versa"""
|
||||
matslist = Path.Tool.getToolMaterials(Path.Tool())
|
||||
if isinstance(material, str):
|
||||
if material in matslist:
|
||||
return matslist.index(material)
|
||||
else:
|
||||
return 0
|
||||
else:
|
||||
return matslist[material]
|
||||
|
||||
def addTool(self):
|
||||
"""adds new tool to the current tool table"""
|
||||
tool = Path.Tool()
|
||||
editor = self.toolEditor(tool)
|
||||
|
||||
r = editor.Parent.exec_()
|
||||
if r:
|
||||
editor.accept()
|
||||
listname = self.TLM.getCurrentTableName()
|
||||
self.TLM.addnew(listname, editor.Tool)
|
||||
self.loadTable(listname)
|
||||
|
||||
def delete(self):
|
||||
"""deletes the selected tool"""
|
||||
listname = self.TLM.getCurrentTableName()
|
||||
model = self.form.ToolsList.model()
|
||||
for i in range(model.rowCount()):
|
||||
item = model.item(i, 0)
|
||||
if item.checkState():
|
||||
t = model.index(i, 1)
|
||||
self.TLM.delete(int(t.data()), listname)
|
||||
self.loadTable(listname)
|
||||
self.toolSelectionChanged()
|
||||
|
||||
def editTool(self, currItem):
|
||||
"""load the tool edit dialog"""
|
||||
if not currItem:
|
||||
currItem = self.form.ToolsList.selectedIndexes()[1]
|
||||
|
||||
row = currItem.row()
|
||||
value = currItem.sibling(row, 1).data()
|
||||
listname = self.TLM.getCurrentTableName()
|
||||
toolnum = int(value)
|
||||
tool = self.TLM.getTool(listname, toolnum)
|
||||
editor = self.toolEditor(tool)
|
||||
|
||||
r = editor.Parent.exec_()
|
||||
if r:
|
||||
editor.accept()
|
||||
if self.TLM.updateTool(listname, toolnum, editor.Tool) is True:
|
||||
self.loadTable(listname)
|
||||
|
||||
def moveUp(self):
|
||||
"""moves a tool to a lower number, if possible"""
|
||||
item = self.form.ToolsList.selectedIndexes()[1].data()
|
||||
if item:
|
||||
number = int(item)
|
||||
listname = self.TLM.getCurrentTableName()
|
||||
success, newNum = self.TLM.moveup(number, listname)
|
||||
if success:
|
||||
self.loadTable(listname)
|
||||
self.updateSelection(newNum)
|
||||
|
||||
def moveDown(self):
|
||||
"""moves a tool to a higher number, if possible"""
|
||||
item = self.form.ToolsList.selectedIndexes()[1].data()
|
||||
if item:
|
||||
number = int(item)
|
||||
listname = self.TLM.getCurrentTableName()
|
||||
success, newNum = self.TLM.movedown(number, listname)
|
||||
if success:
|
||||
self.loadTable(listname)
|
||||
self.updateSelection(newNum)
|
||||
|
||||
def duplicate(self):
|
||||
"""duplicated the selected tool in the current tool table"""
|
||||
item = self.form.ToolsList.selectedIndexes()[1].data()
|
||||
if item:
|
||||
number = int(item)
|
||||
listname = self.TLM.getCurrentTableName()
|
||||
success, newNum = self.TLM.duplicate(number, listname)
|
||||
if success:
|
||||
self.loadTable(listname)
|
||||
self.updateSelection(newNum)
|
||||
|
||||
def updateSelection(self, number):
|
||||
"""update the tool list selection to track moves"""
|
||||
model = self.form.ToolsList.model()
|
||||
for i in range(model.rowCount()):
|
||||
if int(model.index(i, 1).data()) == number:
|
||||
self.form.ToolsList.selectRow(i)
|
||||
self.form.ToolsList.model().item(i, 0).setCheckState(QtCore.Qt.Checked)
|
||||
return
|
||||
|
||||
def importFile(self):
|
||||
"""imports a tooltable from a file"""
|
||||
filename = QtGui.QFileDialog.getOpenFileName(
|
||||
self.form,
|
||||
translate("Path_ToolTable", "Open tooltable"),
|
||||
None,
|
||||
"{};;{};;{}".format(
|
||||
self.TLM.TooltableTypeJSON,
|
||||
self.TLM.TooltableTypeXML,
|
||||
self.TLM.TooltableTypeHeekscad,
|
||||
),
|
||||
)
|
||||
if filename[0]:
|
||||
listname = self.TLM.getNextToolTableName()
|
||||
if self.TLM.read(filename, listname):
|
||||
self.loadToolTables()
|
||||
|
||||
def exportFile(self):
|
||||
"""export a tooltable to a file"""
|
||||
filename = QtGui.QFileDialog.getSaveFileName(
|
||||
self.form,
|
||||
translate("Path_ToolTable", "Save tooltable"),
|
||||
None,
|
||||
"{};;{};;{}".format(
|
||||
self.TLM.TooltableTypeJSON,
|
||||
self.TLM.TooltableTypeXML,
|
||||
self.TLM.TooltableTypeLinuxCNC,
|
||||
),
|
||||
)
|
||||
if filename[0]:
|
||||
listname = self.TLM.getCurrentTableName()
|
||||
self.TLM.write(filename, listname)
|
||||
|
||||
def toolSelectionChanged(self, index=None):
|
||||
"""updates the ui when tools are selected"""
|
||||
if index:
|
||||
self.form.ToolsList.selectRow(index.row())
|
||||
|
||||
self.form.btnCopyTools.setEnabled(False)
|
||||
self.form.ButtonDelete.setEnabled(False)
|
||||
self.form.ButtonUp.setEnabled(False)
|
||||
self.form.ButtonDown.setEnabled(False)
|
||||
self.form.ButtonEdit.setEnabled(False)
|
||||
self.form.ButtonDuplicate.setEnabled(False)
|
||||
|
||||
model = self.form.ToolsList.model()
|
||||
checkCount = 0
|
||||
checkList = []
|
||||
for i in range(model.rowCount()):
|
||||
item = model.item(i, 0)
|
||||
if item.checkState():
|
||||
checkCount += 1
|
||||
checkList.append(i)
|
||||
self.form.btnCopyTools.setEnabled(True)
|
||||
|
||||
# only allow moving or deleting a single tool at a time.
|
||||
if checkCount == 1:
|
||||
# make sure the row is highlighted when the check box gets ticked
|
||||
self.form.ToolsList.selectRow(checkList[0])
|
||||
self.form.ButtonDelete.setEnabled(True)
|
||||
self.form.ButtonUp.setEnabled(True)
|
||||
self.form.ButtonDown.setEnabled(True)
|
||||
self.form.ButtonEdit.setEnabled(True)
|
||||
self.form.ButtonDuplicate.setEnabled(True)
|
||||
|
||||
if len(PathUtils.GetJobs()) == 0:
|
||||
self.form.btnCopyTools.setEnabled(False)
|
||||
|
||||
def copyTools(self):
|
||||
"""copy selected tool"""
|
||||
tools = []
|
||||
model = self.form.ToolsList.model()
|
||||
for i in range(model.rowCount()):
|
||||
item = model.item(i, 0)
|
||||
if item.checkState():
|
||||
item = model.index(i, 1)
|
||||
tools.append(item.data())
|
||||
if len(tools) == 0:
|
||||
return
|
||||
|
||||
targets = self.TLM.getJobList()
|
||||
currList = self.TLM.getCurrentTableName()
|
||||
|
||||
for target in targets:
|
||||
if target == currList:
|
||||
targets.remove(target)
|
||||
|
||||
if len(targets) == 0:
|
||||
FreeCAD.Console.PrintWarning("No Path Jobs in current document")
|
||||
return
|
||||
elif len(targets) == 1:
|
||||
targetlist = targets[0]
|
||||
else:
|
||||
form = FreeCADGui.PySideUic.loadUi(":/panels/DlgToolCopy.ui")
|
||||
form.cboTarget.addItems(targets)
|
||||
r = form.exec_()
|
||||
if r is False:
|
||||
return None
|
||||
else:
|
||||
targetlist = form.cboTarget.currentText()
|
||||
|
||||
for toolnum in tools:
|
||||
tool = self.TLM.getTool(currList, int(toolnum))
|
||||
Path.Log.debug("tool: {}, toolnum: {}".format(tool, toolnum))
|
||||
if self.job:
|
||||
label = "T{}: {}".format(toolnum, tool.Name)
|
||||
tc = PathToolController.Create(
|
||||
label, tool=tool, toolNumber=int(toolnum)
|
||||
)
|
||||
self.job.Proxy.addToolController(tc)
|
||||
else:
|
||||
for job in FreeCAD.ActiveDocument.findObjects("Path::Feature"):
|
||||
if (
|
||||
isinstance(job.Proxy, PathScripts.PathJob.ObjectJob)
|
||||
and job.Label == targetlist
|
||||
):
|
||||
label = "T{}: {}".format(toolnum, tool.Name)
|
||||
tc = PathToolController.Create(
|
||||
label, tool=tool, toolNumber=int(toolnum)
|
||||
)
|
||||
job.Proxy.addToolController(tc)
|
||||
if self.cb:
|
||||
self.cb()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def tableSelected(self, index):
|
||||
"""loads the tools for the selected tool table"""
|
||||
name = self.form.TableList.itemWidget(
|
||||
self.form.TableList.itemFromIndex(index)
|
||||
).getTableName()
|
||||
self.loadTable(name)
|
||||
|
||||
def loadTable(self, name):
|
||||
"""loads the tools for the selected tool table"""
|
||||
tooldata = self.TLM.getTools(name)
|
||||
if tooldata:
|
||||
self.form.ToolsList.setModel(tooldata)
|
||||
self.form.ToolsList.resizeColumnsToContents()
|
||||
self.form.ToolsList.horizontalHeader().setResizeMode(
|
||||
self.form.ToolsList.model().columnCount() - 1, QtGui.QHeaderView.Stretch
|
||||
)
|
||||
self.setCurrentToolTableByName(name)
|
||||
|
||||
def addNewToolTable(self):
|
||||
"""adds new tool to selected tool table"""
|
||||
name = self.TLM.addNewToolTable()
|
||||
self.loadToolTables()
|
||||
self.loadTable(name)
|
||||
|
||||
def loadToolTables(self):
|
||||
"""Load list of available tool tables"""
|
||||
self.form.TableList.clear()
|
||||
model = self.form.ToolsList.model()
|
||||
if model:
|
||||
model.clear()
|
||||
if len(self.TLM.getToolTables()) > 0:
|
||||
for table in self.TLM.getToolTables():
|
||||
listWidgetItem = QtGui.QListWidgetItem()
|
||||
listItem = ToolTableListWidgetItem(self.TLM)
|
||||
listItem.setTableName(table.Name)
|
||||
listItem.setIcon(QtGui.QPixmap(":/icons/Path_ToolTable.svg"))
|
||||
listItem.toolMoved.connect(self.reloadReset)
|
||||
listWidgetItem.setSizeHint(QtCore.QSize(0, 40))
|
||||
self.form.TableList.addItem(listWidgetItem)
|
||||
self.form.TableList.setItemWidget(listWidgetItem, listItem)
|
||||
# Load the first tooltable
|
||||
self.loadTable(self.TLM.getCurrentTableName())
|
||||
|
||||
def reloadReset(self):
|
||||
"""reloads the current tooltable"""
|
||||
name = self.TLM.getCurrentTableName()
|
||||
self.loadTable(name)
|
||||
|
||||
def setCurrentToolTableByName(self, name):
|
||||
"""get the current tool table"""
|
||||
item = self.getToolTableByName(name)
|
||||
if item:
|
||||
self.form.TableList.setCurrentItem(item)
|
||||
|
||||
def getToolTableByName(self, name):
|
||||
"""returns the listWidgetItem for the selected name"""
|
||||
for i in range(self.form.TableList.count()):
|
||||
tableName = self.form.TableList.itemWidget(
|
||||
self.form.TableList.item(i)
|
||||
).getTableName()
|
||||
if tableName == name:
|
||||
return self.form.TableList.item(i)
|
||||
return False
|
||||
|
||||
def removeToolTable(self):
|
||||
"""delete the selected tool table"""
|
||||
self.TLM.deleteToolTable()
|
||||
self.loadToolTables()
|
||||
|
||||
def renameTable(self):
|
||||
"""provides dialog for new tablename and renames the selected tool table"""
|
||||
name = self.TLM.getCurrentTableName()
|
||||
newName, ok = QtGui.QInputDialog.getText(
|
||||
None,
|
||||
translate("Path_ToolTable", "Rename Tooltable"),
|
||||
translate("Path_ToolTable", "Enter Name:"),
|
||||
QtGui.QLineEdit.Normal,
|
||||
name,
|
||||
)
|
||||
if ok and newName:
|
||||
index = self.form.TableList.indexFromItem(
|
||||
self.getToolTableByName(name)
|
||||
).row()
|
||||
reloadTables = self.TLM.renameToolTable(newName, index)
|
||||
if reloadTables:
|
||||
self.loadToolTables()
|
||||
self.loadTable(newName)
|
||||
|
||||
def getStandardButtons(self):
|
||||
return int(QtGui.QDialogButtonBox.Ok)
|
||||
|
||||
def setupUi(self):
|
||||
# Connect Signals and Slots
|
||||
self.form.ButtonNewTool.clicked.connect(self.addTool)
|
||||
self.form.ButtonImport.clicked.connect(self.importFile)
|
||||
self.form.ButtonExport.clicked.connect(self.exportFile)
|
||||
self.form.ButtonDown.clicked.connect(self.moveDown)
|
||||
self.form.ButtonUp.clicked.connect(self.moveUp)
|
||||
self.form.ButtonDelete.clicked.connect(self.delete)
|
||||
self.form.ButtonEdit.clicked.connect(self.editTool)
|
||||
self.form.ButtonDuplicate.clicked.connect(self.duplicate)
|
||||
self.form.btnCopyTools.clicked.connect(self.copyTools)
|
||||
|
||||
self.form.ToolsList.doubleClicked.connect(self.editTool)
|
||||
self.form.ToolsList.clicked.connect(self.toolSelectionChanged)
|
||||
|
||||
self.form.TableList.clicked.connect(self.tableSelected)
|
||||
self.form.TableList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
self.form.TableList.itemChanged.connect(self.renameTable)
|
||||
|
||||
self.form.ButtonAddToolTable.clicked.connect(self.addNewToolTable)
|
||||
self.form.ButtonAddToolTable.setToolTip(
|
||||
translate("Path_ToolTable", "Add New Tool Table")
|
||||
)
|
||||
self.form.ButtonRemoveToolTable.clicked.connect(self.removeToolTable)
|
||||
self.form.ButtonRemoveToolTable.setToolTip(
|
||||
translate("Path_ToolTable", "Delete Selected Tool Table")
|
||||
)
|
||||
self.form.ButtonRenameToolTable.clicked.connect(self.renameTable)
|
||||
self.form.ButtonRenameToolTable.setToolTip(
|
||||
translate("Path_ToolTable", "Rename Selected Tool Table")
|
||||
)
|
||||
|
||||
self.setFields()
|
||||
|
||||
|
||||
class ToolTableListWidgetItem(QtGui.QWidget):
|
||||
|
||||
toolMoved = QtCore.Signal()
|
||||
|
||||
def __init__(self, TLM):
|
||||
super(ToolTableListWidgetItem, self).__init__()
|
||||
|
||||
self.tlm = TLM
|
||||
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(24, 24)
|
||||
self.iconQLabel.setPixmap(icon)
|
||||
|
||||
def dragEnterEvent(self, e):
|
||||
currentToolTable = self.tlm.getCurrentTableName()
|
||||
thisToolTable = self.getTableName()
|
||||
|
||||
if not currentToolTable == thisToolTable:
|
||||
e.accept()
|
||||
else:
|
||||
e.ignore()
|
||||
|
||||
def dropEvent(self, e):
|
||||
selectedTools = e.source().selectedIndexes()
|
||||
if selectedTools:
|
||||
toolData = selectedTools[1].data()
|
||||
|
||||
if toolData:
|
||||
self.tlm.moveToTable(int(toolData), self.getTableName())
|
||||
self.toolMoved.emit()
|
||||
|
||||
|
||||
class CommandToolLibraryEdit:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def edit(self, job=None, cb=None):
|
||||
if PathPreferences.toolsUseLegacyTools():
|
||||
editor = EditorPanel(job, cb)
|
||||
editor.setupUi()
|
||||
editor.form.exec_()
|
||||
else:
|
||||
if PathToolBitLibraryCmd.CommandToolBitLibraryLoad.Execute(job):
|
||||
if cb:
|
||||
cb()
|
||||
|
||||
def GetResources(self):
|
||||
return {
|
||||
"Pixmap": "Path_ToolTable",
|
||||
"MenuText": QT_TRANSLATE_NOOP("Path_ToolTable", "Tool Manager"),
|
||||
"Accel": "P, T",
|
||||
"ToolTip": QT_TRANSLATE_NOOP("Path_ToolTable", "Tool Manager"),
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.edit()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand("Path_ToolLibraryEdit", CommandToolLibraryEdit())
|
||||
@@ -1,561 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2014 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import FreeCAD
|
||||
import Path
|
||||
import PathScripts
|
||||
import PathScripts.PathUtil as PathUtil
|
||||
import json
|
||||
import os
|
||||
import xml.sax
|
||||
from PySide import QtGui
|
||||
|
||||
if False:
|
||||
Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule())
|
||||
Path.Log.trackModule(Path.Log.thisModule())
|
||||
else:
|
||||
Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule())
|
||||
|
||||
translate = FreeCAD.Qt.translate
|
||||
|
||||
# Tooltable XML readers
|
||||
class FreeCADTooltableHandler(xml.sax.ContentHandler):
|
||||
# http://www.tutorialspoint.com/python/python_xml_processing.htm
|
||||
|
||||
def __init__(self):
|
||||
xml.sax.ContentHandler.__init__(self)
|
||||
self.tooltable = None
|
||||
self.tool = None
|
||||
self.number = None
|
||||
|
||||
# Call when an element is found
|
||||
def startElement(self, name, attrs):
|
||||
if name == "Tooltable":
|
||||
self.tooltable = Path.Tooltable()
|
||||
elif name == "Toolslot":
|
||||
self.number = int(attrs["number"])
|
||||
elif name == "Tool":
|
||||
self.tool = Path.Tool()
|
||||
self.tool.Name = str(attrs["name"])
|
||||
self.tool.ToolType = str(attrs["type"])
|
||||
self.tool.Material = str(attrs["mat"])
|
||||
# for some reason without the following line I get an error
|
||||
# print attrs["diameter"]
|
||||
self.tool.Diameter = float(attrs["diameter"])
|
||||
self.tool.LengthOffset = float(attrs["length"])
|
||||
self.tool.FlatRadius = float(attrs["flat"])
|
||||
self.tool.CornerRadius = float(attrs["corner"])
|
||||
self.tool.CuttingEdgeAngle = float(attrs["angle"])
|
||||
self.tool.CuttingEdgeHeight = float(attrs["height"])
|
||||
|
||||
# Call when an elements ends
|
||||
def endElement(self, name):
|
||||
if name == "Toolslot":
|
||||
if self.tooltable and self.tool and self.number:
|
||||
self.tooltable.setTool(self.number, self.tool)
|
||||
self.number = None
|
||||
self.tool = None
|
||||
|
||||
|
||||
class HeeksTooltableHandler(xml.sax.ContentHandler):
|
||||
def __init__(self):
|
||||
xml.sax.ContentHandler.__init__(self)
|
||||
self.tooltable = Path.Tooltable()
|
||||
self.tool = None
|
||||
self.number = None
|
||||
|
||||
# Call when an element is found
|
||||
def startElement(self, name, attrs):
|
||||
if name == "Tool":
|
||||
self.tool = Path.Tool()
|
||||
self.number = int(attrs["tool_number"])
|
||||
self.tool.Name = str(attrs["title"])
|
||||
elif name == "params":
|
||||
t = str(attrs["type"])
|
||||
if t == "drill":
|
||||
self.tool.ToolType = "Drill"
|
||||
elif t == "center_drill_bit":
|
||||
self.tool.ToolType = "CenterDrill"
|
||||
elif t == "end_mill":
|
||||
self.tool.ToolType = "EndMill"
|
||||
elif t == "slot_cutter":
|
||||
self.tool.ToolType = "SlotCutter"
|
||||
elif t == "ball_end_mill":
|
||||
self.tool.ToolType = "BallEndMill"
|
||||
elif t == "chamfer":
|
||||
self.tool.ToolType = "Chamfer"
|
||||
elif t == "engraving_bit":
|
||||
self.tool.ToolType = "Engraver"
|
||||
m = str(attrs["material"])
|
||||
if m == "0":
|
||||
self.tool.Material = "HighSpeedSteel"
|
||||
elif m == "1":
|
||||
self.tool.Material = "Carbide"
|
||||
# for some reason without the following line I get an error
|
||||
# print attrs["diameter"]
|
||||
self.tool.Diameter = float(attrs["diameter"])
|
||||
self.tool.LengthOffset = float(attrs["tool_length_offset"])
|
||||
self.tool.FlatRadius = float(attrs["flat_radius"])
|
||||
self.tool.CornerRadius = float(attrs["corner_radius"])
|
||||
self.tool.CuttingEdgeAngle = float(attrs["cutting_edge_angle"])
|
||||
self.tool.CuttingEdgeHeight = float(attrs["cutting_edge_height"])
|
||||
|
||||
# Call when an elements ends
|
||||
def endElement(self, name):
|
||||
if name == "Tool":
|
||||
if self.tooltable and self.tool and self.number:
|
||||
self.tooltable.setTool(self.number, self.tool)
|
||||
self.number = None
|
||||
self.tool = None
|
||||
|
||||
|
||||
class ToolLibraryManager:
|
||||
"""
|
||||
The Tool Library is a list of individual tool tables. Each
|
||||
Tool Table can contain n tools. The tool library will be persisted to user
|
||||
preferences and all or part of the library can be exported to other formats
|
||||
"""
|
||||
|
||||
TooltableTypeJSON = translate("PathToolLibraryManager", "Tooltable JSON (*.json)")
|
||||
TooltableTypeXML = translate("PathToolLibraryManager", "Tooltable XML (*.xml)")
|
||||
TooltableTypeHeekscad = translate(
|
||||
"PathToolLibraryManager", "HeeksCAD tooltable (*.tooltable)"
|
||||
)
|
||||
TooltableTypeLinuxCNC = translate(
|
||||
"PathToolLibraryManager", "LinuxCNC tooltable (*.tbl)"
|
||||
)
|
||||
|
||||
PreferenceMainLibraryXML = "ToolLibrary"
|
||||
PreferenceMainLibraryJSON = "ToolLibrary-Main"
|
||||
|
||||
def __init__(self):
|
||||
self.prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
|
||||
self.toolTables = []
|
||||
self.currentTableName = None
|
||||
self.loadToolTables()
|
||||
|
||||
def getToolTables(self):
|
||||
"""Return tool table list"""
|
||||
return self.toolTables
|
||||
|
||||
def getCurrentTableName(self):
|
||||
"""return the name of the currently loaded tool table"""
|
||||
return self.currentTableName
|
||||
|
||||
def getCurrentTable(self):
|
||||
"""returns an object of the current tool table"""
|
||||
return self.getTableFromName(self.currentTableName)
|
||||
|
||||
def getTableFromName(self, name):
|
||||
"""get the tool table object from the name"""
|
||||
for table in self.toolTables:
|
||||
if table.Name == name:
|
||||
return table
|
||||
|
||||
def getNextToolTableName(self, tableName="Tool Table"):
|
||||
"""get a unique name for a new tool table"""
|
||||
iter = 1
|
||||
tempName = tableName[-2:]
|
||||
|
||||
if tempName[0] == "-" and tempName[-1].isdigit():
|
||||
tableName = tableName[:-2]
|
||||
|
||||
while any(
|
||||
table.Name == tableName + "-" + str(iter) for table in self.toolTables
|
||||
):
|
||||
iter += 1
|
||||
|
||||
return tableName + "-" + str(iter)
|
||||
|
||||
def addNewToolTable(self):
|
||||
"""creates a new tool table"""
|
||||
tt = Path.Tooltable()
|
||||
tt.Version = 1
|
||||
name = self.getNextToolTableName()
|
||||
tt.Name = name
|
||||
self.toolTables.append(tt)
|
||||
self.saveMainLibrary()
|
||||
return name
|
||||
|
||||
def deleteToolTable(self):
|
||||
"""deletes the selected tool table"""
|
||||
if len(self.toolTables):
|
||||
index = next(
|
||||
(
|
||||
index
|
||||
for (index, d) in enumerate(self.toolTables)
|
||||
if d.Name == self.currentTableName
|
||||
),
|
||||
None,
|
||||
)
|
||||
self.toolTables.pop(index)
|
||||
self.saveMainLibrary()
|
||||
|
||||
def renameToolTable(self, newName, index):
|
||||
"""renames a tool table with the new name"""
|
||||
currentTableName = self.toolTables[index].Name
|
||||
if newName == currentTableName:
|
||||
Path.Log.error(translate("PathToolLibraryManager", "Tool Table Same Name"))
|
||||
return False
|
||||
if newName in self.toolTables:
|
||||
Path.Log.error(translate("PathToolLibraryManager", "Tool Table Name Exists"))
|
||||
return False
|
||||
tt = self.getTableFromName(currentTableName)
|
||||
if tt:
|
||||
tt.Name = newName
|
||||
self.saveMainLibrary()
|
||||
return True
|
||||
|
||||
def templateAttrs(self):
|
||||
"""gets the tool table arributes"""
|
||||
toolTables = []
|
||||
for tt in self.toolTables:
|
||||
tableData = {}
|
||||
tableData["Version"] = 1
|
||||
tableData["TableName"] = tt.Name
|
||||
|
||||
toolData = {}
|
||||
for tool in tt.Tools:
|
||||
toolData[tool] = tt.Tools[tool].templateAttrs()
|
||||
|
||||
tableData["Tools"] = toolData
|
||||
toolTables.append(tableData)
|
||||
|
||||
return toolTables
|
||||
|
||||
def tooltableFromAttrs(self, stringattrs):
|
||||
if stringattrs.get("Version") and 1 == int(stringattrs["Version"]):
|
||||
|
||||
tt = Path.Tooltable()
|
||||
tt.Version = 1
|
||||
tt.Name = self.getNextToolTableName()
|
||||
|
||||
if stringattrs.get("Version"):
|
||||
tt.Version = stringattrs.get("Version")
|
||||
|
||||
if stringattrs.get("TableName"):
|
||||
tt.Name = stringattrs.get("TableName")
|
||||
if any(table.Name == tt.Name for table in self.toolTables):
|
||||
tt.Name = self.getNextToolTableName(tt.Name)
|
||||
|
||||
for key, attrs in PathUtil.keyValueIter(stringattrs["Tools"]):
|
||||
tool = Path.Tool()
|
||||
tool.Name = str(attrs["name"])
|
||||
tool.ToolType = str(attrs["tooltype"])
|
||||
tool.Material = str(attrs["material"])
|
||||
tool.Diameter = float(attrs["diameter"])
|
||||
tool.LengthOffset = float(attrs["lengthOffset"])
|
||||
tool.FlatRadius = float(attrs["flatRadius"])
|
||||
tool.CornerRadius = float(attrs["cornerRadius"])
|
||||
tool.CuttingEdgeAngle = float(attrs["cuttingEdgeAngle"])
|
||||
tool.CuttingEdgeHeight = float(attrs["cuttingEdgeHeight"])
|
||||
tt.setTool(int(key), tool)
|
||||
|
||||
return tt
|
||||
else:
|
||||
Path.Log.error(
|
||||
translate(
|
||||
"PathToolLibraryManager",
|
||||
"Unsupported Path tooltable template version %s",
|
||||
)
|
||||
% stringattrs.get("Version")
|
||||
)
|
||||
return None
|
||||
|
||||
def loadToolTables(self):
|
||||
"""loads the tool tables from the stored data"""
|
||||
self.toolTables = []
|
||||
self.currentTableName = ""
|
||||
|
||||
def addTable(tt):
|
||||
if tt:
|
||||
self.toolTables.append(tt)
|
||||
else:
|
||||
Path.Log.error(
|
||||
translate("PathToolLibraryManager", "Unsupported Path tooltable")
|
||||
)
|
||||
|
||||
prefString = self.prefs.GetString(self.PreferenceMainLibraryJSON, "")
|
||||
|
||||
if not prefString:
|
||||
return
|
||||
|
||||
prefsData = json.loads(prefString)
|
||||
|
||||
if isinstance(prefsData, dict):
|
||||
tt = self.tooltableFromAttrs(prefsData)
|
||||
addTable(tt)
|
||||
|
||||
if isinstance(prefsData, list):
|
||||
for table in prefsData:
|
||||
tt = self.tooltableFromAttrs(table)
|
||||
addTable(tt)
|
||||
|
||||
if len(self.toolTables):
|
||||
self.currentTableName = self.toolTables[0].Name
|
||||
|
||||
def saveMainLibrary(self):
|
||||
"""Persists the permanent library to FreeCAD user preferences"""
|
||||
tmpstring = json.dumps(self.templateAttrs())
|
||||
self.prefs.SetString(self.PreferenceMainLibraryJSON, tmpstring)
|
||||
self.loadToolTables()
|
||||
return True
|
||||
|
||||
def getJobList(self):
|
||||
"""Builds the list of all Tool Table lists"""
|
||||
tablelist = []
|
||||
|
||||
for o in FreeCAD.ActiveDocument.Objects:
|
||||
if hasattr(o, "Proxy"):
|
||||
if isinstance(o.Proxy, PathScripts.PathJob.ObjectJob):
|
||||
tablelist.append(o.Label)
|
||||
|
||||
return tablelist
|
||||
|
||||
def getTool(self, listname, toolnum):
|
||||
"""gets the tool object"""
|
||||
tt = self.getTableFromName(listname)
|
||||
return tt.getTool(toolnum)
|
||||
|
||||
def getTools(self, tablename):
|
||||
"""returns the tool data for a given table"""
|
||||
tooldata = []
|
||||
tableExists = any(table.Name == tablename for table in self.toolTables)
|
||||
if tableExists:
|
||||
self.currentTableName = tablename
|
||||
else:
|
||||
return None
|
||||
|
||||
tt = self.getTableFromName(tablename)
|
||||
headers = ["", "Tool Num.", "Name", "Tool Type", "Diameter"]
|
||||
model = QtGui.QStandardItemModel()
|
||||
model.setHorizontalHeaderLabels(headers)
|
||||
|
||||
def unitconv(ivalue):
|
||||
val = FreeCAD.Units.Quantity(ivalue, FreeCAD.Units.Length)
|
||||
displayed_val = (
|
||||
val.UserString
|
||||
) # just the displayed value-not the internal one
|
||||
return displayed_val
|
||||
|
||||
if tt:
|
||||
if len(tt.Tools) == 0:
|
||||
tooldata.append([])
|
||||
for number, t in PathUtil.keyValueIter(tt.Tools):
|
||||
|
||||
itemcheck = QtGui.QStandardItem()
|
||||
itemcheck.setCheckable(True)
|
||||
itemNumber = QtGui.QStandardItem(str(number))
|
||||
itemName = QtGui.QStandardItem(t.Name)
|
||||
itemToolType = QtGui.QStandardItem(t.ToolType)
|
||||
itemDiameter = QtGui.QStandardItem(unitconv(t.Diameter))
|
||||
|
||||
row = [itemcheck, itemNumber, itemName, itemToolType, itemDiameter]
|
||||
model.appendRow(row)
|
||||
|
||||
return model
|
||||
|
||||
# methods for importing and exporting
|
||||
def read(self, filename, listname):
|
||||
"imports a tooltable from a file"
|
||||
|
||||
importedTables = []
|
||||
|
||||
try:
|
||||
fileExtension = os.path.splitext(filename[0])[1].lower()
|
||||
xmlHandler = None
|
||||
if fileExtension == ".tooltable":
|
||||
xmlHandler = HeeksTooltableHandler()
|
||||
if fileExtension == ".xml":
|
||||
xmlHandler = FreeCADTooltableHandler()
|
||||
|
||||
if xmlHandler:
|
||||
parser = xml.sax.make_parser()
|
||||
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
|
||||
parser.setContentHandler(xmlHandler)
|
||||
parser.parse(PathUtil.toUnicode(filename[0]))
|
||||
if not xmlHandler.tooltable:
|
||||
return None
|
||||
|
||||
ht = xmlHandler.tooltable
|
||||
else:
|
||||
with open(PathUtil.toUnicode(filename[0]), "rb") as fp:
|
||||
tableData = json.load(fp)
|
||||
|
||||
if isinstance(tableData, dict):
|
||||
ht = self.tooltableFromAttrs(tableData)
|
||||
if ht:
|
||||
importedTables.append(ht)
|
||||
|
||||
if isinstance(tableData, list):
|
||||
for table in tableData:
|
||||
ht = self.tooltableFromAttrs(table)
|
||||
if ht:
|
||||
importedTables.append(ht)
|
||||
|
||||
if importedTables:
|
||||
for tt in importedTables:
|
||||
self.toolTables.append(tt)
|
||||
|
||||
self.saveMainLibrary()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print("could not parse file", e)
|
||||
|
||||
def write(self, filename, listname):
|
||||
"exports the tooltable to a file"
|
||||
tt = self.getTableFromName(listname)
|
||||
if tt:
|
||||
try:
|
||||
|
||||
def openFileWithExtension(name, ext):
|
||||
fext = os.path.splitext(name)[1].lower()
|
||||
if fext != ext:
|
||||
name = "{}{}".format(name, ext)
|
||||
return (open(PathUtil.toUnicode(name), "w"), name)
|
||||
|
||||
if filename[1] == self.TooltableTypeXML:
|
||||
fp, fname = openFileWithExtension(filename[0], ".xml")
|
||||
fp.write('<?xml version="1.0" encoding="UTF-8"?>\n')
|
||||
fp.write(tt.Content)
|
||||
elif filename[1] == self.TooltableTypeLinuxCNC:
|
||||
fp, fname = openFileWithExtension(filename[0], ".tbl")
|
||||
for key in tt.Tools:
|
||||
t = tt.Tools[key]
|
||||
fp.write(
|
||||
"T{0} P{0} Y{1} Z{2} A{3} B{4} C{5} U{6} V{7} W{8} D{9} I{10} J{11} Q{12} ;{13}\n".format(
|
||||
key,
|
||||
0,
|
||||
t.LengthOffset,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
t.Diameter,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
t.Name,
|
||||
)
|
||||
)
|
||||
else:
|
||||
fp, fname = openFileWithExtension(filename[0], ".json")
|
||||
json.dump(self.templateAttrs(), fp, sort_keys=True, indent=2)
|
||||
|
||||
fp.close()
|
||||
print("Written ", PathUtil.toUnicode(fname))
|
||||
|
||||
except Exception as e:
|
||||
print("Could not write file:", e)
|
||||
|
||||
def addnew(self, listname, tool, position=None):
|
||||
"adds a new tool at the end of the table"
|
||||
tt = self.getTableFromName(listname)
|
||||
if not tt:
|
||||
tt = Path.Tooltable()
|
||||
if position is None:
|
||||
tt.addTools(tool)
|
||||
newID = list(tt.Tools)[-1]
|
||||
else:
|
||||
tt.setTool(position, tool)
|
||||
newID = position
|
||||
|
||||
if listname == self.getCurrentTableName():
|
||||
self.saveMainLibrary()
|
||||
return newID
|
||||
|
||||
def updateTool(self, listname, toolnum, tool):
|
||||
"""updates tool data"""
|
||||
tt = self.getTableFromName(listname)
|
||||
tt.deleteTool(toolnum)
|
||||
tt.setTool(toolnum, tool)
|
||||
if listname == self.getCurrentTableName():
|
||||
return self.saveMainLibrary()
|
||||
return True
|
||||
|
||||
def moveup(self, number, listname):
|
||||
"moves a tool to a lower number, if possible"
|
||||
target = number - 1
|
||||
if number < 2:
|
||||
return False, target
|
||||
target = number - 1
|
||||
tt = self.getTableFromName(listname)
|
||||
t1 = tt.getTool(number).copy()
|
||||
tt.deleteTool(number)
|
||||
if target in tt.Tools.keys():
|
||||
t2 = tt.getTool(target).copy()
|
||||
tt.deleteTool(target)
|
||||
tt.setTool(number, t2)
|
||||
tt.setTool(target, t1)
|
||||
if listname == self.getCurrentTableName():
|
||||
self.saveMainLibrary()
|
||||
return True, target
|
||||
|
||||
def movedown(self, number, listname):
|
||||
"moves a tool to a higher number, if possible"
|
||||
tt = self.getTableFromName(listname)
|
||||
target = number + 1
|
||||
t1 = tt.getTool(number).copy()
|
||||
tt.deleteTool(number)
|
||||
if target in tt.Tools.keys():
|
||||
t2 = tt.getTool(target).copy()
|
||||
tt.deleteTool(target)
|
||||
tt.setTool(number, t2)
|
||||
tt.setTool(target, t1)
|
||||
if listname == self.getCurrentTableName():
|
||||
self.saveMainLibrary()
|
||||
return True, target
|
||||
|
||||
def duplicate(self, number, listname):
|
||||
"""duplicates the selected tool in the selected tool table"""
|
||||
tt = self.getTableFromName(listname)
|
||||
tool = tt.getTool(number).copy()
|
||||
tt.addTools(tool)
|
||||
|
||||
newID = list(tt.Tools)[-1]
|
||||
|
||||
if listname == self.getCurrentTableName():
|
||||
self.saveMainLibrary()
|
||||
return True, newID
|
||||
|
||||
def moveToTable(self, number, listname):
|
||||
"""Moves the tool to selected tool table"""
|
||||
fromTable = self.getTableFromName(self.getCurrentTableName())
|
||||
toTable = self.getTableFromName(listname)
|
||||
tool = fromTable.getTool(number).copy()
|
||||
toTable.addTools(tool)
|
||||
fromTable.deleteTool(number)
|
||||
|
||||
def delete(self, number, listname):
|
||||
"""deletes a tool from the current list"""
|
||||
tt = self.getTableFromName(listname)
|
||||
tt.deleteTool(number)
|
||||
if listname == self.getCurrentTableName():
|
||||
self.saveMainLibrary()
|
||||
return True
|
||||
@@ -541,10 +541,6 @@ def guessDepths(objshape, subs=None):
|
||||
def drillTipLength(tool):
|
||||
"""returns the length of the drillbit tip."""
|
||||
|
||||
if isinstance(tool, Path.Tool):
|
||||
Path.Log.error(translate("Path", "Legacy Tools not supported"))
|
||||
return 0.0
|
||||
|
||||
if not hasattr(tool, "TipAngle"):
|
||||
Path.Log.error(translate("Path", "Selected tool is not a drill"))
|
||||
return 0.0
|
||||
|
||||
Reference in New Issue
Block a user