26 |
26 |
27 |
27 |
28 import os |
28 import os |
29 import collections |
29 import collections |
30 import shutil |
30 import shutil |
31 import platform as platform_module |
|
32 from zope.interface import implementer |
31 from zope.interface import implementer |
33 from nevow import appserver, inevow, tags, loaders, athena, url, rend |
32 from nevow import appserver, inevow, tags, loaders, athena, url, rend |
34 from nevow.page import renderer |
33 from nevow.page import renderer |
35 from nevow.static import File |
34 from nevow.static import File |
36 from formless import annotate |
35 from formless import annotate |
97 |
96 |
98 setattr(self, 'action_' + name, callback) |
97 setattr(self, 'action_' + name, callback) |
99 |
98 |
100 self.bindingsNames.append(name) |
99 self.bindingsNames.append(name) |
101 |
100 |
|
101 customSettingsURLs = {} |
|
102 def addCustomURL(self, segment, func): |
|
103 self.customSettingsURLs[segment] = func |
|
104 |
|
105 def removeCustomURL(self, segment): |
|
106 del self.customSettingsURLs[segment] |
|
107 |
|
108 def customLocateChild(self, ctx, segments): |
|
109 segment = segments[0] |
|
110 if segment in self.customSettingsURLs: |
|
111 return self.customSettingsURLs[segment](ctx, segments) |
102 |
112 |
103 ConfigurableSettings = ConfigurableBindings() |
113 ConfigurableSettings = ConfigurableBindings() |
104 |
114 |
105 def newExtensionSetting(display, token): |
115 def newExtensionSetting(display, token): |
106 global extensions_settings_od |
116 global extensions_settings_od |
110 |
120 |
111 def removeExtensionSetting(token): |
121 def removeExtensionSetting(token): |
112 global extensions_settings_od |
122 global extensions_settings_od |
113 extensions_settings_od.pop(token) |
123 extensions_settings_od.pop(token) |
114 |
124 |
|
125 |
115 class ISettings(annotate.TypedInterface): |
126 class ISettings(annotate.TypedInterface): |
116 platform = annotate.String(label=_("Platform"), |
127 platform = annotate.String(label=_("Platform"), |
117 default=platform_module.system() + |
128 default=lambda *a,**k:GetPLCObjectSingleton().GetVersions(), |
118 " " + platform_module.release(), |
|
119 immutable=True) |
129 immutable=True) |
120 |
130 |
121 # TODO version ? |
|
122 |
131 |
123 # pylint: disable=no-self-argument |
132 # pylint: disable=no-self-argument |
124 def sendLogMessage( |
133 def sendLogMessage( |
125 ctx=annotate.Context(), |
134 ctx=annotate.Context(), |
126 level=annotate.Choice(LogLevels, |
135 level=annotate.Choice(LogLevels, |
157 uploadFile = annotate.autocallable(uploadFile, |
166 uploadFile = annotate.autocallable(uploadFile, |
158 label=_( |
167 label=_( |
159 "Upload a file to PLC working directory"), |
168 "Upload a file to PLC working directory"), |
160 action=_("Upload")) |
169 action=_("Upload")) |
161 |
170 |
162 customSettingsURLs = { |
|
163 } |
|
164 |
|
165 extensions_settings_od = collections.OrderedDict() |
171 extensions_settings_od = collections.OrderedDict() |
166 |
172 |
|
173 |
|
174 CSS_tags = [tags.link(rel='stylesheet', |
|
175 type='text/css', |
|
176 href=url.here.child("webform_css")), |
|
177 tags.link(rel='stylesheet', |
|
178 type='text/css', |
|
179 href=url.here.child("webinterface_css"))] |
|
180 |
167 @implementer(ISettings) |
181 @implementer(ISettings) |
168 class SettingsPage(rend.Page): |
182 class StyledSettingsPage(rend.Page): |
169 # We deserve a slash |
|
170 addSlash = True |
183 addSlash = True |
171 |
184 |
172 # This makes webform_css url answer some default CSS |
185 # This makes webform_css url answer some default CSS |
173 child_webform_css = webform.defaultCSS |
186 child_webform_css = webform.defaultCSS |
174 child_webinterface_css = File(paths.AbsNeighbourFile(__file__, 'webinterface.css'), 'text/css') |
187 child_webinterface_css = File(paths.AbsNeighbourFile(__file__, 'webinterface.css'), 'text/css') |
|
188 |
|
189 class SettingsPage(StyledSettingsPage): |
175 |
190 |
176 def __getattr__(self, name): |
|
177 global extensions_settings_od |
|
178 if name.startswith('configurable_'): |
|
179 token = name[13:] |
|
180 def configurable_something(ctx): |
|
181 settings, _display = extensions_settings_od[token] |
|
182 return settings |
|
183 return configurable_something |
|
184 raise AttributeError |
|
185 |
|
186 def extensions_settings(self, context, data): |
191 def extensions_settings(self, context, data): |
187 """ Project extensions settings |
192 """ Project extensions settings |
188 Extensions added to Configuration Tree in IDE have their setting rendered here |
193 Extensions added to Configuration Tree in IDE have their setting rendered here |
189 """ |
194 """ |
190 global extensions_settings_od |
195 global extensions_settings_od |
191 res = [] |
196 res = [] |
192 for token in extensions_settings_od: |
197 for token in extensions_settings_od: |
193 _settings, display = extensions_settings_od[token] |
198 _settings, display = extensions_settings_od[token] |
194 res += [tags.h2[display], webform.renderForms(token)] |
199 res += [tags.p[tags.a(href=token)[display]]] |
195 return res |
200 return res |
196 |
201 |
197 docFactory = loaders.stan([tags.html[ |
202 docFactory = loaders.stan([tags.html[ |
198 tags.head[ |
203 tags.head[ |
199 tags.title[_("Beremiz Runtime Settings")], |
204 tags.title[_("Beremiz Runtime Settings")], |
200 tags.link(rel='stylesheet', |
205 CSS_tags |
201 type='text/css', |
|
202 href=url.here.child("webform_css")), |
|
203 tags.link(rel='stylesheet', |
|
204 type='text/css', |
|
205 href=url.here.child("webinterface_css")) |
|
206 ], |
206 ], |
207 tags.body[ |
207 tags.body[ |
|
208 tags.h1["Settings"], |
208 tags.a(href='/')['Back'], |
209 tags.a(href='/')['Back'], |
209 tags.h1["Runtime settings:"], |
210 tags.h2["Runtime service"], |
210 webform.renderForms('staticSettings'), |
211 webform.renderForms('staticSettings'), |
211 tags.h1["Extensions settings:"], |
212 tags.h2["Target specific"], |
212 webform.renderForms('dynamicSettings'), |
213 webform.renderForms('dynamicSettings'), |
|
214 tags.h2["Extensions"], |
213 extensions_settings |
215 extensions_settings |
214 ]]]) |
216 ]]]) |
215 |
217 |
216 def configurable_staticSettings(self, ctx): |
218 def configurable_staticSettings(self, ctx): |
217 return configurable.TypedInterfaceConfigurable(self) |
219 return configurable.TypedInterfaceConfigurable(self) |
240 with open(uploadedfile.filename, 'wb') as destfd: |
242 with open(uploadedfile.filename, 'wb') as destfd: |
241 fobj.seek(0) |
243 fobj.seek(0) |
242 shutil.copyfileobj(fobj,destfd) |
244 shutil.copyfileobj(fobj,destfd) |
243 |
245 |
244 def locateChild(self, ctx, segments): |
246 def locateChild(self, ctx, segments): |
245 if segments[0] in customSettingsURLs: |
247 segment = segments[0] |
246 return customSettingsURLs[segments[0]](ctx, segments) |
248 if segment in extensions_settings_od: |
|
249 settings, display = extensions_settings_od[segment] |
|
250 return ExtensionSettingsPage(settings, display), segments[1:] |
|
251 else: |
|
252 res = ConfigurableSettings.customLocateChild(ctx, segments) |
|
253 if res: |
|
254 return res |
247 return super(SettingsPage, self).locateChild(ctx, segments) |
255 return super(SettingsPage, self).locateChild(ctx, segments) |
|
256 |
|
257 class ExtensionSettingsPage(StyledSettingsPage): |
|
258 |
|
259 docFactory = loaders.stan([ |
|
260 tags.html[ |
|
261 tags.head()[ |
|
262 tags.title[tags.directive("title")], |
|
263 CSS_tags |
|
264 ], |
|
265 tags.body[ |
|
266 tags.h1[tags.directive("title")], |
|
267 tags.a(href='/settings')['Back'], |
|
268 webform.renderForms('settings') |
|
269 ]]]) |
|
270 |
|
271 def render_title(self, ctx, data): |
|
272 return self._display_name |
|
273 |
|
274 def configurable_settings(self, ctx): |
|
275 return self._settings |
|
276 |
|
277 def __init__(self, settings, display): |
|
278 self._settings = settings |
|
279 self._display_name = display |
|
280 |
|
281 def locateChild(self, ctx, segments): |
|
282 res = self._settings.customLocateChild(ctx, segments) |
|
283 if res: |
|
284 return res |
|
285 return super(ExtensionSettingsPage, self).locateChild(ctx, segments) |
|
286 |
248 |
287 |
249 def RegisterWebsite(iface, port): |
288 def RegisterWebsite(iface, port): |
250 website = SettingsPage() |
289 website = SettingsPage() |
251 site = appserver.NevowSite(website) |
290 site = appserver.NevowSite(website) |
252 |
291 |