Skeleton for svghmi extension svghmi
authorEdouard Tisserant
Fri, 12 Jul 2019 11:58:22 +0200
branchsvghmi
changeset 2745 535eb0b8bd9d
parent 2623 26ba948a2e51
child 2746 ad94a928d87d
child 2747 e96aa2e3231e
Skeleton for svghmi extension
svghmi/README
svghmi/__init__.py
svghmi/pous.xml
svghmi/svghmi.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/README	Fri Jul 12 11:58:22 2019 +0200
@@ -0,0 +1,1 @@
+SVG HMI
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/__init__.py	Fri Jul 12 11:58:22 2019 +0200
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz
+# Copyright (C) 2019: Edouard TISSERANT
+#
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+from svghmi.svghmi import *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/pous.xml	Fri Jul 12 11:58:22 2019 +0200
@@ -0,0 +1,55 @@
+<?xml version='1.0' encoding='utf-8'?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xsi:schemaLocation="http://www.plcopen.org/xml/tc6_0201">
+  <fileHeader companyName="Beremiz" productName="Beremiz" productVersion="0.0" creationDateTime="2008-12-14T16:53:26"/>
+  <contentHeader name="Beremiz non-standard POUs library" modificationDateTime="2019-07-09T11:05:01">
+    <coordinateInfo>
+      <fbd>
+        <scaling x="0" y="0"/>
+      </fbd>
+      <ld>
+        <scaling x="0" y="0"/>
+      </ld>
+      <sfc>
+        <scaling x="0" y="0"/>
+      </sfc>
+    </coordinateInfo>
+  </contentHeader>
+  <types>
+    <dataTypes>
+      <dataType name="HMI_INT">
+        <baseType>
+          <INT/>
+        </baseType>
+      </dataType>
+      <dataType name="HMI_REAL">
+        <baseType>
+          <REAL/>
+        </baseType>
+      </dataType>
+      <dataType name="HMI_STRING">
+        <baseType>
+          <STRING/>
+        </baseType>
+      </dataType>
+      <dataType name="HMI_BOOL">
+        <baseType>
+          <BOOL/>
+        </baseType>
+      </dataType>
+      <dataType name="HMI_CLASS">
+        <baseType>
+          <BOOL/>
+        </baseType>
+      </dataType>
+      <dataType name="HMI_LABEL">
+        <baseType>
+          <BOOL/>
+        </baseType>
+      </dataType>
+    </dataTypes>
+    <pous/>
+  </types>
+  <instances>
+    <configurations/>
+  </instances>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/svghmi.py	Fri Jul 12 11:58:22 2019 +0200
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz
+# Copyright (C) 2019: Edouard TISSERANT
+#
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+import os
+import shutil
+
+import wx
+
+import util.paths as paths
+from POULibrary import POULibrary
+from docutil import open_svg
+
+
+class SVGHMILibrary(POULibrary):
+    def GetLibraryPath(self):
+        return paths.AbsNeighbourFile(__file__, "pous.xml")
+
+
+class SVGHMI(object):
+    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+      <xsd:element name="SVGHMI">
+        <xsd:complexType>
+          <xsd:attribute name="enableHTTP" type="xsd:boolean" use="optional" default="false"/>
+          <xsd:attribute name="bindAddress" type="xsd:string" use="optional" default="localhost"/>
+          <xsd:attribute name="port" type="xsd:string" use="optional" default="8080"/>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:schema>
+    """
+
+    ConfNodeMethods = [
+        {
+            "bitmap":    "ImportSVG",
+            "name":    _("Import SVG"),
+            "tooltip": _("Import SVG"),
+            "method":   "_ImportSVG"
+        },
+        {
+            "bitmap":    "ImportSVG",  # should be something different
+            "name":    _("Inkscape"),
+            "tooltip": _("Edit HMI"),
+            "method":   "_StartInkscape"
+        },
+    ]
+
+    def _getSVGpath(self, project_path=None):
+        if project_path is None:
+            project_path = self.CTNPath()
+        # define name for SVG file containing gui layout
+        return os.path.join(project_path, "gui.svg")
+
+
+    def OnCTNSave(self, from_project_path=None):
+        if from_project_path is not None:
+            shutil.copyfile(self._getSVGpath(from_project_path),
+                            self._getSVGpath())
+        return PythonFileCTNMixin.OnCTNSave(self, from_project_path)
+
+    def CTNGenerate_C(self, buildpath, locations):
+        """
+        Return C code generated by iec2c compiler
+        when _generate_softPLC have been called
+        @param locations: ignored
+        @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
+        """
+
+        # TODO : get variable list from Controller
+        # self.GetCTRoot().blah
+        # TODO deduce HMI tree
+
+        svgfile = self._getSVGpath()
+        if os.path.exists(svgfile):
+            # TODO : call xslt transform on Inkscape's SVG to generate
+            #   - Errors on HMI semantics
+            #   - Target XHTML as a DOM
+            #   - ... maybe something to have a global view of what is declared in SVG.
+            pass
+        else:
+            # TODO : use default svg that expose the HMI tree as-is 
+            pass
+
+
+        res = ([], "", False)
+
+        targetpath = os.path.join(self._getBuildPath(), "target.xhtml")
+        targetfile = open(targetpath, 'w')
+
+        # TODO : DOM to string
+        targetfile.write("TODO")
+        targetfile.close()
+        res += (("target.js", open(targetpath, "rb")),)
+
+        # TODO add C code to expose HMI tree variables to shared memory
+        # TODO generate a description of shared memory (xml or CSV) 
+        #      that can be loaded by svghmi QTWeb* app or svghmi server
+
+
+        return res
+
+    def _ImportSVG(self):
+        dialog = wx.FileDialog(self.GetCTRoot().AppFrame, _("Choose a SVG file"), os.getcwd(), "",  _("SVG files (*.svg)|*.svg|All files|*.*"), wx.OPEN)
+        if dialog.ShowModal() == wx.ID_OK:
+            svgpath = dialog.GetPath()
+            if os.path.isfile(svgpath):
+                shutil.copy(svgpath, self._getSVGpath())
+            else:
+                self.GetCTRoot().logger.write_error(_("No such SVG file: %s\n") % svgpath)
+        dialog.Destroy()
+
+    def _StartInkscape(self):
+        svgfile = self._getSVGpath()
+        open_inkscape = True
+        if not self.GetCTRoot().CheckProjectPathPerm():
+            dialog = wx.MessageDialog(self.GetCTRoot().AppFrame,
+                                      _("You don't have write permissions.\nOpen Inkscape anyway ?"),
+                                      _("Open Inkscape"),
+                                      wx.YES_NO | wx.ICON_QUESTION)
+            open_inkscape = dialog.ShowModal() == wx.ID_YES
+            dialog.Destroy()
+        if open_inkscape:
+            if not os.path.isfile(svgfile):
+                svgfile = None
+            open_svg(svgfile)