svghmi/ui.py
branchsvghmi
changeset 3221 3d307ad803ea
parent 3213 afef7011f475
child 3222 6adeeb16ac3e
equal deleted inserted replaced
3220:ec365ef396b1 3221:3d307ad803ea
     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 
    51         self.DeleteAllItems()
    59         self.DeleteAllItems()
    52 
    60 
    53         root_display_name = _("Please build to see HMI Tree") \
    61         root_display_name = _("Please build to see HMI Tree") \
    54             if hmi_tree_root is None else "HMI"
    62             if hmi_tree_root is None else "HMI"
    55         self.root = self.AddRoot(root_display_name)
    63         self.root = self.AddRoot(root_display_name)
    56         self.SetPyData(self.root, None)
    64         self.SetPyData(self.root, hmi_tree_root)
    57 
    65 
    58         if hmi_tree_root is not None:
    66         if hmi_tree_root is not None:
    59             self._recurseTree(hmi_tree_root, self.root)
    67             self._recurseTree(hmi_tree_root, self.root)
    60             self.Expand(self.root)
    68             self.Expand(self.root)
    61 
    69 
   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)
   153         self.preview.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
   160         self.preview.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
   154 
   161 
   155         self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnWidgetSelection, self.widgetpicker)
   162         self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnWidgetSelection, self.widgetpicker)
   156 
   163 
   157         self.msg = _("Drag selected Widget from here to Inkscape")
   164         self.msg = _("Drag selected Widget from here to Inkscape")
       
   165         self.tempf = None 
   158 
   166 
   159     def RecallLibDir(self):
   167     def RecallLibDir(self):
   160         conf = self.Config.Read(_conf_key)
   168         conf = self.Config.Read(_conf_key)
   161         if len(conf) == 0:
   169         if len(conf) == 0:
   162             return None
   170             return None
   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