1 '''
2 Defines L{AEAccAdapter.AEAccAdapter}s for AT-SPI tree accessibles. Trees
3 implement both the Table and the Selection interfaces.
4
5 @author: Peter Parente
6 @author: Eirikur Hallgrimsson
7 @organization: IBM Corporation
8 @copyright: Copyright (c) 2005, 2007 IBM Corporation
9 @license: The BSD License
10
11 @author: Frank Zenker
12 @organization: IT Science Center Ruegen gGmbH, Germany
13 @copyright: Copyright (c) 2007, 2008 ITSC Ruegen
14 @license: The BSD License
15
16 All rights reserved. This program and the accompanying materials are made
17 available under the terms of the BSD license which accompanies
18 this distribution, and is available at
19 U{http://www.opensource.org/licenses/bsd-license.php}
20 '''
21
22 import pyatspi
23 from ContainerAdapter import *
24 from TableAdapter import *
25 from DefaultNav import *
26 from AccessEngine.AEAccInterfaces import *
27 from AccessEngine.AEPor import AEPor
28
30 '''
31 Overrides L{TableAccInfoAdapter} to generate selector events on focus
32 and on selection. Expects the subject to be a C{pyatspi.Accessible}.
33
34 Adapts subject accessibles that provide the C{pyatspi.Accessibility.Accessible.Table}
35 interface and have ROLE_TREE_TABLE.
36 '''
37 provides = [IAccessibleInfo]
38
39 @staticmethod
41 '''
42 Tests if the given subject can be adapted by this class.
43
44 @param por: Point of regard to test
45 @type por: L{AEPor}
46 @return: True when the subject meets the condition named in the docstring
47 for this class, False otherwise
48 @rtype: boolean
49 '''
50 acc = por.accessible
51 r = acc.getRole()
52
53 if r != pyatspi.ROLE_TREE_TABLE:
54 return False
55
56 tab = acc.queryTable()
57 return True
58
59
61 '''
62 Gets the level of a node in a tree where zero is the root.
63
64 @return: Level of the node
65 @rtype: integer
66 @raise NotImplementedError: When a tree doesn't support the NODE_OF
67 accessible relation
68 '''
69
70 if self.item_offset is None:
71 raise NotImplementedError
72
73 count = 0
74 node = self.accessible.getChildAtIndex(self.item_offset)
75 relations = node.getRelationSet()
76 if not relations:
77
78
79 table = (self.accessible).queryTable()
80 row = table.getRowAtIndex(self.item_offset)
81 node = table.getAccessibleAt(row, 0)
82 relations = node.getRelationSet()
83
84 if not relations:
85
86 raise NotImplementedError
87
88 def parent(relations):
89 for rel in relations:
90 if rel.getRelationType() == pyatspi.RELATION_NODE_CHILD_OF:
91 return rel.getTarget(0).getRelationSet()
92 return None
93
94 while True:
95 temp = parent(relations)
96 if temp:
97 count +=1
98 relations = temp
99 else:
100 return count
101
103 '''
104 Overrides L{DefaultNavAdapter} to provide navigation over tree cells as items.
105 Expects the subject to be a L{AEPor}.
106
107 Adapts subject accessibles that provide the C{pyatspi.Accessibility.Accessible..ITable}
108 interface and have ROLE_TREE_TABLE.
109 '''
110 provides = [IAccessibleNav, IItemNav]
111
112 @staticmethod
114 '''
115 Tests if the given subject can be adapted by this class.
116
117 @param subject: L{AEPor} containing an accessible to test
118 @type subject: L{AEPor}
119 @return: True when the subject meets the condition named in the docstring
120 for this class, False otherwise
121 @rtype: boolean
122 '''
123 acc = subject.accessible
124 r = acc.getRole()
125 return (r == pyatspi.ROLE_TREE_TABLE and acc.queryTable())
126
127
129 '''
130 Gets the item offsets of the first and last items in a tree of cells.
131
132 @param only_visible: Only consider the first and last cells visible in
133 the tree (True) or the absolute first and last cells (False)?
134 @return: First and last item offsets
135 @rtype: 2-tuple of integer
136 @raise LookupError: When the first or last item or parent accessible is
137 not available
138 '''
139 acc = self.accessible
140 if only_visible:
141 comp = acc.queryComponent()
142 e = comp.getExtents(pyatspi.DESKTOP_COORDS)
143
144 x, y = e.x+FUDGE_PX, e.y+FUDGE_PX
145 first = comp.getAccessibleAtPoint(x, y, pyatspi.DESKTOP_COORDS)
146
147 x, y = e.x+e.width-FUDGE_PX, e.y+e.height-FUDGE_PX
148 last = comp.getAccessibleAtPoint(x, y, pyatspi.DESKTOP_COORDS)
149 else:
150 first = None
151 last = None
152
153 if first:
154 i = first.getIndexInParent()
155 else:
156 i = 0
157 if last:
158 j = last.getIndexInParent()
159 else:
160 t = acc.queryTable()
161 j = t.getIndexAt(t.nRows-1, t.nColumns-1)
162 return i, j
163
164
166 '''
167 Gets the next item relative to the one indicated by the L{AEPor}
168 providing this interface.
169
170 @param only_visible: True when Item in the returned L{AEPor} must be visible
171 @type only_visible: boolean
172 @return: Point of regard to the next item in the same accessible
173 @rtype: L{AEPor}
174 @raise IndexError: When there is no next item
175 @raise LookupError: When lookup for the next item fails even though it may
176 exist
177 '''
178 acc = self.accessible
179 off = self.item_offset
180
181 i, j = self._getVisibleItemExtents(only_visible)
182
183
184
185
186
187 if off is None or off < i:
188
189 return AEPor(acc, i, 0)
190 elif off+1 >= i and off+1 <= j:
191
192 t = acc.queryTable()
193 r, c = t.getRowAtIndex(off), t.getColumnAtIndex(off)
194
195 if c < t.nColumns-1:
196 c += 1
197 else:
198 r += 1
199 c = 0
200
201 n_off = t.getIndexAt(r, c)
202 return AEPor(acc, n_off, 0)
203 else:
204
205 raise IndexError
206
207
209 '''
210 Gets the previous item relative to the one indicated by the L{AEPor}
211 providing this interface.
212
213 @param only_visible: True when Item in the returned L{AEPor} must be visible
214 @type only_visible: boolean
215 @return: Point of regard to the previous item in the same accessible
216 @rtype: L{AEPor}
217 @raise IndexError: When there is no previous item
218 @raise LookupError: When lookup for the previous item fails even though it
219 may exist
220 '''
221 acc = self.accessible
222 off = self.item_offset
223 comp = acc.queryComponent()
224
225 i, j = self._getVisibleItemExtents(only_visible)
226
227
228 if off is None:
229
230 raise IndexError
231 elif off > j:
232
233 return AEPor(acc, j, 0)
234 elif off-1 >= i and off-1 <= j:
235
236 t = acc.queryTable()
237 r, c = t.getRowAtIndex(off), t.getColumnAtIndex(off)
238
239 if c:
240 c -= 1
241 else:
242 r -= 1
243 c = t.nColumns-1
244
245 p_off = t.getIndexAt(r, c)
246 return AEPor(acc, p_off, 0)
247
248
249
250 else:
251
252 return AEPor(acc, None, 0)
253
254
256 '''
257 Gets the last item relative to the one indicated by the L{AEPor}
258 providing this interface.
259
260 @param only_visible: True when Item in the returned L{AEPor} must be visible
261 @type only_visible: boolean
262 @return: Point of regard to the last item in the same accessible
263 @rtype: L{AEPor}
264 @raise LookupError: When lookup for the last item fails even though it may
265 exist
266 '''
267 acc = self.accessible
268 comp = acc.queryComponent()
269
270 child = acc.getChildAtIndex(acc.childCount-1)
271 if IAccessibleInfo(AEPor(child)).isAccVisible() or not only_visible:
272 return AEPor(acc, acc.childCount-1, 0)
273
274 i, j = self._getVisibleItemExtents(only_visible)
275 return AEPor(acc, j, 0)
276
277
279 '''
280 Gets the first item relative to the one indicated by the L{AEPor}
281 providing this interface.
282
283 @param only_visible: True when Item in the returned L{AEPor} must be visible
284 @type only_visible: boolean
285 @return: Point of regard to the last item in the same accessible
286 @rtype: L{AEPor}
287 @raise LookupError: When lookup for the last item fails even though it may
288 exist
289 '''
290 acc = self.accessible
291 comp = acc.queryComponent()
292
293 child = acc.getChildAtIndex(0)
294 if IAccessibleInfo(AEPor(child)).isAccVisible() or not only_visible:
295 return AEPor(acc, 0, 0)
296
297 i, j = self._getVisibleItemExtents(only_visible)
298 return AEPor(acc, i, 0)
299
300
302 '''
303 Always raises LookupError. Tables have items but no children.
304
305 @raise LookupError: Always
306 '''
307 raise LookupError
308
309
311 '''
312 Always raises LookupError. Tables have items but no children.
313
314 @raise LookupError: Always
315 '''
316 raise LookupError
317
318
319
320
321
322
323
324
325
326