Added library commands and drag&drop for rearranging and copying of tools
This commit is contained in:
@@ -56,15 +56,23 @@ ParameterTypeConstraint = {
|
||||
}
|
||||
|
||||
|
||||
def _findTool(path, typ):
|
||||
def _findTool(path, typ, dbg=False):
|
||||
if os.path.exists(path):
|
||||
if dbg:
|
||||
PathLog.debug("Found {} at {}".format(typ, path))
|
||||
return path
|
||||
|
||||
def searchFor(pname, fname):
|
||||
if dbg:
|
||||
PathLog.debug("Looking for {}".format(pname))
|
||||
if fname:
|
||||
for p in PathPreferences.searchPathsTool(typ):
|
||||
f = os.path.join(p, fname)
|
||||
if dbg:
|
||||
PathLog.debug(" Checking {}".format(f))
|
||||
if os.path.exists(f):
|
||||
if dbg:
|
||||
PathLog.debug(" Found {} at {}".format(typ, f))
|
||||
return f
|
||||
if pname and '/' != pname:
|
||||
ppname, pfname = os.path.split(pname)
|
||||
@@ -78,6 +86,16 @@ def findTemplate(path):
|
||||
'''findTemplate(path) ... search for path, full and partially in all known template directories.'''
|
||||
return _findTool(path, 'Template')
|
||||
|
||||
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 updateConstraint(sketch, name, value):
|
||||
for i, constraint in enumerate(sketch.Constraints):
|
||||
if constraint.Name.split(';')[0] == name:
|
||||
|
||||
@@ -25,93 +25,266 @@
|
||||
|
||||
import FreeCADGui
|
||||
import PathScripts.PathLog as PathLog
|
||||
import PathScripts.PathPreferences as PathPreferences
|
||||
import PathScripts.PathToolBit as PathToolBit
|
||||
import PathScripts.PathToolBitGui as PathToolBitGui
|
||||
import PySide
|
||||
|
||||
import json
|
||||
import os
|
||||
import traceback
|
||||
import uuid
|
||||
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
|
||||
PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
class Delegate(PySide.QtGui.QStyledItemDelegate):
|
||||
_UuidRole = PySide.QtCore.Qt.UserRole + 1
|
||||
_PathRole = PySide.QtCore.Qt.UserRole + 2
|
||||
|
||||
def createEditor(self, parent, option, index):
|
||||
PathLog.track(index)
|
||||
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.setSortingEnabled(True)
|
||||
self.setSelectionBehavior(PySide.QtGui.QAbstractItemView.SelectRows)
|
||||
self.verticalHeader().hide()
|
||||
|
||||
def supportedDropActions(self):
|
||||
return [PySide.QtCore.Qt.CopyAction, PySide.QtCore.Qt.MoveAction]
|
||||
|
||||
def _uuidOfRow(self, row):
|
||||
model = self.model()
|
||||
return model.data(model.index(row, 0), _UuidRole)
|
||||
|
||||
def _rowWithUuid(self, uuid):
|
||||
model = self.model()
|
||||
for row in range(model.rowCount()):
|
||||
if self._uuidOfRow(row) == uuid:
|
||||
return row
|
||||
return None
|
||||
def setEditorData(self, widget, index):
|
||||
PathLog.track(index)
|
||||
def setModelData(self, widget, model, index):
|
||||
PathLog.track(index)
|
||||
def updateEditorGeometry(self, widget, option, index):
|
||||
PathLog.track(index)
|
||||
widget.setGeometry(option.rect)
|
||||
|
||||
def _copyTool(self, uuid_, dstRow):
|
||||
model = self.model()
|
||||
items = []
|
||||
model.insertRow(dstRow)
|
||||
srcRow = self._rowWithUuid(uuid_)
|
||||
for col in range(model.columnCount()):
|
||||
srcItem = model.item(srcRow, col)
|
||||
|
||||
model.setData(model.index(dstRow, col), srcItem.data(PySide.QtCore.Qt.EditRole), PySide.QtCore.Qt.EditRole)
|
||||
if col == 0:
|
||||
model.setData(model.index(dstRow, col), srcItem.data(_PathRole), _PathRole)
|
||||
model.setData(model.index(dstRow, col), uuid.uuid4(), _UuidRole)
|
||||
else:
|
||||
model.item(dstRow, col).setEditable(False)
|
||||
|
||||
def _copyTools(self, uuids, dst):
|
||||
for i, uuid in enumerate(uuids):
|
||||
self._copyTool(uuid, dst + i)
|
||||
|
||||
def dropEvent(self, event):
|
||||
PathLog.track()
|
||||
mime = event.mimeData()
|
||||
data = mime.data('application/x-qstandarditemmodeldatalist')
|
||||
stream = PySide.QtCore.QDataStream(data)
|
||||
srcRows = []
|
||||
while not stream.atEnd():
|
||||
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()
|
||||
srcUuids = [self._uuidOfRow(row) for row in set(srcRows)]
|
||||
destRow = self.rowAt(event.pos().y())
|
||||
|
||||
self._copyTools(srcUuids, destRow)
|
||||
if PySide.QtCore.Qt.DropAction.MoveAction == event.proposedAction():
|
||||
for uuid in srcUuids:
|
||||
model.removeRow(self._rowWithUuid(uuid))
|
||||
|
||||
#class ToolTableModel(PySide.QtGui.QStandardItemModel):
|
||||
|
||||
|
||||
class ToolBitLibrary(object):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, path=None):
|
||||
self.path = path
|
||||
self.form = FreeCADGui.PySideUic.loadUi(':/panels/ToolBitLibraryEdit.ui')
|
||||
#self.form = FreeCADGui.PySideUic.loadUi('src/Mod/Path/Gui/Resources/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()
|
||||
if path:
|
||||
self.libraryLoad(path)
|
||||
|
||||
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)
|
||||
|
||||
toolTemplate = PySide.QtGui.QStandardItem()
|
||||
toolTemplate.setData(os.path.splitext(os.path.basename(tool['template']))[0], PySide.QtCore.Qt.EditRole)
|
||||
toolTemplate.setEditable(False)
|
||||
|
||||
toolDiameter = PySide.QtGui.QStandardItem()
|
||||
toolDiameter.setData(tool['parameter']['Diameter'], PySide.QtCore.Qt.EditRole)
|
||||
toolDiameter.setEditable(False)
|
||||
|
||||
self.model.appendRow([toolNr, toolName, toolTemplate, toolDiameter])
|
||||
|
||||
def toolAdd(self):
|
||||
PathLog.track()
|
||||
try:
|
||||
foo = PathToolBitGui.GetToolFile(self.form)
|
||||
if foo:
|
||||
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)
|
||||
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)
|
||||
|
||||
toolNr = PySide.QtGui.QStandardItem()
|
||||
toolNr.setData(nr + 1, PySide.QtCore.Qt.EditRole)
|
||||
|
||||
toolName = PySide.QtGui.QStandardItem()
|
||||
toolName.setData(tool['name'], PySide.QtCore.Qt.EditRole)
|
||||
toolName.setEditable(False)
|
||||
|
||||
toolTemplate = PySide.QtGui.QStandardItem()
|
||||
toolTemplate.setData(os.path.splitext(os.path.basename(tool['template']))[0], PySide.QtCore.Qt.EditRole)
|
||||
toolTemplate.setEditable(False)
|
||||
|
||||
toolDiameter = PySide.QtGui.QStandardItem()
|
||||
toolDiameter.setData(tool['parameter']['Diameter'], PySide.QtCore.Qt.EditRole)
|
||||
toolDiameter.setEditable(False)
|
||||
|
||||
self.model.appendRow([toolNr, toolName, toolTemplate, toolDiameter])
|
||||
|
||||
self.form.toolTable.resizeColumnsToContents()
|
||||
else:
|
||||
PathLog.info("no tool")
|
||||
self._toolAdd(nr + i, tool, foo)
|
||||
self.toolTableView.resizeColumnsToContents()
|
||||
except:
|
||||
PathLog.error('something happened')
|
||||
PathLog.error(traceback.print_exc())
|
||||
|
||||
def toolDelete(self):
|
||||
PathLog.track()
|
||||
def toolUp(self):
|
||||
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 toolEnumerate(self):
|
||||
PathLog.track()
|
||||
def toolDown(self):
|
||||
for row in range(self.model.rowCount()):
|
||||
self.model.setData(self.model.index(row, 0), row + 1, PySide.QtCore.Qt.EditRole)
|
||||
|
||||
def toolSelect(self, selected, deselected):
|
||||
self.form.toolDelete.setEnabled(len(self.toolTableView.selectedIndexes()) > 0)
|
||||
|
||||
def open(self, path=None):
|
||||
if path:
|
||||
fullPath = PathToolBit.findLibrary(path)
|
||||
if fullPath:
|
||||
self.libraryLoad(fullPath)
|
||||
else:
|
||||
self.libraryOpen()
|
||||
return self.form.exec_()
|
||||
|
||||
def updateToolbar(self):
|
||||
if self.path:
|
||||
self.form.librarySave.setEnabled(True)
|
||||
else:
|
||||
self.form.librarySave.setEnabled(False)
|
||||
|
||||
def libraryOpen(self):
|
||||
PathLog.track()
|
||||
foo = PySide.QtGui.QFileDialog.getOpenFileName(self.form, 'Tool Library', PathPreferences.lastPathToolLibrary(), '*.fctl')
|
||||
if foo and foo[0]:
|
||||
path = foo[0]
|
||||
PathPreferences.setLastPathToolLibrary(os.path.dirname(path))
|
||||
self.libraryLoad(path)
|
||||
|
||||
def libraryLoad(self, path):
|
||||
self.toolTableView.setUpdatesEnabled(False)
|
||||
self.model.clear()
|
||||
if path:
|
||||
with open(path) as fp:
|
||||
library = json.load(fp)
|
||||
for nr in library['tools']:
|
||||
bit = PathToolBit.findBit(library['tools'][nr])
|
||||
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 libraryNew(self):
|
||||
self.libraryLoad(None)
|
||||
|
||||
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)
|
||||
tools[toolNr] = toolPath
|
||||
|
||||
with open(self.path, 'w') as fp:
|
||||
json.dump(library, fp, sort_keys=True, indent=2)
|
||||
|
||||
def librarySaveAs(self):
|
||||
foo = PySide.QtGui.QFileDialog.getSaveFileName(self.form, 'Tool Library', PathPreferences.lastPathToolLibrary(), '*.fctl')
|
||||
if foo and foo[0]:
|
||||
path = foo[0] if foo[0].endswith('.fctl') else "{}.fctl".format(foo[0])
|
||||
PathPreferences.setLastPathToolLibrary(os.path.dirname(path))
|
||||
self.path = path
|
||||
self.librarySave()
|
||||
self.updateToolbar()
|
||||
|
||||
def columnNames(self):
|
||||
return ['Nr', 'Tool', 'Template', 'Diameter']
|
||||
|
||||
def rowsMoved(self, parent, start, end, dest, row):
|
||||
PathLog.track(parent, start, end, dest, row)
|
||||
|
||||
def rowsAboutToBeMoved(self, srcParent, srcStart, srcEnd, destParent, destRow):
|
||||
PathLog.track(srcParent, srcStart, srcEnd, destParent, destRow)
|
||||
|
||||
def setupUI(self):
|
||||
PathLog.track('+')
|
||||
self.delegate = Delegate(self.form)
|
||||
self.model = PySide.QtGui.QStandardItemModel(0, len(self.columnNames()), self.form)
|
||||
self.model = PySide.QtGui.QStandardItemModel(0, len(self.columnNames()), self.toolTableView)
|
||||
self.model.setHorizontalHeaderLabels(self.columnNames())
|
||||
self.model.rowsAboutToBeMoved.connect(self.rowsAboutToBeMoved)
|
||||
self.model.rowsMoved.connect(self.rowsMoved)
|
||||
|
||||
self.form.toolTable.setModel(self.model)
|
||||
self.form.toolTable.resizeColumnsToContents()
|
||||
self.toolTableView.setModel(self.model)
|
||||
self.toolTableView.resizeColumnsToContents()
|
||||
self.toolTableView.selectionModel().selectionChanged.connect(self.toolSelect)
|
||||
|
||||
self.form.toolAdd.clicked.connect(self.toolAdd)
|
||||
self.form.toolDelete.clicked.connect(self.toolDelete)
|
||||
self.form.toolUp.clicked.connect(self.toolUp)
|
||||
self.form.toolDown.clicked.connect(self.toolDown)
|
||||
self.form.toolEnumerate.clicked.connect(self.toolEnumerate)
|
||||
|
||||
self.form.libraryNew.clicked.connect(self.libraryNew)
|
||||
self.form.libraryOpen.clicked.connect(self.libraryOpen)
|
||||
self.form.librarySave.clicked.connect(self.librarySave)
|
||||
self.form.librarySaveAs.clicked.connect(self.librarySaveAs)
|
||||
|
||||
self.toolSelect([], [])
|
||||
self.updateToolbar()
|
||||
PathLog.track('-')
|
||||
|
||||
Reference in New Issue
Block a user