7096d1badd1744560bbbedf505213e7bfbc44e76
[platform/core/uifw/at-spi2-atk.git] / pyatspi / base.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 from dbus.proxies import Interface
17 from dbus.exceptions import *
18
19 import interfaces
20
21 __all__ = [
22            "AccessibleObjectNoLongerExists",
23            "AccessibleObjectNotAvailable",
24            "Enum",
25            "BaseProxy",
26            "_repack_tuple",
27           ]
28
29 class AccessibleObjectNoLongerExists(Exception):
30         pass
31
32 class AccessibleObjectNotAvailable(Exception):
33         pass
34
35 #------------------------------------------------------------------------------
36
37 def _repack_tuple (tup):
38         """
39         Re-packs a tuple moving the last element to the beginning.
40         """
41         return (tup[-1] ,) + tup[:-1]
42
43 #------------------------------------------------------------------------------
44
45 class Enum(dbus.UInt32):
46         def __str__(self):
47                 return self._enum_lookup[int(self)]
48
49         def __eq__(self, other):
50                 if other is None:
51                         return False
52                 if int(self) == int(other):
53                         return True
54                 else:
55                         return False
56
57         def __hash__(self):
58                 return int(self)
59
60 #------------------------------------------------------------------------------
61
62
63 class BaseProxyMeta(type):
64         def __new__(meta, *args, **kwargs):
65                 cls = type.__new__(meta, *args, **kwargs)
66
67                 queryable_interfaces = { 
68                         'Accessible':interfaces.ATSPI_ACCESSIBLE,
69                         'Action':interfaces.ATSPI_ACTION,
70                         'Application':interfaces.ATSPI_APPLICATION,
71                         'Collection':interfaces.ATSPI_COLLECTION,
72                         'Component':interfaces.ATSPI_COMPONENT,
73                         'Desktop':interfaces.ATSPI_DESKTOP,
74                         'Document':interfaces.ATSPI_DOCUMENT,
75                         'EditableText':interfaces.ATSPI_EDITABLE_TEXT,
76                         'Hypertext':interfaces.ATSPI_HYPERTEXT,
77                         'Hyperlink':interfaces.ATSPI_HYPERLINK,
78                         'Image':interfaces.ATSPI_IMAGE,
79                         'Selection':interfaces.ATSPI_SELECTION,
80                         'StreamableContent':interfaces.ATSPI_STREAMABLE_CONTENT,
81                         'Table':interfaces.ATSPI_TABLE,
82                         'Text':interfaces.ATSPI_TEXT,
83                         'Value':interfaces.ATSPI_VALUE,
84                 }
85
86                 def return_query(interface):
87                         def new_query(self):
88                                 return self.queryInterface(interface)
89                         return new_query
90
91                 for interface in queryable_interfaces.keys():
92                         name = 'query%s' % interface
93                         setattr(cls, name, return_query(queryable_interfaces[interface])) 
94
95                 return cls
96
97 #------------------------------------------------------------------------------
98
99 class BaseProxy(object):
100         """
101         The base D-Bus proxy for a remote object that implements one or more
102         of the AT-SPI interfaces.
103         """
104
105         __metaclass__ = BaseProxyMeta
106
107         def __init__(self, app_name, acc_path, cache, interface, dbus_object=None):
108                 """
109                 Create a D-Bus Proxy for an ATSPI interface.
110
111                 cache - ApplicationCache, where the cached data for the accessible can be obtained.
112                 app_name - D-Bus bus name of the application this accessible belongs to.
113                 acc_path - D-Bus object path of the server side accessible object.
114                 parent - Parent accessible.
115                 dbus_object(kwarg) - The D-Bus proxy object used by the accessible for D-Bus method calls.
116                 """
117                 self._cache = cache
118                 self._app_name = app_name
119                 self._acc_path = acc_path
120                 self._dbus_interface = interface
121
122                 if not dbus_object:
123                         dbus_object = cache.connection.get_object(self._app_name,
124                                                                   self._acc_path,
125                                                                   introspect=False)
126                 self._dbus_object = dbus_object
127
128                 self._pgetter = self.get_dbus_method("Get",
129                                                      dbus_interface="org.freedesktop.DBus.Properties")
130                 self._psetter = self.get_dbus_method("Set",
131                                                      dbus_interface="org.freedesktop.DBus.Properties")
132
133         def __str__(self):
134                     try:
135                               return '[%s | %s]' % (self.getRoleName(), self.name)
136                     except Exception:
137                               return '[DEAD]'
138
139         def __eq__(self, other):
140                 if other is None:
141                         return False
142                 try:
143                         if self._app_name == other._app_name and \
144                            self._acc_path == other._acc_path:
145                                 return True
146                         else:
147                                 return False
148                 except AttributeError:
149                         return False
150
151         def __ne__(self, other):
152                 return not self.__eq__(other)
153
154         def __hash__(self):
155                 return hash(self._app_name + self._acc_path)
156
157         def get_dbus_method(self, *args, **kwargs):
158                 method =  self._dbus_object.get_dbus_method(*args, **kwargs)
159
160                 def dbus_method_func(*iargs, **ikwargs):
161                         # TODO Need to throw an AccessibleObjectNoLongerExists exception
162                         # on D-Bus error of the same type.
163                         try:
164                                 return method(*iargs, **ikwargs)
165                         except UnknownMethodException, e:
166                                 raise NotImplementedError(e)
167                         except DBusException, e:
168                                 raise LookupError(e)
169
170                 return dbus_method_func
171
172         @property
173         def cached_data(self):
174                 try:
175                         return self._cache.get_cache_data(self._app_name, self._acc_path)
176                 except KeyError:
177                         raise AccessibleObjectNoLongerExists, \
178                                 'Cache data cannot be found for path %s in app %s' % (self._acc_path, self._app_name)
179
180         @property
181         def interfaces(self):
182                 return self.cached_data.interfaces
183
184         def queryInterface(self, interface):
185                 """
186                 Gets a different accessible interface for this object
187                 or raises a NotImplemented error if the given interface
188                 is not supported.
189                 """
190                 if interface in self.interfaces:
191                         return self._cache.create_accessible(self._app_name,
192                                                              self._acc_path,
193                                                              interface,
194                                                              dbus_object=self._dbus_object)
195                 else:
196                         raise NotImplementedError(
197                                 "%s not supported by accessible object at path %s"
198                                 % (interface, self._acc_path))
199
200         def flushCache(self):
201                 pass
202
203 #END----------------------------------------------------------------------------