Partial re-refactor of the accessibles registration code.
[platform/core/uifw/at-spi2-atk.git] / pyatspi / applicationcache.py
1 #Copyright (C) 2008 Codethink Ltd
2
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.
6
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.
14
15 import dbus
16
17 from accessiblecache import AccessibleCache
18 from desktop import Desktop
19 from factory import accessible_factory
20 from event import Event as _Event
21
22 from interfaces import *
23
24 __all__ = [
25            "ApplicationCache",
26            "TestApplicationCache",
27           ]
28
29 #------------------------------------------------------------------------------
30
31 class TestApplicationCache(object):
32         """
33         Test application store, accesses a single application.
34
35         The store object acts as a central class for creating accessible objects.
36         It interfaces with the ATSPI registry to keep account of all accessible
37         applications. It contains the accessible cache objects from each application.
38
39         @registry:   Each accessible cache object must have a reference to the registry
40                      object to send update events.
41
42         @connection: D-Bus connection used to access applications.
43
44         @bus_name:   The test store only accesses one accessible application, this is its
45                      D-Bus path.
46         """
47
48         def __init__(self, registry, connection, bus_name):
49                 self._connection = connection
50
51                 self.application_list = [bus_name]
52                 self.application_cache = {bus_name:AccessibleCache(registry, connection, bus_name)}
53
54         def get_cache_data(self, app_name, acc_path):
55                 """
56                 Returns the cache tuple for the given application and accessible
57                 object path. Throws an IndexError if the cache data is not found.
58                 """
59                 return self.application_cache[app_name][acc_path]
60
61         def create_application(self, app_name):
62                 """
63                 Creates an accessible object for the root of the application
64                 available at the given D-Bus name.
65                 """
66                 cls = accessible_factory.get_accessible_class(ATSPI_APPLICATION)
67                 return cls(app_name, self.application_cache[app_name].root, self, ATSPI_APPLICATION)
68
69         def create_accessible(self, app_name, acc_path, interface, dbus_object=None):
70                 """
71                 Creates an accessible object.
72
73                 @app_name: D-Bus name of the application where the accessible object resides.
74
75                 @acc_path: D-Bus path of the object within the application.
76
77                 @interface: D-Bus interface of the requested object. A different accessible object
78                             class will be created depending on this. Making the function much like 
79                             an accessible object factory.
80
81                 @dbus_object: If a D-Bus object already exists for the accessible object it can be
82                               provided here so that another one is not created.
83                 """
84                 # An acc_path of '/' implies the desktop object, whatever the app_name.
85                 if acc_path == '/':
86                         return Desktop(self)
87                 else:
88                         cls = accessible_factory.get_accessible_class(interface)
89                         return cls(app_name, acc_path, self, interface, dbus_object=dbus_object)
90
91         @property
92         def connection(self):
93                 """
94                 D-Bus connection used by the store.
95                 """
96                 return self._connection
97
98 #------------------------------------------------------------------------------
99
100 class ApplicationCache(object):
101         """
102         Test application store, accesses a single application.
103
104         The store object acts as a central class for creating accessible objects.
105         It interfaces with the ATSPI registry to keep account of all accessible
106         applications. It contains the accessible cache objects from each application.
107
108         @registry:   Each accessible cache object must have a reference to the registry
109                      object to send update events.
110
111         @connection: D-Bus connection used to access applications.
112
113         @bus_name:   The test store only accesses one accessible application, this is its
114                      D-Bus path.
115         """
116
117         # An accessible path of '/' implies the desktop object, whatever the application name.
118         _DESKTOP_PATH = '/'
119
120         _APPLICATIONS_ADD = 1
121         _APPLICATIONS_REMOVE = 0
122
123         def __init__(self, registry, connection):
124                 self._connection = connection
125                 self._registry = registry
126
127                 self.application_list = []
128                 self.application_cache = {}
129
130                 self._regsig = connection.add_signal_receiver(self.update_handler,
131                                                               dbus_interface=ATSPI_REGISTRY_INTERFACE,
132                                                               signal_name="updateApplications")
133
134                 obj = connection.get_object(ATSPI_REGISTRY_NAME,
135                                             ATSPI_REGISTRY_PATH,
136                                             introspect=False)
137                 self._app_register = dbus.Interface(obj, ATSPI_REGISTRY_INTERFACE)
138
139                 self.application_list.extend(self._app_register.getApplications())
140                 for bus_name in self.application_list:
141                         self.application_cache[bus_name] = AccessibleCache(self._registry, self._connection, bus_name)
142
143         def update_handler (self, update_type, bus_name):
144                 if update_type == ApplicationCache._APPLICATIONS_ADD:
145                         #TODO Check that app does not already exist
146                         self.application_list.append(bus_name)
147                         self.application_cache[bus_name] = AccessibleCache(self._registry, self._connection, bus_name)
148                         event = _Event(self,
149                                        ApplicationCache._DESKTOP_PATH,
150                                        ATSPI_REGISTRY_NAME,
151                                        "org.freedesktop.atspi.Event.Object",
152                                        "children-changed",
153                                        ("add", 0, 0, ""))
154                 elif update_type == ApplicationCache._APPLICATIONS_REMOVE:
155                         #TODO Fail safely if app does not exist
156                         self.application_list.remove(bus_name)
157                         del(self.application_cache[bus_name])
158                         event = _Event(self,
159                                        ApplicationCache._DESKTOP_PATH,
160                                        ATSPI_REGISTRY_NAME,
161                                        "org.freedesktop.atspi.Event.Object",
162                                        "children-changed",
163                                        ("remove", 0, 0, ""))
164
165                 self._registry._notifyChildrenChange(event)
166
167         def get_cache_data(self, app_name, acc_path):
168                 """
169                 Returns the cache tuple for the given application and accessible
170                 object path. Throws an IndexError if the cache data is not found.
171                 """
172                 return self.application_cache[app_name][acc_path]
173
174         def create_application(self, app_name):
175                 """
176                 Creates an accessible object for the root of the application
177                 available at the given D-Bus name.
178                 """
179                 if app_name == ATSPI_REGISTRY_NAME:
180                         return Desktop(self)
181                 else:
182                         cls = accessible_factory.get_accessible_class(ATSPI_APPLICATION)
183                         return cls(app_name, self.application_cache[app_name].root, self, ATSPI_APPLICATION)
184
185         def create_accessible(self, app_name, acc_path, interface, dbus_object=None):
186                 """
187                 Creates an accessible object.
188
189                 @app_name: D-Bus name of the application where the accessible object resides.
190
191                 @acc_path: D-Bus path of the object within the application.
192
193                 @interface: D-Bus interface of the requested object. A different accessible object
194                             class will be created depending on this. Making the function much like 
195                             an accessible object factory.
196
197                 @dbus_object: If a D-Bus object already exists for the accessible object it can be
198                               provided here so that another one is not created.
199                 """
200                 if acc_path == ApplicationCache._DESKTOP_PATH:
201                         return Desktop(self)
202                 else:
203                         cls = accessible_factory.get_accessible_class(interface)
204                         return cls(app_name, acc_path, self, interface, dbus_object=dbus_object)
205
206         @property
207         def connection(self):
208                 """
209                 D-Bus connection used by the store.
210                 """
211                 return self._connection
212
213 #END----------------------------------------------------------------------------