def test00(self): '''Check that isValidBaseObject detects solids.''' box = self.doc.addObject('Part::Box', 'Box') cylinder = self.doc.addObject('Part::Cylinder', 'Cylinder') self.doc.recompute() self.assertTrue(PathUtil.isValidBaseObject(box)) self.assertTrue(PathUtil.isValidBaseObject(cylinder))
def read(self, filename, listname): "imports a tooltable from a file" try: fileExtension = os.path.splitext(filename[0])[1].lower() xmlHandler = None if fileExtension == '.tooltable': xmlHandler = HeeksTooltableHandler() if fileExtension == '.xml': xmlHandler = FreeCADTooltableHandler() if xmlHandler: parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_namespaces, 0) parser.setContentHandler(xmlHandler) parser.parse(PathUtil.toUnicode(filename[0])) if not xmlHandler.tooltable: return None ht = xmlHandler.tooltable else: with open(PathUtil.toUnicode(filename[0]), "rb") as fp: ht = self.tooltableFromAttrs(json.load(fp)) tt = self._findList(listname) for t in ht.Tools: newt = ht.getTool(t).copy() tt.addTools(newt) if listname == "<Main>": self.saveMainLibrary(tt) return True except Exception as e: print("could not parse file", e)
def reject(self, resetEdit=True): '''reject() ... callback invoked when user presses the task panel Cancel button.''' self.preCleanup() FreeCAD.ActiveDocument.abortTransaction() if self.deleteOnReject: FreeCAD.ActiveDocument.openTransaction(translate("Path", "Uncreate AreaOp Operation")) PathUtil.clearExpressionEngine(self.obj) FreeCAD.ActiveDocument.removeObject(self.obj.Name) FreeCAD.ActiveDocument.commitTransaction() self.cleanup(resetEdit) return True
def _traverseTemplateAttributes(attrs, codec): coded = {} for key,value in PathUtil.keyValueIter(attrs): if type(value) == dict: PathLog.debug("%s is a dict" % key) coded[key] = _traverseTemplateAttributes(value, codec) elif type(value) == list: PathLog.debug("%s is a list" % key) coded[key] = [_traverseTemplateAttributes(attr, codec) for attr in value] elif PathUtil.isString(value): PathLog.debug("%s is a string" % key) coded[key] = codec(value) else: PathLog.debug("%s is %s" % (key, type(value))) coded[key] = value return coded
def getTools(self, tablename): '''returns the tool data for a given table''' tooldata = [] tt = self._findList(tablename) headers = ["","Tool Num.","Name","Tool Type","Material","Diameter","Length Offset","Flat Radius","Corner Radius","Cutting Edge Angle","Cutting Edge Height"] model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(headers) def unitconv(ivalue): val = FreeCAD.Units.Quantity(ivalue, FreeCAD.Units.Length) displayed_val = val.UserString #just the displayed value-not the internal one return displayed_val if tt: if len(tt.Tools) == 0: tooldata.append([]) for number, t in PathUtil.keyValueIter(tt.Tools): itemcheck = QtGui.QStandardItem() itemcheck.setCheckable(True) itemNumber = QtGui.QStandardItem(str(number)) itemName = QtGui.QStandardItem(t.Name) itemToolType = QtGui.QStandardItem(t.ToolType) itemMaterial = QtGui.QStandardItem(t.Material) itemDiameter = QtGui.QStandardItem(unitconv(t.Diameter)) itemLengthOffset = QtGui.QStandardItem(unitconv(t.LengthOffset)) itemFlatRadius = QtGui.QStandardItem(unitconv(t.FlatRadius)) itmCornerRadius = QtGui.QStandardItem(unitconv(t.CornerRadius)) itemCuttingEdgeAngle = QtGui.QStandardItem(str(t.CuttingEdgeAngle)) itemCuttingEdgeHeight = QtGui.QStandardItem(unitconv(t.CuttingEdgeHeight)) row = [itemcheck, itemNumber, itemName, itemToolType, itemMaterial, itemDiameter, itemLengthOffset, itemFlatRadius, itmCornerRadius, itemCuttingEdgeAngle, itemCuttingEdgeHeight] model.appendRow(row) return model
def write(self, filename, listname): "exports the tooltable to a file" tt = self._findList(listname) if tt: try: def openFileWithExtension(name, ext): fext = os.path.splitext(name)[1].lower() if fext != ext: name = "{}{}".format(name, ext) return (open(PathUtil.toUnicode(name), 'wb'), name) if filename[1] == self.TooltableTypeXML: fp,fname = openFileWithExtension(filename[0], '.xml') fp.write('<?xml version="1.0" encoding="UTF-8"?>\n') fp.write(tt.Content) elif filename[1] == self.TooltableTypeLinuxCNC: fp,fname = openFileWithExtension(filename[0], '.tbl') for key in tt.Tools: t = tt.Tools[key] fp.write("T{} P{} Y{} Z{} A{} B{} C{} U{} V{} W{} D{} I{} J{} Q{} ;{}\n".format(key,key,0,t.LengthOffset,0,0,0,0,0,0,t.Diameter,0,0,0,t.Name)) else: fp,fname = openFileWithExtension(filename[0], '.json') json.dump(self.templateAttrs(tt), fp, sort_keys=True, indent=2) fp.close() print("Written ", PathUtil.toUnicode(fname)) except Exception as e: print("Could not write file:", e)
def test03(self): '''Check that isValidBaseObject ignores sketches.''' body = self.doc.addObject('PartDesign::Body', 'Body') sketch = self.doc.addObject('Sketcher::SketchObject', 'Sketch') body.addObject(sketch) TestSketcherApp.CreateSlotPlateSet(sketch) self.doc.recompute() pad = self.doc.addObject('PartDesign::Pad', 'Pad') body.addObject(pad) pad.Profile = sketch self.doc.recompute() # the body and the pad are solids self.assertTrue(PathUtil.isValidBaseObject(pad)) self.assertTrue(PathUtil.isValidBaseObject(body)) # however, the sketch is no self.assertFalse(PathUtil.isValidBaseObject(sketch))
def test01(self): '''Check that isValidBaseObject detects PDs.''' body = self.doc.addObject('PartDesign::Body', 'Body') box = self.doc.addObject('PartDesign::AdditiveBox', 'Box') body.addObject(box) self.doc.recompute() self.assertTrue(PathUtil.isValidBaseObject(body))
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) if obj.Stock in solids: # regardless, what stock is/was, it's not a valid choice solids.remove(obj.Stock) return sorted(solids, key=lambda c: c.Label)
def shapeAttrs(self, obj): attrs = {} attrs['version'] = 2 # Path.Tool is version 1 attrs['name'] = obj.Label if PathPreferences.toolsStoreAbsolutePaths(): attrs['shape'] = obj.BitShape else: attrs['shape'] = findRelativePathShape(obj.BitShape) params = {} for name in self.propertyNamesBit(obj): params[name] = PathUtil.getPropertyValueString(obj, name) attrs['parameter'] = params params = {} for name in self.propertyNamesAttribute(obj): params[name] = PathUtil.getPropertyValueString(obj, name) attrs['attribute'] = params return attrs
def operationsWithSettings(self): '''operationsWithSettings() ... returns a list of operations which currently have some settings defined.''' ops = [] for name,value in PathUtil.keyValueIter(_RegisteredOps): for prop in value.registeredPropertyNames(name): if hasattr(self.obj, prop): ops.append(name) break return list(sorted(ops))
def tooltableFromAttrs(self, stringattrs): if stringattrs.get('Version') and 1 == int(stringattrs['Version']): attrs = {} for key, val in PathUtil.keyValueIter(stringattrs['Tools']): attrs[int(key)] = val return Path.Tooltable(attrs) else: PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable template version %s") % stringattrs.get('Version')) return None
def updateSpinBox(self, quantity=None): '''updateSpinBox(quantity=None) ... update the display value of the spin box. If no value is provided the value of the bound property is used. quantity can be of type Quantity or Float.''' if self.valid: if quantity is None: quantity = PathUtil.getProperty(self.obj, self.prop) value = quantity.Value if hasattr(quantity, 'Value') else quantity self.widget.setProperty('rawValue', value)
def updateInputField(obj, prop, widget, onBeforeChange=None): '''updateInputField(obj, prop, widget) ... update obj's property prop with the value of widget. The property's value is only assigned if the new value differs from the current value. This prevents onChanged notifications where the value didn't actually change. Gui::InputField and Gui::QuantitySpinBox widgets are supported - and the property can be of type Quantity or Float. If onBeforeChange is specified it is called before a new value is assigned to the property. Returns True if a new value was assigned, False otherwise (new value is the same as the current). ''' value = FreeCAD.Units.Quantity(widget.text()).Value attr = PathUtil.getProperty(obj, prop) attrValue = attr.Value if hasattr(attr, 'Value') else attr if not PathGeom.isRoughly(attrValue, value): PathLog.debug("updateInputField(%s, %s): %.2f -> %.2f" % (obj.Label, prop, attr, value)) if onBeforeChange: onBeforeChange(obj) PathUtil.setProperty(obj, prop, value) return True return False
def executeUpload(self): '''Post process the current Path.Job and upload the resulting g-code into MK. Tag the uploaded g-code with the job and a hash so we can determine if the uploaded version is consistent with what is currently in FC.''' job = self.job if job: currTool = None postlist = [] for obj in job.Operations.Group: tc = PathUtil.toolControllerForOp(obj) if tc is not None: if tc.ToolNumber != currTool: postlist.append(tc) currTool = tc.ToolNumber postlist.append(obj) post = PathPost.CommandPathPost() fail, gcode = post.exportObjectsWith(postlist, job, False) if not fail: print("POST: ", fail) preamble = "(FreeCAD.Job: %s)\n(FreeCAD.File: %s)\n(FreeCAD.Signature: %d)\n" % ( job.Name, job.Document.FileName, MKUtils.pathSignature(job.Path)) buf = io.BytesIO((preamble + gcode).encode()) endpoint = self.mk.instance.endpoint.get('file') if endpoint: ftp = ftplib.FTP() ftp.connect(endpoint.address(), endpoint.port()) ftp.login() ftp.storbinary("STOR %s" % self.mk.RemoteFilename, buf) ftp.quit() sequence = MKUtils.taskModeMDI(self.mk) for tc in job.ToolController: t = tc.Tool radius = float(t.Diameter) / 2 if hasattr( t, 'Diameter') else 0. offset = t.LengthOffset if hasattr( t, 'LengthOffset') else 0. sequence.append( MKCommandTaskExecute( "G10 L1 P%d R%g Z%g" % (tc.ToolNumber, radius, offset))) sequence.extend(MKUtils.taskModeAuto(self.mk)) sequence.append(MKCommandTaskReset(False)) sequence.extend([ MKCommandOpenFile(self.mk.remoteFilePath(), True), MKCommandOpenFile(self.mk.remoteFilePath(), False) ]) sequence.append(MKCommandTaskRun(True)) self.mk['command'].sendCommands(sequence) else: PathLog.error('No endpoint found') else: PathLog.error('Post processing failed')
def getTools(self, tablename): '''returns the tool data for a given table''' tooldata = [] tableExists = any(table.Name == tablename for table in self.toolTables) if tableExists: self.currentTableName = tablename else: return None tt = self.getTableFromName(tablename) headers = [ "", "Tool Num.", "Name", "Tool Type", "Material", "Diameter", "Length Offset", "Flat Radius", "Corner Radius", "Cutting Edge Angle", "Cutting Edge Height" ] model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(headers) def unitconv(ivalue): val = FreeCAD.Units.Quantity(ivalue, FreeCAD.Units.Length) displayed_val = val.UserString #just the displayed value-not the internal one return displayed_val if tt: if len(tt.Tools) == 0: tooldata.append([]) for number, t in PathUtil.keyValueIter(tt.Tools): itemcheck = QtGui.QStandardItem() itemcheck.setCheckable(True) itemNumber = QtGui.QStandardItem(str(number)) itemName = QtGui.QStandardItem(t.Name) itemToolType = QtGui.QStandardItem(t.ToolType) itemMaterial = QtGui.QStandardItem(t.Material) itemDiameter = QtGui.QStandardItem(unitconv(t.Diameter)) itemLengthOffset = QtGui.QStandardItem(unitconv( t.LengthOffset)) itemFlatRadius = QtGui.QStandardItem(unitconv(t.FlatRadius)) itemCornerRadius = QtGui.QStandardItem(unitconv( t.CornerRadius)) itemCuttingEdgeAngle = QtGui.QStandardItem( str(t.CuttingEdgeAngle)) itemCuttingEdgeHeight = QtGui.QStandardItem( unitconv(t.CuttingEdgeHeight)) row = [ itemcheck, itemNumber, itemName, itemToolType, itemMaterial, itemDiameter, itemLengthOffset, itemFlatRadius, itemCornerRadius, itemCuttingEdgeAngle, itemCuttingEdgeHeight ] model.appendRow(row) return model
def Attach(vobj, name): """Attach(vobj, name) ... attach the appropriate view provider to the view object. If no view provider was registered for the given name a default IconViewProvider is created.""" PathLog.track(vobj.Object.Label, name) global _factory # pylint: disable=global-statement for key, value in PathUtil.keyValueIter(_factory): if key == name: return value(vobj, name) PathLog.track(vobj.Object.Label, name, "PathIconViewProvider") return ViewProvider(vobj, name)
def test03(self): '''Check that isValidBaseObject ignores sketches.''' body = self.doc.addObject('PartDesign::Body', 'Body') sketch = self.doc.addObject('Sketcher::SketchObject', 'Sketch') body.addObject(sketch) TestSketcherApp.CreateSlotPlateSet(sketch) self.doc.recompute() pad = self.doc.addObject('PartDesign::Pad', 'Pad') body.addObject(pad) pad.Profile = sketch self.doc.recompute() # the body is a solid self.assertTrue(PathUtil.isValidBaseObject(body)) # the pad inside the body cannot be used due to the linking constraints self.assertFalse(PathUtil.isValidBaseObject(pad)) # the sketch is no good neither self.assertFalse(PathUtil.isValidBaseObject(sketch))
def Attach(vobj, name): '''Attach(vobj, name) ... attach the appropriate view provider to the view object. If no view provider was registered for the given name a default IconViewProvider is created.''' PathLog.track(vobj.Object.Label, name) global _factory for key,value in PathUtil.keyValueIter(_factory): if key == name: return value(vobj, name) PathLog.track(vobj.Object.Label, name, 'PathIconViewProvider') return ViewProvider(vobj, name)
def __init__(self, obj, form): self.form = form self.obj = obj self.ops = sorted([OpTaskPanel(self.obj, name, op) for name, op in PathUtil.keyValueIter(PathSetupSheet._RegisteredOps)], key = lambda op: op.name) if form: parent = form.tabOpDefaults for op in self.ops: form.opDefaultOp.addItem(op.form.windowTitle(), op) op.form.setParent(parent) parent.layout().addWidget(op.form) op.form.hide() self.currentOp = None
def test04(self): '''Check that Part is handled correctly.''' part = self.doc.addObject('App::Part', 'Part') # an empty part is not a valid base object self.assertFalse(PathUtil.isValidBaseObject(part)) # a none empty part where none of the objects has a shape is no good neither fp = self.doc.addObject('App::FeaturePython', 'Feature') part.addObject(fp) self.assertFalse(PathUtil.isValidBaseObject(part)) # create an valid base object box = self.doc.addObject("Part::Box","Box") self.assertTrue(PathUtil.isValidBaseObject(box)) # a part with at least one valid object is valid part.addObject(box) self.assertTrue(PathUtil.isValidBaseObject(part)) # however, the object itself is no longer valid self.assertFalse(PathUtil.isValidBaseObject(box))
def onDelete(self, obj, arg2=None): '''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: op = obj.Operations.Group[0] if not op.ViewObject or not hasattr(op.ViewObject.Proxy, 'onDelete') or op.ViewObject.Proxy.onDelete(op.ViewObject, ()): PathUtil.clearExpressionEngine(op) doc.removeObject(op.Name) obj.Operations.Group = [] doc.removeObject(obj.Operations.Name) obj.Operations = None # stock could depend on Base 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 # Tool controllers don't depend on anything PathLog.debug('taking down tool controller') for tc in obj.ToolController: PathUtil.clearExpressionEngine(tc) doc.removeObject(tc.Name) obj.ToolController = [] # SetupSheet PathUtil.clearExpressionEngine(obj.SetupSheet) doc.removeObject(obj.SetupSheet.Name) obj.SetupSheet = None return True
def _setupBitShape(self, obj, path=None): PathLog.track(obj.Label) activeDoc = FreeCAD.ActiveDocument (doc, docOpened) = self._loadBitBody(obj, path) obj.Label = doc.RootObjects[0].Label self._deleteBitSetup(obj) bitBody = obj.Document.copyObject(doc.RootObjects[0], True) if docOpened: FreeCAD.setActiveDocument(activeDoc.Name) FreeCAD.closeDocument(doc.Name) if bitBody.ViewObject: bitBody.ViewObject.Visibility = False for sketch in [ o for o in bitBody.Group if o.TypeId == 'Sketcher::SketchObject' ]: for constraint in [c for c in sketch.Constraints if c.Name != '']: typ = ParameterTypeConstraint.get(constraint.Type) PathLog.track(constraint, typ) if typ is not None: parts = [p.strip() for p in constraint.Name.split(';')] prop = parts[0] desc = '' if len(parts) > 1: desc = parts[1] obj.addProperty(typ, prop, PropertyGroupBit, desc) obj.setEditorMode(prop, 1) value = constraint.Value if constraint.Type == 'Angle': value = value * 180 / math.pi PathUtil.setProperty(obj, prop, value) # has to happen last because it could trigger op.execute evaluations obj.BitBody = bitBody self._copyBitShape(obj)
def __init__(self, widget, obj, prop, onBeforeChange=None): self.obj = obj self.widget = widget self.prop = prop self.onBeforeChange = onBeforeChange attr = PathUtil.getProperty(self.obj, self.prop) if attr is not None: if hasattr(attr, 'Value'): widget.setProperty('unit', attr.getUserPreferred()[2]) widget.setProperty('binding', "%s.%s" % (obj.Name, prop)) self.valid = True else: PathLog.warning(translate('PathGui', "Cannot find property %s of %s") % (prop, obj.Label)) self.valid = False
def addBase(self, obj, base, sub): PathLog.track() base = PathUtil.getPublicObject(base) if self._setBaseAndStock(obj): if base == self.job.Proxy.baseObject(self.job): base = self.baseobject baselist = obj.Base if baselist is None: baselist = [] item = (base, sub) if item in baselist: PathLog.notice(translate("Path", "this object already in the list" + "\n")) else: baselist.append(item) obj.Base = baselist
def test02(self): '''Check that isValidBaseObject detects compounds.''' box = self.doc.addObject('Part::Box', 'Box') box.Length = 10 box.Width = 10 box.Height = 1 box.Placement = FreeCAD.Placement(FreeCAD.Vector(-5,-5,0), FreeCAD.Rotation(FreeCAD.Vector(0,0,1), 0)) cyl = self.doc.addObject('Part::Cylinder', 'Cylinder') cyl.Radius = 1 cyl.Height = 10 box.Placement = FreeCAD.Placement(FreeCAD.Vector(0,0,-5), FreeCAD.Rotation(FreeCAD.Vector(0,0,1), 0)) cut = self.doc.addObject('Part::Cut', 'Cut') cut.Base = box cut.Tool = cyl self.doc.recompute() self.assertTrue(PathUtil.isValidBaseObject(cut))
def setDefaultValues(self, obj): '''setDefaultValues(obj) ... base implementation. Do not overwrite, overwrite opSetDefaultValues() instead.''' job = PathUtils.addToJob(obj) obj.Active = True features = self.opFeatures(obj) if FeatureTool & features: if 1 < len(job.Operations.Group): obj.ToolController = PathUtil.toolControllerForOp(job.Operations.Group[-2]) else: obj.ToolController = PathUtils.findToolController(obj) if not obj.ToolController: return None obj.OpToolDiameter = obj.ToolController.Tool.Diameter if FeatureDepths & features: if self.applyExpression(obj, 'StartDepth', job.SetupSheet.StartDepthExpression): obj.OpStartDepth = 1.0 else: obj.StartDepth = 1.0 if self.applyExpression(obj, 'FinalDepth', job.SetupSheet.FinalDepthExpression): obj.OpFinalDepth = 0.0 else: obj.FinalDepth = 0.0 else: obj.StartDepth = 1.0 if FeatureStepDown & features: if not self.applyExpression(obj, 'StepDown', job.SetupSheet.StepDownExpression): obj.StepDown = '1 mm' if FeatureHeights & features: if job.SetupSheet.SafeHeightExpression: if not self.applyExpression(obj, 'SafeHeight', job.SetupSheet.SafeHeightExpression): obj.SafeHeight = '3 mm' if job.SetupSheet.ClearanceHeightExpression: if not self.applyExpression(obj, 'ClearanceHeight', job.SetupSheet.ClearanceHeightExpression): obj.ClearanceHeight = '5 mm' if FeatureStartPoint & features: obj.UseStartPoint = False self.opSetDefaultValues(obj, job) return job
def setFromTemplate(self, attrs): '''setFromTemplate(attrs) ... sets the default values from the given dictionary.''' for name in Template.All: if attrs.get(name) is not None: setattr(self.obj, name, attrs[name]) for opName,op in PathUtil.keyValueIter(_RegisteredOps): opSetting = attrs.get(opName) if opSetting is not None: prototype = op.prototype(opName) for propName in op.properties(): value = opSetting.get(propName) if not value is None: prop = prototype.getProperty(propName) propertyName = OpPropertyName(opName, propName) propertyGroup = OpPropertyGroup(opName) prop.setupProperty(self.obj, propertyName, propertyGroup, prop.valueFromString(value))
def addBase(self, obj, base, sub): PathLog.track(obj, base, sub) base = PathUtil.getPublicObject(base) if self._setBaseAndStock(obj): if base == self.job.Proxy.baseObject(self.job): base = self.baseobject baselist = obj.Base if baselist is None: baselist = [] for p, el in baselist: if p == base and sub in el: PathLog.notice((translate("Path", "Base object %s.%s already in the list")+"\n") % (base.Label, sub)) return baselist.append((base, sub)) obj.Base = baselist
def updateBoneList(self): itemList = [] for loc, (enabled, inaccessible, ids) in PathUtil.keyValueIter(self.obj.Proxy.boneStateList(self.obj)): lbl = '(%.2f, %.2f): %s' % (loc[0], loc[1], ','.join(str(id) for id in ids)) item = QtGui.QListWidgetItem(lbl) if enabled: item.setCheckState(QtCore.Qt.CheckState.Checked) else: item.setCheckState(QtCore.Qt.CheckState.Unchecked) flags = QtCore.Qt.ItemFlag.ItemIsSelectable if not inaccessible: flags |= QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsUserCheckable item.setFlags(flags) item.setData(self.DataIds, ids) item.setData(self.DataKey, ids[0]) itemList.append(item) self.form.bones.clear() for item in sorted(itemList, key=lambda item: item.data(self.DataKey)): self.form.bones.addItem(item)
def Execute(cls, job, path, dialog=None): attrs = job.Proxy.templateAttrs(job) # post processor settings if dialog and not dialog.includePostProcessing(): attrs.pop(PathJob.JobTemplate.PostProcessor, None) attrs.pop(PathJob.JobTemplate.PostProcessorArgs, None) attrs.pop(PathJob.JobTemplate.PostProcessorOutputFile, None) # tool controller settings toolControllers = dialog.includeToolControllers() if dialog else job.ToolController if toolControllers: tcAttrs = [tc.Proxy.templateAttrs(tc) for tc in toolControllers] attrs[PathJob.JobTemplate.ToolController] = tcAttrs # stock settings stockAttrs = None if dialog: if dialog.includeStock(): stockAttrs = PathStock.TemplateAttributes(job.Stock, dialog.includeStockExtent(), dialog.includeStockPlacement()) else: stockAttrs = PathStock.TemplateAttributes(job.Stock) if stockAttrs: attrs[PathJob.JobTemplate.Stock] = stockAttrs # setup sheet setupSheetAttrs = None if dialog: setupSheetAttrs = job.Proxy.setupSheet.templateAttributes(dialog.includeSettingToolRapid(), dialog.includeSettingOperationHeights(), dialog.includeSettingOperationDepths(), dialog.includeSettingOpsSettings()) else: setupSheetAttrs = job.Proxy.setupSheet.templateAttributes(True, True, True) if setupSheetAttrs: attrs[PathJob.JobTemplate.SetupSheet] = setupSheetAttrs encoded = job.Proxy.setupSheet.encodeTemplateAttributes(attrs) # write template with open(PathUtil.toUnicode(path), 'wb') as fp: json.dump(encoded, fp, sort_keys=True, indent=2)
def setFromTemplateFile(self, obj, template): '''setFromTemplateFile(obj, template) ... extract the properties from the given template file and assign to receiver. This will also create any TCs stored in the template.''' tcs = [] if template: with open(PathUtil.toUnicode(template), 'rb') as fp: attrs = json.load(fp) if attrs.get(JobTemplate.Version) and 1 == int(attrs[JobTemplate.Version]): attrs = self.setupSheet.decodeTemplateAttributes(attrs) if attrs.get(JobTemplate.SetupSheet): self.setupSheet.setFromTemplate(attrs[JobTemplate.SetupSheet]) if attrs.get(JobTemplate.GeometryTolerance): obj.GeometryTolerance = float(attrs.get(JobTemplate.GeometryTolerance)) if attrs.get(JobTemplate.PostProcessor): obj.PostProcessor = attrs.get(JobTemplate.PostProcessor) if attrs.get(JobTemplate.PostProcessorArgs): obj.PostProcessorArgs = attrs.get(JobTemplate.PostProcessorArgs) else: obj.PostProcessorArgs = '' if attrs.get(JobTemplate.PostProcessorOutputFile): obj.PostProcessorOutputFile = attrs.get(JobTemplate.PostProcessorOutputFile) if attrs.get(JobTemplate.Description): obj.Description = attrs.get(JobTemplate.Description) if attrs.get(JobTemplate.ToolController): for tc in attrs.get(JobTemplate.ToolController): tcs.append(PathToolController.FromTemplate(tc)) if attrs.get(JobTemplate.Stock): obj.Stock = PathStock.CreateFromTemplate(obj, attrs.get(JobTemplate.Stock)) PathLog.debug("setting tool controllers (%d)" % len(tcs)) obj.ToolController = tcs else: PathLog.error(translate('PathJob', "Unsupported PathJob template version %s") % attrs.get(JobTemplate.Version)) if not tcs: self.addToolController(PathToolController.Create())
def addBase(self, obj, base, sub): PathLog.track(obj, base, sub) base = PathUtil.getPublicObject(base) if self._setBaseAndStock(obj): for model in self.job.Model.Group: if base == self.job.Proxy.baseObject(self.job, model): base = model break baselist = obj.Base if baselist is None: baselist = [] for p, el in baselist: if p == base and sub in el: PathLog.notice((translate("Path", "Base object %s.%s already in the list")+"\n") % (base.Label, sub)) return if not self.opRejectAddBase(obj, base, sub): baselist.append((base, sub)) obj.Base = baselist else: PathLog.notice((translate("Path", "Base object %s.%s rejected by operation")+"\n") % (base.Label, sub))
def onDelete(self, vobj, arg2=None): PathUtil.clearExpressionEngine(vobj.Object) return True
def setupModel(self, job = None): if job: preSelected = Counter([PathUtil.getPublicObject(job.Proxy.baseObject(job, obj)).Label for obj in job.Model.Group]) jobResources = job.Model.Group + [job.Stock] else: preSelected = Counter([obj.Label for obj in FreeCADGui.Selection.getSelection()]) jobResources = [] self.candidates = sorted(PathJob.ObjectJob.baseCandidates(), key=lambda o: o.Label) # If there is only one possibility we might as well make sure it's selected if not preSelected and 1 == len(self.candidates): preSelected = Counter([self.candidates[0].Label]) expandSolids = False expand2Ds = False expandJobs = False 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) item1.setEnabled(True) item1.setEditable(True) if base.Label in preSelected: itemSelected = True item0.setCheckState(QtCore.Qt.CheckState.Checked) item1.setData(preSelected[base.Label], QtCore.Qt.EditRole) else: itemSelected = False item0.setCheckState(QtCore.Qt.CheckState.Unchecked) item1.setData(0, QtCore.Qt.EditRole) if PathUtil.isSolid(base): self.itemsSolid.appendRow([item0, item1]) if itemSelected: expandSolids = True else: self.items2D.appendRow([item0, item1]) if itemSelected: expand2Ds = True for j in sorted(PathJob.Instances(), key=lambda x: x.Label): if j != job: item0 = QtGui.QStandardItem() item1 = QtGui.QStandardItem() item0.setData(j.Label, QtCore.Qt.EditRole) item0.setData(j, self.DataObject) item0.setCheckable(True) item0.setEditable(False) item1.setEnabled(True) item1.setEditable(True) if j.Label in preSelected: expandJobs = True item0.setCheckState(QtCore.Qt.CheckState.Checked) item1.setData(preSelected[j.Label], QtCore.Qt.EditRole) else: item0.setCheckState(QtCore.Qt.CheckState.Unchecked) item1.setData(0, QtCore.Qt.EditRole) self.itemsJob.appendRow([item0, item1]) self.delegate = _ItemDelegate(self, self.dialog.modelTree) 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.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.setItemDelegateForColumn(1, self.delegate) 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.dialog.modelGroup.show()
def baseObjectViewObject(self, obj): return PathUtil.getPublicObject(self.obj.Proxy.baseObject(obj)).ViewObject
def isBaseCandidate(cls, obj): '''Answer true if the given object can be used as a Base for a job.''' return PathUtil.isValidBaseObject(obj) or isArchPanelSheet(obj)
def removeBase(self, obj, base, removeFromModel): if isResourceClone(obj, base, None): PathUtil.clearExpressionEngine(base) if removeFromModel: obj.Model.removeObject(base) obj.Document.removeObject(base.Name)