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