From d78d65628a3efd7568198ef3804e63071a146362 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Tue, 28 Aug 2018 20:54:36 -0700 Subject: [PATCH] Basic job creation dialog with multiple base models. --- src/Mod/Path/Gui/Resources/Path.qrc | 2 +- .../Path/Gui/Resources/panels/DlgJobCreate.ui | 82 +++-- .../Gui/Resources/panels/DlgJobModelSelect.ui | 101 ++++++ src/Mod/Path/Gui/Resources/panels/JobEdit.ui | 316 ------------------ src/Mod/Path/PathScripts/PathJob.py | 80 +++-- src/Mod/Path/PathScripts/PathJobCmd.py | 44 ++- src/Mod/Path/PathScripts/PathJobGui.py | 116 ++++--- src/Mod/Path/PathScripts/PathStock.py | 20 +- 8 files changed, 314 insertions(+), 447 deletions(-) create mode 100644 src/Mod/Path/Gui/Resources/panels/DlgJobModelSelect.ui delete mode 100644 src/Mod/Path/Gui/Resources/panels/JobEdit.ui diff --git a/src/Mod/Path/Gui/Resources/Path.qrc b/src/Mod/Path/Gui/Resources/Path.qrc index 11b4b791c5..98b0f03bbd 100644 --- a/src/Mod/Path/Gui/Resources/Path.qrc +++ b/src/Mod/Path/Gui/Resources/Path.qrc @@ -67,6 +67,7 @@ icons/preferences-path.svg panels/DlgJobChooser.ui panels/DlgJobCreate.ui + panels/DlgJobModelSelect.ui panels/DlgJobTemplateExport.ui panels/DlgSelectPostProcessor.ui panels/DlgToolControllerEdit.ui @@ -75,7 +76,6 @@ panels/DlgTCChooser.ui panels/DogboneEdit.ui panels/HoldingTagsEdit.ui - panels/JobEdit.ui panels/PageBaseGeometryEdit.ui panels/PageBaseHoleGeometryEdit.ui panels/PageBaseLocationEdit.ui diff --git a/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui b/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui index 62b84a8eca..818ea2cb83 100644 --- a/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui +++ b/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui @@ -6,44 +6,82 @@ 0 0 - 365 - 147 + 388 + 616 - Dialog + Create Job - - - - true - - - <html><head/><body><p>Select a template to be used for the job.</p><p>In case there are no templates you can create one through the popup menu of an existing job. Name the file job_*.json and place it in the macro or the path directory (see preferences) in order to be selectable from this list.</p></body></html> - - - - - - Base Model + + + Template + + + + + true + + + <html><head/><body><p>Select a template to be used for the job.</p><p>In case there are no templates you can create one through the popup menu of an existing job. Name the file job_*.json and place it in the macro or the path directory (see preferences) in order to be selectable from this list.</p></body></html> + + + + - - - Template + + + Model + + + + + 0 + + + + Solids + + + + + + + + + + 2D + + + + + + + + + + Base Models + + + + + + + + + + - - - diff --git a/src/Mod/Path/Gui/Resources/panels/DlgJobModelSelect.ui b/src/Mod/Path/Gui/Resources/panels/DlgJobModelSelect.ui new file mode 100644 index 0000000000..e5a1313a3a --- /dev/null +++ b/src/Mod/Path/Gui/Resources/panels/DlgJobModelSelect.ui @@ -0,0 +1,101 @@ + + + Dialog + + + + 0 + 0 + 383 + 786 + + + + Select Base Models + + + + + + 0 + + + + Solids + + + + + + + + + + 2D + + + + + + + + + + Base Models + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/Mod/Path/Gui/Resources/panels/JobEdit.ui b/src/Mod/Path/Gui/Resources/panels/JobEdit.ui deleted file mode 100644 index 39d1da0204..0000000000 --- a/src/Mod/Path/Gui/Resources/panels/JobEdit.ui +++ /dev/null @@ -1,316 +0,0 @@ - - - frmCNCJob - - - - 0 - 0 - 396 - 517 - - - - - 0 - 0 - - - - - 0 - 400 - - - - CNC Job - - - - - - - 0 - 0 - - - - 0 - - - - - 0 - 0 - 363 - 443 - - - - - :/icons/Path-OperationB.svg:/icons/Path-OperationB.svg - - - General - - - - - - - 0 - 0 - - - - - - - Job Type - - - - - - - label - - - - - - - - Milling - - - - - - - - - - - Base Object - - - - - - - Create Linked Clone - - - - - - - Reorder operations by dragging them to their correct location - - - true - - - - - - - - 0 - 0 - - - - true - - - QAbstractItemView::InternalMove - - - Qt::MoveAction - - - - - - - - - - - - - - - 0 - 0 - 353 - 173 - - - - - :/icons/Path-Stock.svg:/icons/Path-Stock.svg - - - Stock - - - - - - - - - Use Part Bounding Box - - - true - - - - - - - false - - - - Create from Part Bounding Box - - - - - - - - Material - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - 0 - 0 - 378 - 391 - - - - - :/icons/Path-Post.svg:/icons/Path-Post.svg - - - Post Processing - - - - - - - - - Output File - - - - - - - - 0 - 0 - - - - ... - - - - - - - - 0 - 0 - - - - <html><head/><body><p>Enter a path and optional file name (see below) to be used as the default for the post processor export.</p><p>The following substitutions are performed before the name is resolved at the time of the post processing:</p><p>%D ... directory of the active document<br/>%d ... name of the active document (with extension)<br/>%M ... user macro directory<br/>%j ... name of the active Job object</p><p>The following example stores all files with the same name as the document in the directory /home/freecad (please remove quotes):</p><p>&quot;/home/cnc/%d.g-code&quot;</p><p>See the file save policy below on how to deal with name conflicts.</p></body></html> - - - - - - - - - - Post Processor - - - - - - - - - - Post Processor Arguments - - - - - - - <html><head/><body><p>Optional arguments passed to the Post Processor. The arguments are specific for each Post Processor, please see its documentation for details.</p></body></html> - - - - - - - Qt::Vertical - - - - 13 - 290 - - - - - - - - - - - - - - - diff --git a/src/Mod/Path/PathScripts/PathJob.py b/src/Mod/Path/PathScripts/PathJob.py index cb407e0f54..482b3f41d9 100644 --- a/src/Mod/Path/PathScripts/PathJob.py +++ b/src/Mod/Path/PathScripts/PathJob.py @@ -65,12 +65,9 @@ class JobTemplate: def isArchPanelSheet(obj): return hasattr(obj, 'Proxy') and isinstance(obj.Proxy, ArchPanel.PanelSheet) -def isResourceClone(obj, propName, resourceName=None): - '''isResourceClone(obj, propName, resourceName) ... Return True if the given property of obj is a clone of type resourceName.''' - if hasattr(obj, propName): - propLink = getattr(obj, propName) - if hasattr(propLink, 'PathResource') and ((resourceName and resourceName == propLink.PathResource) or (resourceName is None and propName == propLink.PathResource)): - return True +def isResourceClone(obj, propLink, resourceName): + if hasattr(propLink, 'PathResource') and resourceName == propLink.PathResource: + return True return False def createResourceClone(obj, orig, name, icon): @@ -90,16 +87,16 @@ def createResourceClone(obj, orig, name, icon): class ObjectJob: - def __init__(self, obj, base, templateFile = None): + def __init__(self, obj, models, templateFile = None): self.obj = obj - obj.addProperty("App::PropertyFile", "PostProcessorOutputFile", "Output", QtCore.QT_TRANSLATE_NOOP("App::Property","The NC output file for this project")) - obj.addProperty("App::PropertyEnumeration", "PostProcessor", "Output", QtCore.QT_TRANSLATE_NOOP("App::Property","Select the Post Processor")) - obj.addProperty("App::PropertyString", "PostProcessorArgs", "Output", QtCore.QT_TRANSLATE_NOOP("App::Property", "Arguments for the Post Processor (specific to the script)")) + obj.addProperty("App::PropertyFile", "PostProcessorOutputFile", "Output", QtCore.QT_TRANSLATE_NOOP("PathJob","The NC output file for this project")) + obj.addProperty("App::PropertyEnumeration", "PostProcessor", "Output", QtCore.QT_TRANSLATE_NOOP("PathJob","Select the Post Processor")) + obj.addProperty("App::PropertyString", "PostProcessorArgs", "Output", QtCore.QT_TRANSLATE_NOOP("PathJob", "Arguments for the Post Processor (specific to the script)")) - obj.addProperty("App::PropertyString", "Description", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property","An optional description for this job")) - obj.addProperty("App::PropertyDistance", "GeometryTolerance", "Geometry", QtCore.QT_TRANSLATE_NOOP("App::Property", "For computing Paths; smaller increases accuracy, but slows down computation")) + obj.addProperty("App::PropertyString", "Description", "Path", QtCore.QT_TRANSLATE_NOOP("PathJob","An optional description for this job")) + obj.addProperty("App::PropertyDistance", "GeometryTolerance", "Geometry", QtCore.QT_TRANSLATE_NOOP("PathJob", "For computing Paths; smaller increases accuracy, but slows down computation")) - obj.addProperty("App::PropertyLink", "Base", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "The base object for all operations")) + obj.addProperty("App::PropertyLink", "Model", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "The base objects for all operations")) obj.addProperty("App::PropertyLink", "Stock", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "Solid object to be used as stock.")) obj.addProperty("App::PropertyLink", "Operations", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "Compound path of all operations in the order they are processed.")) obj.addProperty("App::PropertyLinkList", "ToolController", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "Collection of tool controllers available for this job.")) @@ -120,13 +117,19 @@ class ObjectJob: if ops.ViewObject: ops.ViewObject.Proxy = 0 ops.ViewObject.Visibility = False + obj.Operations = ops obj.setEditorMode('Operations', 2) # hide obj.setEditorMode('Placement', 2) self.setupSetupSheet(obj) - obj.Base = createResourceClone(obj, base, 'Base', 'BaseGeometry') + model = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", "Model") + if model.ViewObject: + model.ViewObject.Visibility = False + model.addObjects([createResourceClone(obj, base, 'Model', 'BaseGeometry') for base in models]) + obj.Model = model + obj.Proxy = self self.setFromTemplateFile(obj, templateFile) @@ -151,6 +154,7 @@ class ObjectJob: '''Called by the view provider, there doesn't seem to be a callback on the obj itself.''' PathLog.track(obj.Label, arg2) doc = obj.Document + # the first to tear down are the ops, they depend on other resources PathLog.debug('taking down ops: %s' % [o.Name for o in self.allOperations()]) while obj.Operations.Group: @@ -161,19 +165,24 @@ class ObjectJob: obj.Operations.Group = [] doc.removeObject(obj.Operations.Name) obj.Operations = None - # stock could depend on Base + + # stock could depend on Model, so delete it first if obj.Stock: PathLog.debug('taking down stock') PathUtil.clearExpressionEngine(obj.Stock) doc.removeObject(obj.Stock.Name) obj.Stock = None + # base doesn't depend on anything inside job - if obj.Base: - PathLog.debug('taking down base') - if isResourceClone(obj, 'Base'): - PathUtil.clearExpressionEngine(obj.Base) - doc.removeObject(obj.Base.Name) - obj.Base = None + for base in obj.Model.Group: + PathLog.debug("taking down base " % base.Label) + if isResourceClone(obj, base, 'Model'): + PathUtil.clearExpressionEngine(base) + doc.removeObject(base.Name) + obj.Model.Group = [] + doc.removeObject(obj.Model.Name) + obj.Model = None + # Tool controllers don't depend on anything PathLog.debug('taking down tool controller') for tc in obj.ToolController: @@ -187,10 +196,11 @@ class ObjectJob: return True def fixupResourceClone(self, obj, name, icon): - if not isResourceClone(obj, name, name) and not isArchPanelSheet(obj): - orig = getattr(obj, name) - if orig: - setattr(obj, name, createResourceClone(obj, orig, name, icon)) + #if not isResourceClone(obj, name) and not isArchPanelSheet(obj): + # orig = getattr(obj, name) + # if orig: + # setattr(obj, name, createResourceClone(obj, orig, name, icon)) + pass def fixupOperations(self, obj): if obj.Operations.ViewObject: @@ -221,11 +231,15 @@ class ObjectJob: self.tooltip = processor.tooltip self.tooltipArgs = processor.tooltipArgs - def baseObject(self, obj): + def baseObject(self, obj, base): '''Return the base object, not its clone.''' - if isResourceClone(obj, 'Base', 'Base'): - return obj.Base.Objects[0] - return obj.Base + if isResourceClone(obj, base, 'Model'): + return base.Objects[0] + return base + + def baseObjects(self, obj): + '''Return the base objects, not their clones.''' + return [self.baseObject(obj, base) for base in obj.Model.Group] def setFromTemplateFile(self, obj, template): '''setFromTemplateFile(obj, template) ... extract the properties from the given template file and assign to receiver. @@ -351,7 +365,13 @@ def Instances(): def Create(name, base, templateFile = None): '''Create(name, base, templateFile=None) ... creates a new job and all it's resources. If a template file is specified the new job is initialized with the values from the template.''' + if str == type(base[0]): + models = [] + for baseName in base: + models.append(FreeCAD.ActiveDocument.getObject(baseName)) + else: + models = base obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) - proxy = ObjectJob(obj, base, templateFile) + proxy = ObjectJob(obj, models, templateFile) return obj diff --git a/src/Mod/Path/PathScripts/PathJobCmd.py b/src/Mod/Path/PathScripts/PathJobCmd.py index 77b4e07886..7cb6c8f0c3 100644 --- a/src/Mod/Path/PathScripts/PathJobCmd.py +++ b/src/Mod/Path/PathScripts/PathJobCmd.py @@ -40,20 +40,27 @@ def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) class DlgJobCreate: + DataObject = QtCore.Qt.ItemDataRole.UserRole def __init__(self, parent=None): self.dialog = FreeCADGui.PySideUic.loadUi(":/panels/DlgJobCreate.ui") + self.items = [] + sel = FreeCADGui.Selection.getSelection() if sel: - selected = sel[0].Label + selected = [s.Label for s in sel] else: selected = None index = 0 - for base in PathJob.ObjectJob.baseCandidates(): - if base.Label == selected: - index = self.dialog.cbModel.count() - self.dialog.cbModel.addItem(base.Label) - self.dialog.cbModel.setCurrentIndex(index) + for base in sorted(PathJob.ObjectJob.baseCandidates(), key=lambda o: o.Label): + item = QtGui.QListWidgetItem(base.Label) + item.setData(self.DataObject, base) + item.setCheckState(QtCore.Qt.CheckState.Checked if base.Label in selected else QtCore.Qt.CheckState.Unchecked) + if PathUtil.isSolid(base): + self.dialog.solidList.addItem(item) + else: + self.dialog.twoDList.addItem(item) + self.items.append(item) templateFiles = [] for path in PathPreferences.searchPaths(): @@ -72,12 +79,12 @@ class DlgJobCreate: template[name] = tFile selectTemplate = PathPreferences.defaultJobTemplate() index = 0 - self.dialog.cbTemplate.addItem('', '') + self.dialog.jobTemplate.addItem('', '') for name in sorted(template.keys()): if template[name] == selectTemplate: - index = self.dialog.cbTemplate.count() - self.dialog.cbTemplate.addItem(name, template[name]) - self.dialog.cbTemplate.setCurrentIndex(index) + index = self.dialog.jobTemplate.count() + self.dialog.jobTemplate.addItem(name, template[name]) + self.dialog.jobTemplate.setCurrentIndex(index) def templateFilesIn(self, path): '''templateFilesIn(path) ... answer all file in the given directory which fit the job template naming convention. @@ -85,14 +92,13 @@ class DlgJobCreate: PathLog.track(path) return glob.glob(path + '/job_*.json') - def getModel(self): - '''answer the base model selected for the job''' - label = self.dialog.cbModel.currentText() - return filter(lambda obj: obj.Label == label, FreeCAD.ActiveDocument.Objects)[0] + def getModels(self): + '''answer the base models selected for the job''' + return [item.data(self.DataObject) for item in self.items if item.checkState() == QtCore.Qt.CheckState.Checked] def getTemplate(self): '''answer the file name of the template to be assigned''' - return self.dialog.cbTemplate.itemData(self.dialog.cbTemplate.currentIndex()) + return self.dialog.jobTemplate.itemData(self.dialog.jobTemplate.currentIndex()) def exec_(self): return self.dialog.exec_() @@ -116,8 +122,10 @@ class CommandJobCreate: def Activated(self): dialog = DlgJobCreate() if dialog.exec_() == 1: - self.Execute(dialog.getModel(), dialog.getTemplate()) - FreeCAD.ActiveDocument.recompute() + models = dialog.getModels() + if models: + self.Execute(models, dialog.getTemplate()) + FreeCAD.ActiveDocument.recompute() @classmethod def Execute(cls, base, template): @@ -126,7 +134,7 @@ class CommandJobCreate: template = "'%s'" % template else: template = 'None' - FreeCADGui.doCommand('PathScripts.PathJobGui.Create(App.ActiveDocument.%s, %s)' % (base.Name, template)) + FreeCADGui.doCommand('PathScripts.PathJobGui.Create(%s, %s)' % ([o.Name for o in base], template)) class DlgJobTemplateExport: diff --git a/src/Mod/Path/PathScripts/PathJobGui.py b/src/Mod/Path/PathScripts/PathJobGui.py index d209f6da95..b0ba1e49e0 100644 --- a/src/Mod/Path/PathScripts/PathJobGui.py +++ b/src/Mod/Path/PathScripts/PathJobGui.py @@ -139,8 +139,8 @@ class ViewProvider: def editObject(self, obj): if obj: - if obj == self.obj.Base: - return self.openTaskPanel('Base') + if obj in self.obj.Model.Group: + return self.openTaskPanel('Model') if obj == self.obj.Stock: return self.openTaskPanel('Stock') PathLog.info("Expected a specific object to edit - %s not recognized" % obj.Label) @@ -155,8 +155,7 @@ class ViewProvider: def claimChildren(self): children = self.obj.ToolController children.append(self.obj.Operations) - if self.obj.Base: - children.append(self.obj.Base) + children.append(self.obj.Model) if self.obj.Stock: children.append(self.obj.Stock) if hasattr(self.obj, 'SetupSheet'): @@ -172,44 +171,65 @@ class ViewProvider: def updateData(self, obj, prop): PathLog.track(obj.Label, prop) # make sure the resource view providers are setup properly - if prop == 'Base' and self.obj.Base and self.obj.Base.ViewObject and self.obj.Base.ViewObject.Proxy: - if not PathJob.isArchPanelSheet(self.obj.Base): - self.obj.Base.ViewObject.Proxy.onEdit(_OpenCloseResourceEditor) + if prop == 'Model': + for base in self.obj.Model.Group: + if base.ViewObject and base.ViewObject.Proxy and not PathJob.isArchPanelSheet(base): + base.ViewObject.Proxy.onEdit(_OpenCloseResourceEditor) if prop == 'Stock' and self.obj.Stock and self.obj.Stock.ViewObject and self.obj.Stock.ViewObject.Proxy: self.obj.Stock.ViewObject.Proxy.onEdit(_OpenCloseResourceEditor) def baseObjectViewObject(self, obj): - return PathUtil.getPublicObject(self.obj.Proxy.baseObject(obj)).ViewObject + return [PathUtil.getPublicObject(base).ViewObject for base in self.obj.Proxy.baseObjects(obj)] def baseObjectSaveVisibility(self, obj): baseVO = self.baseObjectViewObject(self.obj) - if baseVO: - self.baseOrigVisibility = baseVO.Visibility - baseVO.Visibility = False - if obj.Base and obj.Base.ViewObject: - obj.Base.ViewObject.Visibility = True + baseOrigVisibility = [] + for vo in baseVO: + baseOrigVisibility = vo.Visibility + vo.Visibility = False + self.baseOrigVisibility = baseOrigVisibility + + for base in obj.Model.Group: + if base.ViewObject: + base.ViewObject.Visibility = True def baseObjectRestoreVisibility(self, obj): baseVO = self.baseObjectViewObject(self.obj) - if baseVO: - baseVO.Visibility = self.baseOrigVisibility + if self.baseOrigVisibility: + for vo, visibility in zip(baseVO, self.baseOrigVisibility): + vo.Visibility = visibility + else: + for vo in baseVO: + vo.Visibility = False + + def setupModelVisibility(self, obj): + baseVisibility = [] + origVisibility = [] + for base in obj.Model.Group: + if base.ViewObject: + orig = PathUtil.getPublicObject(obj.Proxy.baseObject(obj, base)) + PathLog.track(obj.Label, base.Label, orig.Label) + origVisibility.append(orig.ViewObject.Visibility) + orig.ViewObject.Visibility = False + baseVisibility.append(base.ViewObject.Visibility) + base.ViewObject.Visibility = True + self.baseVisibility = baseVisibility + self.baseOrigVisibility = origVisibility + def setupEditVisibility(self, obj): - self.baseVisibility = False - self.baseOrigVisibility = False - if obj.Base and obj.Base.ViewObject: - self.baseVisibility = obj.Base.ViewObject.Visibility - self.baseObjectSaveVisibility(obj) - + self.setupModelVisibility(obj) self.stockVisibility = False if obj.Stock and obj.Stock.ViewObject: self.stockVisibility = obj.Stock.ViewObject.Visibility self.obj.Stock.ViewObject.Visibility = True def resetEditVisibility(self, obj): - if obj.Base and obj.Base.ViewObject: - obj.Base.ViewObject.Visibility = self.baseVisibility - self.baseObjectRestoreVisibility(obj) + for base, baseVisibility, origVisibility in zip(obj.Model.Group, self.baseVisibility, self.baseOrigVisibility): + if base.ViewObject: + orig = PathUtil.getPublicObject(obj.Proxy.baseObject(obj, base)) + base.ViewObject.Visibility = baseVisibility + orig.ViewObject.Visibility = origVisibility if obj.Stock and obj.Stock.ViewObject: obj.Stock.ViewObject.Visibility = self.stockVisibility @@ -422,8 +442,9 @@ class StockFromExistingEdit(StockEdit): def candidates(self, obj): solids = [o for o in obj.Document.Objects if PathUtil.isSolid(o)] - if obj.Base in solids and PathJob.isResourceClone(obj, 'Base'): - solids.remove(obj.Base) + for base in obj.Model.Group: + if base in solids and PathJob.isResourceClone(obj, base, 'Model'): + solids.remove(base) if obj.Stock in solids: # regardless, what stock is/was, it's not a valid choice solids.remove(obj.Stock) @@ -474,12 +495,8 @@ class TaskPanel: self.obj.PostProcessor = postProcessors self.obj.PostProcessor = currentPostProcessor - base = self.obj.Base if PathJob.isResourceClone(self.obj, 'Base') else None - stock = self.obj.Stock - for o in PathJob.ObjectJob.baseCandidates(): - if o != base and o != stock: - self.form.jobModel.addItem(o.Label, o) - self.selectComboBoxText(self.form.jobModel, self.obj.Proxy.baseObject(self.obj).Label) + for base in self.obj.Model.Group: + self.form.jobModel.addItem(base.Label) self.postProcessorDefaultTooltip = self.form.postProcessor.toolTip() self.postProcessorArgsDefaultTooltip = self.form.postProcessorArguments.toolTip() @@ -554,13 +571,13 @@ class TaskPanel: self.obj.Description = str(self.form.jobDescription.toPlainText()) self.obj.Operations.Group = [self.form.operationsList.item(i).data(self.DataObject) for i in range(self.form.operationsList.count())] - selObj = self.form.jobModel.itemData(self.form.jobModel.currentIndex()) - if self.obj.Proxy.baseObject(self.obj) != selObj: - self.vproxy.baseObjectRestoreVisibility(self.obj) - if PathJob.isResourceClone(self.obj, 'Base'): - self.obj.Document.removeObject(self.obj.Base.Name) - self.obj.Base = PathJob.createResourceClone(self.obj, selObj, 'Base', 'Base') - self.vproxy.baseObjectSaveVisibility(self.obj) + #selObj = self.form.jobModel.itemData(self.form.jobModel.currentIndex()) + #if self.obj.Proxy.baseObject(self.obj) != selObj: + # self.vproxy.baseObjectRestoreVisibility(self.obj) + # if PathJob.isResourceClone(self.obj, 'Model'): + # self.obj.Document.removeObject(self.obj.Base.Name) + # self.obj.Base = PathJob.createResourceClone(self.obj, selObj, 'Base', 'Base') + # self.vproxy.baseObjectSaveVisibility(self.obj) self.updateTooltips() self.stockEdit.getFields(self.obj) @@ -654,14 +671,9 @@ class TaskPanel: item.setData(self.DataObject, child) self.form.operationsList.addItem(item) - baseindex = -1 - if self.obj.Base: - baseindex = self.form.jobModel.findText(self.obj.Base.Label, QtCore.Qt.MatchFixedString) - else: - for o in FreeCADGui.Selection.getCompleteSelection(): - baseindex = self.form.jobModel.findText(o.Label, QtCore.Qt.MatchFixedString) - if baseindex >= 0: - self.form.jobModel.setCurrentIndex(baseindex) + self.form.jobModel.clear() + for base in self.obj.Model.Group: + self.form.jobModel.addItem(base.Label) self.updateToolController() self.stockEdit.setFields(self.obj) @@ -955,14 +967,10 @@ class TaskPanel: self.form.setOrigin.setEnabled(False) self.form.moveToOrigin.setEnabled(False) - if len(sel) == 1 and sel[0].Object == self.obj.Base: + if len(sel) == 1 and sel[0].Object in self.obj.Model.Group: self.form.centerInStock.setEnabled(True) self.form.centerInStockXY.setEnabled(True) else: - if len(sel) == 1 and self.obj.Base: - PathLog.debug("sel = %s / %s" % (sel[0].Object.Label, self.obj.Base.Label)) - else: - PathLog.debug("sel len = %d" % len(sel)) self.form.centerInStock.setEnabled(False) self.form.centerInStockXY.setEnabled(False) @@ -983,7 +991,7 @@ class TaskPanel: # Info self.form.jobLabel.editingFinished.connect(self.getFields) - self.form.jobModel.currentIndexChanged.connect(self.getFields) + #self.form.jobModelEdit.clicked.connect(self.jobModelEdit) # Post Processor self.form.postProcessor.currentIndexChanged.connect(self.getFields) @@ -1071,7 +1079,7 @@ def Create(base, template=None): obj.ViewObject.Proxy.editObject(obj.Stock) return obj except Exception as exc: - PathLog.error(sys.exc_info()) + PathLog.error(exc) traceback.print_exc(exc) FreeCAD.ActiveDocument.abortTransaction() diff --git a/src/Mod/Path/PathScripts/PathStock.py b/src/Mod/Path/PathScripts/PathStock.py index 3b661421ed..8e3c84f9cf 100644 --- a/src/Mod/Path/PathScripts/PathStock.py +++ b/src/Mod/Path/PathScripts/PathStock.py @@ -66,6 +66,13 @@ class StockType: return cls.Unknown def shapeBoundBox(obj): + PathLog.track(type(obj)) + if list == type(obj) and obj: + bb = FreeCAD.BoundBox() + for o in obj: + bb.add(shapeBoundBox(o)) + return bb + if hasattr(obj, 'Shape'): return obj.Shape.BoundBox if obj and 'App::Part' == obj.TypeId: @@ -115,7 +122,8 @@ class StockFromBase(Stock): return None def execute(self, obj): - bb = shapeBoundBox(obj.Base) + bb = shapeBoundBox(obj.Base.Group) + PathLog.track(obj.Label, bb) # Sometimes, when the Base changes it's temporarily not assigned when # Stock.execute is triggered - it'll be set correctly the next time around. @@ -212,7 +220,7 @@ def SetupStockObject(obj, stockType): obj.ViewObject.DisplayMode = 'Wireframe' def CreateFromBase(job, neg=None, pos=None, placement=None): - base = job.Base if job and hasattr(job, 'Base') else None + base = job.Model if job and hasattr(job, 'Model') else None if base: base.Shape.tessellate(0.1) obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Stock') @@ -237,7 +245,7 @@ def CreateFromBase(job, neg=None, pos=None, placement=None): return obj def CreateBox(job, extent=None, placement=None): - base = job.Base if job and hasattr(job, 'Base') else None + base = job.Model.Group if job else None if base: base.Shape.tessellate(0.1) obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Stock') @@ -262,10 +270,10 @@ def CreateBox(job, extent=None, placement=None): return obj def CreateCylinder(job, radius=None, height=None, placement=None): - base = job.Base if job and hasattr(job, 'Base') else None - if base: - base.Shape.tessellate(0.1) + base = job.Model.Group if job else None obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Stock') + if base: + base.Shape.tessellate(0.1) obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Stock') proxy = StockCreateCylinder(obj) if radius: