runtime/NevowServer.py
changeset 2225 2a9549e4380e
parent 2219 73042b2d8d65
child 2246 51047284cb0e
child 2266 ed415982a9aa
--- a/runtime/NevowServer.py	Fri Jun 15 09:48:05 2018 +0200
+++ b/runtime/NevowServer.py	Fri Jul 20 11:05:17 2018 +0200
@@ -26,10 +26,19 @@
 from __future__ import absolute_import
 from __future__ import print_function
 import os
-from nevow import appserver, inevow, tags, loaders, athena
+import platform
+from zope.interface import implements
+from nevow import appserver, inevow, tags, loaders, athena, url, rend
 from nevow.page import renderer
+from formless import annotate
+from formless import webform
+from formless import configurable
 from twisted.internet import reactor
+
 import util.paths as paths
+from runtime.loglevels import LogLevels, LogLevelsDict
+
+PAGE_TITLE = 'Beremiz Runtime Web Interface'
 
 xhtml_header = '''<?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
@@ -37,6 +46,7 @@
 '''
 
 WorkingDir = None
+_PySrv = None
 
 
 class PLCHMI(athena.LiveElement):
@@ -49,7 +59,6 @@
     def HMIinitialisation(self):
         self.HMIinitialised(None)
 
-
 class DefaultPLCStartedHMI(PLCHMI):
     docFactory = loaders.stan(
         tags.div(render=tags.directive('liveElement'))[
@@ -119,19 +128,113 @@
         for child in self.liveFragmentChildren[:]:
             child.detach()
 
+class ConfigurableBindings(configurable.Configurable):
+
+    def __init__(self):
+        configurable.Configurable.__init__(self, None)
+        self.bindingsNames = []
+
+    def getBindingNames(self, ctx):
+        return self.bindingsNames
+
+    def addExtension(self, name, desc, fields, btnlabel, callback):
+        def _bind(ctx):
+            return annotate.MethodBinding(
+                'action_'+name,
+                annotate.Method(arguments=[
+                    annotate.Argument(*field)
+                    for field in fields],
+                    label = desc),
+                action = btnlabel)
+        setattr(self, 'bind_'+name, _bind)
+            
+        setattr(self, 'action_'+name, callback)
+
+        self.bindingsNames.append(name)
+
+ConfigurableSettings = ConfigurableBindings()
+
+class ISettings(annotate.TypedInterface):
+    platform = annotate.String(label = _("Platform"),
+                           default = platform.system() + " " + platform.release(),
+                           immutable = True)
+    # TODO version ?
+
+    def sendLogMessage(
+        ctx = annotate.Context(),
+        level = annotate.Choice(LogLevels,
+                                required=True, 
+                                label=_("Log message level")),
+        message = annotate.String(label=_("Message text"))):
+            pass
+    sendLogMessage = annotate.autocallable(sendLogMessage, 
+                                           label=_("Send a message to the log"),
+                                           action=_("Send"))
+
+customSettingsURLs = {
+}
+
+class SettingsPage(rend.Page):
+    # We deserve a slash
+    addSlash = True
+    
+    # This makes webform_css url answer some default CSS
+    child_webform_css = webform.defaultCSS
+
+    implements(ISettings)
+
+
+    docFactory = loaders.stan([tags.html[
+                                   tags.head[
+                                       tags.title[_("Beremiz Runtime Settings")],
+                                       tags.link(rel='stylesheet',
+                                                 type='text/css', 
+                                                 href=url.here.child("webform_css"))
+                                   ],
+                                   tags.body[ 
+                                       tags.h1["Runtime settings:"],
+                                       webform.renderForms('staticSettings'),
+                                       tags.h2["Extensions settings:"],
+                                       webform.renderForms('dynamicSettings'),
+                                   ]]])
+
+    def configurable_staticSettings(self, ctx):
+        return configurable.TypedInterfaceConfigurable(self)
+
+    def configurable_dynamicSettings(self, ctx):
+        return ConfigurableSettings
+    
+    def sendLogMessage(self, level, message, **kwargs):
+        level = LogLevelsDict[level]
+        if _PySrv.plcobj is not None:
+            _PySrv.plcobj.LogMessage(level, "Web form log message: " + message )
+
+    def locateChild(self, ctx, segments):
+        if segments[0] in customSettingsURLs :
+            return customSettingsURLs[segments[0]](ctx, segments)
+        return super(SettingsPage, self).locateChild(ctx, segments)
+
 
 class WebInterface(athena.LivePage):
 
     docFactory = loaders.stan([tags.raw(xhtml_header),
                                tags.html(xmlns="http://www.w3.org/1999/xhtml")[
-                                   tags.head(render=tags.directive('liveglue')),
+                                   tags.head(render=tags.directive('liveglue'))[
+                                       tags.title[PAGE_TITLE],
+                                       tags.link(rel='stylesheet',
+                                                 type='text/css', 
+                                                 href=url.here.child("webform_css"))
+                                   ],
                                    tags.body[
                                        tags.div[
-                                           tags.div(render=tags.directive("MainPage"))
+                                           tags.div(render=tags.directive("MainPage")),
                                        ]]]])
     MainPage = MainPage()
     PLCHMI = PLCHMI
 
+    def child_settings(self, context):
+        return SettingsPage()
+
     def __init__(self, plcState=False, *a, **kw):
         super(WebInterface, self).__init__(*a, **kw)
         self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile(__file__, 'webinterface.js')
@@ -184,6 +287,7 @@
         # print "We will be called back when the client disconnects"
 
 
+
 def RegisterWebsite(port):
     website = WebInterface()
     site = appserver.NevowSite(website)
@@ -209,3 +313,9 @@
 
 def website_statuslistener_factory(site):
     return statuslistener(site).listen
+
+
+def SetServer(pysrv):
+    global _PySrv
+    _PySrv = pysrv
+