andrej@1511: #!/usr/bin/env python laurent@371: # -*- coding: utf-8 -*- laurent@371: andrej@1511: # This file is part of Beremiz, a Integrated Development Environment for andrej@1511: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. andrej@1511: # andrej@1511: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD andrej@1511: # andrej@1511: # See COPYING file for copyrights details. andrej@1511: # andrej@1511: # This program is free software; you can redistribute it and/or andrej@1511: # modify it under the terms of the GNU General Public License andrej@1511: # as published by the Free Software Foundation; either version 2 andrej@1511: # of the License, or (at your option) any later version. andrej@1511: # andrej@1511: # This program is distributed in the hope that it will be useful, andrej@1511: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1511: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1511: # GNU General Public License for more details. andrej@1511: # andrej@1511: # You should have received a copy of the GNU General Public License andrej@1511: # along with this program; if not, write to the Free Software andrej@1511: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. andrej@1511: laurent@371: import os laurent@371: laurent@371: from nevow import rend, appserver, inevow, tags, loaders, athena laurent@371: import simplejson as json laurent@371: laurent@371: svgfile = '%(svgfile)s' laurent@371: laurent@381: svguiWidgets = {} laurent@381: laurent@381: currentId = 0 laurent@381: def getNewId(): laurent@381: global currentId laurent@381: currentId += 1 laurent@381: return currentId laurent@371: laurent@371: class SvguiWidget: laurent@371: laurent@381: def __init__(self, classname, id, **kwargs): laurent@371: self.classname = classname laurent@381: self.id = id laurent@371: self.attrs = kwargs.copy() laurent@381: self.inputs = {} laurent@381: self.outputs = {} laurent@371: self.inhibit = False laurent@371: self.changed = False laurent@371: laurent@381: def setinput(self, attrname, value): laurent@381: self.inputs[attrname] = value laurent@371: laurent@381: def getinput(self, attrname, default=None): laurent@381: if not self.inputs.has_key(attrname): laurent@381: self.inputs[attrname] = default laurent@381: return self.inputs[attrname] laurent@371: laurent@381: def setoutput(self, attrname, value): laurent@381: if self.outputs.get(attrname) != value: laurent@381: self.outputs[attrname] = value laurent@381: self.changed = True laurent@381: self.RefreshInterface() laurent@381: laurent@381: def updateoutputs(self, **kwargs): laurent@371: for attrname, value in kwargs.iteritems(): laurent@381: if self.outputs.get(attrname) != value: laurent@381: self.outputs[attrname] = value laurent@371: self.changed = True laurent@381: self.RefreshInterface() laurent@381: laurent@381: def RefreshInterface(self): laurent@371: interface = website.getHMI() laurent@381: if isinstance(interface, SVGUI_HMI) and self.changed and not self.inhibit: laurent@371: self.changed = False laurent@381: d = interface.sendData(self) laurent@381: if d is not None: laurent@381: self.inhibit = True laurent@381: d.addCallback(self.InterfaceRefreshed) laurent@381: laurent@381: def InterfaceRefreshed(self, result): laurent@381: self.inhibit = False laurent@381: if self.changed: laurent@381: self.RefreshInterface() laurent@371: laurent@381: def get_object_init_state(obj): laurent@371: # Convert objects to a dictionary of their representation laurent@381: attrs = obj.attrs.copy() laurent@381: attrs.update(obj.inputs) laurent@381: d = { '__class__': obj.classname, laurent@381: 'id': obj.id, laurent@381: 'kwargs': json.dumps(attrs), laurent@371: } laurent@371: return d laurent@371: laurent@381: def get_object_current_state(obj): laurent@381: # Convert objects to a dictionary of their representation laurent@381: d = { '__class__': obj.classname, laurent@381: 'id': obj.id, laurent@381: 'kwargs': json.dumps(obj.outputs), laurent@381: } laurent@381: return d laurent@371: laurent@381: class SVGUI_HMI(website.PLCHMI): laurent@371: jsClass = u"LiveSVGPage.LiveSVGWidget" laurent@371: laurent@371: docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ laurent@371: tags.xml(loaders.xmlfile(os.path.join(WorkingDir, svgfile))), laurent@371: ]) laurent@381: laurent@381: def HMIinitialisation(self): laurent@381: gadgets = [] laurent@381: for gadget in svguiWidgets.values(): laurent@381: gadgets.append(unicode(json.dumps(gadget, default=get_object_init_state, indent=2), 'ascii')) laurent@381: d = self.callRemote('init', gadgets) laurent@381: d.addCallback(self.HMIinitialised) laurent@381: laurent@381: def sendData(self,data): laurent@381: if self.initialised: laurent@381: return self.callRemote('receiveData',unicode(json.dumps(data, default=get_object_current_state, indent=2), 'ascii')) laurent@381: return None laurent@381: laurent@381: def setattr(self, id, attrname, value): laurent@381: svguiWidgets[id].setinput(attrname, value) laurent@371: laurent@381: def createSVGUIControl(*args, **kwargs): laurent@381: id = getNewId() laurent@381: gad = SvguiWidget(args[0], id, **kwargs) laurent@381: svguiWidgets[id] = gad laurent@381: gadget = [unicode(json.dumps(gad, default=get_object_init_state, indent=2), 'ascii')] laurent@381: interface = website.getHMI() laurent@381: if isinstance(interface, SVGUI_HMI) and interface.initialised: laurent@381: interface.callRemote('init', gadget) laurent@381: return id laurent@371: laurent@381: def setAttr(id, attrname, value): laurent@381: gad = svguiWidgets.get(id, None) laurent@381: if gad is not None: laurent@381: gad.setoutput(attrname, value) laurent@371: laurent@381: def updateAttr(id, **kwargs): laurent@381: gad = svguiWidgets.get(id, None) laurent@381: if gad is not None: laurent@381: gad.updateoutput(**kwargs) laurent@371: laurent@381: def getAttr(id, attrname, default=None): laurent@381: gad = svguiWidgets.get(id, None) laurent@381: if gad is not None: laurent@381: return gad.getinput(attrname, default) laurent@381: return default laurent@381: