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):