svghmi/svghmi.py
author Edouard Tisserant
Thu, 18 Jul 2019 14:09:33 +0200
branchsvghmi
changeset 2749 2769b3aed34d
parent 2747 e96aa2e3231e
child 2750 2694170cd88e
permissions -rw-r--r--
Use a POU Library's Generate_C to collect all variables in SVGHMI.
#!/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

HMI_TYPES_DESC = {
    "HMI_CLASS":{},
    "HMI_LABEL":{},
    "HMI_STRING":{},
    "HMI_INT":{},
    "HMI_REAL":{}
}

HMI_TYPES = HMI_TYPES_DESC.keys()

class SVGHMILibrary(POULibrary):
    def GetLibraryPath(self):
        return paths.AbsNeighbourFile(__file__, "pous.xml")

    def Generate_C(self, buildpath, varlist, IECCFLAGS):

        # Filter known HMI types
        hmi_types_instances = [v for v in varlist if v["derived"] in HMI_TYPES]

        # TODO deduce HMI tree

        # TODO generate C code to observe/access HMI tree variables
        svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c")
        svghmi_c_file = open(svghmi_c_filepath, 'r')
        svghmi_c_code = svghmi_c_file.read()
        svghmi_c_file.close()
        svghmi_c_code = svghmi_c_code % { "the code": "/* TODO */"}

        gen_svghmi_c_path = os.path.join(buildpath, "svghmi.c")
        gen_svghmi_c = open(gen_svghmi_c_path, 'w')
        gen_svghmi_c.write(svghmi_c_code)
        gen_svghmi_c.close()

        return (["svghmi"], [(gen_svghmi_c_path, IECCFLAGS)], True), ""

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())

    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 fetch HMI tree from library

        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)