Basic workflow. No editing

concept dock work
most functions working.
made linuxcnc export work
Fixed some defaults on new install
fixed display label in dock
This commit is contained in:
sliptonic
2020-10-06 17:50:29 -05:00
parent 55e3aad3c7
commit b556aa47de
10 changed files with 1047 additions and 848 deletions

View File

@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * *
# * Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
# * *
# * This program is free software; you can redistribute it and/or modify *
@@ -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,6 +147,7 @@ def searchPathsPost():
paths.append(pathScriptsSourcePath())
return paths
def searchPathsTool(sub='Bit'):
paths = []
@@ -148,30 +168,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 +207,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 +222,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)

View File

@@ -45,16 +45,17 @@ __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):
@@ -83,20 +84,27 @@ 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):
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 +116,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 +140,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 +155,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 +204,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 +220,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:
@@ -286,7 +306,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
@@ -315,12 +335,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 +353,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,20 +361,33 @@ class ToolBit(object):
attrs['attribute'] = params
return attrs
def Declaration(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'))
class ToolBitFactory(object):
@@ -372,23 +405,24 @@ class ToolBitFactory(object):
proto = AttributePrototype()
uservals = {}
for pname in params:
#print(f"pname: {pname}")
# print(f"pname: {pname}")
try:
prop = proto.getProperty(pname)
val = prop.valueFromString(params[pname])
# val = prop.valueFromString(params[pname])
prop.setupProperty(obj, pname, PropertyGroupAttribute, prop.valueFromString(params[pname]))
except:
except Exception:
# prop = obj.addProperty('App::PropertyString', pname, "Attribute", translate('PathTooolBit', 'User Defined Value'))
# setattr(obj, pname, params[pname])
prop = proto.getProperty("UserAttributes")
uservals.update({pname: params[pname]})
#prop.setupProperty(obj, pname, "UserAttributes", prop.valueFromString(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]))
# 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()

View File

@@ -45,13 +45,15 @@ class ToolBitEditor(object):
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, ondone=None):
self.form = FreeCADGui.PySideUic.loadUi(":/panels/ToolBitEditor.ui")
if parentWidget:
self.form.setParent(parentWidget)
parentWidget.layout().addWidget(self.form)
self.ondone = ondone
self.tool = tool
if not tool.BitShape:
self.tool.BitShape = 'endmill.fcstd'
@@ -210,6 +212,9 @@ class ToolBitEditor(object):
self.form.shapePath.setText(foo[0])
self.updateShape()
def ok(self):
self.form.close()
def setupUI(self):
PathLog.track()
self.updateUI()
@@ -217,3 +222,8 @@ class ToolBitEditor(object):
self.form.toolName.editingFinished.connect(self.refresh)
self.form.shapePath.editingFinished.connect(self.updateShape)
self.form.shapeSet.clicked.connect(self.selectShape)
self.form.buttonBox.accepted.connect(self.ok)
self.form.buttonBox.rejected.connect(self.ok)
if self.ondone is not None:
self.form.buttonBox.rejected.connect(self.ondone)

View File

@@ -280,6 +280,23 @@ def GetToolFiles(parent = None):
return foo[0]
return []
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.'''

View File

@@ -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,40 @@ class CommandToolBitLibraryOpen:
def GetResources(self):
return {'Pixmap': 'Path-ToolTable',
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Open ToolBit Library editor"),
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "ToolBit Dock"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathToolBitLibrary", "Toggle the Toolbit Dock"),
'Accel': "P, T"}
def IsActive(self):
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")}
def IsActive(self):
return True
return FreeCAD.ActiveDocument is not None
def Activated(self):
import PathScripts.PathToolBitLibraryGui as PathToolBitLibraryGui
@@ -52,55 +82,56 @@ 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")

View File

@@ -35,12 +35,13 @@ from PySide import QtCore, QtGui
import PySide
import json
import os
import glob
import traceback
import uuid as UUID
from functools import partial
# PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
# PathLog.trackModule(PathLog.thisModule())
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
_UuidRole = PySide.QtCore.Qt.UserRole + 1
_PathRole = PySide.QtCore.Qt.UserRole + 2
@@ -55,11 +56,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 +69,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 +109,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 +121,378 @@ 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']:
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']))
def _toolAdd(self, nr, tool, path):
strShape = os.path.splitext(os.path.basename(tool['shape']))[0]
strDiam = tool['parameter']['Diameter']
tooltip = "{}: {}".format(strShape, strDiam)
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)
toolDiameter = PySide.QtGui.QStandardItem()
toolDiameter.setData(strDiam, PySide.QtCore.Qt.EditRole)
toolDiameter.setEditable(False)
return [toolNr, toolName, toolShape, toolDiameter]
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:
PathLog.error(traceback.print_exc())
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 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 = os.path.split(PathPreferences.lastFileToolLibrary())[1]
libName = os.path.splitext(libfile)[0]
return libName
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)
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.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
def selectedOrAllToolControllers(self):
tools = self.selectedOrAllTools()
filename = PathToolBitGui.GetNewToolFile()
if filename == None:
return
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()
# 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)
f = PathToolBit.ToolBitFactory()
newtool = f.Create(name=fname)
newtool.BitShape = shapefile
newtool.Label = fname
newtool.Proxy.saveToFile(newtool, fullpath)
# 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 toolEdit(self, selected):
item = self.toolModel.item(selected.row(), 0)
if selected.column() == 0: # editing Nr
pass
else:
tbpath = item.data(_PathRole)
# Clear view
self.form.TableList.clear()
self.LibFiles.clear()
self.form.lineLibPath.clear()
self.form.lineLibPath.insert(path)
temptool = PathToolBit.ToolBitFactory().CreateFrom(tbpath, 'temptool')
self.editor = PathToolBitEdit.ToolBitEditor(temptool,
self.form.toolTableGroup, ondone=self.toolEditDone)
# Find all tool tables in directory
for file in glob.glob(path + '/*.fctl'):
self.LibFiles.append(file)
QBtn = QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel
self.LibFiles.sort()
buttonBox = QtGui.QDialogButtonBox(QBtn)
# self.buttonBox.accepted.connect(self.accept)
# self.buttonBox.rejected.connect(self.reject)
# 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)
layout = self.editor.form.layout() #QVBoxLayout()
layout.addWidget(buttonBox)
#self.setLayout(self.layout)
self.path = []
self.form.ButtonRemoveToolTable.setEnabled(False)
self.form.ButtonRenameToolTable.setEnabled(False)
self.toolTableView.setUpdatesEnabled(False)
self.model.clear()
self.model.setHorizontalHeaderLabels(self.columnNames())
self.toolTableView.resizeColumnsToContents()
self.toolTableView.setUpdatesEnabled(True)
# 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
# Load selected table
self.libraryLoad(self.LibFiles[idx])
self.form.TableList.setCurrentRow(idx)
self.form.ButtonRemoveToolTable.setEnabled(True)
self.form.ButtonRenameToolTable.setEnabled(True)
def libraryLoad(self, path):
self.toolTableView.setUpdatesEnabled(False)
self.model.clear()
self.model.setHorizontalHeaderLabels(self.columnNames())
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 +501,112 @@ 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()
#loc = os.path.split(lib)[0]
PathLog.track("lib: {} loc: {}".format(lib, loc))
return lib, loc
def columnNames(self):
return ['Nr', 'Tool', 'Shape', 'Diameter']
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 +629,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()))