X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=Ihm%2FCONNECTOR.py;h=45c099217e1cc9a19bf393dae857b0aefd019d4d;hb=9f4ff7ed9afd87c96e11d61e442e39e5511f60d1;hp=09d1fbc16fd7b613fc418765874d990389a194af;hpb=36ca867c4099d6a804374b8f6a2b897d9ea69a09;p=tools%2Feficas.git diff --git a/Ihm/CONNECTOR.py b/Ihm/CONNECTOR.py index 09d1fbc1..45c09921 100644 --- a/Ihm/CONNECTOR.py +++ b/Ihm/CONNECTOR.py @@ -1,42 +1,48 @@ -# -*- coding: iso-8859-15 -*- -# CONFIGURATION MANAGEMENT OF EDF VERSION -# ====================================================================== -# COPYRIGHT (C) 1991 - 2002 EDF R&D WWW.CODE-ASTER.ORG -# THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY -# IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY -# THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR -# (AT YOUR OPTION) ANY LATER VERSION. +#i -*- coding: utf-8 -*- +# Copyright (C) 2007-2013 EDF R&D # -# THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT -# WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF -# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU -# GENERAL PUBLIC LICENSE FOR MORE DETAILS. +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. # -# YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE -# ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER, -# 1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. # +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -# ====================================================================== """ - La classe CONNECTOR sert à enregistrer les observateurs d'objets et à délivrer - les messages émis à ces objets. + La classe CONNECTOR sert a enregistrer les observateurs d'objets et a delivrer + les messages emis a ces objets. - Le principe général est le suivant : un objet (subscriber) s'enregistre aupres du + Le principe general est le suivant : un objet (subscriber) s'enregistre aupres du connecteur global (theconnector) pour observer un objet emetteur de messages (publisher) - sur un canal donné (channel). Il demande à etre notifie par appel d'une fonction (listener). - La séquence est donc : + sur un canal donne (channel). Il demande a etre notifie par appel d'une fonction (listener). + La sequence est donc : - enregistrement du subscriber pour le publisher : theconnector.Connect(publisher,channel,listener,args) - - émission du message par le publisher : theconnector.Emit(publisher,channel,cargs) + - emission du message par le publisher : theconnector.Emit(publisher,channel,cargs) - args et cargs sont des tuples contenant les arguments de la fonction listener qui sera appelée + args et cargs sont des tuples contenant les arguments de la fonction listener qui sera appelee comme suit:: listener(cargs+args) """ +from __future__ import absolute_import +from __future__ import print_function import traceback from copy import copy +import weakref + + +class ConnectorError(Exception): + pass class CONNECTOR: @@ -44,73 +50,143 @@ class CONNECTOR: self.connections={} def Connect(self, object, channel, function, args): - ###print "Connect",object, channel, function, args + #print ("Connect",object, channel, function, args) idx = id(object) - if self.connections.has_key(idx): + #if self.connections.has_key(idx): + if idx in self.connections : channels = self.connections[idx] else: channels = self.connections[idx] = {} - if channels.has_key(channel): + #if channels.has_key(channel): + if channel in channels : receivers = channels[channel] else: receivers = channels[channel] = [] - info = (function, args) - if info in receivers: - receivers.remove(info) - receivers.append(info) - ###print "Connect",receivers + for funct,fargs in receivers[:]: + if funct() is None: + receivers.remove((funct,fargs)) + elif (function,args) == (funct(),fargs): + receivers.remove((funct,fargs)) + + receivers.append((ref(function),args)) def Disconnect(self, object, channel, function, args): try: receivers = self.connections[id(object)][channel] except KeyError: - raise ConnectorError, \ - 'no receivers for channel %s of %s' % (channel, object) - try: - receivers.remove((function, args)) - except ValueError: - raise ConnectorError,\ + raise ConnectorError ( + 'no receivers for channel %s of %s' % (channel, object)) + + for funct,fargs in receivers[:]: + if funct() is None: + receivers.remove((funct,fargs)) + + for funct,fargs in receivers: + if (function,args) == (funct(),fargs): + receivers.remove((funct,fargs)) + if not receivers: + # the list of receivers is empty now, remove the channel + channels = self.connections[id(object)] + del channels[channel] + if not channels: + # the object has no more channels + del self.connections[id(object)] + return + + raise ConnectorError( 'receiver %s%s is not connected to channel %s of %s' \ - % (function, args, channel, object) + % (function, args, channel, object)) + - if not receivers: - # the list of receivers is empty now, remove the channel - channels = self.connections[id(object)] - del channels[channel] - if not channels: - # the object has no more channels - del self.connections[id(object)] def Emit(self, object, channel, *args): - ###print "Emit",object, channel, args + #print "Emit",object, channel, args try: receivers = self.connections[id(object)][channel] except KeyError: return - ###print "Emit",object, channel, receivers + #print "Emit",object, channel, receivers # Attention : copie pour eviter les pbs lies aux deconnexion reconnexion # pendant l'execution des emit - for func, fargs in copy(receivers): + for rfunc, fargs in copy(receivers): try: - apply(func, args + fargs) + func=rfunc() + if func: + #print (func,args,fargs) + #rint args + fargs + #apply(func, args + fargs) + if args + fargs == () : func() + else : func ( args + fargs) + else: + # Le receveur a disparu + if (rfunc,fargs) in receivers:receivers.remove((rfunc,fargs)) except: traceback.print_exc() +def ref(target,callback=None): + #if hasattr(target,"im_self"): + # return BoundMethodWeakref(target) + if hasattr(target,"__self__"): + return BoundMethodWeakref(target) + else: + return weakref.ref(target,callback) + +class BoundMethodWeakref(object): + def __init__(self,callable): + #self.Self=weakref.ref(callable.im_self) + #self.Func=weakref.ref(callable.im_func) + self.Self=weakref.ref(callable.__self__) + self.Func=weakref.ref(callable.__func__) + + def __call__(self): + target=self.Self() + if not target:return None + func=self.Func() + if func: + return func.__get__(self.Self()) + _the_connector =CONNECTOR() Connect = _the_connector.Connect Emit = _the_connector.Emit Disconnect = _the_connector.Disconnect if __name__ == "__main__": - class A:pass + class A: + pass + class B: def add(self,a): - print "add",a + print(("--------------------------------add ", self , a)) + + def __del__(self): + print(("__del__", self)) + + def f(a): + print((f, a)) a=A() b=B() + c=B() + + Connect(a,"add",b.add,()) Connect(a,"add",b.add,()) + Connect(a,"add",c.add,()) + Connect(a,"add",f,()) + Emit(a,"add",1) + + print ("del b") + del b + + Emit(a,"add",1) + print ("del f") + del f + + Emit(a,"add",1) + Disconnect(a,"add",c.add,()) + Emit(a,"add",1) + +