diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index cbed71184b..22d1be765b 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -121,6 +121,7 @@ SET(PathTests_SRCS PathTests/TestPathGeom.py PathTests/TestPathLog.py PathTests/TestPathPost.py + PathTests/TestPathSetupSheet.py PathTests/TestPathStock.py PathTests/TestPathTool.py PathTests/TestPathToolController.py diff --git a/src/Mod/Path/PathScripts/PathSetupSheet.py b/src/Mod/Path/PathScripts/PathSetupSheet.py index ecf95a4616..4d1e45740f 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheet.py +++ b/src/Mod/Path/PathScripts/PathSetupSheet.py @@ -47,17 +47,38 @@ class Default: SafeHeight = 'DefaultSafeHeight' ClearanceHeight = 'DefaultClearanceHeight' +def _traverseTemplateAttributes(attrs, codec): + coded = {} + for key,value in attrs.iteritems(): + 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 type(value) == str or type(value) == unicode: + 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 + class SetupSheet: '''Spreadsheet used by a Job to hold global reference values. It's mostly a convencience wrapper around Spreadsheet. ''' + TemplateReference = '${SetupSheet}' + def __init__(self, obj): self.obj = obj - def setup(self): - '''setup() ... initializes receiver with default values.''' + def setup(self, label=None): + '''setup(label=None) ... initializes receiver with default values.''' self.obj.SetupSheet = self.obj.Document.addObject('Spreadsheet::Sheet', 'SetupSheet') + if label: + self.obj.SetupSheet.Label = label self.obj.SetupSheet.set('A2', translate('PathSetupSheet', 'Tool Rapid Speeds')) self.createSetting(3, Default.HorizRapid, '0 mm/s', translate('PathSetupSheet', 'Horizontal'), translate('PathSetupSheet', 'Default speed for horizzontal rapid moves.')) self.createSetting(4, Default.VertRapid, '0 mm/s', translate('PathSetupSheet', 'Vertical'), translate('PathSetupSheet', 'Default speed for vertical rapid moves.')) @@ -93,7 +114,7 @@ It's mostly a convencience wrapper around Spreadsheet. if attrs.get(Default.ClearanceHeight): self.updateSetting(Default.ClearanceHeight, attrs[Default.ClearanceHeight]) - def templateAttributes(self, includeRapids, includeHeights): + def templateAttributes(self, includeRapids=True, includeHeights=True): '''templateAttributes(includeRapids, includeHeights) ... answers a dictionary with the default values.''' attrs = {} if includeRapids: @@ -107,3 +128,11 @@ It's mostly a convencience wrapper around Spreadsheet. def expressionReference(self): '''expressionReference() ... returns the string to be used in expressions''' return self.obj.SetupSheet.Label + + def encodeTemplateAttributes(self, attrs): + '''encodeTemplateAttributes(attrs) ... return a dictionary with all values encoded.''' + return _traverseTemplateAttributes(attrs, lambda value: value.replace(self.expressionReference(), self.TemplateReference)) + + def decodeTemplateAttributes(self, attrs): + '''decodeTemplateAttributes(attrs) ... expand template attributes to reference the receiver where applicable.''' + return _traverseTemplateAttributes(attrs, lambda value: value.replace(self.TemplateReference, self.expressionReference())) diff --git a/src/Mod/Path/PathTests/TestPathSetupSheet.py b/src/Mod/Path/PathTests/TestPathSetupSheet.py new file mode 100644 index 0000000000..834097a6de --- /dev/null +++ b/src/Mod/Path/PathTests/TestPathSetupSheet.py @@ -0,0 +1,157 @@ +# -*- 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 +import PathScripts.PathSetupSheet as PathSetupSheet + +from PathTests.PathTestUtils import PathTestBase + +class TestPathSetupSheet(PathTestBase): + class TestObject: + def __init__(self, doc): + self.Document = doc + self.SetupSheet = None + + def setUp(self): + self.doc = FreeCAD.newDocument("TestPathSetupSheet") + self.obj = self.TestObject(self.doc) + + def tearDown(self): + FreeCAD.closeDocument(self.doc.Name) + + def test00(self): + '''Verify SetupSheet templateAttributes''' + ss = PathSetupSheet.SetupSheet(self.obj) + ss.setup() + self.doc.recompute() + + attrs = ss.templateAttributes(True, True) + + self.assertEqual(attrs[PathSetupSheet.Default.HorizRapid], '0.00 mm/s') + self.assertEqual(attrs[PathSetupSheet.Default.VertRapid], '0.00 mm/s') + self.assertEqual(attrs[PathSetupSheet.Default.SafeHeight], '3.00 mm') + self.assertEqual(attrs[PathSetupSheet.Default.ClearanceHeight], '5.00 mm') + + def test01(self): + '''Verify SetupSheet template attributes roundtrip.''' + ss = PathSetupSheet.SetupSheet(self.obj) + ss.setup() + self.doc.recompute() + ss.DefaultVertRapid = '10 mm/s' + ss.DefaultHorizRapid = '22 mm/s' + ss.DefaultSafeHeight = '18 mm' + ss.DefaultClearanceHeight = '23 mm' + + o2 = self.TestObject(self.doc) + s2 = PathSetupSheet.SetupSheet(o2) + s2.setup() + self.doc.recompute() + s2.setFromTemplate(ss.templateAttributes()) + self.doc.recompute() + + self.assertRoughly(self.obj.SetupSheet.DefaultVertRapid, o2.SetupSheet.DefaultVertRapid) + self.assertRoughly(self.obj.SetupSheet.DefaultHorizRapid, o2.SetupSheet.DefaultHorizRapid) + self.assertRoughly(self.obj.SetupSheet.DefaultSafeHeight, o2.SetupSheet.DefaultSafeHeight) + self.assertRoughly(self.obj.SetupSheet.DefaultClearanceHeight, o2.SetupSheet.DefaultClearanceHeight) + + def test10(self): + '''Verify template attributes encoding/decoding of floats.''' + ss = PathSetupSheet.SetupSheet(self.obj) + ss.setup('x') + + self.assertEqual(ss.expressionReference(), 'x') + + self.assertEqual(str(ss.encodeTemplateAttributes({'00': 13.00})), "{'00': 13.0}") + self.assertEqual(str(ss.decodeTemplateAttributes({'00': 13.00})), "{'00': 13.0}") + + def test11(self): + '''Verify template attributes encoding/decoding of strings.''' + ss = PathSetupSheet.SetupSheet(self.obj) + ss.setup('x') + + self.assertEqual(str(ss.encodeTemplateAttributes({'00': 'SetupSheet'})), "{'00': u'SetupSheet'}") + self.assertEqual(str(ss.encodeTemplateAttributes({'00': 'x'})), "{'00': u'${SetupSheet}'}") + self.assertEqual(str(ss.encodeTemplateAttributes({'00': 'x.y'})), "{'00': u'${SetupSheet}.y'}") + self.assertEqual(str(ss.encodeTemplateAttributes({'00': '${SetupSheet}'})), "{'00': u'${SetupSheet}'}") + + self.assertEqual(str(ss.decodeTemplateAttributes({'00': 'SetupSheet'})), "{'00': u'SetupSheet'}") + self.assertEqual(str(ss.decodeTemplateAttributes({'00': '${SetupSheet}'})), "{'00': u'x'}") + self.assertEqual(str(ss.decodeTemplateAttributes({'00': '${SetupSheet}.y'})), "{'00': u'x.y'}") + self.assertEqual(str(ss.decodeTemplateAttributes({'00': '${SetupSheet}.y - ${SetupSheet}.z'})), "{'00': u'x.y - x.z'}") + + def test12(self): + '''Verify template attributes encoding/decoding of dictionaries.''' + ss = PathSetupSheet.SetupSheet(self.obj) + ss.setup('rrr') + + self.assertEqual(str(ss.encodeTemplateAttributes({'00': {'01': 'SetupSheet'}})), "{'00': {'01': u'SetupSheet'}}") + self.assertEqual(str(ss.encodeTemplateAttributes({'00': {'01': 'rrr.y - rrr.z'}})), "{'00': {'01': u'${SetupSheet}.y - ${SetupSheet}.z'}}") + + self.assertEqual(str(ss.decodeTemplateAttributes({'00': {'01': 'SetupSheet'}})), "{'00': {'01': u'SetupSheet'}}") + self.assertEqual(str(ss.decodeTemplateAttributes({'00': {'01': '${SetupSheet}.y - ${SetupSheet}.z'}})), "{'00': {'01': u'rrr.y - rrr.z'}}") + + def test13(self): + '''Verify template attributes encoding/decoding of lists.''' + ss = PathSetupSheet.SetupSheet(self.obj) + ss.setup('hugo') + + attrs = {} + attrs['00'] = 'x.hugo' + attrs['01'] = [{'10': 'hugo', '11': 'hugo.y'}, {'20': 'hugo'}] + attrs['02'] = [{'a': [{'b': 'hugo'}, {'c': 'hugo'}], 'b': [{'b': 'hugo'}]}] + + encoded = ss.encodeTemplateAttributes(attrs) + self.assertEqual(encoded['00'], 'x.${SetupSheet}') + self.assertEqual(len(encoded['01']), 2) + self.assertEqual(encoded['01'][0]['10'], '${SetupSheet}') + self.assertEqual(encoded['01'][0]['11'], '${SetupSheet}.y') + self.assertEqual(str(encoded['01'][1]), "{'20': u'${SetupSheet}'}") + self.assertEqual(len(encoded['02']), 1) + self.assertEqual(len(encoded['02'][0]['a']), 2) + self.assertEqual(str(encoded['02'][0]['a'][0]), "{'b': u'${SetupSheet}'}") + self.assertEqual(str(encoded['02'][0]['a'][1]), "{'c': u'${SetupSheet}'}") + self.assertEqual(len(encoded['02'][0]['b']), 1) + self.assertEqual(str(encoded['02'][0]['b'][0]), "{'b': u'${SetupSheet}'}") + + decoded = ss.decodeTemplateAttributes(encoded) + self.assertEqual(len(decoded), len(attrs)) + self.assertEqual(decoded['00'], attrs['00']) + self.assertEqual(len(decoded['01']), len(attrs['01'])) + self.assertEqual(decoded['01'][0]['10'], attrs['01'][0]['10']) + self.assertEqual(decoded['01'][0]['11'], attrs['01'][0]['11']) + self.assertEqual(decoded['01'][1]['20'], attrs['01'][1]['20']) + self.assertEqual(len(decoded['02']), len(attrs['02'])) + self.assertEqual(len(decoded['02'][0]['a']), len(attrs['02'][0]['a'])) + self.assertEqual(decoded['02'][0]['a'][0]['b'], attrs['02'][0]['a'][0]['b']) + self.assertEqual(decoded['02'][0]['a'][1]['c'], attrs['02'][0]['a'][1]['c']) + self.assertEqual(len(decoded['02'][0]['b']), len(attrs['02'][0]['b'])) + self.assertEqual(decoded['02'][0]['b'][0]['b'], attrs['02'][0]['b'][0]['b']) + + # just to be safe ... + self.obj.SetupSheet.Label = 'xxx' + self.assertEqual(ss.expressionReference(), 'xxx') + dec = ss.decodeTemplateAttributes(encoded) + # pick one + self.assertEqual(dec['01'][0]['11'], 'xxx.y') diff --git a/src/Mod/Path/TestPathApp.py b/src/Mod/Path/TestPathApp.py index f8ca143226..ecf3a25d6e 100644 --- a/src/Mod/Path/TestPathApp.py +++ b/src/Mod/Path/TestPathApp.py @@ -36,3 +36,5 @@ from PathTests.TestPathStock import TestPathStock from PathTests.TestPathTool import TestPathTool from PathTests.TestPathTooltable import TestPathTooltable from PathTests.TestPathToolController import TestPathToolController +from PathTests.TestPathSetupSheet import TestPathSetupSheet +