2 Utility functions for AT-SPI for querying interfaces, searching the hierarchy,
3 converting constants to strings, and so forth.
6 @organization: IBM Corporation
7 @copyright: Copyright (c) 2005, 2007 IBM Corporation
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
20 You should have received a copy of the GNU Library General Public
21 License along with this library; if not, write to the
22 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA.
25 Portions of this code originally licensed and copyright (c) 2005, 2007
26 IBM Corporation under the BSD license, available at
27 U{http://www.opensource.org/licenses/bsd-license.php}
29 def getInterfaceIID(cls):
31 Gets the ID of an interface class in string format for use in queryInterface.
33 @param cls: Class representing an AT-SPI interface
35 @return: IID for the interface
37 @raise AttributeError: When the parameter does not provide typecode info
39 return cls.__typecode__.repo_id
41 def getInterfaceName(cls):
43 Gets the human readable name of an interface class in string format.
45 @param cls: Class representing an AT-SPI interface
47 @return: Name of the interface
49 @raise AttributeError: When the parameter does not provide typecode info
51 return cls.__typecode__.name
53 # we're importing here to avoid cyclic importants; constants relies on the
57 def stringToConst(prefix, suffix):
59 Maps a string name to an AT-SPI constant. The rules for the mapping are as
61 - The prefix is captalized and has an _ appended to it.
62 - All spaces in the suffix are mapped to the _ character.
63 - All alpha characters in the suffix are mapped to their uppercase.
65 The resulting name is used with getattr to look up a constant with that name
66 in the L{pyLinAcc.Constants} module. If such a constant does not exist, the
67 string suffix is returned instead.
69 This method allows strings to be used to refer to roles, relations, etc.
70 without direct access to the constants. It also supports the future expansion
71 of roles, relations, etc. by allowing arbitrary strings which may or may not
72 map to the current standard set of roles, relations, etc., but may still match
73 some non-standard role, relation, etc. being reported by an application.
75 @param prefix: Prefix of the constant name such as role, relation, state,
78 @param suffix: Name of the role, relation, etc. to use to lookup the constant
80 @return: The matching constant value
83 name = prefix.upper()+'_'+suffix.upper().replace(' ', '_')
84 return getattr(constants, name, suffix)
86 def stateToString(value):
88 Converts a state value to a string based on the name of the state constant in
89 the L{Constants} module that has the given value.
91 @param value: An AT-SPI state
92 @type value: Accessibility.StateType
93 @return: Human readable, untranslated name of the state
96 return constants.STATE_VALUE_TO_NAME.get(value)
98 def relationToString(value):
100 Converts a relation value to a string based on the name of the state constant
101 in the L{Constants} module that has the given value.
103 @param value: An AT-SPI relation
104 @type value: Accessibility.RelationType
105 @return: Human readable, untranslated name of the relation
108 return constants.RELATION_VALUE_TO_NAME.get(value)
112 Generates all possible keyboard modifiers for use with
113 L{Registry.Registry.registerKeystrokeListener}.
116 while mask <= (1 << constants.MODIFIER_NUMLOCK):
120 def findDescendant(acc, pred, breadth_first=False):
122 Searches for a descendant node satisfying the given predicate starting at
123 this node. The search is performed in depth-first order by default or
124 in breadth first order if breadth_first is True. For example,
126 my_win = findDescendant(lambda x: x.name == 'My Window')
128 will search all descendants of node until one is located with the name 'My
129 Window' or all nodes are exausted. Calls L{_findDescendantDepth} or
130 L{_findDescendantBreadth} to start the recursive search.
132 @param acc: Root accessible of the search
133 @type acc: Accessibility.Accessible
134 @param pred: Search predicate returning True if accessible matches the
135 search criteria or False otherwise
137 @param breadth_first: Search breadth first (True) or depth first (False)?
138 @type breadth_first: boolean
139 @return: Accessible matching the criteria or None if not found
140 @rtype: Accessibility.Accessible or None
143 return _findDescendantBreadth(acc, pred)
147 ret = _findDescendantDepth(acc, pred)
150 if ret is not None: return ret
152 def _findDescendantBreadth(acc, pred):
154 Internal function for locating one descendant. Called by
155 L{AccessibleMixin.findDescendant} to start the search.
157 @param acc: Root accessible of the search
158 @type acc: Accessibility.Accessible
159 @param pred: Search predicate returning True if accessible matches the
160 search criteria or False otherwise
162 @return: Matching node or None to keep searching
163 @rtype: Accessibility.Accessible or None
167 if pred(child): return child
172 ret = _findDescedantBreadth(child, pred)
175 if ret is not None: return ret
177 def _findDescendantDepth(acc, pred):
179 Internal function for locating one descendant. Called by
180 L{AccessibleMixin.findDescendant} to start the search.
182 @param acc: Root accessible of the search
183 @type acc: Accessibility.Accessible
184 @param pred: Search predicate returning True if accessible matches the
185 search criteria or False otherwise
187 @return: Matching node or None to keep searching
188 @rtype: Accessibility.Accessible or None
191 if pred(acc): return acc
196 ret = _findDescendantDepth(child, pred)
199 if ret is not None: return ret
201 def findAllDescendants(acc, pred):
203 Searches for all descendant nodes satisfying the given predicate starting at
204 this node. Does an in-order traversal. For example,
206 pred = lambda x: x.getRole() == pyatspi.ROLE_PUSH_BUTTON
207 buttons = pyatspi.findAllDescendants(node, pred)
209 will locate all push button descendants of node.
211 @param acc: Root accessible of the search
212 @type acc: Accessibility.Accessible
213 @param pred: Search predicate returning True if accessible matches the
214 search criteria or False otherwise
216 @return: All nodes matching the search criteria
220 _findAllDescendants(acc, pred, matches)
223 def _findAllDescendants(acc, pred, matches):
225 Internal method for collecting all descendants. Reuses the same matches
226 list so a new one does not need to be built on each recursive step.
230 if pred(child): matches.append(child)
233 findAllDescendants(child, pred, matches)
235 def findAncestor(acc, pred):
237 Searches for an ancestor satisfying the given predicate. Note that the
238 AT-SPI hierarchy is not always doubly linked. Node A may consider node B its
239 child, but B is not guaranteed to have node A as its parent (i.e. its parent
240 may be set to None). This means some searches may never make it all the way
241 up the hierarchy to the desktop level.
243 @param acc: Starting accessible object
244 @type acc: Accessibility.Accessible
245 @param pred: Search predicate returning True if accessible matches the
246 search criteria or False otherwise
248 @return: Node matching the criteria or None if not found
249 @rtype: Accessibility.Accessible
252 # guard against bad start condition
255 if acc.parent is None:
256 # stop if there is no parent and we haven't returned yet
259 if pred(acc.parent): return acc.parent
267 Gets the path from the application ancestor to the given accessible in
268 terms of its child index at each level.
270 @param acc: Target accessible
271 @type acc: Accessibility.Accessible
272 @return: Path to the target
273 @rtype: list of integer
274 @raise LookupError: When the application accessible cannot be reached
278 if acc.parent is None:
282 path.append(acc.getIndexInParent())