Edouard@2745: #!/usr/bin/env python Edouard@2745: # -*- coding: utf-8 -*- Edouard@2745: Edouard@2745: # This file is part of Beremiz Edouard@2745: # Copyright (C) 2019: Edouard TISSERANT Edouard@2745: # Edouard@2745: # See COPYING file for copyrights details. Edouard@2745: Edouard@2745: from __future__ import absolute_import Edouard@2745: import os Edouard@2745: import shutil Edouard@2745: Edouard@2745: import wx Edouard@2745: Edouard@2745: import util.paths as paths Edouard@2745: from POULibrary import POULibrary Edouard@2745: from docutil import open_svg Edouard@2753: from lxml import etree Edouard@2745: Edouard@2749: HMI_TYPES_DESC = { Edouard@2749: "HMI_CLASS":{}, Edouard@2749: "HMI_LABEL":{}, Edouard@2749: "HMI_STRING":{}, Edouard@2749: "HMI_INT":{}, Edouard@2749: "HMI_REAL":{} Edouard@2749: } Edouard@2749: Edouard@2749: HMI_TYPES = HMI_TYPES_DESC.keys() Edouard@2745: Edouard@2753: from XSLTransform import XSLTransform Edouard@2753: Edouard@2753: ScriptDirectory = paths.AbsDir(__file__) Edouard@2753: Edouard@2745: class SVGHMILibrary(POULibrary): Edouard@2745: def GetLibraryPath(self): Edouard@2750: return paths.AbsNeighbourFile(__file__, "pous.xml") Edouard@2745: Edouard@2749: def Generate_C(self, buildpath, varlist, IECCFLAGS): Edouard@2749: Edouard@2749: # Filter known HMI types Edouard@2749: hmi_types_instances = [v for v in varlist if v["derived"] in HMI_TYPES] Edouard@2749: Edouard@2749: # TODO deduce HMI tree Edouard@2749: Edouard@2749: # TODO generate C code to observe/access HMI tree variables Edouard@2749: svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c") Edouard@2749: svghmi_c_file = open(svghmi_c_filepath, 'r') Edouard@2749: svghmi_c_code = svghmi_c_file.read() Edouard@2749: svghmi_c_file.close() Edouard@2753: svghmi_c_code = svghmi_c_code % { "hmi_tree": "TODO !!!"} Edouard@2749: Edouard@2749: gen_svghmi_c_path = os.path.join(buildpath, "svghmi.c") Edouard@2749: gen_svghmi_c = open(gen_svghmi_c_path, 'w') Edouard@2749: gen_svghmi_c.write(svghmi_c_code) Edouard@2749: gen_svghmi_c.close() Edouard@2749: Edouard@2749: return (["svghmi"], [(gen_svghmi_c_path, IECCFLAGS)], True), "" Edouard@2745: Edouard@2745: class SVGHMI(object): Edouard@2745: XSD = """ Edouard@2745: Edouard@2745: Edouard@2745: Edouard@2745: Edouard@2745: Edouard@2745: Edouard@2745: Edouard@2745: Edouard@2745: Edouard@2745: """ Edouard@2745: Edouard@2745: ConfNodeMethods = [ Edouard@2745: { Edouard@2745: "bitmap": "ImportSVG", Edouard@2745: "name": _("Import SVG"), Edouard@2745: "tooltip": _("Import SVG"), Edouard@2745: "method": "_ImportSVG" Edouard@2745: }, Edouard@2745: { Edouard@2745: "bitmap": "ImportSVG", # should be something different Edouard@2745: "name": _("Inkscape"), Edouard@2745: "tooltip": _("Edit HMI"), Edouard@2745: "method": "_StartInkscape" Edouard@2745: }, Edouard@2745: ] Edouard@2745: Edouard@2745: def _getSVGpath(self, project_path=None): Edouard@2745: if project_path is None: Edouard@2745: project_path = self.CTNPath() Edouard@2745: # define name for SVG file containing gui layout Edouard@2745: return os.path.join(project_path, "gui.svg") Edouard@2745: Edouard@2745: Edouard@2745: def OnCTNSave(self, from_project_path=None): Edouard@2745: if from_project_path is not None: Edouard@2745: shutil.copyfile(self._getSVGpath(from_project_path), Edouard@2745: self._getSVGpath()) Edouard@2750: return True Edouard@2745: Edouard@2753: def GetSVGGeometry(self): Edouard@2753: # TODO : invoke inskscape -S, csv-parse output, produce elements Edouard@2753: return [etree.Element("bbox", id="blah0", x="1", y="2", w="3", h="4"), Edouard@2753: etree.Element("bbox", id="blah1", x="5", y="6", w="7", h="8")] Edouard@2753: Edouard@2745: def CTNGenerate_C(self, buildpath, locations): Edouard@2745: """ Edouard@2745: Return C code generated by iec2c compiler Edouard@2745: when _generate_softPLC have been called Edouard@2745: @param locations: ignored Edouard@2745: @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND Edouard@2745: """ Edouard@2745: Edouard@2749: # TODO fetch HMI tree from library Edouard@2745: Edouard@2745: svgfile = self._getSVGpath() Edouard@2745: if os.path.exists(svgfile): Edouard@2753: Edouard@2753: # TODO : move to __init__ Edouard@2753: transform = XSLTransform(os.path.join(ScriptDirectory, "gen_index_xhtml.xslt"), Edouard@2753: [("GetSVGGeometry", lambda *_ignored:self.GetSVGGeometry())]) Edouard@2753: Edouard@2753: Edouard@2753: # load svg as a DOM with Etree Edouard@2753: svgdom = etree.parse(svgfile) Edouard@2753: Edouard@2753: # call xslt transform on Inkscape's SVG to generate XHTML Edouard@2753: result = transform.transform(svgdom) Edouard@2753: Edouard@2753: print(str(result)) Edouard@2753: print(transform.xslt.error_log) Edouard@2753: Edouard@2753: # TODO Edouard@2745: # - Errors on HMI semantics Edouard@2745: # - ... maybe something to have a global view of what is declared in SVG. Edouard@2753: Edouard@2745: else: Edouard@2745: # TODO : use default svg that expose the HMI tree as-is Edouard@2745: pass Edouard@2745: Edouard@2745: Edouard@2745: res = ([], "", False) Edouard@2745: Edouard@2745: targetpath = os.path.join(self._getBuildPath(), "target.xhtml") Edouard@2745: targetfile = open(targetpath, 'w') Edouard@2745: Edouard@2745: # TODO : DOM to string Edouard@2745: targetfile.write("TODO") Edouard@2745: targetfile.close() Edouard@2745: res += (("target.js", open(targetpath, "rb")),) Edouard@2745: Edouard@2745: # TODO add C code to expose HMI tree variables to shared memory Edouard@2745: # TODO generate a description of shared memory (xml or CSV) Edouard@2745: # that can be loaded by svghmi QTWeb* app or svghmi server Edouard@2745: Edouard@2745: Edouard@2745: return res Edouard@2745: Edouard@2745: def _ImportSVG(self): Edouard@2745: dialog = wx.FileDialog(self.GetCTRoot().AppFrame, _("Choose a SVG file"), os.getcwd(), "", _("SVG files (*.svg)|*.svg|All files|*.*"), wx.OPEN) Edouard@2745: if dialog.ShowModal() == wx.ID_OK: Edouard@2745: svgpath = dialog.GetPath() Edouard@2745: if os.path.isfile(svgpath): Edouard@2745: shutil.copy(svgpath, self._getSVGpath()) Edouard@2745: else: Edouard@2745: self.GetCTRoot().logger.write_error(_("No such SVG file: %s\n") % svgpath) Edouard@2745: dialog.Destroy() Edouard@2745: Edouard@2745: def _StartInkscape(self): Edouard@2745: svgfile = self._getSVGpath() Edouard@2745: open_inkscape = True Edouard@2745: if not self.GetCTRoot().CheckProjectPathPerm(): Edouard@2745: dialog = wx.MessageDialog(self.GetCTRoot().AppFrame, Edouard@2745: _("You don't have write permissions.\nOpen Inkscape anyway ?"), Edouard@2745: _("Open Inkscape"), Edouard@2745: wx.YES_NO | wx.ICON_QUESTION) Edouard@2745: open_inkscape = dialog.ShowModal() == wx.ID_YES Edouard@2745: dialog.Destroy() Edouard@2745: if open_inkscape: Edouard@2745: if not os.path.isfile(svgfile): Edouard@2745: svgfile = None Edouard@2745: open_svg(svgfile)