ada9dbb8c9b927c6597f75802766618a2e201dae
[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 import interfaces
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(interfaces.ATSPI_APPLICATION)
67                 return cls(app_name, self.application_cache[app_name].root, self, interfaces.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         _REGISTRY_PATH = '/org/freedesktop/atspi/registry'
118         _REGISTRY_INTERFACE = 'org.freedesktop.atspi.Registry'
119         _REGISTRY_NAME = 'org.freedesktop.atspi.Registry'
120
121         # An accessible path of '/' implies the desktop object, whatever the application name.
122         _DESKTOP_PATH = '/'
123
124         _APPLICATIONS_ADD = 1
125         _APPLICATIONS_REMOVE = 0
126
127         def __init__(self, registry, connection):
128                 self._connection = connection
129                 self._registry = registry
130
131                 self.application_list = []
132                 self.application_cache = {}
133
134                 self._regsig = connection.add_signal_receiver(self.update_handler,
135                                                               dbus_interface=ApplicationCache._REGISTRY_INTERFACE,
136                                                               signal_name="updateApplications")
137
138                 obj = connection.get_object(ApplicationCache._REGISTRY_NAME,
139                                             ApplicationCache._REGISTRY_PATH,
140                                             introspect=False)
141                 self._app_register = dbus.Interface(obj, ApplicationCache._REGISTRY_INTERFACE)
142
143                 self.application_list.extend(self._app_register.getApplications())
144                 for bus_name in self.application_list:
145                         self.application_cache[bus_name] = AccessibleCache(self._registry, self._connection, bus_name)
146
147         def update_handler (self, update_type, bus_name):
148                 if update_type == ApplicationCache._APPLICATIONS_ADD:
149                         #TODO Check that app does not already exist
150                         self.application_list.append(bus_name)
151                         self.application_cache[bus_name] = AccessibleCache(self._registry, self._connection, bus_name)
152                         event = _Event(self,
153                                        ApplicationCache._DESKTOP_PATH,
154                                        ApplicationCache._REGISTRY_NAME,
155                                        "org.freedesktop.atspi.Event.Object",
156                                        "children-changed",
157                                        ("add", 0, 0, ""))
158                 elif update_type == ApplicationCache._APPLICATIONS_REMOVE:
159                         #TODO Fail safely if app does not exist
160                         self.application_list.remove(bus_name)
161                         del(self.application_cache[bus_name])
162                         event = _Event(self,
163                                        ApplicationCache._DESKTOP_PATH,
164                                        ApplicationCache._REGISTRY_NAME,
165                                        "org.freedesktop.atspi.Event.Object",
166                                        "children-changed",
167                                        ("remove", 0, 0, ""))
168
169                 self._registry._notifyChildrenChange(event)
170
171         def get_cache_data(self, app_name, acc_path):
172                 """
173                 Returns the cache tuple for the given application and accessible
174                 object path. Throws an IndexError if the cache data is not found.
175                 """
176                 return self.application_cache[app_name][acc_path]
177
178         def create_application(self, app_name):
179                 """
180                 Creates an accessible object for the root of the application
181                 available at the given D-Bus name.
182                 """
183                 if app_name == ApplicationCache._REGISTRY_NAME:
184                         return Desktop(self)
185                 else:
186                         cls = accessible_factory.get_accessible_class(interfaces.ATSPI_APPLICATION)
187                         return cls(app_name, self.application_cache[app_name].root, self, interfaces.ATSPI_APPLICATION)
188
189         def create_accessible(self, app_name, acc_path, interface, dbus_object=None):
190                 """
191                 Creates an accessible object.
192
193                 @app_name: D-Bus name of the application where the accessible object resides.
194
195                 @acc_path: D-Bus path of the object within the application.
196
197                 @interface: D-Bus interface of the requested object. A different accessible object
198                             class will be created depending on this. Making the function much like 
199                             an accessible object factory.
200
201                 @dbus_object: If a D-Bus object already exists for the accessible object it can be
202                               provided here so that another one is not created.
203                 """
204                 if acc_path == ApplicationCache._DESKTOP_PATH:
205                         return Desktop(self)
206                 else:
207                         cls = accessible_factory.get_accessible_class(interface)
208                         return cls(app_name, acc_path, self, interface, dbus_object=dbus_object)
209
210         @property
211         def connection(self):
212                 """
213                 D-Bus connection used by the store.
214                 """
215                 return self._connection
216
217 #END----------------------------------------------------------------------------