22 # You should have received a copy of the GNU General Public License |
22 # You should have received a copy of the GNU General Public License |
23 # along with this program; if not, write to the Free Software |
23 # along with this program; if not, write to the Free Software |
24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
25 |
25 |
26 import wx |
26 import wx |
27 import os, sys, shutil |
27 import os |
|
28 import sys |
|
29 import shutil |
28 from xml.dom import minidom |
30 from xml.dom import minidom |
29 |
31 |
30 import util.paths as paths |
32 import util.paths as paths |
31 from py_ext import PythonFileCTNMixin |
33 from py_ext import PythonFileCTNMixin |
32 |
34 |
|
35 |
33 class WxGladeHMI(PythonFileCTNMixin): |
36 class WxGladeHMI(PythonFileCTNMixin): |
34 |
37 |
35 ConfNodeMethods = [ |
38 ConfNodeMethods = [ |
36 {"bitmap" : "editWXGLADE", |
39 { |
37 "name" : _("WXGLADE GUI"), |
40 "bitmap": "editWXGLADE", |
38 "tooltip" : _("Edit a WxWidgets GUI with WXGlade"), |
41 "name": _("WXGLADE GUI"), |
39 "method" : "_editWXGLADE"}, |
42 "tooltip": _("Edit a WxWidgets GUI with WXGlade"), |
|
43 "method": "_editWXGLADE" |
|
44 }, |
40 ] |
45 ] |
41 |
46 |
42 def GetIconName(self): |
47 def GetIconName(self): |
43 return "wxGlade" |
48 return "wxGlade" |
44 |
49 |
49 if project_path is None: |
54 if project_path is None: |
50 project_path = self.CTNPath() |
55 project_path = self.CTNPath() |
51 # define name for wxGlade gui file |
56 # define name for wxGlade gui file |
52 return os.path.join(project_path, "hmi.wxg") |
57 return os.path.join(project_path, "hmi.wxg") |
53 |
58 |
54 |
|
55 def GetWxGladePath(self): |
59 def GetWxGladePath(self): |
56 path = None |
60 path = None |
57 try: |
61 try: |
58 from wxglade import __file__ as fileName |
62 from wxglade import __file__ as fileName |
59 path = os.path.dirname(fileName) |
63 path = os.path.dirname(fileName) |
60 return path |
64 return path |
61 except ImportError: |
65 except ImportError: |
62 pass |
66 pass |
63 |
67 |
64 defLibDir="/usr/share/wxglade" |
68 defLibDir = "/usr/share/wxglade" |
65 if os.path.isdir(defLibDir): |
69 if os.path.isdir(defLibDir): |
66 path = defLibDir |
70 path = defLibDir |
67 |
71 |
68 return path |
72 return path |
69 |
73 |
70 def launch_wxglade(self, options, wait=False): |
74 def launch_wxglade(self, options, wait=False): |
71 path = self.GetWxGladePath() |
75 path = self.GetWxGladePath() |
72 glade = os.path.join(path, 'wxglade.py') |
76 glade = os.path.join(path, 'wxglade.py') |
73 if wx.Platform == '__WXMSW__': |
77 if wx.Platform == '__WXMSW__': |
74 glade = "\"%s\""%glade |
78 glade = "\"%s\"" % glade |
75 mode = {False:os.P_NOWAIT, True:os.P_WAIT}[wait] |
79 mode = {False: os.P_NOWAIT, True: os.P_WAIT}[wait] |
76 os.spawnv(mode, sys.executable, ["\"%s\""%sys.executable] + [glade] + options) |
80 os.spawnv(mode, sys.executable, ["\"%s\"" % sys.executable] + [glade] + options) |
77 |
81 |
78 def OnCTNSave(self, from_project_path=None): |
82 def OnCTNSave(self, from_project_path=None): |
79 if from_project_path is not None: |
83 if from_project_path is not None: |
80 shutil.copyfile(self._getWXGLADEpath(from_project_path), |
84 shutil.copyfile(self._getWXGLADEpath(from_project_path), |
81 self._getWXGLADEpath()) |
85 self._getWXGLADEpath()) |
82 return PythonFileCTNMixin.OnCTNSave(self, from_project_path) |
86 return PythonFileCTNMixin.OnCTNSave(self, from_project_path) |
83 |
87 |
84 def CTNGenerate_C(self, buildpath, locations): |
88 def CTNGenerate_C(self, buildpath, locations): |
85 |
89 |
86 hmi_frames = [] |
90 hmi_frames = [] |
87 |
91 |
88 wxgfile_path=self._getWXGLADEpath() |
92 wxgfile_path = self._getWXGLADEpath() |
89 if os.path.exists(wxgfile_path): |
93 if os.path.exists(wxgfile_path): |
90 wxgfile = open(wxgfile_path, 'r') |
94 wxgfile = open(wxgfile_path, 'r') |
91 wxgtree = minidom.parse(wxgfile) |
95 wxgtree = minidom.parse(wxgfile) |
92 wxgfile.close() |
96 wxgfile.close() |
93 |
97 |
94 for node in wxgtree.childNodes[1].childNodes: |
98 for node in wxgtree.childNodes[1].childNodes: |
95 if node.nodeType == wxgtree.ELEMENT_NODE: |
99 if node.nodeType == wxgtree.ELEMENT_NODE: |
96 hmi_frames.append({ |
100 hmi_frames.append({ |
97 "name" : node.getAttribute("name"), |
101 "name": node.getAttribute("name"), |
98 "class" : node.getAttribute("class"), |
102 "class": node.getAttribute("class"), |
99 "handlers" : [ |
103 "handlers": [ |
100 hnode.firstChild.data for hnode in |
104 hnode.firstChild.data for hnode in |
101 node.getElementsByTagName("handler")]}) |
105 node.getElementsByTagName("handler")]}) |
102 |
106 |
103 hmipyfile_path=os.path.join(self._getBuildPath(), "hmi.py") |
107 hmipyfile_path = os.path.join(self._getBuildPath(), "hmi.py") |
104 if wx.Platform == '__WXMSW__': |
108 if wx.Platform == '__WXMSW__': |
105 wxgfile_path = "\"%s\""%wxgfile_path |
109 wxgfile_path = "\"%s\"" % wxgfile_path |
106 wxghmipyfile_path = "\"%s\""%hmipyfile_path |
110 wxghmipyfile_path = "\"%s\"" % hmipyfile_path |
107 else: |
111 else: |
108 wxghmipyfile_path = hmipyfile_path |
112 wxghmipyfile_path = hmipyfile_path |
109 self.launch_wxglade(['-o', wxghmipyfile_path, '-g', 'python', wxgfile_path], wait=True) |
113 self.launch_wxglade(['-o', wxghmipyfile_path, '-g', 'python', wxgfile_path], wait=True) |
110 |
114 |
111 hmipyfile = open(hmipyfile_path, 'r') |
115 hmipyfile = open(hmipyfile_path, 'r') |
112 define_hmi = hmipyfile.read().decode('utf-8') |
116 define_hmi = hmipyfile.read().decode('utf-8') |
113 hmipyfile.close() |
117 hmipyfile.close() |
114 |
118 |
115 else: |
119 else: |
116 define_hmi = "" |
120 define_hmi = "" |
117 |
121 |
118 declare_hmi = "\n".join(["%(name)s = None\n" % x + |
122 declare_hmi = "\n".join(["%(name)s = None\n" % x + |
119 "\n".join(["%(class)s.%(h)s = %(h)s"% |
123 "\n".join(["%(class)s.%(h)s = %(h)s" % |
120 dict(x,h=h) for h in x['handlers']]) |
124 dict(x, h=h) for h in x['handlers']]) |
121 for x in hmi_frames]) |
125 for x in hmi_frames]) |
122 global_hmi = ("global %s\n"%",".join( |
126 global_hmi = ("global %s\n" % ",".join( |
123 [x["name"] for x in hmi_frames]) |
127 [x["name"] for x in hmi_frames]) |
124 if len(hmi_frames) > 0 else "") |
128 if len(hmi_frames) > 0 else "") |
125 init_hmi = "\n".join(["""\ |
129 init_hmi = "\n".join(["""\ |
126 def OnCloseFrame(evt): |
130 def OnCloseFrame(evt): |
127 wx.MessageBox(_("Please stop PLC to close")) |
131 wx.MessageBox(_("Please stop PLC to close")) |
128 |
132 |
129 %(name)s = %(class)s(None) |
133 %(name)s = %(class)s(None) |
130 %(name)s.Bind(wx.EVT_CLOSE, OnCloseFrame) |
134 %(name)s.Bind(wx.EVT_CLOSE, OnCloseFrame) |
131 %(name)s.Show() |
135 %(name)s.Show() |
132 """ % x for x in hmi_frames]) |
136 """ % x for x in hmi_frames]) |
133 cleanup_hmi = "\n".join( |
137 cleanup_hmi = "\n".join( |
134 ["if %(name)s is not None: %(name)s.Destroy()" % x |
138 ["if %(name)s is not None: %(name)s.Destroy()" % x |
135 for x in hmi_frames]) |
139 for x in hmi_frames]) |
136 |
140 |
137 self.PreSectionsTexts = { |
141 self.PreSectionsTexts = { |
138 "globals":define_hmi, |
142 "globals": define_hmi, |
139 "start":global_hmi, |
143 "start": global_hmi, |
140 "stop":global_hmi + cleanup_hmi |
144 "stop": global_hmi + cleanup_hmi |
141 } |
145 } |
142 self.PostSectionsTexts = { |
146 self.PostSectionsTexts = { |
143 "globals":declare_hmi, |
147 "globals": declare_hmi, |
144 "start":init_hmi, |
148 "start": init_hmi, |
145 } |
149 } |
146 |
150 |
147 return PythonFileCTNMixin.CTNGenerate_C(self, buildpath, locations) |
151 return PythonFileCTNMixin.CTNGenerate_C(self, buildpath, locations) |
148 |
152 |
149 def _editWXGLADE(self): |
153 def _editWXGLADE(self): |
151 open_wxglade = True |
155 open_wxglade = True |
152 if not self.GetCTRoot().CheckProjectPathPerm(): |
156 if not self.GetCTRoot().CheckProjectPathPerm(): |
153 dialog = wx.MessageDialog(self.GetCTRoot().AppFrame, |
157 dialog = wx.MessageDialog(self.GetCTRoot().AppFrame, |
154 _("You don't have write permissions.\nOpen wxGlade anyway ?"), |
158 _("You don't have write permissions.\nOpen wxGlade anyway ?"), |
155 _("Open wxGlade"), |
159 _("Open wxGlade"), |
156 wx.YES_NO|wx.ICON_QUESTION) |
160 wx.YES_NO | wx.ICON_QUESTION) |
157 open_wxglade = dialog.ShowModal() == wx.ID_YES |
161 open_wxglade = dialog.ShowModal() == wx.ID_YES |
158 dialog.Destroy() |
162 dialog.Destroy() |
159 if open_wxglade: |
163 if open_wxglade: |
160 if not os.path.exists(wxg_filename): |
164 if not os.path.exists(wxg_filename): |
161 hmi_name = self.BaseParams.getName() |
165 hmi_name = self.BaseParams.getName() |
162 open(wxg_filename,"w").write("""<?xml version="1.0"?> |
166 open(wxg_filename, "w").write("""<?xml version="1.0"?> |
163 <application path="" name="" class="" option="0" language="python" top_window="%(name)s" encoding="UTF-8" use_gettext="0" overwrite="0" use_new_namespace="1" for_version="2.8" is_template="0"> |
167 <application path="" name="" class="" option="0" language="python" top_window="%(name)s" encoding="UTF-8" use_gettext="0" overwrite="0" use_new_namespace="1" for_version="2.8" is_template="0"> |
164 <object class="%(class)s" name="%(name)s" base="EditFrame"> |
168 <object class="%(class)s" name="%(name)s" base="EditFrame"> |
165 <style>wxDEFAULT_FRAME_STYLE</style> |
169 <style>wxDEFAULT_FRAME_STYLE</style> |
166 <title>frame_1</title> |
170 <title>frame_1</title> |
167 <object class="wxBoxSizer" name="sizer_1" base="EditBoxSizer"> |
171 <object class="wxBoxSizer" name="sizer_1" base="EditBoxSizer"> |