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 import Accessibility__POA
31 def getInterfaceIID(cls):
33 Gets the ID of an interface class in string format for use in queryInterface.
35 @param cls: Class representing an AT-SPI interface
37 @return: IID for the interface
39 @raise AttributeError: When the parameter does not provide typecode info
41 return cls.__typecode__.repo_id
43 def getInterfaceName(cls):
45 Gets the human readable name of an interface class in string format.
47 @param cls: Class representing an AT-SPI interface
49 @return: Name of the interface
51 @raise AttributeError: When the parameter does not provide typecode info
53 return cls.__typecode__.name
55 # we're importing here to avoid cyclic importants; constants relies on the
59 def stringToConst(prefix, suffix):
61 Maps a string name to an AT-SPI constant. The rules for the mapping are as
63 - The prefix is captalized and has an _ appended to it.
64 - All spaces in the suffix are mapped to the _ character.
65 - All alpha characters in the suffix are mapped to their uppercase.
67 The resulting name is used with getattr to look up a constant with that name
68 in the L{constants} module. If such a constant does not exist, the string
69 suffix is returned instead.
71 This method allows strings to be used to refer to roles, relations, etc.
72 without direct access to the constants. It also supports the future expansion
73 of roles, relations, etc. by allowing arbitrary strings which may or may not
74 map to the current standard set of roles, relations, etc., but may still match
75 some non-standard role, relation, etc. being reported by an application.
77 @param prefix: Prefix of the constant name such as role, relation, state,
80 @param suffix: Name of the role, relation, etc. to use to lookup the constant
82 @return: The matching constant value
85 name = prefix.upper()+'_'+suffix.upper().replace(' ', '_')
86 return getattr(constants, name, suffix)
88 def stateToString(value):
90 Converts a state value to a string based on the name of the state constant in
91 the L{constants} module that has the given value.
93 @param value: An AT-SPI state
94 @type value: Accessibility.StateType
95 @return: Human readable, untranslated name of the state
98 return constants.STATE_VALUE_TO_NAME.get(value)
100 def relationToString(value):
102 Converts a relation value to a string based on the name of the state constant
103 in the L{constants} module that has the given value.
105 @param value: An AT-SPI relation
106 @type value: Accessibility.RelationType
107 @return: Human readable, untranslated name of the relation
110 return constants.RELATION_VALUE_TO_NAME.get(value)
114 Generates all possible keyboard modifiers for use with
115 L{registry.Registry.registerKeystrokeListener}.
118 while mask <= (1 << constants.MODIFIER_NUMLOCK):
122 def findDescendant(acc, pred, breadth_first=False):
124 Searches for a descendant node satisfying the given predicate starting at
125 this node. The search is performed in depth-first order by default or
126 in breadth first order if breadth_first is True. For example,
128 my_win = findDescendant(lambda x: x.name == 'My Window')
130 will search all descendants of node until one is located with the name 'My
131 Window' or all nodes are exausted. Calls L{_findDescendantDepth} or
132 L{_findDescendantBreadth} to start the recursive search.
134 @param acc: Root accessible of the search
135 @type acc: Accessibility.Accessible
136 @param pred: Search predicate returning True if accessible matches the
137 search criteria or False otherwise
139 @param breadth_first: Search breadth first (True) or depth first (False)?
140 @type breadth_first: boolean
141 @return: Accessible matching the criteria or None if not found
142 @rtype: Accessibility.Accessible or None
145 return _findDescendantBreadth(acc, pred)
149 ret = _findDescendantDepth(acc, pred)
152 if ret is not None: return ret
154 def _findDescendantBreadth(acc, pred):
156 Internal function for locating one descendant. Called by L{findDescendant} to
159 @param acc: Root accessible of the search
160 @type acc: Accessibility.Accessible
161 @param pred: Search predicate returning True if accessible matches the
162 search criteria or False otherwise
164 @return: Matching node or None to keep searching
165 @rtype: Accessibility.Accessible or None
169 if pred(child): return child
174 ret = _findDescedantBreadth(child, pred)
177 if ret is not None: return ret
179 def _findDescendantDepth(acc, pred):
181 Internal function for locating one descendant. Called by L{findDescendant} to
184 @param acc: Root accessible of the search
185 @type acc: Accessibility.Accessible
186 @param pred: Search predicate returning True if accessible matches the
187 search criteria or False otherwise
189 @return: Matching node or None to keep searching
190 @rtype: Accessibility.Accessible or None
193 if pred(acc): return acc
198 ret = _findDescendantDepth(child, pred)
201 if ret is not None: return ret
203 def findAllDescendants(acc, pred):
205 Searches for all descendant nodes satisfying the given predicate starting at
206 this node. Does an in-order traversal. For example,
208 pred = lambda x: x.getRole() == pyatspi.ROLE_PUSH_BUTTON
209 buttons = pyatspi.findAllDescendants(node, pred)
211 will locate all push button descendants of node.
213 @param acc: Root accessible of the search
214 @type acc: Accessibility.Accessible
215 @param pred: Search predicate returning True if accessible matches the
216 search criteria or False otherwise
218 @return: All nodes matching the search criteria
222 _findAllDescendants(acc, pred, matches)
225 def _findAllDescendants(acc, pred, matches):
227 Internal method for collecting all descendants. Reuses the same matches
228 list so a new one does not need to be built on each recursive step.
232 if pred(child): matches.append(child)
235 findAllDescendants(child, pred, matches)
237 def findAncestor(acc, pred):
239 Searches for an ancestor satisfying the given predicate. Note that the
240 AT-SPI hierarchy is not always doubly linked. Node A may consider node B its
241 child, but B is not guaranteed to have node A as its parent (i.e. its parent
242 may be set to None). This means some searches may never make it all the way
243 up the hierarchy to the desktop level.
245 @param acc: Starting accessible object
246 @type acc: Accessibility.Accessible
247 @param pred: Search predicate returning True if accessible matches the
248 search criteria or False otherwise
250 @return: Node matching the criteria or None if not found
251 @rtype: Accessibility.Accessible
254 # guard against bad start condition
257 if acc.parent is None:
258 # stop if there is no parent and we haven't returned yet
261 if pred(acc.parent): return acc.parent
269 Gets the path from the application ancestor to the given accessible in
270 terms of its child index at each level.
272 @param acc: Target accessible
273 @type acc: Accessibility.Accessible
274 @return: Path to the target
275 @rtype: list of integer
276 @raise LookupError: When the application accessible cannot be reached
280 if acc.parent is None:
284 path.append(acc.getIndexInParent())
289 class StateSet(Accessibility__POA.StateSet):
291 Convenience implementation of AT-SPI StateSet, for future use with Collection
294 @param states: Set of states
297 def __init__(self, *states):
298 '''Initializes the state set with the given states.'''
299 self.states = set(states)
301 def contains(self, state):
303 Checks if this L{StateSet} contains the given state.
305 @param state: State to check
306 @type state: Accessibility.StateType
307 @return: True if the set contains the given state
310 return state in self.states
312 def add(self, *state):
314 Adds one or more states to this set.
316 @param state: State(s) to add
317 @type state: Accessibility.StateType
319 self.states.add(state)
321 def remove(self, *state):
323 Removes one or more states from this set.
325 @param state: State(s) to remove
326 @type state: Accessibility.StateType
328 self.states.remove(state)
330 def equals(self, state_set):
332 Checks if this L{StateSet} contains exactly the same members as the given
335 @param state_set: Another set
336 @type state_set: L{StateSet}
337 @return: Are the sets equivalent in terms of their contents?
340 return self.state_set == self.states
342 def compare(self, state_set):
344 Computes the symmetric differences of this L{StateSet} and the given
347 @param state_set: Another set
348 @type state_set: L{StateSet}
349 @return: Elements in only one of the two sets
352 diff = self.states.symmetric_difference(state_set.states)
353 return StateSet(*diff)
357 Checks if this L{StateSet} is empty.
359 @return: Is it empty?
362 return len(self.states) == 0
366 Gets the sequence of all states in this set.
368 @return: List of states
371 return list(self.states)