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 |
|
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 |
117 |
126 |
118 def detachFragmentChildren(self): |
127 def detachFragmentChildren(self): |
119 for child in self.liveFragmentChildren[:]: |
128 for child in self.liveFragmentChildren[:]: |
120 child.detach() |
129 child.detach() |
121 |
130 |
|
131 class ConfigurableBindings(configurable.Configurable): |
|
132 |
|
133 def __init__(self): |
|
134 configurable.Configurable.__init__(self, None) |
|
135 self.bindingsNames = [] |
|
136 |
|
137 def getBindingNames(self, ctx): |
|
138 return self.bindingsNames |
|
139 |
|
140 def addExtension(self, name, desc, fields, btnlabel, callback): |
|
141 def _bind(ctx): |
|
142 return annotate.MethodBinding( |
|
143 'action_'+name, |
|
144 annotate.Method(arguments=[ |
|
145 annotate.Argument(*field) |
|
146 for field in fields], |
|
147 label = desc), |
|
148 action = btnlabel) |
|
149 setattr(self, 'bind_'+name, _bind) |
|
150 |
|
151 setattr(self, 'action_'+name, callback) |
|
152 |
|
153 self.bindingsNames.append(name) |
|
154 |
|
155 ConfigurableSettings = ConfigurableBindings() |
|
156 |
|
157 class ISettings(annotate.TypedInterface): |
|
158 platform = annotate.String(label = _("Platform"), |
|
159 default = platform.system() + " " + platform.release(), |
|
160 immutable = True) |
|
161 # TODO version ? |
|
162 |
|
163 def sendLogMessage( |
|
164 ctx = annotate.Context(), |
|
165 level = annotate.Choice(LogLevels, |
|
166 required=True, |
|
167 label=_("Log message level")), |
|
168 message = annotate.String(label=_("Message text"))): |
|
169 pass |
|
170 sendLogMessage = annotate.autocallable(sendLogMessage, |
|
171 label=_("Send a message to the log"), |
|
172 action=_("Send")) |
|
173 |
|
174 customSettingsURLs = { |
|
175 } |
|
176 |
|
177 class SettingsPage(rend.Page): |
|
178 # We deserve a slash |
|
179 addSlash = True |
|
180 |
|
181 # This makes webform_css url answer some default CSS |
|
182 child_webform_css = webform.defaultCSS |
|
183 |
|
184 implements(ISettings) |
|
185 |
|
186 |
|
187 docFactory = loaders.stan([tags.html[ |
|
188 tags.head[ |
|
189 tags.title[_("Beremiz Runtime Settings")], |
|
190 tags.link(rel='stylesheet', |
|
191 type='text/css', |
|
192 href=url.here.child("webform_css")) |
|
193 ], |
|
194 tags.body[ |
|
195 tags.h1["Runtime settings:"], |
|
196 webform.renderForms('staticSettings'), |
|
197 tags.h2["Extensions settings:"], |
|
198 webform.renderForms('dynamicSettings'), |
|
199 ]]]) |
|
200 |
|
201 def configurable_staticSettings(self, ctx): |
|
202 return configurable.TypedInterfaceConfigurable(self) |
|
203 |
|
204 def configurable_dynamicSettings(self, ctx): |
|
205 return ConfigurableSettings |
|
206 |
|
207 def sendLogMessage(self, level, message, **kwargs): |
|
208 level = LogLevelsDict[level] |
|
209 if _PySrv.plcobj is not None: |
|
210 _PySrv.plcobj.LogMessage(level, "Web form log message: " + message ) |
|
211 |
|
212 def locateChild(self, ctx, segments): |
|
213 if segments[0] in customSettingsURLs : |
|
214 return customSettingsURLs[segments[0]](ctx, segments) |
|
215 return super(SettingsPage, self).locateChild(ctx, segments) |
|
216 |
122 |
217 |
123 class WebInterface(athena.LivePage): |
218 class WebInterface(athena.LivePage): |
124 |
219 |
125 docFactory = loaders.stan([tags.raw(xhtml_header), |
220 docFactory = loaders.stan([tags.raw(xhtml_header), |
126 tags.html(xmlns="http://www.w3.org/1999/xhtml")[ |
221 tags.html(xmlns="http://www.w3.org/1999/xhtml")[ |
127 tags.head(render=tags.directive('liveglue')), |
222 tags.head(render=tags.directive('liveglue'))[ |
|
223 tags.title[PAGE_TITLE], |
|
224 tags.link(rel='stylesheet', |
|
225 type='text/css', |
|
226 href=url.here.child("webform_css")) |
|
227 ], |
128 tags.body[ |
228 tags.body[ |
129 tags.div[ |
229 tags.div[ |
130 tags.div(render=tags.directive("MainPage")) |
230 tags.div(render=tags.directive("MainPage")), |
131 ]]]]) |
231 ]]]]) |
132 MainPage = MainPage() |
232 MainPage = MainPage() |
133 PLCHMI = PLCHMI |
233 PLCHMI = PLCHMI |
|
234 |
|
235 def child_settings(self, context): |
|
236 return SettingsPage() |
134 |
237 |
135 def __init__(self, plcState=False, *a, **kw): |
238 def __init__(self, plcState=False, *a, **kw): |
136 super(WebInterface, self).__init__(*a, **kw) |
239 super(WebInterface, self).__init__(*a, **kw) |
137 self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile(__file__, 'webinterface.js') |
240 self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile(__file__, 'webinterface.js') |
138 self.plcState = plcState |
241 self.plcState = plcState |