24 |
24 |
25 |
25 |
26 from __future__ import absolute_import |
26 from __future__ import absolute_import |
27 from __future__ import print_function |
27 from __future__ import print_function |
28 import os |
28 import os |
29 from nevow import appserver, inevow, tags, loaders, athena |
29 import platform as platform_module |
|
30 from zope.interface import implements |
|
31 from nevow import appserver, inevow, tags, loaders, athena, url, rend |
30 from nevow.page import renderer |
32 from nevow.page import renderer |
|
33 from formless import annotate |
|
34 from formless import webform |
|
35 from formless import configurable |
31 from twisted.internet import reactor |
36 from twisted.internet import reactor |
|
37 |
32 import util.paths as paths |
38 import util.paths as paths |
|
39 from runtime.loglevels import LogLevels, LogLevelsDict |
|
40 |
|
41 PAGE_TITLE = 'Beremiz Runtime Web Interface' |
33 |
42 |
34 xhtml_header = '''<?xml version="1.0" encoding="utf-8"?> |
43 xhtml_header = '''<?xml version="1.0" encoding="utf-8"?> |
35 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" |
44 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" |
36 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
45 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
37 ''' |
46 ''' |
38 |
47 |
39 WorkingDir = None |
48 WorkingDir = None |
|
49 _PySrv = None |
40 |
50 |
41 |
51 |
42 class PLCHMI(athena.LiveElement): |
52 class PLCHMI(athena.LiveElement): |
43 |
53 |
44 initialised = False |
54 initialised = False |
118 def detachFragmentChildren(self): |
128 def detachFragmentChildren(self): |
119 for child in self.liveFragmentChildren[:]: |
129 for child in self.liveFragmentChildren[:]: |
120 child.detach() |
130 child.detach() |
121 |
131 |
122 |
132 |
|
133 class ConfigurableBindings(configurable.Configurable): |
|
134 |
|
135 def __init__(self): |
|
136 configurable.Configurable.__init__(self, None) |
|
137 self.bindingsNames = [] |
|
138 |
|
139 def getBindingNames(self, ctx): |
|
140 return self.bindingsNames |
|
141 |
|
142 def addExtension(self, name, desc, fields, btnlabel, callback): |
|
143 def _bind(ctx): |
|
144 return annotate.MethodBinding( |
|
145 'action_' + name, |
|
146 annotate.Method( |
|
147 arguments=[ |
|
148 annotate.Argument(*field) |
|
149 for field in fields], |
|
150 label=desc), |
|
151 action=btnlabel) |
|
152 setattr(self, 'bind_' + name, _bind) |
|
153 |
|
154 setattr(self, 'action_' + name, callback) |
|
155 |
|
156 self.bindingsNames.append(name) |
|
157 |
|
158 |
|
159 ConfigurableSettings = ConfigurableBindings() |
|
160 |
|
161 |
|
162 class ISettings(annotate.TypedInterface): |
|
163 platform = annotate.String(label=_("Platform"), |
|
164 default=platform_module.system() + |
|
165 " " + platform_module.release(), |
|
166 immutable=True) |
|
167 |
|
168 # TODO version ? |
|
169 |
|
170 # pylint: disable=no-self-argument |
|
171 def sendLogMessage( |
|
172 ctx=annotate.Context(), |
|
173 level=annotate.Choice(LogLevels, |
|
174 required=True, |
|
175 label=_("Log message level")), |
|
176 message=annotate.String(label=_("Message text"))): |
|
177 pass |
|
178 |
|
179 sendLogMessage = annotate.autocallable(sendLogMessage, |
|
180 label=_( |
|
181 "Send a message to the log"), |
|
182 action=_("Send")) |
|
183 |
|
184 |
|
185 customSettingsURLs = { |
|
186 } |
|
187 |
|
188 |
|
189 class SettingsPage(rend.Page): |
|
190 # We deserve a slash |
|
191 addSlash = True |
|
192 |
|
193 # This makes webform_css url answer some default CSS |
|
194 child_webform_css = webform.defaultCSS |
|
195 |
|
196 implements(ISettings) |
|
197 |
|
198 docFactory = loaders.stan([ |
|
199 tags.html[ |
|
200 tags.head[ |
|
201 tags.title[_("Beremiz Runtime Settings")], |
|
202 tags.link(rel='stylesheet', |
|
203 type='text/css', |
|
204 href=url.here.child("webform_css")) |
|
205 ], |
|
206 tags.body[ |
|
207 tags.h1["Runtime settings:"], |
|
208 webform.renderForms('staticSettings'), |
|
209 tags.h2["Extensions settings:"], |
|
210 webform.renderForms('dynamicSettings'), |
|
211 ] |
|
212 ] |
|
213 ]) |
|
214 |
|
215 def configurable_staticSettings(self, ctx): |
|
216 return configurable.TypedInterfaceConfigurable(self) |
|
217 |
|
218 def configurable_dynamicSettings(self, ctx): |
|
219 return ConfigurableSettings |
|
220 |
|
221 def sendLogMessage(self, level, message, **kwargs): |
|
222 level = LogLevelsDict[level] |
|
223 if _PySrv.plcobj is not None: |
|
224 _PySrv.plcobj.LogMessage( |
|
225 level, "Web form log message: " + message) |
|
226 |
|
227 def locateChild(self, ctx, segments): |
|
228 if segments[0] in customSettingsURLs: |
|
229 return customSettingsURLs[segments[0]](ctx, segments) |
|
230 return super(SettingsPage, self).locateChild(ctx, segments) |
|
231 |
|
232 |
123 class WebInterface(athena.LivePage): |
233 class WebInterface(athena.LivePage): |
124 |
234 |
125 docFactory = loaders.stan([tags.raw(xhtml_header), |
235 docFactory = loaders.stan([tags.raw(xhtml_header), |
126 tags.html(xmlns="http://www.w3.org/1999/xhtml")[ |
236 tags.html(xmlns="http://www.w3.org/1999/xhtml")[ |
127 tags.head(render=tags.directive('liveglue')), |
237 tags.head(render=tags.directive('liveglue'))[ |
|
238 tags.title[PAGE_TITLE], |
|
239 tags.link(rel='stylesheet', |
|
240 type='text/css', |
|
241 href=url.here.child("webform_css")) |
|
242 ], |
128 tags.body[ |
243 tags.body[ |
129 tags.div[ |
244 tags.div[ |
130 tags.div(render=tags.directive("MainPage")) |
245 tags.div( |
|
246 render=tags.directive( |
|
247 "MainPage")), |
131 ]]]]) |
248 ]]]]) |
132 MainPage = MainPage() |
249 MainPage = MainPage() |
133 PLCHMI = PLCHMI |
250 PLCHMI = PLCHMI |
134 |
251 |
|
252 def child_settings(self, context): |
|
253 return SettingsPage() |
|
254 |
135 def __init__(self, plcState=False, *a, **kw): |
255 def __init__(self, plcState=False, *a, **kw): |
136 super(WebInterface, self).__init__(*a, **kw) |
256 super(WebInterface, self).__init__(*a, **kw) |
137 self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile(__file__, 'webinterface.js') |
257 self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile( |
|
258 __file__, 'webinterface.js') |
138 self.plcState = plcState |
259 self.plcState = plcState |
139 self.MainPage.setPLCState(plcState) |
260 self.MainPage.setPLCState(plcState) |
140 |
261 |
141 def getHMI(self): |
262 def getHMI(self): |
142 return self.MainPage.getHMI() |
263 return self.MainPage.getHMI() |