1 #i -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2021 EDF R&D
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 La classe CONNECTOR sert a enregistrer les observateurs d'objets et a delivrer
22 les messages emis a ces objets.
24 Le principe general est le suivant : un objet (subscriber) s'enregistre aupres du
25 connecteur global (theconnector) pour observer un objet emetteur de messages (publisher)
26 sur un canal donne (channel). Il demande a etre notifie par appel d'une fonction (listener).
27 La sequence est donc :
29 - enregistrement du subscriber pour le publisher : theconnector.Connect(publisher,channel,listener,args)
30 - emission du message par le publisher : theconnector.Emit(publisher,channel,cargs)
32 args et cargs sont des tuples contenant les arguments de la fonction listener qui sera appelee
37 from __future__ import absolute_import
38 from __future__ import print_function
44 class ConnectorError(Exception):
52 def Connect(self, object, channel, function, args):
53 #print ("Connect",object, channel, function, args)
55 #if self.connections.has_key(idx):
56 if idx in self.connections :
57 channels = self.connections[idx]
59 channels = self.connections[idx] = {}
61 #if channels.has_key(channel):
62 if channel in channels :
63 receivers = channels[channel]
65 receivers = channels[channel] = []
67 for funct,fargs in receivers[:]:
69 receivers.remove((funct,fargs))
70 elif (function,args) == (funct(),fargs):
71 receivers.remove((funct,fargs))
73 receivers.append((ref(function),args))
76 def Disconnect(self, object, channel, function, args):
78 receivers = self.connections[id(object)][channel]
80 raise ConnectorError (
81 'no receivers for channel %s of %s' % (channel, object))
83 for funct,fargs in receivers[:]:
85 receivers.remove((funct,fargs))
87 for funct,fargs in receivers:
88 if (function,args) == (funct(),fargs):
89 receivers.remove((funct,fargs))
91 # the list of receivers is empty now, remove the channel
92 channels = self.connections[id(object)]
95 # the object has no more channels
96 del self.connections[id(object)]
100 'receiver %s%s is not connected to channel %s of %s' \
101 % (function, args, channel, object))
105 def Emit(self, object, channel, *args):
106 #print "Emit",object, channel, args
108 receivers = self.connections[id(object)][channel]
111 #print "Emit",object, channel, receivers
112 # Attention : copie pour eviter les pbs lies aux deconnexion reconnexion
113 # pendant l'execution des emit
114 for rfunc, fargs in copy(receivers):
118 #print (func,args,fargs)
120 #apply(func, args + fargs)
121 if args + fargs == () : func()
122 else : func ( args + fargs)
124 # Le receveur a disparu
125 if (rfunc,fargs) in receivers:receivers.remove((rfunc,fargs))
127 traceback.print_exc()
129 def ref(target,callback=None):
130 #if hasattr(target,"im_self"):
131 # return BoundMethodWeakref(target)
132 if hasattr(target,"__self__"):
133 return BoundMethodWeakref(target)
135 return weakref.ref(target,callback)
137 class BoundMethodWeakref(object):
138 def __init__(self,callable):
139 #self.Self=weakref.ref(callable.im_self)
140 #self.Func=weakref.ref(callable.im_func)
141 self.Self=weakref.ref(callable.__self__)
142 self.Func=weakref.ref(callable.__func__)
146 if not target:return None
149 return func.__get__(self.Self())
151 _the_connector =CONNECTOR()
152 Connect = _the_connector.Connect
153 Emit = _the_connector.Emit
154 Disconnect = _the_connector.Disconnect
156 if __name__ == "__main__":
162 print(("--------------------------------add ", self , a))
165 print(("__del__", self))
174 Connect(a,"add",b.add,())
175 Connect(a,"add",b.add,())
176 Connect(a,"add",c.add,())
177 Connect(a,"add",f,())
189 Disconnect(a,"add",c.add,())