SVGHMI: Added simple HMI Tree View. svghmi
authorEdouard Tisserant
Fri, 15 Nov 2019 10:34:14 +0100
branchsvghmi
changeset 2816 d813ecfe8941
parent 2815 77b2a3757e66
child 2817 45bbfb2e120f
SVGHMI: Added simple HMI Tree View.
svghmi/svghmi.py
tests/svghmi/plc.xml
--- a/svghmi/svghmi.py	Thu Nov 14 08:46:32 2019 +0100
+++ b/svghmi/svghmi.py	Fri Nov 15 10:34:14 2019 +0100
@@ -12,17 +12,23 @@
 from itertools import izip, imap
 from pprint import pprint, pformat
 import hashlib
+import weakref
 
 import wx
+import wx.dataview as dv
+
+from lxml import etree
+from lxml.etree import XSLTApplyError
 
 import util.paths as paths
 from POULibrary import POULibrary
 from docutil import open_svg, get_inkscape_path
-from lxml import etree
 
 from util.ProcessLogger import ProcessLogger
 from runtime.typemapping import DebugTypesSize
 import targets
+from editors.ConfTreeNodeEditor import ConfTreeNodeEditor
+from XSLTransform import XSLTransform
 
 HMI_TYPES_DESC = {
     "HMI_NODE":{},
@@ -33,8 +39,6 @@
 
 HMI_TYPES = HMI_TYPES_DESC.keys()
 
-from XSLTransform import XSLTransform
-from lxml.etree import XSLTApplyError
 
 ScriptDirectory = paths.AbsDir(__file__)
 
@@ -127,12 +131,14 @@
 
 hmi_tree_root = None
 
+hmi_tree_updated = None
+
 class SVGHMILibrary(POULibrary):
     def GetLibraryPath(self):
          return paths.AbsNeighbourFile(__file__, "pous.xml")
 
     def Generate_C(self, buildpath, varlist, IECCFLAGS):
-        global hmi_tree_root, hmi_tree_unique_id 
+        global hmi_tree_root, hmi_tree_updated, hmi_tree_unique_id 
 
         """
         PLC Instance Tree:
@@ -194,6 +200,9 @@
             new_node = HMITreeNode(path, name, derived, v["type"], v["vartype"], **kwargs)
             hmi_tree_root.place_node(new_node)
 
+        if hmi_tree_updated is not None:
+            hmi_tree_updated()
+
         variable_decl_array = []
         extern_variables_declarations = []
         buf_index = 0
@@ -262,6 +271,69 @@
         return ((["svghmi"], [(gen_svghmi_c_path, IECCFLAGS)], True), "",
                 ("runtime_svghmi0.py", open(runtimefile_path, "rb")))
 
+
+class SVGHMIEditor(ConfTreeNodeEditor):
+    CONFNODEEDITOR_TABS = [
+        (_("HMI Tree"), "CreateHMITreeView")]
+
+    def SVGHMIEditorUpdater(self):
+        selfref = weakref.ref(self)
+        def SVGHMIEditorUpdate():
+            o = selfref()
+            if o is not None:
+                wx.CallAfter(o.MakeTree)
+        return SVGHMIEditorUpdate
+
+    def CreateHMITreeView(self, parent):
+        global hmi_tree_updated 
+
+        dvtc = dv.DataViewTreeCtrl(parent)
+        isz = (16,16)
+        self.ImageList = il = wx.ImageList(*isz)
+        self.fldridx     = il.AddIcon(wx.ArtProvider.GetIcon(wx.ART_FOLDER,      wx.ART_OTHER, isz))
+        self.fldropenidx = il.AddIcon(wx.ArtProvider.GetIcon(wx.ART_FOLDER_OPEN, wx.ART_OTHER, isz))
+        self.fileidx     = il.AddIcon(wx.ArtProvider.GetIcon(wx.ART_NORMAL_FILE, wx.ART_OTHER, isz))
+        dvtc.SetImageList(il)
+
+
+        self.HMITreeView = dvtc
+        hmi_tree_updated = self.SVGHMIEditorUpdater()
+        self.MakeTree()
+        return self.HMITreeView
+
+    def _recurseTree(self, current_hmitree_root, current_dvtc_root):
+        dvtc = self.HMITreeView
+        for c in current_hmitree_root.children:
+            if hasattr(c, "children"):
+                display_name = ('{} (class={})'.format(c.name, c.hmiclass)) \
+                               if c.hmiclass is not None else c.name
+                dvtc_child = dvtc.AppendContainer(
+                                 current_dvtc_root, display_name,
+                                 self.fldridx, self.fldropenidx)
+
+                self._recurseTree(c,dvtc_child)
+            else:
+                display_name = '{} {}'.format(c.nodetype[4:], c.name)
+                dvtc.AppendContainer(
+                    current_dvtc_root, display_name,
+                    self.fileidx, self.fileidx)
+
+    def MakeTree(self):
+        global hmi_tree_root 
+        
+        dvtc = self.HMITreeView
+
+        dvtc.Freeze()
+        dvtc.DeleteAllItems()
+
+        root_display_name = _("Please build to see HMI Tree") if hmi_tree_root is None else "HMI"
+        root = dvtc.AppendContainer(dv.NullDataViewItem,
+                                    root_display_name,
+                                    self.fldridx, self.fldropenidx)
+        if hmi_tree_root is not None:
+            self._recurseTree(hmi_tree_root, root)
+        dvtc.Thaw()
+
 class SVGHMI(object):
     XSD = """<?xml version="1.0" encoding="utf-8" ?>
     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
@@ -274,7 +346,8 @@
       </xsd:element>
     </xsd:schema>
     """
-    # TODO : add comma separated supported language list
+
+    EditorType = SVGHMIEditor
 
     ConfNodeMethods = [
         {
--- a/tests/svghmi/plc.xml	Thu Nov 14 08:46:32 2019 +0100
+++ b/tests/svghmi/plc.xml	Fri Nov 15 10:34:14 2019 +0100
@@ -1,7 +1,7 @@
 <?xml version='1.0' encoding='utf-8'?>
 <project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.plcopen.org/xml/tc6_0201">
   <fileHeader companyName="Unknown" productName="Unnamed" productVersion="1" creationDateTime="2019-08-06T14:23:42"/>
-  <contentHeader name="Unnamed" modificationDateTime="2019-11-12T13:19:15">
+  <contentHeader name="Unnamed" modificationDateTime="2019-11-14T13:42:40">
     <coordinateInfo>
       <fbd>
         <scaling x="5" y="5"/>
@@ -30,11 +30,6 @@
                 <derived name="PumpControl"/>
               </type>
             </variable>
-            <variable name="Pump1">
-              <type>
-                <derived name="PumpControl"/>
-              </type>
-            </variable>
           </localVars>
         </interface>
         <body>
@@ -62,24 +57,6 @@
               </connectionPointOut>
               <expression>TargetPressure</expression>
             </inVariable>
-            <block localId="1" typeName="PumpControl" instanceName="Pump1" executionOrderId="0" height="40" width="127">
-              <position x="605" y="145"/>
-              <inputVariables>
-                <variable formalParameter="TargetPressure">
-                  <connectionPointIn>
-                    <relPosition x="0" y="30"/>
-                    <connection refLocalId="5">
-                      <position x="605" y="175"/>
-                      <position x="587" y="175"/>
-                      <position x="587" y="80"/>
-                      <position x="570" y="80"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-              </inputVariables>
-              <inOutVariables/>
-              <outputVariables/>
-            </block>
           </FBD>
         </body>
       </pou>