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