1 #Copyright (C) 2008 Codethink Ltd
3 #This library is free software; you can redistribute it and/or
4 #modify it under the terms of the GNU Lesser General Public
5 #License version 2 as published by the Free Software Foundation.
7 #This program is distributed in the hope that it will be useful,
8 #but WITHOUT ANY WARRANTY; without even the implied warranty of
9 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 #GNU General Public License for more details.
11 #You should have received a copy of the GNU Lesser General Public License
12 #along with this program; if not, write to the Free Software
13 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 from event import Event as _Event
19 #------------------------------------------------------------------------------
21 class _CacheData(object):
31 def __init__(self, data):
34 def _update(self, data):
35 #Don't cache the path here, used as lookup in cache object dict.
42 self.description) = data
44 #------------------------------------------------------------------------------
46 def _list_items_added_removed (l1, l2):
48 Returns a tuple (boolean, boolean).
49 The first value indicates if, when
50 moving from l1 to l2, any items have been added.
51 The second value indicates whether any items have
54 l1notl2 = [item for item in l1 if item not in l2]
55 l2notl1 = [item for item in l2 if item not in l1]
56 return ((len(l1notl2) > 0), (len(l2notl1) > 0))
58 #------------------------------------------------------------------------------
60 class AccessibleCache(object):
62 There is one accessible cache per application.
63 For each application the accessible cache stores
64 data on every accessible object within the app.
66 It also acts as the factory for creating client
67 side proxies for these accessible objects.
69 connection - DBus connection.
70 busName - Name of DBus connection where cache interface resides.
73 _PATH = '/org/freedesktop/atspi/tree'
74 _INTERFACE = 'org.freedesktop.atspi.Tree'
75 _GET_METHOD = 'getTree'
76 _UPDATE_SIGNAL = 'updateTree'
78 def __init__(self, registry, connection, bus_name):
82 connection - DBus connection.
83 busName - Name of DBus connection where cache interface resides.
85 self._registry = registry
86 self._connection = connection
87 self._bus_name = bus_name
89 obj = connection.get_object(bus_name, self._PATH, introspect=False)
90 itf = _dbus.Interface(obj, self._INTERFACE)
94 get_method = itf.get_dbus_method(self._GET_METHOD)
95 self._update_objects(get_method())
97 self._signalMatch = itf.connect_to_signal(self._UPDATE_SIGNAL, self._update_handler)
99 obj = connection.get_object(self._bus_name, self._PATH, introspect=False)
100 itf = _dbus.Interface(obj, self._INTERFACE)
102 self._root = itf.getRoot()
104 def __getitem__(self, key):
105 return self._objects[key]
107 def __contains__(self, key):
108 return key in self._objects
110 def _dispatch_event(self, olddata, newdata):
111 if olddata.name != newdata.name:
112 event = _Event(self._registry._cache,
115 "org.freedesktop.atspi.Event.Object",
117 ("name", 0, 0, newdata.name))
118 self._registry._notifyNameChange(event)
120 if olddata.description != newdata.description:
121 event = _Event(self._registry._cache,
124 "org.freedesktop.atspi.Event.Object",
126 ("description", 0, 0, description))
127 self._registry._notifyDescriptionChange(event)
129 if olddata.parent != newdata.parent:
130 event = _Event(self._registry._cache,
133 "org.freedesktop.atspi.Event.Object",
135 ("parent", 0, 0, ""))
136 self._registry._notifyParentChange(event)
138 added, removed = _list_items_added_removed (olddata.children, newdata.children):
141 event = _Event(self._registry._cache,
144 "org.freedesktop.atspi.Event.Object",
147 self._registry._notifyChildrenChange(event)
150 event = _Event(self._registry._cache,
153 "org.freedesktop.atspi.Event.Object",
155 ("remove", 0, 0, ""))
156 self._registry._notifyChildrenChange(event)
158 def _update_handler(self, update, remove):
159 self._remove_objects(remove)
160 self._update_objects(update)
162 def _update_objects(self, objects):
163 cache_update_objects = []
165 #First element is the object path.
167 if path in self._objects:
168 olddata = self._objects[path]
169 newdata = _CacheData(data)
170 cache_update_objects.append((olddata, newdata))
171 self._objects[path] = newdata
173 self._objects[path] = _CacheData(data)
174 for old, new in cache_update_objects:
175 self._dispatch_event(old, new)
177 def _remove_objects(self, paths):
179 # TODO I'm squashing a possible error here
180 # I've seen things appear to be deleted twice
181 # which needs investigation
183 del(self._objects[path])
190 root = property(fget=_get_root)
192 #END---------------------------------------------------------------------------