diff --git a/src/Mod/Path/App/TooltablePy.xml b/src/Mod/Path/App/TooltablePy.xml
index 6433a3b9d7..8de47b88f3 100644
--- a/src/Mod/Path/App/TooltablePy.xml
+++ b/src/Mod/Path/App/TooltablePy.xml
@@ -52,5 +52,15 @@ deletes the tool found at the given position
+
+
+ setFromTemplate(dict) ... restores receiver from given template attribute dictionary
+
+
+
+
+ templateAttrs() ... returns a dictionary representing the receivers attributes for a template
+
+
diff --git a/src/Mod/Path/App/TooltablePyImp.cpp b/src/Mod/Path/App/TooltablePyImp.cpp
index 5e8f098625..56cd60f1f9 100644
--- a/src/Mod/Path/App/TooltablePyImp.cpp
+++ b/src/Mod/Path/App/TooltablePyImp.cpp
@@ -71,8 +71,11 @@ int ToolPy::PyInit(PyObject* args, PyObject* kwd)
static char *kwlist[] = {"name", "tooltype", "material", "diameter", "lengthOffset", "flatRadius", "cornerRadius", "cuttingEdgeAngle", "cuttingEdgeHeight" ,NULL};
PyObject *dict = 0;
- if (!kwd && PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict)) {
- PyObject *arg = PyTuple_New(0);
+ if (!kwd && (PyObject_TypeCheck(args, &PyDict_Type) || PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict))) {
+ static PyObject *arg = PyTuple_New(0);
+ if (PyObject_TypeCheck(args, &PyDict_Type)) {
+ dict = args;
+ }
if (!PyArg_ParseTupleAndKeywords(arg, dict, "|sssOOOOOO", kwlist, &name, &type, &mat, &dia, &len, &fla, &cor, &ang, &hei)) {
return -1;
}
@@ -321,13 +324,19 @@ PyObject* ToolPy::setFromTemplate(PyObject * args)
#if PY_MAJOR_VERSION >= 3
# define PYSTRING_FROMSTRING(str) PyUnicode_FromString(str)
+# define PYINT_TYPE PyLong_Type
+# define PYINT_FROMLONG(l) PyLong_FromLong(l)
+# define PYINT_ASLONG(o) PyLong_AsLong(o)
#else
# define PYSTRING_FROMSTRING(str) PyString_FromString(str)
+# define PYINT_TYPE PyInt_Type
+# define PYINT_FROMLONG(l) PyInt_FromLong(l)
+# define PYINT_ASLONG(o) PyInt_AsLong(o)
#endif
PyObject* ToolPy::templateAttrs(PyObject * args)
{
- if (PyArg_ParseTuple(args, "")) {
+ if (!args || PyArg_ParseTuple(args, "")) {
PyObject *dict = PyDict_New();
PyDict_SetItemString(dict, "name", PYSTRING_FROMSTRING(getToolPtr()->Name.c_str()));
PyDict_SetItemString(dict, "tooltype",PYSTRING_FROMSTRING(Tool::TypeName(getToolPtr()->Type)));
@@ -373,24 +382,12 @@ int TooltablePy::PyInit(PyObject* args, PyObject* /*kwd*/)
PyObject *pcObj;
if (PyArg_ParseTuple(args, "O!", &(PyDict_Type), &pcObj)) {
- PyObject *key, *value;
- Py_ssize_t pos = 0;
- while (PyDict_Next(pcObj, &pos, &key, &value)) {
-#if PY_MAJOR_VERSION >= 3
- if ( !PyObject_TypeCheck(key,&(PyLong_Type)) || !PyObject_TypeCheck(value,&(Path::ToolPy::Type)) ) {
-#else
- if ( !PyObject_TypeCheck(key,&(PyInt_Type)) || !PyObject_TypeCheck(value,&(Path::ToolPy::Type)) ) {
-#endif
- PyErr_SetString(PyExc_TypeError, "The dictionary can only contain int:tool pairs");
- return -1;
- }
-#if PY_MAJOR_VERSION >= 3
- int ckey = (int)PyLong_AsLong(key);
-#else
- int ckey = (int)PyInt_AsLong(key);
-#endif
- Path::Tool &tool = *static_cast(value)->getToolPtr();
- getTooltablePtr()->setTool(tool,ckey);
+ try {
+ Py::Dict dict(pcObj);
+ setTools(dict);
+ } catch(...) {
+ PyErr_SetString(PyExc_TypeError, "The dictionary can only contain int:tool pairs");
+ return -1;
}
return 0;
}
@@ -418,11 +415,7 @@ Py::Dict TooltablePy::getTools(void) const
PyObject *dict = PyDict_New();
for(std::map::iterator i = getTooltablePtr()->Tools.begin(); i != getTooltablePtr()->Tools.end(); ++i) {
PyObject *tool = new Path::ToolPy(i->second);
-#if PY_MAJOR_VERSION >= 3
- PyDict_SetItem(dict,PyLong_FromLong(i->first),tool);
-#else
- PyDict_SetItem(dict,PyInt_FromLong(i->first),tool);
-#endif
+ PyDict_SetItem(dict,PYINT_FROMLONG(i->first),tool);
}
return Py::Dict(dict);
}
@@ -434,15 +427,21 @@ void TooltablePy::setTools(Py::Dict arg)
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(dict_copy, &pos, &key, &value)) {
-#if PY_MAJOR_VERSION >= 3
- if ( PyObject_TypeCheck(key,&(PyLong_Type)) && (PyObject_TypeCheck(value,&(Path::ToolPy::Type))) ) {
- int ckey = (int)PyLong_AsLong(key);
-#else
- if ( PyObject_TypeCheck(key,&(PyInt_Type)) && (PyObject_TypeCheck(value,&(Path::ToolPy::Type))) ) {
- int ckey = (int)PyInt_AsLong(key);
-#endif
- Path::Tool &tool = *static_cast(value)->getToolPtr();
- getTooltablePtr()->setTool(tool,ckey);
+ if ( PyObject_TypeCheck(key,&(PYINT_TYPE)) && ((PyObject_TypeCheck(value, &(Path::ToolPy::Type))) || PyObject_TypeCheck(value, &PyDict_Type))) {
+ int ckey = (int)PYINT_ASLONG(key);
+ if (PyObject_TypeCheck(value, &(Path::ToolPy::Type))) {
+ Path::Tool &tool = *static_cast(value)->getToolPtr();
+ getTooltablePtr()->setTool(tool, ckey);
+ } else {
+ PyErr_Clear();
+ Path::Tool *tool = new Path::Tool;
+ Path::ToolPy pyTool(tool);
+ if (!pyTool.setFromTemplate(value)) {
+ PyErr_Print();
+ throw Py::Exception("something went wrong");
+ }
+ getTooltablePtr()->setTool(*tool, ckey);
+ }
} else {
throw Py::Exception("The dictionary can only contain int:tool pairs");
}
@@ -542,3 +541,27 @@ int TooltablePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
}
+PyObject* TooltablePy::setFromTemplate(PyObject * args)
+{
+ PyObject *dict = 0;
+ if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict)) {
+ Py::Dict d(dict);
+ setTools(d);
+ Py_Return ;
+ }
+
+ PyErr_SetString(PyExc_TypeError, "argument must be a dictionary returned from templateAttrs()");
+ return 0;
+}
+
+PyObject* TooltablePy::templateAttrs(PyObject * args)
+{
+ (void)args;
+ PyObject *dict = PyDict_New();
+ for(std::map::iterator i = getTooltablePtr()->Tools.begin(); i != getTooltablePtr()->Tools.end(); ++i) {
+ Path::ToolPy tool(new Path::Tool(*i->second));
+ PyObject *attrs = tool.templateAttrs(0);
+ PyDict_SetItem(dict, PYINT_FROMLONG(i->first), attrs);
+ }
+ return dict;
+}
diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt
index 40653a547e..e3183b1f20 100644
--- a/src/Mod/Path/CMakeLists.txt
+++ b/src/Mod/Path/CMakeLists.txt
@@ -121,6 +121,7 @@ SET(PathTests_SRCS
PathTests/TestPathPost.py
PathTests/TestPathStock.py
PathTests/TestPathTool.py
+ PathTests/TestPathTooltable.py
PathTests/TestPathUtil.py
)
diff --git a/src/Mod/Path/PathTests/TestPathTooltable.py b/src/Mod/Path/PathTests/TestPathTooltable.py
new file mode 100644
index 0000000000..dbde438e09
--- /dev/null
+++ b/src/Mod/Path/PathTests/TestPathTooltable.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+
+# ***************************************************************************
+# * *
+# * Copyright (c) 2017 sliptonic *
+# * *
+# * This program is free software; you can redistribute it and/or modify *
+# * it under the terms of the GNU Lesser General Public License (LGPL) *
+# * as published by the Free Software Foundation; either version 2 of *
+# * the License, or (at your option) any later version. *
+# * for detail see the LICENCE text file. *
+# * *
+# * This program is distributed in the hope that it will be useful, *
+# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+# * GNU Library General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU Library General Public *
+# * License along with this program; if not, write to the Free Software *
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+# * USA *
+# * *
+# ***************************************************************************
+
+import FreeCAD
+import Path
+
+from PathTests.PathTestUtils import PathTestBase
+
+class TestPathTooltable(PathTestBase):
+
+ def test00(self):
+ '''Verify templateAttrs'''
+
+ t = Path.Tool(name='t', diameter=1.2)
+ u = Path.Tool(name='u', diameter=3.4)
+ v = Path.Tool(name='v', diameter=5.6)
+
+ tt = Path.Tooltable()
+ tt.setTool(3, t)
+ tt.setTool(1, u)
+ tt.addTools(v)
+
+ attrs = tt.templateAttrs()
+ self.assertEqual(3, len(attrs))
+ self.assertTrue(1 in attrs)
+ self.assertFalse(2 in attrs)
+ self.assertTrue(3 in attrs)
+ self.assertTrue(4 in attrs)
+
+ self.assertEqual(attrs[1]['name'], 'u')
+ self.assertEqual(attrs[1]['diameter'], 3.4)
+ self.assertEqual(attrs[3]['name'], 't')
+ self.assertEqual(attrs[3]['diameter'], 1.2)
+ self.assertEqual(attrs[4]['name'], 'v')
+ self.assertEqual(attrs[4]['diameter'], 5.6)
+ return tt
+
+ def test01(self):
+ '''Verify setFromTemplate roundtrip.'''
+ tt = self.test00()
+ uu = Path.Tooltable()
+ uu.setFromTemplate(tt.templateAttrs())
+
+ self.assertEqual(tt.Content, uu.Content)
+
+
+ def test02(self):
+ '''Verify template constructor.'''
+ tt = self.test00()
+ uu = Path.Tooltable(tt.templateAttrs())
+ self.assertEqual(tt.Content, uu.Content)
+
diff --git a/src/Mod/Path/TestPathApp.py b/src/Mod/Path/TestPathApp.py
index b7a6b94762..0add394bdc 100644
--- a/src/Mod/Path/TestPathApp.py
+++ b/src/Mod/Path/TestPathApp.py
@@ -34,3 +34,4 @@ from PathTests.TestPathDressupHoldingTags import TestHoldingTags
from PathTests.TestPathDressupDogbone import TestDressupDogbone
from PathTests.TestPathStock import TestPathStock
from PathTests.TestPathTool import TestPathTool
+from PathTests.TestPathTooltable import TestPathTooltable