8 |
8 |
9 from __future__ import absolute_import |
9 from __future__ import absolute_import |
10 import os |
10 import os |
11 import hashlib |
11 import hashlib |
12 import weakref |
12 import weakref |
|
13 from tempfile import NamedTemporaryFile |
13 |
14 |
14 import wx |
15 import wx |
15 |
16 |
|
17 from lxml import etree |
|
18 from lxml.etree import XSLTApplyError |
|
19 from XSLTransform import XSLTransform |
|
20 |
|
21 import util.paths as paths |
16 from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath |
22 from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath |
17 from docutil import get_inkscape_path |
23 from docutil import get_inkscape_path |
18 |
24 |
19 from util.ProcessLogger import ProcessLogger |
25 from util.ProcessLogger import ProcessLogger |
|
26 |
|
27 ScriptDirectory = paths.AbsDir(__file__) |
20 |
28 |
21 class HMITreeSelector(wx.TreeCtrl): |
29 class HMITreeSelector(wx.TreeCtrl): |
22 def __init__(self, parent): |
30 def __init__(self, parent): |
23 global on_hmitree_update |
31 global on_hmitree_update |
24 wx.TreeCtrl.__init__(self, parent, style=( |
32 wx.TreeCtrl.__init__(self, parent, style=( |
33 for c in current_hmitree_root.children: |
41 for c in current_hmitree_root.children: |
34 if hasattr(c, "children"): |
42 if hasattr(c, "children"): |
35 display_name = ('{} (class={})'.format(c.name, c.hmiclass)) \ |
43 display_name = ('{} (class={})'.format(c.name, c.hmiclass)) \ |
36 if c.hmiclass is not None else c.name |
44 if c.hmiclass is not None else c.name |
37 tc_child = self.AppendItem(current_tc_root, display_name) |
45 tc_child = self.AppendItem(current_tc_root, display_name) |
38 self.SetPyData(tc_child, None) # TODO |
46 self.SetPyData(tc_child, c) |
39 |
47 |
40 self._recurseTree(c,tc_child) |
48 self._recurseTree(c,tc_child) |
41 else: |
49 else: |
42 display_name = '{} {}'.format(c.nodetype[4:], c.name) |
50 display_name = '{} {}'.format(c.nodetype[4:], c.name) |
43 tc_child = self.AppendItem(current_tc_root, display_name) |
51 tc_child = self.AppendItem(current_tc_root, display_name) |
44 self.SetPyData(tc_child, None) # TODO |
52 self.SetPyData(tc_child, c) |
45 |
53 |
46 def MakeTree(self, hmi_tree_root=None): |
54 def MakeTree(self, hmi_tree_root=None): |
47 |
55 |
48 self.Freeze() |
56 self.Freeze() |
49 |
57 |
137 sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=0) |
145 sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=0) |
138 sizer.AddGrowableCol(0) |
146 sizer.AddGrowableCol(0) |
139 sizer.AddGrowableRow(1) |
147 sizer.AddGrowableRow(1) |
140 self.libbutton = wx.Button(self, -1, _("Select SVG widget library")) |
148 self.libbutton = wx.Button(self, -1, _("Select SVG widget library")) |
141 self.widgetpicker = WidgetPicker(self, self.libdir) |
149 self.widgetpicker = WidgetPicker(self, self.libdir) |
142 self.preview = wx.Panel(self, size=(-1, _preview_height + 10)) #, style=wx.SIMPLE_BORDER) |
150 self.preview = wx.Panel(self, size=(-1, _preview_height + 10)) |
143 #self.preview.SetBackgroundColour(wx.WHITE) |
|
144 sizer.AddWindow(self.libbutton, flag=wx.GROW) |
151 sizer.AddWindow(self.libbutton, flag=wx.GROW) |
145 sizer.AddWindow(self.widgetpicker, flag=wx.GROW) |
152 sizer.AddWindow(self.widgetpicker, flag=wx.GROW) |
146 sizer.AddWindow(self.preview, flag=wx.GROW) |
153 sizer.AddWindow(self.preview, flag=wx.GROW) |
147 sizer.Layout() |
154 sizer.Layout() |
148 self.SetAutoLayout(True) |
155 self.SetAutoLayout(True) |
246 digest = hasher.hexdigest() |
254 digest = hasher.hexdigest() |
247 thumbfname = os.path.splitext(fname)[0]+"_"+digest+".png" |
255 thumbfname = os.path.splitext(fname)[0]+"_"+digest+".png" |
248 thumbdir = os.path.join(dname, ".svghmithumbs") |
256 thumbdir = os.path.join(dname, ".svghmithumbs") |
249 thumbpath = os.path.join(thumbdir, thumbfname) |
257 thumbpath = os.path.join(thumbdir, thumbfname) |
250 |
258 |
251 self.msg = None |
|
252 have_thumb = os.path.exists(thumbpath) |
259 have_thumb = os.path.exists(thumbpath) |
253 |
260 |
254 if not have_thumb: |
261 try: |
255 try: |
262 if not have_thumb: |
256 if not os.path.exists(thumbdir): |
263 if not os.path.exists(thumbdir): |
257 os.mkdir(thumbdir) |
264 os.mkdir(thumbdir) |
258 except IOError: |
|
259 self.msg = _("Widget library must be writable") |
|
260 else: |
|
261 have_thumb = self.GenThumbnail(svgpath, thumbpath) |
265 have_thumb = self.GenThumbnail(svgpath, thumbpath) |
262 |
266 |
263 self.bmp = wx.Bitmap(thumbpath) if have_thumb else None |
267 self.bmp = wx.Bitmap(thumbpath) if have_thumb else None |
264 |
268 |
265 self.selected_SVG = svgpath if have_thumb else None |
269 self.selected_SVG = svgpath if have_thumb else None |
266 self.ValidateWidget() |
270 self.ValidateWidget() |
|
271 except IOError: |
|
272 self.msg = _("Widget library must be writable") |
267 |
273 |
268 self.Refresh() |
274 self.Refresh() |
269 event.Skip() |
275 event.Skip() |
270 |
276 |
271 def OnHMITreeNodeSelection(self, hmitree_node): |
277 def OnHMITreeNodeSelection(self, hmitree_node): |
272 self.hmitree_node = hmitree_node |
278 self.hmitree_node = hmitree_node |
273 self.ValidateWidget() |
279 self.ValidateWidget() |
274 self.Refresh() |
280 self.Refresh() |
275 |
281 |
276 def OnLeftDown(self, evt): |
282 def OnLeftDown(self, evt): |
277 if self.selected_SVG is not None: |
283 if self.tempf is not None: |
278 # TODO replace with generated widget file |
284 filename = self.tempf.name |
279 filename = self.selected_SVG |
|
280 data = wx.FileDataObject() |
285 data = wx.FileDataObject() |
281 data.AddFile(filename) |
286 data.AddFile(filename) |
282 dropSource = wx.DropSource(self) |
287 dropSource = wx.DropSource(self) |
283 dropSource.SetData(data) |
288 dropSource.SetData(data) |
284 dropSource.DoDragDrop(wx.Drag_AllowMove) |
289 dropSource.DoDragDrop(wx.Drag_AllowMove) |
285 |
290 |
|
291 def GiveDetails(self, _context, msgs): |
|
292 for msg in msgs: |
|
293 self.msg += msg+"\n" |
|
294 |
286 def ValidateWidget(self): |
295 def ValidateWidget(self): |
287 if self.selected_SVG is not None: |
296 self.msg = "" |
288 if self.hmitree_node is not None: |
297 |
289 pass |
298 if self.tempf is not None: |
290 # XXX TODO: |
299 os.unlink(self.tempf.name) |
291 # - check SVG is valid for selected HMI tree item |
300 self.tempf = None |
292 # - prepare for D'n'D |
301 |
293 |
302 try: |
|
303 if self.selected_SVG is None: |
|
304 raise Exception(_("No widget selected")) |
|
305 if self.hmitree_node is None: |
|
306 raise Exception(_("No HMI tree node selected")) |
|
307 |
|
308 transform = XSLTransform( |
|
309 os.path.join(ScriptDirectory, "gen_dnd_widget_svg.xslt"), |
|
310 [("GiveDetails", self.GiveDetails)]) |
|
311 |
|
312 svgdom = etree.parse(self.selected_SVG) |
|
313 |
|
314 result = transform.transform(svgdom) |
|
315 # hmi_path=self.hmitree_node.path, |
|
316 # hmi_type=self.hmitree_node.nodetype) |
|
317 |
|
318 for entry in transform.get_error_log(): |
|
319 self.msg += "XSLT: " + entry.message + "\n" |
|
320 |
|
321 self.tempf = NamedTemporaryFile(suffix='.svg', delete=False) |
|
322 result.write(self.tempf, encoding="utf-8") |
|
323 self.tempf.close() |
|
324 |
|
325 except Exception as e: |
|
326 self.msg += str(e) |
|
327 except XSLTApplyError as e: |
|
328 self.msg += "Widget transform error: " + e.message |
|
329 |
|
330 def __del__(self): |
|
331 if self.tempf is not None: |
|
332 os.unlink(self.tempf.name) |
294 |
333 |
295 class SVGHMI_UI(wx.SplitterWindow): |
334 class SVGHMI_UI(wx.SplitterWindow): |
296 |
335 |
297 def __init__(self, parent, register_for_HMI_tree_updates): |
336 def __init__(self, parent, register_for_HMI_tree_updates): |
298 wx.SplitterWindow.__init__(self, parent, |
337 wx.SplitterWindow.__init__(self, parent, |
300 |
339 |
301 self.SelectionTree = HMITreeSelector(self) |
340 self.SelectionTree = HMITreeSelector(self) |
302 self.Staging = WidgetLibBrowser(self) |
341 self.Staging = WidgetLibBrowser(self) |
303 self.SplitVertically(self.SelectionTree, self.Staging, 300) |
342 self.SplitVertically(self.SelectionTree, self.Staging, 300) |
304 register_for_HMI_tree_updates(weakref.ref(self)) |
343 register_for_HMI_tree_updates(weakref.ref(self)) |
|
344 self.Bind(wx.EVT_TREE_SEL_CHANGED, |
|
345 self.OnHMITreeNodeSelection, self.SelectionTree) |
|
346 |
|
347 def OnHMITreeNodeSelection(self, event): |
|
348 item_pydata = self.SelectionTree.GetPyData(event.GetItem()) |
|
349 self.Staging.OnHMITreeNodeSelection(item_pydata) |
305 |
350 |
306 def HMITreeUpdate(self, hmi_tree_root): |
351 def HMITreeUpdate(self, hmi_tree_root): |
307 self.SelectionTree.MakeTree(hmi_tree_root) |
352 self.SelectionTree.MakeTree(hmi_tree_root) |
308 |
353 |