From 0bc3aee2f589d22a35ee16f47c6d31b8a4493838 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Tue, 13 Nov 2018 18:29:36 -0800 Subject: [PATCH] Enable multiple copies of a model as base object for a job --- .../Path/Gui/Resources/panels/DlgJobCreate.ui | 21 +-- src/Mod/Path/PathScripts/PathJobDlg.py | 169 +++++++++++------- src/Mod/Path/PathScripts/PathJobGui.py | 32 ++-- 3 files changed, 129 insertions(+), 93 deletions(-) diff --git a/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui b/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui index ca922809ff..c8802bb6ac 100644 --- a/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui +++ b/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui @@ -6,7 +6,7 @@ 0 0 - 388 + 532 616 @@ -43,30 +43,13 @@ - + QAbstractItemView::NoEditTriggers true - - QAbstractItemView::MultiSelection - - - 1 - - - false - - - true - - - - 1 - - diff --git a/src/Mod/Path/PathScripts/PathJobDlg.py b/src/Mod/Path/PathScripts/PathJobDlg.py index 6f7016d607..c0f619a5f3 100644 --- a/src/Mod/Path/PathScripts/PathJobDlg.py +++ b/src/Mod/Path/PathScripts/PathJobDlg.py @@ -33,6 +33,7 @@ import glob import os from PySide import QtCore, QtGui +from collections import Counter # Qt tanslation handling def translate(context, text, disambig=None): @@ -49,9 +50,9 @@ class JobCreate: def __init__(self, parent=None, sel=None): self.dialog = FreeCADGui.PySideUic.loadUi(":/panels/DlgJobCreate.ui") - self.itemsSolid = QtGui.QTreeWidgetItem([translate('PathJob', 'Solids')]) - self.itemsTwoD = QtGui.QTreeWidgetItem([translate('PathJob', '2D')]) - self.itemsJob = QtGui.QTreeWidgetItem([translate('PathJob', 'Jobs')]) + self.itemsSolid = QtGui.QStandardItem(translate('PathJob', 'Solids')) + self.items2D = QtGui.QStandardItem(translate('PathJob', '2D')) + self.itemsJob = QtGui.QStandardItem(translate('PathJob', 'Jobs')) self.dialog.templateGroup.hide() self.dialog.modelGroup.hide() @@ -59,72 +60,117 @@ class JobCreate: self.dialog.setWindowTitle(title) def setupModel(self, job = None): + if job: - sel = [PathUtil.getPublicObject(job.Proxy.baseObject(job, obj)) for obj in job.Model.Group] - xxx = job.Model.Group + [job.Stock] + preSelected = Counter([PathUtil.getPublicObject(job.Proxy.baseObject(job, obj)).Label for obj in job.Model.Group]) + jobResources = job.Model.Group + [job.Stock] else: - sel = FreeCADGui.Selection.getSelection() - xxx = [] + preSelected = Counter([obj.Label for obj in FreeCADGui.Selection.getSelection()]) + jobResources = [] - if sel: - selected = [s.Label for s in sel] - else: - selected = [] - - PathLog.track('selected', selected) + self.candidates = sorted(PathJob.ObjectJob.baseCandidates(), key=lambda o: o.Label) expandSolids = False - expandTwoDs = False + expand2Ds = False expandJobs = False - index = 0 - candidates = sorted(PathJob.ObjectJob.baseCandidates(), key=lambda o: o.Label) - for base in candidates: - PathLog.track(base.Label) - if not base in xxx and not PathJob.isResourceClone(job, base, None) and not hasattr(base, 'StockType'): - PathLog.track('base', base.Label) - item = QtGui.QTreeWidgetItem([base.Label]) - item.setData(0, self.DataObject, base) - sel = base.Label in selected - if sel or (1 == len(candidates) and not selected): - item.setCheckState(0, QtCore.Qt.CheckState.Checked) + + for i, base in enumerate(self.candidates): + if not base in jobResources and not PathJob.isResourceClone(job, base, None) and not hasattr(base, 'StockType'): + item0 = QtGui.QStandardItem() + item1 = QtGui.QStandardItem() + + item0.setData(base.Label, QtCore.Qt.EditRole) + item0.setData(base, self.DataObject) + item0.setCheckable(True) + item0.setEditable(False) + + if base.Label in preSelected: + itemSelected = True + item0.setCheckState(QtCore.Qt.CheckState.Checked) + item1.setEnabled(True) + item1.setData(preSelected[base.Label], QtCore.Qt.EditRole) else: - item.setCheckState(0, QtCore.Qt.CheckState.Unchecked) + itemSelected = False + item0.setCheckState(QtCore.Qt.CheckState.Unchecked) + item1.setEnabled(False) + item1.setData(0, QtCore.Qt.EditRole) + if PathUtil.isSolid(base): - self.itemsSolid.addChild(item) - if sel: + self.itemsSolid.appendRow([item0, item1]) + if itemSelected: expandSolids = True else: - self.itemsTwoD.addChild(item) - if sel: - expandTwoDs = True + self.items2D.appendRow([item0, item1]) + if itemSelected: + expand2Ds = True for j in sorted(PathJob.Instances(), key=lambda x: x.Label): if j != job: - item = QtGui.QTreeWidgetItem([j.Label]) - item.setData(0, self.DataObject, j) - if j.Label in selected: - expandJobs = True - item.setCheckState(0, QtCore.Qt.CheckState.Checked) - else: - item.setCheckState(0, QtCore.Qt.CheckState.Unchecked) - self.itemsJob.addChild(item) + item0 = QtGui.QStandardItem() + item1 = QtGui.QStandardItem() - if self.itemsSolid.childCount() > 0: - self.dialog.modelTree.addTopLevelItem(self.itemsSolid) - if expandSolids or not (expandTwoDs or expandJobs): - PathLog.track() - self.itemsSolid.setExpanded(True) + item0.setData(j.Label, QtCore.Qt.EditRole) + item0.setData(j, self.DataObject) + + item0.setCheckable(True) + item0.setEditable(False) + + if j.Label in preSelected: + expandJobs = True + item0.setCheckState(QtCore.Qt.CheckState.Checked) + item1.setEnabled(True) + item1.setData(preSelected[j.Label], QtCore.Qt.EditRole) + else: + item0.setCheckState(QtCore.Qt.CheckState.Unchecked) + item1.setEnabled(False) + item1.setData(0, QtCore.Qt.EditRole) + + self.itemsJob.appendRow([item0, item1]) + + self.model = QtGui.QStandardItemModel(self.dialog) + self.model.setHorizontalHeaderLabels(['Model', 'Count']) + + + if self.itemsSolid.hasChildren(): + self.model.appendRow(self.itemsSolid) + if expandSolids or not (expand2Ds or expandJobs): expandSolids = True - if self.itemsTwoD.childCount() > 0: - self.dialog.modelTree.addTopLevelItem(self.itemsTwoD) - if expandTwoDs: - self.itemsTwoD.setExpanded(True) - if self.itemsJob.childCount() > 0: - self.dialog.modelTree.addTopLevelItem(self.itemsJob) - if expandJobs: - self.itemsJob.setExpanded(True) + if self.items2D.hasChildren(): + self.model.appendRow(self.items2D) + if self.itemsJob.hasChildren(): + self.model.appendRow(self.itemsJob) + + self.dialog.modelTree.setModel(self.model) + self.dialog.modelTree.expandAll() + self.dialog.modelTree.resizeColumnToContents(0) + self.dialog.modelTree.resizeColumnToContents(1) + self.dialog.modelTree.collapseAll() + + if expandSolids: + self.dialog.modelTree.setExpanded(self.itemsSolid.index(), True) + if expand2Ds: + self.dialog.modelTree.setExpanded(self.items2D.index(), True) + if expandJobs: + self.dialog.modelTree.setExpanded(self.itemsJob.index(), True) + + self.dialog.modelTree.setEditTriggers(QtGui.QAbstractItemView.AllEditTriggers) + self.dialog.modelTree.setSelectionBehavior(QtGui.QAbstractItemView.SelectItems) + + self.model.dataChanged.connect(self.updateData) self.dialog.modelGroup.show() + def updateData(self, topLeft, bottomRight): + if topLeft.column() == bottomRight.column() == 0: + item0 = self.model.itemFromIndex(topLeft) + item1 = self.model.itemFromIndex(topLeft.sibling(topLeft.row(), 1)) + if item0.checkState() == QtCore.Qt.Checked: + item1.setEnabled(True) + item1.setEditable(True) + item1.setData(1, QtCore.Qt.EditRole) + else: + item1.setEnabled(False) + item1.setEditable(False) + item1.setData(0, QtCore.Qt.EditRole) def setupTemplate(self): templateFiles = [] @@ -159,23 +205,22 @@ class JobCreate: return glob.glob(path + '/job_*.json') def getModels(self): - '''answer the base models selected for the job''' models = [] - for i in range(self.itemsSolid.childCount()): - if self.itemsSolid.child(i).checkState(0) == QtCore.Qt.CheckState.Checked: - models.append(self.itemsSolid.child(i).data(0, self.DataObject)) + for i in range(self.itemsSolid.rowCount()): + for j in range(self.itemsSolid.child(i, 1).data(QtCore.Qt.EditRole)): + models.append(self.itemsSolid.child(i).data(self.DataObject)) - for i in range(self.itemsTwoD.childCount()): - if self.itemsTwoD.child(i).checkState(0) == QtCore.Qt.CheckState.Checked: - models.append(self.itemsTwoD.child(i).data(0, self.DataObject)) + for i in range(self.items2D.rowCount()): + for j in range(self.items2D.child(i, 1).data(QtCore.Qt.EditRole)): + models.append(self.items2D.child(i).data(self.DataObject)) - for i in range(self.itemsJob.childCount()): - if self.itemsJob.child(i).checkState(0) == QtCore.Qt.CheckState.Checked: + for i in range(self.itemsJob.rowCount()): + for j in range(self.itemsJob.child(i, 1).data(QtCore.Qt.EditRole)): # Note that we do want to use the models (resource clones) of the # source job as base objects for the new job in order to get the # identical placement, and anything else that's been customized. - models.extend(self.itemsJob.child(i).data(0, self.DataObject).Model.Group) + models.extend(self.itemsJob.child(i, 0).data(self.DataObject).Model.Group) return models diff --git a/src/Mod/Path/PathScripts/PathJobGui.py b/src/Mod/Path/PathScripts/PathJobGui.py index 588d697a72..5619b764b8 100644 --- a/src/Mod/Path/PathScripts/PathJobGui.py +++ b/src/Mod/Path/PathScripts/PathJobGui.py @@ -45,6 +45,7 @@ import sys import traceback from PySide import QtCore, QtGui +from collections import Counter from contextlib import contextmanager from pivy import coin @@ -1072,23 +1073,30 @@ class TaskPanel: obj = self.obj proxy = obj.Proxy - # first remove all retired base models - retired = [base for base in self.obj.Model.Group if not proxy.baseObject(obj, base) in models] - for base in retired: - self.vproxy.forgetBaseVisibility(obj, base) - self.obj.Proxy.removeBase(obj, base, True) + want = Counter(models) + have = Counter([proxy.baseObject(obj, o) for o in obj.Model.Group]) + + obsolete = have - want + additions = want - have + + # first remove all obsolete base models + for model, count in PathUtil.keyValueIter(obsolete): + for i in range(count): + # it seems natural to remove the last of all the base objects for a given model + base = [b for b in obj.Model.Group if proxy.baseObject(obj, b) == model][-1] + self.vproxy.forgetBaseVisibility(obj, base) + self.obj.Proxy.removeBase(obj, base, True) # do not access any of the retired objects after this point, they don't exist anymore # then add all rookie base models - baseOrigNames = [proxy.baseObject(obj, base).Name for base in obj.Model.Group] - rookies = [base for base in models if not base.Name in baseOrigNames] - for orig in rookies: - base = PathJob.createModelResourceClone(obj, orig) - obj.Model.addObject(base) - self.vproxy.rememberBaseVisibility(obj, base) + for model, count in PathUtil.keyValueIter(additions): + for i in range(count): + base = PathJob.createModelResourceClone(obj, model) + obj.Model.addObject(base) + self.vproxy.rememberBaseVisibility(obj, base) # refresh the view - if retired or rookies: + if obsolete or additions: self.setFields() else: PathLog.track('no changes to model')