1 '''
2 Defines default L{AEAccAdapter.AEAccAdapter}s for the
3 L{AEAccInterfaces.IAccessibleAction} interface on
4 C{pyatspi.Accessibility.Accessible} objects.
5
6 @author: Brett Clippingdale
7 @author: Peter Parente
8 @author: Eirikur Hallgrimsson
9 @author: Scott Haeger
10 @organization: IBM Corporation
11 @copyright: Copyright (c) 2005, 2007 IBM Corporation
12 @license: The BSD License
13
14 All rights reserved. This program and the accompanying materials are made
15 available under the terms of the BSD license which accompanies
16 this distribution, and is available at
17 U{http://www.opensource.org/licenses/bsd-license.php}
18 '''
19 from AccessEngine.AEAccAdapter import PORAdapter
20 from AccessEngine.AEAccInterfaces import *
21
22 import pyatspi
23
25 '''
26 Adapts all AT-SPI accessibles to the L{IAccessibleAction} interface. No
27 condition for adaption is given implying that this adapter is used as a
28 default by L{AEAccAdapter} when no better adapter is available.
29
30 Expects the subject to be a C{pyatspi.Accessibility.Accessible}.
31 '''
32 provides = [IAccessibleAction]
33
34
36 '''
37 Moves the caret to the location given by the item offset + the char offset.
38 Moves to the beginning of the text if the item offset is None.
39
40 @return: Indicator of whether the caret was moved successfully
41 @rtype: boolean
42 @raise LookupError: When the accessible object is dead
43 @raise NotImplementedError: When the Text interface is not supported
44 '''
45 acc = self.accessible
46 if self.item_offset is None:
47 off = 0
48 else:
49 off = self.item_offset + self.char_offset
50 tex = acc.queryText()
51 return tex.setCaretOffset(off)
52
53
54 - def setAccText(self, text):
55 '''
56 Replace contents of text area with the given text.
57
58 @param text: Text to set as the content of the text area given by the
59 L{AEPor}
60 @type text: string
61 @return: Indicator of whether the text was set successfully or not
62 @rtype: boolean
63 @raise LookupError: When the accessible object is dead
64 @raise NotImplementedError: When the EditableText interface is not
65 supported
66 '''
67 tex = (self.accessible).queryEditableText()
68 return tex.setTextContents(text)
69
70
71 - def insertAccText(self, text, attrs):
72 '''
73 Inserts text at the location given by the item offset + the char offset.
74 Inserts at the beginning of the text if the item offset is None.
75
76 @param text: Text to insert at the given position
77 @type text: string
78 @param attrs: Dictionary of string name/value pairs of text attributes to
79 set on the inserted text
80 @type attrs: dictionary
81 @return: Indicator of whether the text was inserted successfully or not
82 @rtype: boolean
83 @raise LookupError: When the accessible object is dead
84 @raise NotImplementedError: When the EditableText interface is not
85 supported
86 '''
87 acc = self.accessible
88 if self.item_offset is None:
89 off = 0
90 else:
91 off = self.item_offset + self.char_offset
92 tex = acc.queryEditableText()
93 if len(attrs) == 0:
94 return tex.insertText(off, text, len(text))
95 else:
96 attrs = '; '.join(['%s:%s' % (name, val) for name, val in attrs.items()])
97 return tex.insertTextWithAttributes(off, text, len(text), attrs)
98
99
100 - def setAccTextAttrs(self, por, attrs):
101 '''
102 Sets the accessible text attributes starting at item offset + char offset
103 up to the offset given by the L{AEPor}. Always replaces the current
104 attributes at present.
105
106 @param por: Point of regard to the end of the text run
107 @type por: L{AEPor}
108 @param attrs: Dictionary of string name/value pairs of text attributes to
109 set on the text range
110 @type attrs: dictionary
111 @return: Indicator of whether the text attributes were set successfully or
112 not
113 @rtype: boolean
114 @raise LookupError: When the accessible object is dead
115 @raise NotImplementedError: When the EditableText interface is not
116 supported
117 '''
118 acc = self.accessible
119 if self.item_offset is None:
120 start_off = 0
121 else:
122 start_off = self.item_offset + self.char_offset
123 text_area = acc.queryEditableText()
124 if por.item_offset is None:
125 end_off = text_area.characterCount
126 else:
127 end_off = por.item_offset + por.char_offset
128
129 attrs = '; '.join(['%s:%s' % (name, val) for name, val in attrs.items()])
130 try:
131
132 return text_area.setAttributeRun(attrs, start_off, end_off, True)
133 except (pyatspi.NotImplemented, AttributeError):
134 return text_area.setAttributes(attrs, start_off, end_off)
135
136
137 - def copyAccText(self, por):
138 '''
139 Copies the text starting at item offset + char offset up to the offset
140 given by the L{AEPor}. Copies from the beginning of the text if subject item
141 offset is None. Copies to the end of the text if the L{AEPor} item offset is
142 None.
143
144 @param por: Point of regard to the end terminus of the copy operation
145 @type por: L{AEPor}
146 @return: Indicator of whether the text was copied successfully or not
147 @rtype: boolean
148 @raise LookupError: When the accessible object is dead
149 @raise NotImplementedError: When the EditableText interface is not
150 supported
151 '''
152 acc = self.accessible
153 if self.item_offset is None:
154 start_off = 0
155 else:
156 start_off = self.item_offset + self.char_offset
157 text_area = acc.queryEditableText()
158 if por.item_offset is None:
159 end_off = text_area.characterCount
160 else:
161 end_off = por.item_offset + por.char_offset
162 return text_area.copyText(start_off, end_off)
163
164
165 - def cutAccText(self, por):
166 '''
167 Cuts the text starting at item offset + char offset up to the offset given
168 by the L{AEPor}. Cuts from the beginning of the text if subject item offset
169 is None. Cuts to the end of the text if the L{AEPor} item offset is None.
170
171 @param por: Point of regard to the end terminus of the cut operation
172 @type por: L{AEPor}
173 @return: Indicator of whether the text was cut successfully or not
174 @rtype: boolean
175 @raise LookupError: When the accessible object is dead
176 @raise NotImplementedError: When the EditableText interface is not supported
177 '''
178 acc = self.accessible
179 if self.item_offset is None:
180 start_off = 0
181 else:
182 start_off = self.item_offset + self.char_offset
183 text_area = acc.queryEditableText()
184 if por.item_offset is None:
185 end_off = text_area.characterCount
186 else:
187 end_off = por.item_offset + por.char_offset
188 return text_area.cutText(start_off, end_off)
189
190
191 - def deleteAccText(self, por):
192 '''
193 Deletes the text starting at item offset + char offset up to the offset
194 given by the L{AEPor}. Deletes from the beginning of the text if subject item
195 offset is None. Deletes to the end of the text if the L{AEPor} item_offset is
196 None.
197
198 @param por: Point of regard to the end terminus of the delete operation
199 @type por: L{AEPor}
200 @return: Indicator of whether the text was deleted successfully or not
201 @rtype: boolean
202 @raise LookupError: When the accessible object is dead
203 @raise NotImplementedError: When the EditableText interface is not
204 supported
205 '''
206 acc = self.accessible
207 if self.item_offset is None:
208 start_off = 0
209 else:
210 start_off = self.item_offset + self.char_offset
211 text_area = acc.queryEditableText()
212 if por.item_offset is None:
213 end_off = text_area.characterCount
214 else:
215 end_off = por.item_offset + por.char_offset
216 return text_area.deleteText(start_off, end_off)
217
218
219 - def pasteAccText(self):
220 '''
221 Pastes the text at item offset + char offset. Pastes from the beginning of
222 the text is item offset is None.
223
224 @return: Indicator of whether the text was pasted successfully or not
225 @rtype: boolean
226 @raise LookupError: When the accessible object is dead
227 @raise NotImplementedError: When the EditableText interface is not
228 supported
229 '''
230 acc = self.accessible
231 if self.item_offset is None:
232 start_off = 0
233 else:
234 start_off = self.item_offset + self.char_offset
235 text_area = acc.queryEditableText()
236 return text_area.pasteText(start_off)
237
238
239 - def selectAccText(self, por, n=None):
240 '''
241 Adds a new selection if n is None or sets the nth selection otherwise.
242 Selects the text starting at item offset + char offset up to the offset
243 given by the L{AEPor}. Selects to the end of the text if the L{AEPor}
244 item_offset is None.
245
246 @param por: Point of regard to the end terminus of the select operation
247 @type por: L{AEPor}
248 @return: Indicator of whether the text was selected successfully or not
249 @rtype: boolean
250 @raise LookupError: When the accessible object is dead
251 @raise NotImplementedError: When the Text interface is not supported
252 '''
253 acc = self.accessible
254 if self.item_offset is None:
255 start_off = 0
256 else:
257 start_off = self.item_offset + self.char_offset
258 text_area = acc.queryText()
259 if por.item_offset is None:
260 end_off = text_area.characterCount
261 else:
262 end_off = por.item_offset + por.char_offset
263 if n is None:
264
265 return text_area.addSelection(start_off, end_off)
266 else:
267
268 return text_area.setSelection(n, start_off, end_off)
269
270 - def deselectAccText(self, n=None):
271 '''
272 Removes a all text selections if n is None or removes the nth text
273 selection otherwise. When n is None, returns True if at least one selection
274 was removed.
275
276 @return: Indicator of whether the text was deselected successfully or not
277 @rtype: boolean
278 @raise LookupError: When the accessible object is dead
279 @raise NotImplementedError: When the Text interface is not supported
280 '''
281 text_area = acc.queryText()
282 if n is None:
283
284 values = [text_area.removeSelection(i) for i in
285 xrange(text_area.getNSelections())]
286
287 return reduce(lambda x, y: x or y, values)
288 else:
289
290 return text_area.removeSelection(n)
291
292
294 '''
295 Performs a mouse event on the center of a given point of regard.
296
297 @param event: Mouse event to perform
298 @type event: integer (EVENT_SYNTHMOUSE*)
299 @return: Indicator of whether the event succeded or not
300 @raise LookupError: When the accessible object is dead
301 '''
302 ai = IAccessibleInfo(self.subject)
303 vpt_x, vpt_y = ai.getAccPosition()
304 width, height = ai.getAccVisualExtents()
305 pyatspi.Registry.generateMouseEvent(vpt_x + width*.5, vpt_y+ height*.5,
306 event)
307
308
309 return True
310
311
313 '''
314 Gives the subject accessible the keyboard focus.
315
316 @return: Did accessible accept (True) or refuse (False) the focus change?
317 @rtype: boolean
318 @raise LookupError: When the accessible object is dead
319 @raise NotImplementedError: When the accessible does not support an
320 interface for setting focus
321 '''
322 c = (self.accessible).queryComponent()
323 return c.grabFocus()
324
325
327 '''
328 Selects the subject accessible if all is False. Selects all children if all
329 is True.
330
331 @param all: Select all children?
332 @type all: boolean
333 @return: Did accessible accept (True) or refuse (False) the selection?
334 @rtype: boolean
335 @raise LookupError: When the accessible object is dead
336 @raise NotImplementedError: When the accessible does not support an
337 interface for setting selection
338 '''
339 acc = self.accessible
340 if all:
341
342 isel = acc.querySelection()
343
344 return isel.selectAll()
345 else:
346
347 i = acc.getIndexInParent()
348 parent = acc.parent
349
350 isel = parent.querySelection()
351 return isel.selectChild(i)
352
353
355 '''
356 Deselects the subject accessible if all is False. Deselects all children if
357 all is True.
358
359 @param all: Deselect all children?
360 @type all: boolean
361 @return: Did accessible accept (True) or refuse (False) the deselection?
362 @rtype: boolean
363 @raise LookupError: When the accessible object is dead
364 @raise NotImplementedError: When the accessible does not support an
365 interface for setting selection
366 '''
367 acc = self.accessible
368 if all:
369
370 isel = acc.querySelection()
371
372 return isel.clearSelection()
373 else:
374
375 i = acc.getIndexInParent()
376 parent = acc.parent
377
378 isel = parent.querySelection()
379 return isel.deselectChild(i)
380
381
383 '''
384 Executes the accessible action given by the index.
385
386 @param index: Index of the action to execute
387 @type index: integer
388 @return: Did the action execute (True) or not (False)?
389 @rtype: boolean
390 @raise LookupError: When the accessible object is dead
391 @raise NotImplementedError: When the accessible does not support the action
392 interface
393 '''
394 act = (self.accessible).queryAction()
395 return act.doAction(index)
396