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