diff --git a/src/Mod/Path/App/ToolPy.xml b/src/Mod/Path/App/ToolPy.xml index 059e7fc6ff..647c7aeb3a 100644 --- a/src/Mod/Path/App/ToolPy.xml +++ b/src/Mod/Path/App/ToolPy.xml @@ -86,6 +86,11 @@ HighCarbonToolSteel CastAlloy, Ceramics, Diamond, Sialon or Undefined returns a copy of this tool + + + fills receiver with values from the template string + + diff --git a/src/Mod/Path/App/Tooltable.cpp b/src/Mod/Path/App/Tooltable.cpp index c61f816bcd..6efe81b682 100644 --- a/src/Mod/Path/App/Tooltable.cpp +++ b/src/Mod/Path/App/Tooltable.cpp @@ -133,14 +133,15 @@ void Tool::Restore(XMLReader &reader) { reader.readElement("Tool"); Name = reader.getAttribute("name"); - Diameter = (double) reader.getAttributeAsFloat("diameter"); - LengthOffset = (double) reader.getAttributeAsFloat("length"); - FlatRadius = (double) reader.getAttributeAsFloat("flat"); - CornerRadius = (double) reader.getAttributeAsFloat("corner"); - CuttingEdgeAngle = (double) reader.getAttributeAsFloat("angle"); - CuttingEdgeHeight = (double) reader.getAttributeAsFloat("height"); - - std::string type = reader.getAttribute("type"); + Diameter = reader.hasAttribute("diameter") ? (double) reader.getAttributeAsFloat("diameter") : 0.0; + LengthOffset = reader.hasAttribute("length") ? (double) reader.getAttributeAsFloat("length") : 0.0; + FlatRadius = reader.hasAttribute("flat") ? (double) reader.getAttributeAsFloat("flat") : 0.0; + CornerRadius = reader.hasAttribute("corner") ? (double) reader.getAttributeAsFloat("corner") : 0.0; + CuttingEdgeAngle = reader.hasAttribute("angle") ? (double) reader.getAttributeAsFloat("angle") : 0.0; + CuttingEdgeHeight = reader.hasAttribute("height") ? (double) reader.getAttributeAsFloat("height") : 0.0; + std::string type = reader.hasAttribute("type") ? reader.getAttribute("type") : ""; + std::string mat = reader.hasAttribute("mat") ? reader.getAttribute("mat") : ""; + if(type=="EndMill") Type = Tool::ENDMILL; else if(type=="Drill") @@ -168,7 +169,6 @@ void Tool::Restore(XMLReader &reader) else Type = Tool::UNDEFINED; - std::string mat = reader.getAttribute("mat"); if(mat=="Carbide") Material = Tool::CARBIDE; else if(mat=="HighSpeedSteel") diff --git a/src/Mod/Path/App/TooltablePyImp.cpp b/src/Mod/Path/App/TooltablePyImp.cpp index abae1958e4..f0ad0c55be 100644 --- a/src/Mod/Path/App/TooltablePyImp.cpp +++ b/src/Mod/Path/App/TooltablePyImp.cpp @@ -22,7 +22,7 @@ #include "PreCompiled.h" - +#include "Base/Reader.h" #include "Mod/Path/App/Tooltable.h" // inclusion of the generated files (generated out of ToolPy.xml and TooltablePy.xml) @@ -328,6 +328,22 @@ PyObject* ToolPy::copy(PyObject * args) } +PyObject* ToolPy::fromTemplate(PyObject * args) +{ + PyObject *pcObj; + if (PyArg_ParseTuple(args, "S", &pcObj)) { + if (PyString_Check(pcObj)) { + // embed actual string in dummy tag so XMLReader can consume that on construction + std::ostringstream os; + os << "" << PyString_AsString(pcObj) << ""; + std::istringstream is(os.str()); + Base::XMLReader reader("", is); + getToolPtr()->Restore(reader); + Py_Return ; + } + } + throw Py::Exception("only string argument accepted."); +} // TooltablePy diff --git a/src/Mod/Path/Gui/Resources/Path.qrc b/src/Mod/Path/Gui/Resources/Path.qrc index 8c65d9a9ae..599bce0ae0 100644 --- a/src/Mod/Path/Gui/Resources/Path.qrc +++ b/src/Mod/Path/Gui/Resources/Path.qrc @@ -52,6 +52,7 @@ icons/preferences-path.svg panels/ContourEdit.ui panels/DlgJobChooser.ui + panels/DlgJobCreate.ui panels/DlgSelectPostProcessor.ui panels/DlgToolCopy.ui panels/DlgTCChooser.ui diff --git a/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui b/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui new file mode 100644 index 0000000000..98d69bc8a9 --- /dev/null +++ b/src/Mod/Path/Gui/Resources/panels/DlgJobCreate.ui @@ -0,0 +1,120 @@ + + + Dialog + + + + 0 + 0 + 400 + 208 + + + + Dialog + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Base Model + + + + + + + + + + Template + + + + + + + true + + + + + + + + + Job.xml + + + + + + + + Stock + + + + + + + false + + + + coming soon + + + + + + + + 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/PathScripts/PathJob.py b/src/Mod/Path/PathScripts/PathJob.py index c6862478ec..e13ca9cef7 100644 --- a/src/Mod/Path/PathScripts/PathJob.py +++ b/src/Mod/Path/PathScripts/PathJob.py @@ -26,8 +26,9 @@ import Draft import FreeCAD import Path import PathScripts.PathLog as PathLog -import sys +import PathScripts.PathToolController as PathToolController import lxml.etree as xml +import sys from PySide import QtCore, QtGui from PathScripts.PathPostProcessor import PostProcessor @@ -52,7 +53,8 @@ def translate(context, text, disambig=None): class ObjectPathJob: - def __init__(self, obj): + def __init__(self, obj, base): + self.obj = obj obj.addProperty("App::PropertyFile", "PostProcessorOutputFile", "Output", QtCore.QT_TRANSLATE_NOOP("App::Property","The NC output file for this project")) obj.PostProcessorOutputFile = PathPreferences.defaultOutputFile() obj.setEditorMode("PostProcessorOutputFile", 0) # set to default mode @@ -74,12 +76,20 @@ class ObjectPathJob: obj.GeometryTolerance = PathPreferences.defaultGeometryTolerance() obj.addProperty("App::PropertyLink", "Base", "Base", "The base object for all operations") + obj.Base = base obj.Proxy = self if FreeCAD.GuiUp: ViewProviderJob(obj.ViewObject) + def assignTemplate(self, template): + if template: + tree = xml.parse(template) + for tc in tree.getroot().iter('ToolController'): + PathToolController.CommandPathToolController.FromTemplate(self.obj, tc) + else: + PathToolController.CommandPathToolController.Create(self.obj.Name) def __getstate__(self): return None @@ -96,16 +106,6 @@ class ObjectPathJob: self.tooltip = processor.tooltip self.tooltipArgs = processor.tooltipArgs - # def getToolControllers(self, obj): - # '''returns a list of ToolControllers for the current job''' - # controllers = [] - # for o in obj.Group: - # if "Proxy" in o.PropertiesList: - # if isinstance(o.Proxy, PathToolController.ToolController): - # controllers.append (o.Name) - # return controllers - - def execute(self, obj): cmds = [] for child in obj.Group: @@ -162,6 +162,7 @@ class ViewProviderJob: class TaskPanel: def __init__(self, obj, deleteOnReject): + PathLog.error("Edit Job") FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Edit Job")) self.obj = obj self.deleteOnReject = deleteOnReject @@ -196,6 +197,7 @@ class TaskPanel: FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.abortTransaction() if self.deleteOnReject: + PathLog.error("Uncreate Job") FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Uncreate Job")) for child in self.obj.Group: FreeCAD.ActiveDocument.removeObject(child.Name) @@ -295,6 +297,32 @@ class TaskPanel: self.setFields() +class DlgJobCreate: + + def __init__(self, parent=None): + self.dialog = FreeCADGui.PySideUic.loadUi(":/panels/DlgJobCreate.ui") + sel = FreeCADGui.Selection.getSelection() + if sel: + selected = sel[0].Label + else: + selected = None + index = 0 + for solid in sorted(filter(lambda obj: hasattr(obj, 'Shape') and obj.Shape.isClosed(), FreeCAD.ActiveDocument.Objects), key=lambda o: o.Label): + if solid.Label == selected: + index = self.dialog.cbModel.count() + self.dialog.cbModel.addItem(solid.Label) + self.dialog.cbModel.setCurrentIndex(index) + + def getModel(self): + label = self.dialog.cbModel.currentText() + return filter(lambda obj: obj.Label == label, FreeCAD.ActiveDocument.Objects)[0] + + def getTemplate(self): + return self.dialog.cbTemplate.currentText() + + def exec_(self): + return self.dialog.exec_() + class CommandJobCreate: def GetResources(self): @@ -307,22 +335,17 @@ class CommandJobCreate: return FreeCAD.ActiveDocument is not None def Activated(self): - self.Create() - FreeCAD.ActiveDocument.recompute() + dialog = DlgJobCreate() + if dialog.exec_() == 1: + self.Create(dialog.getModel(), dialog.getTemplate()) + FreeCAD.ActiveDocument.recompute() @classmethod - def Execute(cls): - FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Create Job")) + def Create(cls, base, template): FreeCADGui.addModule('PathScripts.PathUtils') - FreeCADGui.addModule('PathScripts.PathToolController') - snippet = ''' -import PathScripts.PathToolController as PathToolController -obj = FreeCAD.ActiveDocument.addObject("Path::FeatureCompoundPython", "Job") -PathScripts.PathJob.ObjectPathJob(obj) -PathToolController.CommandPathToolController.Create(obj.Name) -obj.ViewObject.Proxy.deleteOnReject = True -obj.ViewObject.startEditing() -''' + FreeCADGui.addModule('PathScripts.PathJob') + FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Create Job")) + snippet = 'PathScripts.PathJob.ObjectPathJob(FreeCAD.ActiveDocument.addObject("Path::FeatureCompoundPython", "Job"), FreeCAD.ActiveDocument.%s).assignTemplate("%s")' % (base.Name, template) FreeCADGui.doCommand(snippet) FreeCAD.ActiveDocument.commitTransaction() @@ -344,12 +367,13 @@ class CommandJobExportTemplate: @classmethod def Execute(cls, job): + PathLog.error("Export Job template") FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Export Job template")) root = xml.Element('PathJobConfiguration') for obj in job.Group: if hasattr(obj, 'Tool') and hasattr(obj, 'SpindleDir'): - tc = xml.SubElement(root, 'ToolController', {'Label': obj.Label}) attrs = {} + attrs['label'] = ("%s" % (obj.Label)) attrs['nr'] = ("%d" % (obj.ToolNumber)) attrs['vfeed'] = ("%s" % (obj.VertFeed)) attrs['hfeed'] = ("%s" % (obj.HorizFeed)) @@ -358,15 +382,12 @@ class CommandJobExportTemplate: attrs['speed'] = ("%f" % (obj.SpindleSpeed)) attrs['dir'] = ("%s" % (obj.SpindleDir)) - xml.SubElement(tc, 'Controller', attrs) + tc = xml.SubElement(root, 'ToolController', attrs) tc.append(xml.fromstring(obj.Tool.Content)) - xml.ElementTree(root).write("./%s.xml" % job.Label, pretty_print=True) + xml.ElementTree(root).write("./%s.xml" % job.Label, pretty_print=True) FreeCAD.ActiveDocument.commitTransaction() - - - if FreeCAD.GuiUp: # register the FreeCAD command FreeCADGui.addCommand('Path_Job', CommandJobCreate()) diff --git a/src/Mod/Path/PathScripts/PathToolController.py b/src/Mod/Path/PathScripts/PathToolController.py index b27ef26519..494f620a2e 100644 --- a/src/Mod/Path/PathScripts/PathToolController.py +++ b/src/Mod/Path/PathScripts/PathToolController.py @@ -30,6 +30,7 @@ import Path import PathScripts import PathScripts.PathLog as PathLog import PathUtils +import lxml.etree as xml from FreeCAD import Units from PySide import QtCore, QtGui @@ -203,6 +204,37 @@ class CommandPathToolController: obj.ToolNumber = toolNumber PathUtils.addToJob(obj, jobname) + @staticmethod + def FromTemplate(job, template, assignViewProvider=True): + PathLog.track() + + obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", template.get('label')) + PathScripts.PathToolController.ToolController(obj) + if assignViewProvider: + PathScripts.PathToolController._ViewProviderToolController(obj.ViewObject) + + if template.get('vfeed'): + obj.HorizFeed = template.get('vfeed') + if template.get('hfeed'): + obj.HorizFeed = template.get('hfeed') + if template.get('vrapid'): + obj.HorizRapid = template.get('vrapid') + if template.get('hrapid'): + obj.HorizRapid = template.get('hrapid') + if template.get('speed'): + obj.SpindleSpeed = float(template.get('speed')) + if template.get('dir'): + obj.SpindleDir = template.get('dir') + if template.get('nr'): + obj.ToolNumber = int(template.get('nr')) + + for t in template.iter('Tool'): + tool = Path.Tool() + tool.fromTemplate(xml.tostring(t)) + obj.Tool = tool + + PathUtils.addToJob(obj, job.Name) + class TaskPanel: def __init__(self):