f086bdc998ca8891ad994c4c368fe2d24d52a9b6
[platform/core/uifw/at-spi2-atk.git] / pyatspi / utils.py
1 #Copyright (C) 2008 Codethink Ltd
2 #copyright: Copyright (c) 2005, 2007 IBM Corporation
3
4 #This library is free software; you can redistribute it and/or
5 #modify it under the terms of the GNU Lesser General Public
6 #License version 2 as published by the Free Software Foundation.
7
8 #This program is distributed in the hope that it will be useful,
9 #but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #GNU General Public License for more details.
12 #You should have received a copy of the GNU Lesser General Public License
13 #along with this program; if not, write to the Free Software
14 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15
16 #Portions of this code originally licensed and copyright (c) 2005, 2007
17 #IBM Corporation under the BSD license, available at
18 #U{http://www.opensource.org/licenses/bsd-license.php}
19
20 #authors: Peter Parente, Mark Doffman
21
22 def setCacheLevel(level):
23         pass
24
25 def getCacheLevel():
26         return None
27
28 def clearCache():
29         pass
30
31 def printCache():
32         print "Print cache function is deprecated";
33
34 def getInterfaceIID(obj):
35         """
36         Gets the ID of an interface class or object in string format for use in
37         queryInterface.
38         
39         @param obj: Class representing an AT-SPI interface or instance
40         @type obj: object
41         @return: IID for the interface
42         @rtype: string
43         @raise AttributeError: When the parameter does not provide typecode info
44
45         WARNING!! DEPRECATED!!
46
47         In current D-Bus version of pyatspi this simply returns a null string.
48         """
49         return ""
50
51 def getInterfaceName(obj):
52         """
53         Gets the human readable name of an interface class or object in string
54         format.
55         
56         @param obj: Class representing an AT-SPI interface or instance
57         @type obj: class
58         @return: Name of the interface
59         @rtype: string
60         @raise AttributeError: When the parameter does not provide typecode info
61         """
62         return obj._dbus_interface.lstrip("org.freedesktop.atspi.")
63
64 # we're importing here to avoid cyclic importants; constants relies on the
65 # two functions above
66 import constants
67
68 def listInterfaces(obj):
69         """
70         Gets a list of the names of all interfaces supported by this object. The
71         names are the short-hand interface names like "Accessible" and "Component",
72         not the full interface identifiers.
73
74         @param obj: Arbitrary object to query for all accessibility related
75         interfaces. Must provide a queryInterface method.
76         @type obj: object
77         @return: Set of supported interface names
78         @rtype: set
79         @raise AttributeError: If the object provide does not implement
80         queryInterface
81         """
82         return [itf.lstrip("org.freedesktop.atspi.") for itf in obj.interfaces]
83
84 def stringToConst(prefix, suffix):
85         """
86         Maps a string name to an AT-SPI constant. The rules for the mapping are as 
87         follows:
88                 - The prefix is captalized and has an _ appended to it.
89                 - All spaces in the suffix are mapped to the _ character. 
90                 - All alpha characters in the suffix are mapped to their uppercase.
91                 
92         The resulting name is used with getattr to look up a constant with that name
93         in the L{constants} module. If such a constant does not exist, the string
94         suffix is returned instead.
95
96         This method allows strings to be used to refer to roles, relations, etc.
97         without direct access to the constants. It also supports the future expansion
98         of roles, relations, etc. by allowing arbitrary strings which may or may not
99         map to the current standard set of roles, relations, etc., but may still
100         match some non-standard role, relation, etc. being reported by an
101         application.
102         
103         @param prefix: Prefix of the constant name such as role, relation, state, 
104                 text, modifier, key
105         @type prefix: string
106         @param suffix: Name of the role, relation, etc. to use to lookup the constant
107         @type suffix: string
108         @return: The matching constant value
109         @rtype: object
110         """
111         name = prefix.upper()+'_'+suffix.upper().replace(' ', '_')
112         return getattr(constants, name, suffix)
113
114 def stateToString(value):
115         """
116         Converts a state value to a string based on the name of the state constant in
117         the L{constants} module that has the given value.
118         
119         @param value: An AT-SPI state
120         @type value: Accessibility.StateType
121         @return: Human readable, untranslated name of the state
122         @rtype: string
123         """
124         return constants.STATE_VALUE_TO_NAME.get(value)
125
126 def relationToString(value):
127         """
128         Converts a relation value to a string based on the name of the state constant
129         in the L{constants} module that has the given value.
130         
131         @param value: An AT-SPI relation
132         @type value: Accessibility.RelationType
133         @return: Human readable, untranslated name of the relation
134         @rtype: string
135         """
136         return constants.RELATION_VALUE_TO_NAME.get(value)
137
138 def allModifiers():
139         """
140         Generates all possible keyboard modifiers for use with 
141         L{registry.Registry.registerKeystrokeListener}.
142         """
143         mask = 0
144         while mask <= (1 << constants.MODIFIER_NUMLOCK):
145                 yield mask
146                 mask += 1
147
148 def findDescendant(acc, pred, breadth_first=False):
149         """
150         Searches for a descendant node satisfying the given predicate starting at 
151         this node. The search is performed in depth-first order by default or
152         in breadth first order if breadth_first is True. For example,
153         
154         my_win = findDescendant(lambda x: x.name == 'My Window')
155         
156         will search all descendants of x until one is located with the name 'My
157         Window' or all nodes are exausted. Calls L{_findDescendantDepth} or
158         L{_findDescendantBreadth} to start the recursive search.
159         
160         @param acc: Root accessible of the search
161         @type acc: Accessibility.Accessible
162         @param pred: Search predicate returning True if accessible matches the 
163                         search criteria or False otherwise
164         @type pred: callable
165         @param breadth_first: Search breadth first (True) or depth first (False)?
166         @type breadth_first: boolean
167         @return: Accessible matching the criteria or None if not found
168         @rtype: Accessibility.Accessible or None
169         """
170         if breadth_first:
171                 return _findDescendantBreadth(acc, pred)
172
173         for child in acc:
174                 try:
175                         ret = _findDescendantDepth(acc, pred)
176                 except Exception:
177                         ret = None
178                 if ret is not None: return ret
179
180 def _findDescendantBreadth(acc, pred):
181         """             
182         Internal function for locating one descendant. Called by L{findDescendant} to
183         start the search.
184         
185         @param acc: Root accessible of the search
186         @type acc: Accessibility.Accessible
187         @param pred: Search predicate returning True if accessible matches the 
188                         search criteria or False otherwise
189         @type pred: callable
190         @return: Matching node or None to keep searching
191         @rtype: Accessibility.Accessible or None
192         """
193         for child in acc:
194                 try:
195                         if pred(child): return child
196                 except Exception:
197                         pass
198         for child in acc:
199                 try:
200                         ret = _findDescendantBreadth(child, pred)
201                 except Exception:
202                         ret = None
203                 if ret is not None: return ret
204
205 def _findDescendantDepth(acc, pred):
206         """
207         Internal function for locating one descendant. Called by L{findDescendant} to
208         start the search.
209
210         @param acc: Root accessible of the search
211         @type acc: Accessibility.Accessible
212         @param pred: Search predicate returning True if accessible matches the 
213                 search criteria or False otherwise
214         @type pred: callable
215         @return: Matching node or None to keep searching
216         @rtype: Accessibility.Accessible or None
217         """
218         try:
219                 if pred(acc): return acc
220         except Exception:
221                 pass
222         for child in acc:
223                 try:
224                         ret = _findDescendantDepth(child, pred)
225                 except Exception:
226                         ret = None
227                 if ret is not None: return ret
228                 
229 def findAllDescendants(acc, pred):
230         """
231         Searches for all descendant nodes satisfying the given predicate starting at 
232         this node. Does an in-order traversal. For example,
233         
234         pred = lambda x: x.getRole() == pyatspi.ROLE_PUSH_BUTTON
235         buttons = pyatspi.findAllDescendants(node, pred)
236         
237         will locate all push button descendants of node.
238         
239         @param acc: Root accessible of the search
240         @type acc: Accessibility.Accessible
241         @param pred: Search predicate returning True if accessible matches the 
242                         search criteria or False otherwise
243         @type pred: callable
244         @return: All nodes matching the search criteria
245         @rtype: list
246         """
247         matches = []
248         _findAllDescendants(acc, pred, matches)
249         return matches
250
251 def _findAllDescendants(acc, pred, matches):
252         """
253         Internal method for collecting all descendants. Reuses the same matches
254         list so a new one does not need to be built on each recursive step.
255         """
256         for child in acc:
257                 try:
258                         if pred(child): matches.append(child)
259                 except Exception:
260                         pass
261                 _findAllDescendants(child, pred, matches)
262         
263 def findAncestor(acc, pred):
264         """
265         Searches for an ancestor satisfying the given predicate. Note that the
266         AT-SPI hierarchy is not always doubly linked. Node A may consider node B its
267         child, but B is not guaranteed to have node A as its parent (i.e. its parent
268         may be set to None). This means some searches may never make it all the way
269         up the hierarchy to the desktop level.
270         
271         @param acc: Starting accessible object
272         @type acc: Accessibility.Accessible
273         @param pred: Search predicate returning True if accessible matches the 
274                 search criteria or False otherwise
275         @type pred: callable
276         @return: Node matching the criteria or None if not found
277         @rtype: Accessibility.Accessible
278         """
279         if acc is None:
280                 # guard against bad start condition
281                 return None
282         while 1:
283                 if acc.parent is None:
284                         # stop if there is no parent and we haven't returned yet
285                         return None
286                 try:
287                         if pred(acc.parent): return acc.parent
288                 except Exception:
289                         pass
290                 # move to the parent
291                 acc = acc.parent
292
293 def getPath(acc):
294         """
295         Gets the path from the application ancestor to the given accessible in
296         terms of its child index at each level.
297         
298         @param acc: Target accessible
299         @type acc: Accessibility.Accessible
300         @return: Path to the target
301         @rtype: list of integer
302         @raise LookupError: When the application accessible cannot be reached
303         """
304         path = []
305         while 1:
306                 if acc.parent is None:
307                         path.reverse()
308                         return path
309                 try:
310                         path.append(acc.getIndexInParent())
311                 except Exception:
312                         raise LookupError
313                 acc = acc.parent
314
315 del constants