andrej@1511: #!/usr/bin/env python andrej@1511: # -*- coding: utf-8 -*- andrej@1511: andrej@1511: # This file is part of Beremiz, a Integrated Development Environment for andrej@1511: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. andrej@1511: # andrej@1511: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD andrej@1680: # Copyright (C) 2017: Andrey Skvortsov andrej@1511: # andrej@1511: # See COPYING file for copyrights details. andrej@1511: # andrej@1511: # This program is free software; you can redistribute it and/or andrej@1511: # modify it under the terms of the GNU General Public License andrej@1511: # as published by the Free Software Foundation; either version 2 andrej@1511: # of the License, or (at your option) any later version. andrej@1511: # andrej@1511: # This program is distributed in the hope that it will be useful, andrej@1511: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1511: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1511: # GNU General Public License for more details. andrej@1511: # andrej@1511: # You should have received a copy of the GNU General Public License andrej@1511: # along with this program; if not, write to the Free Software andrej@1511: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. andrej@1511: laurent@367: import wx andrej@1732: import os andrej@1732: import sys andrej@1732: import shutil laurent@367: from xml.dom import minidom laurent@367: andrej@1680: import util.paths as paths Edouard@728: from py_ext import PythonFileCTNMixin laurent@367: Edouard@728: class WxGladeHMI(PythonFileCTNMixin): laurent@367: Edouard@717: ConfNodeMethods = [ Edouard@734: {"bitmap" : "editWXGLADE", laurent@367: "name" : _("WXGLADE GUI"), laurent@367: "tooltip" : _("Edit a WxWidgets GUI with WXGlade"), laurent@367: "method" : "_editWXGLADE"}, laurent@367: ] laurent@367: Laurent@1163: def GetIconName(self): Laurent@1163: return "wxGlade" Laurent@1163: Edouard@728: def ConfNodePath(self): andrej@1680: return paths.AbsDir(__file__) Edouard@728: Laurent@1061: def _getWXGLADEpath(self, project_path=None): Laurent@1061: if project_path is None: Laurent@1061: project_path = self.CTNPath() Laurent@1061: # define name for wxGlade gui file Laurent@1061: return os.path.join(project_path, "hmi.wxg") laurent@367: andrej@1688: andrej@1688: def GetWxGladePath(self): andrej@1688: path = None andrej@1688: try: andrej@1688: from wxglade import __file__ as fileName andrej@1730: path = os.path.dirname(fileName) andrej@1688: return path andrej@1688: except ImportError: andrej@1688: pass andrej@1688: andrej@1688: defLibDir="/usr/share/wxglade" andrej@1688: if os.path.isdir(defLibDir): andrej@1688: path = defLibDir andrej@1688: andrej@1688: return path andrej@1730: laurent@367: def launch_wxglade(self, options, wait=False): andrej@1688: path = self.GetWxGladePath() laurent@367: glade = os.path.join(path, 'wxglade.py') laurent@367: if wx.Platform == '__WXMSW__': laurent@367: glade = "\"%s\""%glade laurent@367: mode = {False:os.P_NOWAIT, True:os.P_WAIT}[wait] laurent@367: os.spawnv(mode, sys.executable, ["\"%s\""%sys.executable] + [glade] + options) laurent@367: Laurent@1061: def OnCTNSave(self, from_project_path=None): Laurent@1061: if from_project_path is not None: Laurent@1061: shutil.copyfile(self._getWXGLADEpath(from_project_path), Laurent@1061: self._getWXGLADEpath()) Laurent@1061: return PythonFileCTNMixin.OnCTNSave(self, from_project_path) laurent@367: Edouard@718: def CTNGenerate_C(self, buildpath, locations): andrej@1730: Edouard@1155: hmi_frames = [] andrej@1730: laurent@367: wxgfile_path=self._getWXGLADEpath() laurent@367: if os.path.exists(wxgfile_path): laurent@367: wxgfile = open(wxgfile_path, 'r') laurent@367: wxgtree = minidom.parse(wxgfile) laurent@367: wxgfile.close() andrej@1730: laurent@367: for node in wxgtree.childNodes[1].childNodes: laurent@367: if node.nodeType == wxgtree.ELEMENT_NODE: Edouard@1155: hmi_frames.append({ Edouard@1155: "name" : node.getAttribute("name"), Edouard@1155: "class" : node.getAttribute("class"), Edouard@1155: "handlers" : [ andrej@1730: hnode.firstChild.data for hnode in Edouard@1155: node.getElementsByTagName("handler")]}) andrej@1730: laurent@367: hmipyfile_path=os.path.join(self._getBuildPath(), "hmi.py") laurent@367: if wx.Platform == '__WXMSW__': laurent@367: wxgfile_path = "\"%s\""%wxgfile_path laurent@384: wxghmipyfile_path = "\"%s\""%hmipyfile_path laurent@384: else: laurent@384: wxghmipyfile_path = hmipyfile_path laurent@384: self.launch_wxglade(['-o', wxghmipyfile_path, '-g', 'python', wxgfile_path], wait=True) andrej@1730: laurent@367: hmipyfile = open(hmipyfile_path, 'r') Edouard@1132: define_hmi = hmipyfile.read().decode('utf-8') laurent@367: hmipyfile.close() andrej@1730: Laurent@1256: else: Laurent@1256: define_hmi = "" andrej@1730: andrej@1730: declare_hmi = "\n".join(["%(name)s = None\n" % x + Edouard@1155: "\n".join(["%(class)s.%(h)s = %(h)s"% Edouard@1155: dict(x,h=h) for h in x['handlers']]) Edouard@1155: for x in hmi_frames]) Laurent@1256: global_hmi = ("global %s\n"%",".join( andrej@1730: [x["name"] for x in hmi_frames]) Laurent@1256: if len(hmi_frames) > 0 else "") Edouard@1155: init_hmi = "\n".join(["""\ Edouard@1132: def OnCloseFrame(evt): Edouard@1132: wx.MessageBox(_("Please stop PLC to close")) Edouard@1132: Edouard@1132: %(name)s = %(class)s(None) Edouard@1132: %(name)s.Bind(wx.EVT_CLOSE, OnCloseFrame) Edouard@1132: %(name)s.Show() Edouard@1155: """ % x for x in hmi_frames]) Edouard@1155: cleanup_hmi = "\n".join( andrej@1730: ["if %(name)s is not None: %(name)s.Destroy()" % x Edouard@1155: for x in hmi_frames]) andrej@1730: Edouard@1132: self.PreSectionsTexts = { Edouard@1155: "globals":define_hmi, Edouard@1132: "start":global_hmi, Laurent@1151: "stop":global_hmi + cleanup_hmi Edouard@1132: } Edouard@1132: self.PostSectionsTexts = { Edouard@1155: "globals":declare_hmi, Edouard@1132: "start":init_hmi, Edouard@1132: } Laurent@1124: Edouard@1132: return PythonFileCTNMixin.CTNGenerate_C(self, buildpath, locations) laurent@367: laurent@367: def _editWXGLADE(self): laurent@367: wxg_filename = self._getWXGLADEpath() greg@427: open_wxglade = True Edouard@718: if not self.GetCTRoot().CheckProjectPathPerm(): Edouard@718: dialog = wx.MessageDialog(self.GetCTRoot().AppFrame, greg@427: _("You don't have write permissions.\nOpen wxGlade anyway ?"), greg@427: _("Open wxGlade"), greg@427: wx.YES_NO|wx.ICON_QUESTION) greg@427: open_wxglade = dialog.ShowModal() == wx.ID_YES greg@427: dialog.Destroy() greg@427: if open_wxglade: greg@427: if not os.path.exists(wxg_filename): greg@427: hmi_name = self.BaseParams.getName() greg@427: open(wxg_filename,"w").write(""" greg@427: greg@427: greg@427: greg@427: frame_1 laurent@834: laurent@834: wxVERTICAL laurent@834: laurent@834: greg@427: greg@427: greg@427: """ % {"name": hmi_name, "class": "Class_%s" % hmi_name}) greg@427: if wx.Platform == '__WXMSW__': greg@427: wxg_filename = "\"%s\""%wxg_filename greg@427: self.launch_wxglade([wxg_filename])