1 |
|
# Orca |
2 |
|
# |
3 |
|
# Copyright 2005-2007 Sun Microsystems Inc. |
4 |
|
# |
5 |
|
# This library is free software; you can redistribute it and/or |
6 |
|
# modify it under the terms of the GNU Library General Public |
7 |
|
# License as published by the Free Software Foundation; either |
8 |
|
# version 2 of the License, or (at your option) any later version. |
9 |
|
# |
10 |
|
# This library is distributed in the hope that it will be useful, |
11 |
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 |
|
# Library General Public License for more details. |
14 |
|
# |
15 |
|
# You should have received a copy of the GNU Library General Public |
16 |
|
# License along with this library; if not, write to the |
17 |
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 |
|
# Boston, MA 02111-1307, USA. |
19 |
|
|
20 |
|
"""Utilities for obtaining speech utterances for objects. In general, |
21 |
|
there probably should be a singleton instance of the SpeechGenerator |
22 |
|
class. For those wishing to override the speech generators, however, |
23 |
|
one can create a new instance and replace/extend the speech generators |
24 |
1 |
as they see fit.""" |
25 |
|
|
26 |
1 |
__id__ = "$Id: speechgenerator.py 2126 2007-03-06 21:35:17Z richb $" |
27 |
1 |
__version__ = "$Revision: 2126 $" |
28 |
1 |
__date__ = "$Date: 2007-03-06 13:35:17 -0800 (Tue, 06 Mar 2007) $" |
29 |
1 |
__copyright__ = "Copyright (c) 2005-2006 Sun Microsystems Inc." |
30 |
1 |
__license__ = "LGPL" |
31 |
|
|
32 |
1 |
import math |
33 |
|
|
34 |
1 |
import atspi |
35 |
1 |
import debug |
36 |
1 |
import orca_state |
37 |
1 |
import rolenames |
38 |
1 |
import settings |
39 |
|
|
40 |
1 |
from orca_i18n import _ # for gettext support |
41 |
|
|
42 |
2 |
class SpeechGenerator: |
43 |
|
"""Takes accessible objects and produces a string to speak for |
44 |
|
those objects. See the getSpeech method, which is the primary |
45 |
|
entry point. Subclasses can feel free to override/extend the |
46 |
|
speechGenerators instance field as they see fit.""" |
47 |
|
|
48 |
1 |
def __init__(self, script): |
49 |
|
|
50 |
|
# The script that created us. This allows us to ask the |
51 |
|
# script for information if we need it. |
52 |
|
# |
53 |
61 |
self._script = script |
54 |
|
|
55 |
|
# Set up a dictionary that maps role names to functions |
56 |
|
# that generate speech for objects that implement that role. |
57 |
|
# |
58 |
61 |
self.speechGenerators = {} |
59 |
61 |
self.speechGenerators[rolenames.ROLE_ALERT] = \ |
60 |
|
self._getSpeechForAlert |
61 |
61 |
self.speechGenerators[rolenames.ROLE_ANIMATION] = \ |
62 |
|
self._getSpeechForAnimation |
63 |
61 |
self.speechGenerators[rolenames.ROLE_ARROW] = \ |
64 |
|
self._getSpeechForArrow |
65 |
61 |
self.speechGenerators[rolenames.ROLE_CHECK_BOX] = \ |
66 |
|
self._getSpeechForCheckBox |
67 |
61 |
self.speechGenerators[rolenames.ROLE_CHECK_MENU] = \ |
68 |
|
self._getSpeechForCheckMenuItem |
69 |
61 |
self.speechGenerators[rolenames.ROLE_CHECK_MENU_ITEM] = \ |
70 |
|
self._getSpeechForCheckMenuItem |
71 |
61 |
self.speechGenerators[rolenames.ROLE_COLUMN_HEADER] = \ |
72 |
|
self._getSpeechForColumnHeader |
73 |
61 |
self.speechGenerators[rolenames.ROLE_COMBO_BOX] = \ |
74 |
|
self._getSpeechForComboBox |
75 |
61 |
self.speechGenerators[rolenames.ROLE_DESKTOP_ICON] = \ |
76 |
|
self._getSpeechForDesktopIcon |
77 |
61 |
self.speechGenerators[rolenames.ROLE_DIAL] = \ |
78 |
|
self._getSpeechForDial |
79 |
61 |
self.speechGenerators[rolenames.ROLE_DIALOG] = \ |
80 |
|
self._getSpeechForDialog |
81 |
61 |
self.speechGenerators[rolenames.ROLE_DIRECTORY_PANE] = \ |
82 |
|
self._getSpeechForDirectoryPane |
83 |
61 |
self.speechGenerators[rolenames.ROLE_FRAME] = \ |
84 |
|
self._getSpeechForFrame |
85 |
61 |
self.speechGenerators[rolenames.ROLE_HTML_CONTAINER] = \ |
86 |
|
self._getSpeechForHtmlContainer |
87 |
61 |
self.speechGenerators[rolenames.ROLE_ICON] = \ |
88 |
|
self._getSpeechForIcon |
89 |
61 |
self.speechGenerators[rolenames.ROLE_IMAGE] = \ |
90 |
|
self._getSpeechForImage |
91 |
61 |
self.speechGenerators[rolenames.ROLE_LABEL] = \ |
92 |
|
self._getSpeechForLabel |
93 |
61 |
self.speechGenerators[rolenames.ROLE_LAYERED_PANE] = \ |
94 |
|
self._getSpeechForLayeredPane |
95 |
61 |
self.speechGenerators[rolenames.ROLE_LIST] = \ |
96 |
|
self._getSpeechForList |
97 |
61 |
self.speechGenerators[rolenames.ROLE_MENU] = \ |
98 |
|
self._getSpeechForMenu |
99 |
61 |
self.speechGenerators[rolenames.ROLE_MENU_BAR] = \ |
100 |
|
self._getSpeechForMenuBar |
101 |
61 |
self.speechGenerators[rolenames.ROLE_MENU_ITEM] = \ |
102 |
|
self._getSpeechForMenuItem |
103 |
61 |
self.speechGenerators[rolenames.ROLE_OPTION_PANE] = \ |
104 |
|
self._getSpeechForOptionPane |
105 |
61 |
self.speechGenerators[rolenames.ROLE_PAGE_TAB] = \ |
106 |
|
self._getSpeechForPageTab |
107 |
61 |
self.speechGenerators[rolenames.ROLE_PAGE_TAB_LIST] = \ |
108 |
|
self._getSpeechForPageTabList |
109 |
61 |
self.speechGenerators[rolenames.ROLE_PARAGRAPH] = \ |
110 |
|
self._getSpeechForText |
111 |
61 |
self.speechGenerators[rolenames.ROLE_PASSWORD_TEXT] = \ |
112 |
|
self._getSpeechForText |
113 |
61 |
self.speechGenerators[rolenames.ROLE_PROGRESS_BAR] = \ |
114 |
|
self._getSpeechForProgressBar |
115 |
61 |
self.speechGenerators[rolenames.ROLE_PUSH_BUTTON] = \ |
116 |
|
self._getSpeechForPushButton |
117 |
61 |
self.speechGenerators[rolenames.ROLE_RADIO_BUTTON] = \ |
118 |
|
self._getSpeechForRadioButton |
119 |
61 |
self.speechGenerators[rolenames.ROLE_RADIO_MENU] = \ |
120 |
|
self._getSpeechForRadioMenuItem |
121 |
61 |
self.speechGenerators[rolenames.ROLE_RADIO_MENU_ITEM] = \ |
122 |
|
self._getSpeechForRadioMenuItem |
123 |
61 |
self.speechGenerators[rolenames.ROLE_ROW_HEADER] = \ |
124 |
|
self._getSpeechForRowHeader |
125 |
61 |
self.speechGenerators[rolenames.ROLE_SCROLL_BAR] = \ |
126 |
|
self._getSpeechForScrollBar |
127 |
61 |
self.speechGenerators[rolenames.ROLE_SLIDER] = \ |
128 |
|
self._getSpeechForSlider |
129 |
61 |
self.speechGenerators[rolenames.ROLE_SPIN_BUTTON] = \ |
130 |
|
self._getSpeechForSpinButton |
131 |
61 |
self.speechGenerators[rolenames.ROLE_SPLIT_PANE] = \ |
132 |
|
self._getSpeechForSplitPane |
133 |
61 |
self.speechGenerators[rolenames.ROLE_TABLE] = \ |
134 |
|
self._getSpeechForTable |
135 |
61 |
self.speechGenerators[rolenames.ROLE_TABLE_CELL] = \ |
136 |
|
self._getSpeechForTableCellRow |
137 |
61 |
self.speechGenerators[rolenames.ROLE_TABLE_COLUMN_HEADER] = \ |
138 |
|
self._getSpeechForTableColumnHeader |
139 |
61 |
self.speechGenerators[rolenames.ROLE_TABLE_ROW_HEADER] = \ |
140 |
|
self._getSpeechForTableRowHeader |
141 |
61 |
self.speechGenerators[rolenames.ROLE_TEAR_OFF_MENU_ITEM] = \ |
142 |
|
self._getSpeechForMenu |
143 |
61 |
self.speechGenerators[rolenames.ROLE_TERMINAL] = \ |
144 |
|
self._getSpeechForTerminal |
145 |
61 |
self.speechGenerators[rolenames.ROLE_TEXT] = \ |
146 |
|
self._getSpeechForText |
147 |
61 |
self.speechGenerators[rolenames.ROLE_TOGGLE_BUTTON] = \ |
148 |
|
self._getSpeechForToggleButton |
149 |
61 |
self.speechGenerators[rolenames.ROLE_TOOL_BAR] = \ |
150 |
|
self._getSpeechForToolBar |
151 |
61 |
self.speechGenerators[rolenames.ROLE_TREE] = \ |
152 |
|
self._getSpeechForTable |
153 |
61 |
self.speechGenerators[rolenames.ROLE_TREE_TABLE] = \ |
154 |
|
self._getSpeechForTable |
155 |
61 |
self.speechGenerators[rolenames.ROLE_WINDOW] = \ |
156 |
|
self._getSpeechForWindow |
157 |
|
|
158 |
1 |
def _getSpeechForObjectAccelerator(self, obj): |
159 |
|
"""Returns a list of utterances that describes the keyboard |
160 |
|
accelerator (and possibly shortcut) for the given object. |
161 |
|
|
162 |
|
Arguments: |
163 |
|
- obj: the Accessible object |
164 |
|
|
165 |
|
Returns a list of utterances to be spoken. |
166 |
|
""" |
167 |
|
|
168 |
220 |
result = self._script.getAcceleratorAndShortcut(obj) |
169 |
|
|
170 |
220 |
accelerator = result[0] |
171 |
|
#shortcut = result[1] |
172 |
|
|
173 |
220 |
utterances = [] |
174 |
|
|
175 |
|
# [[[TODO: WDW - various stuff preserved while we work out the |
176 |
|
# desired verbosity here.]]] |
177 |
|
# |
178 |
|
#if len(shortcut) > 0: |
179 |
|
# utterances.append(_("shortcut") + " " + shortcut) |
180 |
|
# utterances.append(accelerator) |
181 |
220 |
if len(accelerator) > 0: |
182 |
|
#utterances += (_("accelerator") + " " + accelerator) |
183 |
40 |
utterances.append(accelerator) |
184 |
|
|
185 |
220 |
return utterances |
186 |
|
|
187 |
1 |
def _getSpeechForObjectAvailability(self, obj): |
188 |
|
"""Returns a list of utterances that describes the availability |
189 |
|
of the given object. |
190 |
|
|
191 |
|
Arguments: |
192 |
|
- obj: the Accessible object |
193 |
|
|
194 |
|
Returns a list of utterances to be spoken. |
195 |
|
""" |
196 |
644 |
if obj.state.count(atspi.Accessibility.STATE_SENSITIVE) == 0: |
197 |
1 |
return [_("grayed")] |
198 |
|
else: |
199 |
643 |
return [] |
200 |
|
|
201 |
1 |
def _getSpeechForObjectLabel(self, obj): |
202 |
556 |
label = self._script.getDisplayedLabel(obj) |
203 |
556 |
if label: |
204 |
47 |
return [label] |
205 |
|
else: |
206 |
509 |
return [] |
207 |
|
|
208 |
1 |
def _getSpeechForObjectName(self, obj): |
209 |
658 |
name = self._script.getDisplayedText(obj) |
210 |
658 |
if name: |
211 |
550 |
return [name] |
212 |
108 |
elif obj.description: |
213 |
16 |
return [obj.description] |
214 |
|
else: |
215 |
92 |
return [] |
216 |
|
|
217 |
1 |
def _getSpeechForObjectRole(self, obj): |
218 |
548 |
if (obj.role != rolenames.ROLE_UNKNOWN): |
219 |
548 |
return [rolenames.getSpeechForRoleName(obj)] |
220 |
|
else: |
221 |
0 |
return [] |
222 |
|
|
223 |
1 |
def _debugGenerator(self, generatorName, obj, already_focused, utterances): |
224 |
|
"""Prints debug.LEVEL_FINER information regarding the speech generator. |
225 |
|
|
226 |
|
Arguments: |
227 |
|
- generatorName: the name of the generator |
228 |
|
- obj: the object being presented |
229 |
|
- already_focused: False if object just received focus |
230 |
|
- utterances: the generated text |
231 |
|
""" |
232 |
|
|
233 |
1519 |
debug.println(debug.LEVEL_FINER, |
234 |
1519 |
"GENERATOR: %s" % generatorName) |
235 |
1519 |
debug.println(debug.LEVEL_FINER, |
236 |
1519 |
" obj = %s" % obj.name) |
237 |
1519 |
debug.println(debug.LEVEL_FINER, |
238 |
1519 |
" role = %s" % obj.role) |
239 |
1519 |
debug.println(debug.LEVEL_FINER, |
240 |
1519 |
" already_focused = %s" % already_focused) |
241 |
1519 |
debug.println(debug.LEVEL_FINER, |
242 |
1519 |
" utterances:") |
243 |
4606 |
for text in utterances: |
244 |
3087 |
debug.println(debug.LEVEL_FINER, |
245 |
3087 |
" (%s)" % text) |
246 |
|
|
247 |
1 |
def _getDefaultSpeech(self, obj, already_focused): |
248 |
|
"""Gets a list of utterances to be spoken for the current |
249 |
|
object's name, role, and any accelerators. This is usually the |
250 |
|
fallback speech generator should no other specialized speech |
251 |
|
generator exist for this object. |
252 |
|
|
253 |
|
The default speech will be of the following form: |
254 |
|
|
255 |
|
label name role availability |
256 |
|
|
257 |
|
Arguments: |
258 |
|
- obj: an Accessible |
259 |
|
- already_focused: False if object just received focus |
260 |
|
|
261 |
|
Returns a list of utterances to be spoken for the object. |
262 |
|
""" |
263 |
|
|
264 |
347 |
utterances = [] |
265 |
|
|
266 |
347 |
if not already_focused: |
267 |
347 |
label = self._getSpeechForObjectLabel(obj) |
268 |
347 |
utterances.extend(label) |
269 |
347 |
name = self._getSpeechForObjectName(obj) |
270 |
347 |
if name != label: |
271 |
331 |
utterances.extend(name) |
272 |
347 |
utterances.extend(self._getSpeechForObjectRole(obj)) |
273 |
|
|
274 |
347 |
utterances.extend(self._getSpeechForObjectAvailability(obj)) |
275 |
|
|
276 |
347 |
self._debugGenerator("_getDefaultSpeech", |
277 |
347 |
obj, |
278 |
347 |
already_focused, |
279 |
347 |
utterances) |
280 |
|
|
281 |
347 |
return utterances |
282 |
|
|
283 |
1 |
def _getSpeechForAlert(self, obj, already_focused): |
284 |
|
"""Gets the title of the dialog and the contents of labels inside the |
285 |
|
dialog that are not associated with any other objects. |
286 |
|
|
287 |
|
Arguments: |
288 |
|
- obj: the Accessible dialog |
289 |
|
- already_focused: False if object just received focus |
290 |
|
|
291 |
|
Returns a list of utterances be spoken. |
292 |
|
""" |
293 |
|
|
294 |
14 |
utterances = [] |
295 |
14 |
label = self._getSpeechForObjectLabel(obj) |
296 |
14 |
utterances.extend(label) |
297 |
14 |
name = self._getSpeechForObjectName(obj) |
298 |
14 |
if name != label: |
299 |
12 |
utterances.extend(name) |
300 |
|
|
301 |
|
# Find all the unrelated labels in the dialog and speak them. |
302 |
|
# |
303 |
14 |
labels = self._script.findUnrelatedLabels(obj) |
304 |
44 |
for label in labels: |
305 |
30 |
utterances.append(label.name) |
306 |
|
|
307 |
14 |
self._debugGenerator("_getSpeechForAlert", |
308 |
14 |
obj, |
309 |
14 |
already_focused, |
310 |
14 |
utterances) |
311 |
|
|
312 |
14 |
return utterances |
313 |
|
|
314 |
1 |
def _getSpeechForAnimation(self, obj, already_focused): |
315 |
|
"""Gets the speech for an animation. |
316 |
|
|
317 |
|
Arguments: |
318 |
|
- obj: the animation |
319 |
|
- already_focused: False if object just received focus |
320 |
|
|
321 |
|
Returns a list of utterances to be spoken. |
322 |
|
""" |
323 |
|
|
324 |
0 |
utterances = [] |
325 |
0 |
label = self._getSpeechForObjectLabel(obj) |
326 |
0 |
utterances.extend(label) |
327 |
0 |
name = self._getSpeechForObjectName(obj) |
328 |
0 |
if name != label: |
329 |
0 |
utterances.extend(name) |
330 |
|
|
331 |
0 |
self._debugGenerator("_getSpeechForAnimation", |
332 |
0 |
obj, |
333 |
0 |
already_focused, |
334 |
0 |
utterances) |
335 |
|
|
336 |
0 |
return utterances |
337 |
|
|
338 |
1 |
def _getSpeechForArrow(self, obj, already_focused): |
339 |
|
"""Gets a list of utterances to be spoken for an arrow. |
340 |
|
|
341 |
|
Arguments: |
342 |
|
- obj: the arrow |
343 |
|
- already_focused: False if object just received focus |
344 |
|
|
345 |
|
Returns a list of utterances to be spoken for the object. |
346 |
|
""" |
347 |
|
|
348 |
|
# [[[TODO: determine orientation of arrow. Logged as bugzilla bug |
349 |
|
# 319744.]]] |
350 |
|
# text = arrow direction (left, right, up, down) |
351 |
|
# |
352 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
353 |
|
|
354 |
0 |
self._debugGenerator("_getSpeechForArrow", |
355 |
0 |
obj, |
356 |
0 |
already_focused, |
357 |
0 |
utterances) |
358 |
|
|
359 |
0 |
return utterances |
360 |
|
|
361 |
1 |
def _getSpeechForCheckBox(self, obj, already_focused): |
362 |
|
"""Get the speech for a check box. If the check box already had |
363 |
|
focus, then only the state is spoken. |
364 |
|
|
365 |
|
Arguments: |
366 |
|
- obj: the check box |
367 |
|
- already_focused: False if object just received focus |
368 |
|
|
369 |
|
Returns a list of utterances to be spoken for the object. |
370 |
|
""" |
371 |
|
|
372 |
129 |
utterances = [] |
373 |
129 |
if obj.state.count(atspi.Accessibility.STATE_CHECKED): |
374 |
51 |
checkedState = _("checked") |
375 |
|
else: |
376 |
78 |
checkedState = _("not checked") |
377 |
|
|
378 |
|
# If it's not already focused, say it's name |
379 |
|
# |
380 |
129 |
if not already_focused: |
381 |
123 |
label = self._getSpeechForObjectLabel(obj) |
382 |
123 |
utterances.extend(label) |
383 |
123 |
name = self._getSpeechForObjectName(obj) |
384 |
123 |
if name != label: |
385 |
54 |
utterances.extend(name) |
386 |
123 |
utterances.extend(self._getSpeechForObjectRole(obj)) |
387 |
123 |
utterances.append(checkedState) |
388 |
123 |
utterances.extend(self._getSpeechForObjectAvailability(obj)) |
389 |
|
else: |
390 |
6 |
utterances.append(checkedState) |
391 |
|
|
392 |
129 |
self._debugGenerator("_getSpeechForCheckBox", |
393 |
129 |
obj, |
394 |
129 |
already_focused, |
395 |
129 |
utterances) |
396 |
|
|
397 |
129 |
return utterances |
398 |
|
|
399 |
1 |
def _getSpeechForCheckMenuItem(self, obj, already_focused): |
400 |
|
"""Get the speech for a check menu item. If the check menu item |
401 |
|
already had focus, then only the state is spoken. |
402 |
|
|
403 |
|
Arguments: |
404 |
|
- obj: the check menu item |
405 |
|
- already_focused: False if object just received focus |
406 |
|
|
407 |
|
Returns a list of utterances to be spoken for the object. |
408 |
|
""" |
409 |
|
|
410 |
23 |
utterances = self._getSpeechForCheckBox(obj, already_focused) |
411 |
|
|
412 |
23 |
if (settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE)\ |
413 |
|
and not already_focused: |
414 |
23 |
utterances.extend(self._getSpeechForObjectAccelerator(obj)) |
415 |
|
|
416 |
23 |
self._debugGenerator("_getSpeechForCheckMenuItem", |
417 |
23 |
obj, |
418 |
23 |
already_focused, |
419 |
23 |
utterances) |
420 |
|
|
421 |
23 |
return utterances |
422 |
|
|
423 |
1 |
def _getSpeechForColumnHeader(self, obj, already_focused): |
424 |
|
"""Get the speech for a column header. |
425 |
|
|
426 |
|
Arguments: |
427 |
|
- obj: the column header |
428 |
|
- already_focused: False if object just received focus |
429 |
|
|
430 |
|
Returns a list of utterances to be spoken for the object. |
431 |
|
""" |
432 |
|
|
433 |
21 |
utterances = self._getDefaultSpeech(obj, already_focused) |
434 |
|
|
435 |
21 |
self._debugGenerator("_getSpeechForColumnHeader", |
436 |
21 |
obj, |
437 |
21 |
already_focused, |
438 |
21 |
utterances) |
439 |
|
|
440 |
21 |
return utterances |
441 |
|
|
442 |
1 |
def _getSpeechForComboBox(self, obj, already_focused): |
443 |
|
"""Get the speech for a combo box. If the combo box already has focus, |
444 |
|
then only the selection is spoken. |
445 |
|
|
446 |
|
Arguments: |
447 |
|
- obj: the combo box |
448 |
|
- already_focused: False if object just received focus |
449 |
|
|
450 |
|
Returns a list of utterances to be spoken for the object. |
451 |
|
""" |
452 |
|
|
453 |
40 |
utterances = [] |
454 |
|
|
455 |
40 |
if not already_focused: |
456 |
30 |
label = self._getSpeechForObjectLabel(obj) |
457 |
30 |
utterances.extend(label) |
458 |
|
else: |
459 |
10 |
label = None |
460 |
|
|
461 |
40 |
name = self._getSpeechForObjectName(obj) |
462 |
40 |
if name != label: |
463 |
37 |
utterances.extend(name) |
464 |
|
|
465 |
40 |
if not already_focused: |
466 |
30 |
utterances.extend(self._getSpeechForObjectRole(obj)) |
467 |
|
|
468 |
40 |
utterances.extend(self._getSpeechForObjectAvailability(obj)) |
469 |
|
|
470 |
40 |
self._debugGenerator("_getSpeechForComboBox", |
471 |
40 |
obj, |
472 |
40 |
already_focused, |
473 |
40 |
utterances) |
474 |
|
|
475 |
40 |
return utterances |
476 |
|
|
477 |
1 |
def _getSpeechForDesktopIcon(self, obj, already_focused): |
478 |
|
"""Get the speech for a desktop icon. |
479 |
|
|
480 |
|
Arguments: |
481 |
|
- obj: the desktop icon |
482 |
|
- already_focused: False if object just received focus |
483 |
|
|
484 |
|
Returns a list of utterances to be spoken for the object. |
485 |
|
""" |
486 |
|
|
487 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
488 |
|
|
489 |
0 |
self._debugGenerator("_getSpeechForDesktopIcon", |
490 |
0 |
obj, |
491 |
0 |
already_focused, |
492 |
0 |
utterances) |
493 |
|
|
494 |
0 |
return utterances |
495 |
|
|
496 |
1 |
def _getSpeechForDial(self, obj, already_focused): |
497 |
|
"""Get the speech for a dial. |
498 |
|
|
499 |
|
Arguments: |
500 |
|
- obj: the dial |
501 |
|
- already_focused: False if object just received focus |
502 |
|
|
503 |
|
Returns a list of utterances to be spoken for the object. |
504 |
|
""" |
505 |
|
|
506 |
|
# [[[TODO: WDW - might need to include the value here? Logged as |
507 |
|
# bugzilla bug 319746.]]] |
508 |
|
# |
509 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
510 |
|
|
511 |
0 |
self._debugGenerator("_getSpeechForDial", |
512 |
0 |
obj, |
513 |
0 |
already_focused, |
514 |
0 |
utterances) |
515 |
|
|
516 |
0 |
return utterances |
517 |
|
|
518 |
1 |
def _getSpeechForDialog(self, obj, already_focused): |
519 |
|
"""Get the speech for a dialog box. |
520 |
|
|
521 |
|
Arguments: |
522 |
|
- obj: the dialog box |
523 |
|
- already_focused: False if object just received focus |
524 |
|
|
525 |
|
Returns a list of utterances to be spoken for the object. |
526 |
|
""" |
527 |
|
|
528 |
10 |
utterances = self._getSpeechForAlert(obj, already_focused) |
529 |
|
|
530 |
10 |
self._debugGenerator("_getSpeechForDialog", |
531 |
10 |
obj, |
532 |
10 |
already_focused, |
533 |
10 |
utterances) |
534 |
|
|
535 |
10 |
return utterances |
536 |
|
|
537 |
1 |
def _getSpeechForDirectoryPane(self, obj, already_focused): |
538 |
|
"""Get the speech for a directory pane. |
539 |
|
|
540 |
|
Arguments: |
541 |
|
- obj: the dial |
542 |
|
- already_focused: False if object just received focus |
543 |
|
|
544 |
|
Returns a list of utterances to be spoken for the object. |
545 |
|
""" |
546 |
|
|
547 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
548 |
|
|
549 |
0 |
self._debugGenerator("_getSpeechForDirectoryPane", |
550 |
0 |
obj, |
551 |
0 |
already_focused, |
552 |
0 |
utterances) |
553 |
|
|
554 |
0 |
return utterances |
555 |
|
|
556 |
1 |
def _getSpeechForFrame(self, obj, already_focused): |
557 |
|
"""Get the speech for a frame. |
558 |
|
|
559 |
|
Arguments: |
560 |
|
- obj: the frame |
561 |
|
- already_focused: False if object just received focus |
562 |
|
|
563 |
|
Returns a list of utterances to be spoken for the object. |
564 |
|
""" |
565 |
|
|
566 |
|
# [[[TODO: richb - readjusted to just get the default speech instead |
567 |
|
# of treating the frame like an alert and speaking all unrelated |
568 |
|
# labels. We'll need to see if this has any adverse effects and |
569 |
|
# adjust accordingly.]]] |
570 |
|
# |
571 |
39 |
utterances = self._getDefaultSpeech(obj, already_focused) |
572 |
|
#utterances = self._getSpeechForAlert(obj, already_focused) |
573 |
|
|
574 |
39 |
self._debugGenerator("_getSpeechForFrame", |
575 |
39 |
obj, |
576 |
39 |
already_focused, |
577 |
39 |
utterances) |
578 |
|
|
579 |
39 |
return utterances |
580 |
|
|
581 |
1 |
def _getSpeechForHtmlContainer(self, obj, already_focused): |
582 |
|
"""Get the speech for an HTML container. |
583 |
|
|
584 |
|
Arguments: |
585 |
|
- obj: the dial |
586 |
|
- already_focused: False if object just received focus |
587 |
|
|
588 |
|
Returns a list of utterances to be spoken for the object. |
589 |
|
""" |
590 |
|
|
591 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
592 |
|
|
593 |
0 |
self._debugGenerator("_getSpeechForHtmlContainer", |
594 |
0 |
obj, |
595 |
0 |
already_focused, |
596 |
0 |
utterances) |
597 |
|
|
598 |
0 |
return utterances |
599 |
|
|
600 |
1 |
def _getSpeechForIcon(self, obj, already_focused): |
601 |
|
"""Get the speech for an icon. |
602 |
|
|
603 |
|
Arguments: |
604 |
|
- obj: the icon |
605 |
|
- already_focused: False if object just received focus |
606 |
|
|
607 |
|
Returns a list of utterances to be spoken for the object. |
608 |
|
""" |
609 |
|
|
610 |
|
# [[[TODO: WDW - HACK to remove availability output because nautilus |
611 |
|
# doesn't include this information for desktop icons. If, at some |
612 |
|
# point, it is determined that availability should be added back in, |
613 |
|
# then a custom script for nautilus needs to be written to remove the |
614 |
|
# availability.]]] |
615 |
|
# |
616 |
0 |
utterances = [] |
617 |
0 |
label = self._getSpeechForObjectLabel(obj) |
618 |
0 |
utterances.extend(label) |
619 |
0 |
name = self._getSpeechForObjectName(obj) |
620 |
0 |
if name != label: |
621 |
0 |
utterances.extend(name) |
622 |
|
|
623 |
0 |
if obj.image: |
624 |
0 |
description = obj.image.imageDescription |
625 |
0 |
if description and len(description): |
626 |
0 |
utterances.append(description) |
627 |
|
|
628 |
0 |
if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE: |
629 |
0 |
utterances.append(rolenames.getSpeechForRoleName(obj)) |
630 |
|
|
631 |
0 |
self._debugGenerator("_getSpeechForIcon", |
632 |
0 |
obj, |
633 |
0 |
already_focused, |
634 |
0 |
utterances) |
635 |
|
|
636 |
0 |
return utterances |
637 |
|
|
638 |
1 |
def _getSpeechForImage(self, obj, already_focused): |
639 |
|
"""Get the speech for an image. |
640 |
|
|
641 |
|
Arguments: |
642 |
|
- obj: the image |
643 |
|
- already_focused: False if object just received focus |
644 |
|
|
645 |
|
Returns a list of utterances to be spoken for the object. |
646 |
|
""" |
647 |
|
|
648 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
649 |
|
|
650 |
0 |
self._debugGenerator("_getSpeechForImage", |
651 |
0 |
obj, |
652 |
0 |
already_focused, |
653 |
0 |
utterances) |
654 |
|
|
655 |
0 |
return utterances |
656 |
|
|
657 |
1 |
def _getSpeechForLabel(self, obj, already_focused): |
658 |
|
"""Get the speech for a label. |
659 |
|
|
660 |
|
Arguments: |
661 |
|
- obj: the label |
662 |
|
- already_focused: False if object just received focus |
663 |
|
|
664 |
|
Returns a list of utterances to be spoken for the object. |
665 |
|
""" |
666 |
|
|
667 |
2 |
utterances = self._getDefaultSpeech(obj, already_focused) |
668 |
|
|
669 |
2 |
self._debugGenerator("_getSpeechForLabel", |
670 |
2 |
obj, |
671 |
2 |
already_focused, |
672 |
2 |
utterances) |
673 |
|
|
674 |
2 |
return utterances |
675 |
|
|
676 |
1 |
def _getSpeechForLayeredPane(self, obj, already_focused): |
677 |
|
"""Get the speech for a layered pane |
678 |
|
|
679 |
|
Arguments: |
680 |
|
- obj: the table |
681 |
|
- already_focused: False if object just received focus |
682 |
|
|
683 |
|
Returns a list of utterances to be spoken for the object. |
684 |
|
""" |
685 |
|
|
686 |
3 |
utterances = self._getDefaultSpeech(obj, already_focused) |
687 |
|
|
688 |
3 |
self._debugGenerator("_getSpeechForLayeredPane", |
689 |
3 |
obj, |
690 |
3 |
already_focused, |
691 |
3 |
utterances) |
692 |
|
|
693 |
|
# If this has no children, then let the user know. |
694 |
|
# |
695 |
3 |
hasItems = False |
696 |
3 |
for i in range(0, obj.childCount): |
697 |
0 |
child = obj.child(i) |
698 |
0 |
if child.state.count(atspi.Accessibility.STATE_SHOWING): |
699 |
0 |
hasItems = True |
700 |
0 |
break |
701 |
3 |
if not hasItems: |
702 |
3 |
utterances.append(_("0 items")) |
703 |
|
|
704 |
3 |
return utterances |
705 |
|
|
706 |
1 |
def _getSpeechForList(self, obj, already_focused): |
707 |
|
"""Get the speech for a list. |
708 |
|
|
709 |
|
Arguments: |
710 |
|
- obj: the list |
711 |
|
- already_focused: False if object just received focus |
712 |
|
|
713 |
|
Returns a list of utterances to be spoken for the object. |
714 |
|
""" |
715 |
|
|
716 |
|
# [[[TODO: WDW - include how many items in the list? |
717 |
|
# Logged as bugzilla bug 319749.]]] |
718 |
|
# |
719 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
720 |
|
|
721 |
0 |
self._debugGenerator("_getSpeechForList", |
722 |
0 |
obj, |
723 |
0 |
already_focused, |
724 |
0 |
utterances) |
725 |
|
|
726 |
0 |
return utterances |
727 |
|
|
728 |
1 |
def _getSpeechForMenu(self, obj, already_focused): |
729 |
|
"""Get the speech for a menu. |
730 |
|
|
731 |
|
Arguments: |
732 |
|
- obj: the menu |
733 |
|
- already_focused: False if object just received focus |
734 |
|
|
735 |
|
Returns a list of utterances to be spoken for the object. |
736 |
|
""" |
737 |
|
|
738 |
81 |
utterances = self._getDefaultSpeech(obj, already_focused) |
739 |
|
|
740 |
81 |
if (obj == orca_state.locusOfFocus) \ |
741 |
|
and (settings.speechVerbosityLevel \ |
742 |
|
== settings.VERBOSITY_LEVEL_VERBOSE): |
743 |
81 |
utterances.extend(self._getSpeechForObjectAccelerator(obj)) |
744 |
|
|
745 |
81 |
self._debugGenerator("_getSpeechForMenu", |
746 |
81 |
obj, |
747 |
81 |
already_focused, |
748 |
81 |
utterances) |
749 |
|
|
750 |
81 |
return utterances |
751 |
|
|
752 |
1 |
def _getSpeechForMenuBar(self, obj, already_focused): |
753 |
|
"""Get the speech for a menu bar. |
754 |
|
|
755 |
|
Arguments: |
756 |
|
- obj: the menu bar |
757 |
|
- already_focused: False if object just received focus |
758 |
|
|
759 |
|
Returns a list of utterances to be spoken for the object. |
760 |
|
""" |
761 |
|
|
762 |
2 |
utterances = self._getDefaultSpeech(obj, already_focused) |
763 |
|
|
764 |
2 |
self._debugGenerator("_getSpeechForMenuBar", |
765 |
2 |
obj, |
766 |
2 |
already_focused, |
767 |
2 |
utterances) |
768 |
|
|
769 |
2 |
return utterances |
770 |
|
|
771 |
1 |
def _getSpeechForMenuItem(self, obj, already_focused): |
772 |
|
"""Get the speech for a menu item. |
773 |
|
|
774 |
|
Arguments: |
775 |
|
- obj: the menu item |
776 |
|
- already_focused: False if object just received focus |
777 |
|
|
778 |
|
Returns a list of utterances to be spoken for the object. |
779 |
|
""" |
780 |
|
|
781 |
|
# No need to say "menu item" because we already know that. |
782 |
|
# |
783 |
116 |
utterances = self._getSpeechForObjectName(obj) |
784 |
116 |
if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE: |
785 |
116 |
utterances.extend(self._getSpeechForObjectAvailability(obj)) |
786 |
116 |
utterances.extend(self._getSpeechForObjectAccelerator(obj)) |
787 |
|
|
788 |
116 |
self._debugGenerator("_getSpeechForMenuItem", |
789 |
116 |
obj, |
790 |
116 |
already_focused, |
791 |
116 |
utterances) |
792 |
|
|
793 |
116 |
return utterances |
794 |
|
|
795 |
1 |
def _getSpeechForText(self, obj, already_focused): |
796 |
|
"""Get the speech for a text component. |
797 |
|
|
798 |
|
Arguments: |
799 |
|
- obj: the text component |
800 |
|
- already_focused: False if object just received focus |
801 |
|
|
802 |
|
Returns a list of utterances to be spoken for the object. |
803 |
|
""" |
804 |
|
|
805 |
|
# [[[TODO: WDW - HACK to remove availability because some text |
806 |
|
# areas, such as those in yelp, come up as insensitive though |
807 |
|
# they really are ineditable.]]] |
808 |
|
# |
809 |
30 |
utterances = [] |
810 |
30 |
utterances.extend(self._getSpeechForObjectLabel(obj)) |
811 |
30 |
if len(utterances) == 0: |
812 |
10 |
if obj.name and (len(obj.name)): |
813 |
0 |
utterances.append(obj.name) |
814 |
30 |
if obj.role != rolenames.ROLE_PARAGRAPH: |
815 |
30 |
utterances.extend(self._getSpeechForObjectRole(obj)) |
816 |
|
|
817 |
30 |
[text, caretOffset, startOffset] = self._script.getTextLineAtCaret(obj) |
818 |
30 |
utterances.append(text) |
819 |
|
|
820 |
30 |
self._debugGenerator("_getSpeechForText", |
821 |
30 |
obj, |
822 |
30 |
already_focused, |
823 |
30 |
utterances) |
824 |
|
|
825 |
30 |
return utterances |
826 |
|
|
827 |
1 |
def _getSpeechForOptionPane(self, obj, already_focused): |
828 |
|
"""Get the speech for an option pane. |
829 |
|
|
830 |
|
Arguments: |
831 |
|
- obj: the option pane |
832 |
|
- already_focused: False if object just received focus |
833 |
|
|
834 |
|
Returns a list of utterances to be spoken for the object. |
835 |
|
""" |
836 |
|
|
837 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
838 |
|
|
839 |
0 |
self._debugGenerator("_getSpeechForOptionPane", |
840 |
0 |
obj, |
841 |
0 |
already_focused, |
842 |
0 |
utterances) |
843 |
|
|
844 |
0 |
return utterances |
845 |
|
|
846 |
1 |
def _getSpeechForPageTab(self, obj, already_focused): |
847 |
|
"""Get the speech for a page tab. |
848 |
|
|
849 |
|
Arguments: |
850 |
|
- obj: the page tab |
851 |
|
- already_focused: False if object just received focus |
852 |
|
|
853 |
|
Returns a list of utterances to be spoken for the object. |
854 |
|
""" |
855 |
|
|
856 |
32 |
utterances = self._getDefaultSpeech(obj, already_focused) |
857 |
|
|
858 |
32 |
self._debugGenerator("_getSpeechForPageTab", |
859 |
32 |
obj, |
860 |
32 |
already_focused, |
861 |
32 |
utterances) |
862 |
|
|
863 |
32 |
return utterances |
864 |
|
|
865 |
1 |
def _getSpeechForPageTabList(self, obj, already_focused): |
866 |
|
"""Get the speech for a page tab list. |
867 |
|
|
868 |
|
Arguments: |
869 |
|
- obj: the page tab list |
870 |
|
- already_focused: False if object just received focus |
871 |
|
|
872 |
|
Returns a list of utterances to be spoken for the object. |
873 |
|
""" |
874 |
|
|
875 |
6 |
utterances = self._getDefaultSpeech(obj, already_focused) |
876 |
|
|
877 |
|
#if obj.childCount == 1: |
878 |
|
# utterances.append(_("one tab")) |
879 |
|
#else: |
880 |
|
# utterances.append(("%d " % obj.childCount) + _("tabs")) |
881 |
|
|
882 |
6 |
self._debugGenerator("_getSpeechForPageTabList", |
883 |
6 |
obj, |
884 |
6 |
already_focused, |
885 |
6 |
utterances) |
886 |
|
|
887 |
6 |
return utterances |
888 |
|
|
889 |
1 |
def _getSpeechForProgressBar(self, obj, already_focused): |
890 |
|
"""Get the speech for a progress bar. If the object already |
891 |
|
had focus, just the new value is spoken. |
892 |
|
|
893 |
|
Arguments: |
894 |
|
- obj: the progress bar |
895 |
|
- already_focused: False if object just received focus |
896 |
|
|
897 |
|
Returns a list of utterances to be spoken for the object. |
898 |
|
""" |
899 |
|
|
900 |
0 |
percentage = ("%d" % obj.value.currentValue) + " " \ |
901 |
|
+ _("percent") + ". " |
902 |
|
|
903 |
0 |
utterances = [] |
904 |
|
|
905 |
0 |
if not already_focused: |
906 |
0 |
label = self._getSpeechForObjectLabel(obj) |
907 |
0 |
utterances.extend(label) |
908 |
0 |
name = self._getSpeechForObjectName(obj) |
909 |
0 |
if name != label: |
910 |
0 |
utterances.extend(name) |
911 |
0 |
utterances.extend(self._getSpeechForObjectRole(obj)) |
912 |
|
|
913 |
0 |
utterances.append(percentage) |
914 |
|
|
915 |
0 |
self._debugGenerator("_getSpeechForProgressBar", |
916 |
0 |
obj, |
917 |
0 |
already_focused, |
918 |
0 |
utterances) |
919 |
|
|
920 |
0 |
return utterances |
921 |
|
|
922 |
1 |
def _getSpeechForPushButton(self, obj, already_focused): |
923 |
|
"""Get the speech for a push button |
924 |
|
|
925 |
|
Arguments: |
926 |
|
- obj: the push button |
927 |
|
- already_focused: False if object just received focus |
928 |
|
|
929 |
|
Returns a list of utterances to be spoken for the object. |
930 |
|
""" |
931 |
|
|
932 |
137 |
utterances = self._getDefaultSpeech(obj, already_focused) |
933 |
|
|
934 |
137 |
self._debugGenerator("_getSpeechForPushButton", |
935 |
137 |
obj, |
936 |
137 |
already_focused, |
937 |
137 |
utterances) |
938 |
|
|
939 |
137 |
return utterances |
940 |
|
|
941 |
1 |
def _getSpeechForRadioButton(self, obj, already_focused): |
942 |
|
"""Get the speech for a radio button. If the button already had |
943 |
|
focus, then only the state is spoken. |
944 |
|
|
945 |
|
Arguments: |
946 |
|
- obj: the check box |
947 |
|
- already_focused: False if object just received focus |
948 |
|
|
949 |
|
Returns a list of utterances to be spoken for the object. |
950 |
|
""" |
951 |
|
|
952 |
6 |
utterances = [] |
953 |
6 |
if obj.state.count(atspi.Accessibility.STATE_CHECKED): |
954 |
6 |
selectionState = _("selected") |
955 |
|
else: |
956 |
0 |
selectionState = _("not selected") |
957 |
|
|
958 |
|
# If it's not already focused, say it's name |
959 |
|
# |
960 |
6 |
if not already_focused: |
961 |
|
# The label is handled as a context in default.py |
962 |
|
# |
963 |
|
#utterances.extend(self._getSpeechForObjectLabel(obj)) |
964 |
6 |
utterances.extend(self._getSpeechForObjectName(obj)) |
965 |
6 |
utterances.append(selectionState) |
966 |
6 |
utterances.extend(self._getSpeechForObjectRole(obj)) |
967 |
6 |
utterances.extend(self._getSpeechForObjectAvailability(obj)) |
968 |
|
else: |
969 |
0 |
utterances.append(selectionState) |
970 |
|
|
971 |
6 |
self._debugGenerator("_getSpeechForRadioButton", |
972 |
6 |
obj, |
973 |
6 |
already_focused, |
974 |
6 |
utterances) |
975 |
|
|
976 |
6 |
return utterances |
977 |
|
|
978 |
1 |
def _getSpeechForRadioMenuItem(self, obj, already_focused): |
979 |
|
"""Get the speech for a radio menu item. If the menu item |
980 |
|
already had focus, then only the state is spoken. |
981 |
|
|
982 |
|
Arguments: |
983 |
|
- obj: the check menu item |
984 |
|
- already_focused: False if object just received focus |
985 |
|
|
986 |
|
Returns a list of utterances to be spoken for the object. |
987 |
|
""" |
988 |
|
|
989 |
0 |
utterances = self._getSpeechForRadioButton(obj, False) |
990 |
|
|
991 |
0 |
if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE: |
992 |
0 |
utterances.extend(self._getSpeechForObjectAvailability(obj)) |
993 |
0 |
utterances.extend(self._getSpeechForObjectAccelerator(obj)) |
994 |
|
|
995 |
0 |
self._debugGenerator("_getSpeechForRadioMenuItem", |
996 |
0 |
obj, |
997 |
0 |
already_focused, |
998 |
0 |
utterances) |
999 |
|
|
1000 |
0 |
return utterances |
1001 |
|
|
1002 |
1 |
def _getSpeechForRowHeader(self, obj, already_focused): |
1003 |
|
"""Get the speech for a row header. |
1004 |
|
|
1005 |
|
Arguments: |
1006 |
|
- obj: the column header |
1007 |
|
- already_focused: False if object just received focus |
1008 |
|
|
1009 |
|
Returns a list of utterances to be spoken for the object. |
1010 |
|
""" |
1011 |
|
|
1012 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
1013 |
|
|
1014 |
0 |
self._debugGenerator("_getSpeechForRowHeader", |
1015 |
0 |
obj, |
1016 |
0 |
already_focused, |
1017 |
0 |
utterances) |
1018 |
|
|
1019 |
0 |
return utterances |
1020 |
|
|
1021 |
1 |
def _getSpeechForScrollBar(self, obj, already_focused): |
1022 |
|
"""Get the speech for a scroll bar. |
1023 |
|
|
1024 |
|
Arguments: |
1025 |
|
- obj: the scroll bar |
1026 |
|
- already_focused: False if object just received focus |
1027 |
|
|
1028 |
|
Returns a list of utterances to be spoken for the object. |
1029 |
|
""" |
1030 |
|
|
1031 |
|
# [[[TODO: WDW - want to get orientation and maybe the |
1032 |
|
# percentage scrolled so far. Logged as bugzilla bug |
1033 |
|
# 319744.]]] |
1034 |
|
# |
1035 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
1036 |
|
|
1037 |
0 |
self._debugGenerator("_getSpeechForScrollBar", |
1038 |
0 |
obj, |
1039 |
0 |
already_focused, |
1040 |
0 |
utterances) |
1041 |
|
|
1042 |
0 |
return utterances |
1043 |
|
|
1044 |
1 |
def _getSpeechForSlider(self, obj, already_focused): |
1045 |
|
"""Get the speech for a slider. If the object already |
1046 |
|
had focus, just the value is spoken. |
1047 |
|
|
1048 |
|
Arguments: |
1049 |
|
- obj: the slider |
1050 |
|
- already_focused: False if object just received focus |
1051 |
|
|
1052 |
|
Returns a list of utterances to be spoken for the object. |
1053 |
|
""" |
1054 |
|
|
1055 |
0 |
value = obj.value |
1056 |
|
|
1057 |
|
# OK, this craziness is all about trying to figure out the most |
1058 |
|
# meaningful formatting string for the floating point values. |
1059 |
|
# The number of places to the right of the decimal point should |
1060 |
|
# be set by the minimumIncrement, but the minimumIncrement isn't |
1061 |
|
# always set. So...we'll default the minimumIncrement to 1/100 |
1062 |
|
# of the range. But, if max == min, then we'll just go for showing |
1063 |
|
# them off to two meaningful digits. |
1064 |
|
# |
1065 |
0 |
try: |
1066 |
0 |
minimumIncrement = value.minimumIncrement |
1067 |
0 |
except: |
1068 |
0 |
minimumIncrement = 0.0 |
1069 |
|
|
1070 |
0 |
if minimumIncrement == 0.0: |
1071 |
0 |
minimumIncrement = (value.maximumValue - value.minimumValue) \ |
1072 |
|
/ 100.0 |
1073 |
|
|
1074 |
0 |
try: |
1075 |
0 |
decimalPlaces = max(0, -math.log10(minimumIncrement)) |
1076 |
0 |
except: |
1077 |
0 |
try: |
1078 |
0 |
decimalPlaces = max(0, -math.log10(value.minimumValue)) |
1079 |
0 |
except: |
1080 |
0 |
try: |
1081 |
0 |
decimalPlaces = max(0, -math.log10(value.maximumValue)) |
1082 |
0 |
except: |
1083 |
0 |
decimalPlaces = 0 |
1084 |
|
|
1085 |
0 |
formatter = "%%.%df" % decimalPlaces |
1086 |
0 |
valueString = formatter % value.currentValue |
1087 |
|
#minString = formatter % value.minimumValue |
1088 |
|
#maxString = formatter % value.maximumValue |
1089 |
|
|
1090 |
0 |
if already_focused: |
1091 |
0 |
utterances = [valueString] |
1092 |
|
else: |
1093 |
0 |
utterances = [] |
1094 |
0 |
utterances.extend(self._getSpeechForObjectLabel(obj)) |
1095 |
|
|
1096 |
|
# Ignore the text on the slider. See bug 340559 |
1097 |
|
# (http://bugzilla.gnome.org/show_bug.cgi?id=340559): the |
1098 |
|
# implementors of the slider support decided to put in a |
1099 |
|
# Unicode left-to-right character as part of the text, |
1100 |
|
# even though that is not painted on the screen. |
1101 |
|
# |
1102 |
|
# In Java, however, there are sliders without a label. In |
1103 |
|
# this case, we'll add to presentation the slider name if |
1104 |
|
# it exists and we haven't found anything yet. |
1105 |
|
# |
1106 |
0 |
if not utterances: |
1107 |
0 |
utterances.extend(self._getSpeechForObjectName(obj)) |
1108 |
|
|
1109 |
0 |
utterances.extend(self._getSpeechForObjectRole(obj)) |
1110 |
0 |
utterances.append(valueString) |
1111 |
0 |
utterances.extend(self._getSpeechForObjectAvailability(obj)) |
1112 |
|
|
1113 |
0 |
self._debugGenerator("_getSpeechForSlider", |
1114 |
0 |
obj, |
1115 |
0 |
already_focused, |
1116 |
0 |
utterances) |
1117 |
|
|
1118 |
0 |
return utterances |
1119 |
|
|
1120 |
1 |
def _getSpeechForSpinButton(self, obj, already_focused): |
1121 |
|
"""Get the speech for a spin button. If the object already has |
1122 |
|
focus, then only the new value is spoken. |
1123 |
|
|
1124 |
|
Arguments: |
1125 |
|
- obj: the spin button |
1126 |
|
- already_focused: False if object just received focus |
1127 |
|
|
1128 |
|
Returns a list of utterances to be spoken for the object. |
1129 |
|
""" |
1130 |
|
|
1131 |
4 |
if already_focused: |
1132 |
0 |
utterances = [self._script.getDisplayedText(obj)] |
1133 |
|
else: |
1134 |
4 |
utterances = self._getDefaultSpeech(obj, already_focused) |
1135 |
|
|
1136 |
4 |
self._debugGenerator("_getSpeechForSpinButton", |
1137 |
4 |
obj, |
1138 |
4 |
already_focused, |
1139 |
4 |
utterances) |
1140 |
|
|
1141 |
4 |
return utterances |
1142 |
|
|
1143 |
1 |
def _getSpeechForSplitPane(self, obj, already_focused): |
1144 |
|
"""Get the speech for a split pane. |
1145 |
|
|
1146 |
|
Arguments: |
1147 |
|
- obj: the split pane |
1148 |
|
- already_focused: False if object just received focus |
1149 |
|
|
1150 |
|
Returns a list of utterances to be spoken for the object. |
1151 |
|
""" |
1152 |
|
|
1153 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
1154 |
|
|
1155 |
0 |
self._debugGenerator("_getSpeechForSplitPane", |
1156 |
0 |
obj, |
1157 |
0 |
already_focused, |
1158 |
0 |
utterances) |
1159 |
|
|
1160 |
0 |
return utterances |
1161 |
|
|
1162 |
1 |
def _getSpeechForTable(self, obj, already_focused): |
1163 |
|
"""Get the speech for a table |
1164 |
|
|
1165 |
|
Arguments: |
1166 |
|
- obj: the table |
1167 |
|
- already_focused: False if object just received focus |
1168 |
|
|
1169 |
|
Returns a list of utterances to be spoken for the object. |
1170 |
|
""" |
1171 |
|
|
1172 |
4 |
utterances = self._getDefaultSpeech(obj, already_focused) |
1173 |
|
|
1174 |
4 |
self._debugGenerator("_getSpeechForTable", |
1175 |
4 |
obj, |
1176 |
4 |
already_focused, |
1177 |
4 |
utterances) |
1178 |
|
|
1179 |
|
# If this is a table with no children, then let the user know. |
1180 |
|
# |
1181 |
4 |
hasItems = False |
1182 |
4 |
for i in range(0, obj.childCount): |
1183 |
4 |
child = obj.child(i) |
1184 |
4 |
if child.state.count(atspi.Accessibility.STATE_SHOWING): |
1185 |
4 |
hasItems = True |
1186 |
4 |
break |
1187 |
4 |
if not hasItems: |
1188 |
0 |
utterances.append(_("0 items")) |
1189 |
|
|
1190 |
4 |
return utterances |
1191 |
|
|
1192 |
1 |
def _getSpeechForTableCell(self, obj, already_focused): |
1193 |
|
"""Get the speech utterances for a single table cell |
1194 |
|
|
1195 |
|
Arguments: |
1196 |
|
- obj: the table |
1197 |
|
- already_focused: False if object just received focus |
1198 |
|
|
1199 |
|
Returns a list of utterances to be spoken for the object. |
1200 |
|
""" |
1201 |
|
|
1202 |
253 |
utterances = [] |
1203 |
|
|
1204 |
|
# [[[TODO: WDW - Attempt to infer the cell type. There's a |
1205 |
|
# bunch of stuff we can do here, such as check the EXPANDABLE |
1206 |
|
# state, check the NODE_CHILD_OF relation, etc. Logged as |
1207 |
|
# bugzilla bug 319750.]]] |
1208 |
|
# |
1209 |
253 |
action = obj.action |
1210 |
253 |
if action: |
1211 |
454 |
for i in range(0, action.nActions): |
1212 |
281 |
debug.println(debug.LEVEL_FINEST, |
1213 |
281 |
"speechgenerator.__getTableCellUtterances " \ |
1214 |
|
+ "looking at action %d" % i) |
1215 |
281 |
if action.getName(i) == "toggle": |
1216 |
73 |
obj.role = rolenames.ROLE_CHECK_BOX |
1217 |
73 |
utterances = self._getSpeechForCheckBox(obj, |
1218 |
73 |
already_focused) |
1219 |
73 |
obj.role = rolenames.ROLE_TABLE_CELL |
1220 |
73 |
break |
1221 |
|
|
1222 |
253 |
utterances.append(self._script.getDisplayedText(\ |
1223 |
|
self._script.getRealActiveDescendant(obj))) |
1224 |
|
|
1225 |
|
# [[[TODO: WDW - HACK attempt to determine if this is a node; |
1226 |
|
# if so, describe its state.]]] |
1227 |
|
# |
1228 |
253 |
if obj.state.count(atspi.Accessibility.STATE_EXPANDABLE): |
1229 |
15 |
if obj.state.count(atspi.Accessibility.STATE_EXPANDED): |
1230 |
6 |
utterances.append(_("expanded")) |
1231 |
|
else: |
1232 |
9 |
utterances.append(_("collapsed")) |
1233 |
|
|
1234 |
|
# If this is an expandable table cell with no children, then |
1235 |
|
# let the user know. |
1236 |
|
# |
1237 |
15 |
if obj.childCount == 0: |
1238 |
15 |
utterances.append(_("0 items")) |
1239 |
|
|
1240 |
253 |
self._debugGenerator("_getSpeechForTableCell", |
1241 |
253 |
obj, |
1242 |
253 |
already_focused, |
1243 |
253 |
utterances) |
1244 |
|
|
1245 |
253 |
return utterances |
1246 |
|
|
1247 |
1 |
def _getSpeechForTableCellRow(self, obj, already_focused): |
1248 |
|
"""Get the speech for a table cell row or a single table cell |
1249 |
|
if settings.readTableCellRow is False. |
1250 |
|
|
1251 |
|
Arguments: |
1252 |
|
- obj: the table |
1253 |
|
- already_focused: False if object just received focus |
1254 |
|
|
1255 |
|
Returns a list of utterances to be spoken for the object. |
1256 |
|
""" |
1257 |
|
|
1258 |
169 |
utterances = [] |
1259 |
|
|
1260 |
169 |
if (not already_focused): |
1261 |
162 |
if settings.readTableCellRow and obj.parent.table \ |
1262 |
|
and (not self._script.isLayoutOnly(obj.parent)): |
1263 |
162 |
parent = obj.parent |
1264 |
162 |
row = parent.table.getRowAtIndex(obj.index) |
1265 |
162 |
column = parent.table.getColumnAtIndex(obj.index) |
1266 |
|
|
1267 |
|
# This is an indication of whether we should speak all the |
1268 |
|
# table cells (the user has moved focus up or down a row), |
1269 |
|
# or just the current one (focus has moved left or right in |
1270 |
|
# the same row). |
1271 |
|
# |
1272 |
162 |
speakAll = True |
1273 |
162 |
if parent.__dict__.has_key("lastRow") and \ |
1274 |
|
parent.__dict__.has_key("lastColumn"): |
1275 |
151 |
speakAll = (parent.lastRow != row) or \ |
1276 |
|
((row == 0 or row == parent.table.nRows-1) and \ |
1277 |
|
parent.lastColumn == column) |
1278 |
|
|
1279 |
162 |
if speakAll: |
1280 |
317 |
for i in range(0, parent.table.nColumns): |
1281 |
202 |
accRow = parent.table.getAccessibleAt(row, i) |
1282 |
202 |
cell = atspi.Accessible.makeAccessible(accRow) |
1283 |
202 |
showing = cell.state.count( \ |
1284 |
|
atspi.Accessibility.STATE_SHOWING) |
1285 |
202 |
if showing: |
1286 |
199 |
utterances.extend(self._getSpeechForTableCell(cell, |
1287 |
199 |
already_focused)) |
1288 |
|
else: |
1289 |
47 |
utterances.extend(self._getSpeechForTableCell(obj, |
1290 |
47 |
already_focused)) |
1291 |
|
else: |
1292 |
0 |
utterances = self._getSpeechForTableCell(obj, already_focused) |
1293 |
|
else: |
1294 |
7 |
utterances = self._getSpeechForTableCell(obj, already_focused) |
1295 |
|
|
1296 |
169 |
self._debugGenerator("_getSpeechForTableCellRow", |
1297 |
169 |
obj, |
1298 |
169 |
already_focused, |
1299 |
169 |
utterances) |
1300 |
|
|
1301 |
169 |
return utterances |
1302 |
|
|
1303 |
1 |
def _getSpeechForTableColumnHeader(self, obj, already_focused): |
1304 |
|
"""Get the speech for a table column header |
1305 |
|
|
1306 |
|
Arguments: |
1307 |
|
- obj: the table column header |
1308 |
|
- already_focused: False if object just received focus |
1309 |
|
|
1310 |
|
Returns a list of utterances to be spoken for the object. |
1311 |
|
""" |
1312 |
|
|
1313 |
21 |
utterances = self._getSpeechForColumnHeader(obj, already_focused) |
1314 |
|
|
1315 |
21 |
self._debugGenerator("_getSpeechForTableColumnHeader", |
1316 |
21 |
obj, |
1317 |
21 |
already_focused, |
1318 |
21 |
utterances) |
1319 |
|
|
1320 |
21 |
return utterances |
1321 |
|
|
1322 |
1 |
def _getSpeechForTableRowHeader(self, obj, already_focused): |
1323 |
|
"""Get the speech for a table row header |
1324 |
|
|
1325 |
|
Arguments: |
1326 |
|
- obj: the table row header |
1327 |
|
- already_focused: False if object just received focus |
1328 |
|
|
1329 |
|
Returns a list of utterances to be spoken for the object. |
1330 |
|
""" |
1331 |
|
|
1332 |
0 |
utterances = self._getSpeechForRowHeader(obj, already_focused) |
1333 |
|
|
1334 |
0 |
self._debugGenerator("_getSpeechForTableRowHeader", |
1335 |
0 |
obj, |
1336 |
0 |
already_focused, |
1337 |
0 |
utterances) |
1338 |
|
|
1339 |
0 |
return utterances |
1340 |
|
|
1341 |
1 |
def _getSpeechForTearOffMenuItem(self, obj, already_focused): |
1342 |
|
"""Get the speech for a tear off menu item |
1343 |
|
|
1344 |
|
Arguments: |
1345 |
|
- obj: the tear off menu item |
1346 |
|
- already_focused: False if object just received focus |
1347 |
|
|
1348 |
|
Returns a list of utterances to be spoken for the object. |
1349 |
|
""" |
1350 |
|
|
1351 |
0 |
if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE: |
1352 |
0 |
utterances = [_("tear off menu item")] |
1353 |
|
else: |
1354 |
0 |
utterances = [_("tear off")] |
1355 |
|
|
1356 |
0 |
self._debugGenerator("_getSpeechForTearOffMenuItem", |
1357 |
0 |
obj, |
1358 |
0 |
already_focused, |
1359 |
0 |
utterances) |
1360 |
|
|
1361 |
0 |
return utterances |
1362 |
|
|
1363 |
1 |
def _getSpeechForTerminal(self, obj, already_focused): |
1364 |
|
"""Get the speech for a terminal |
1365 |
|
|
1366 |
|
Arguments: |
1367 |
|
- obj: the terminal |
1368 |
|
- already_focused: False if object just received focus |
1369 |
|
|
1370 |
|
Returns a list of utterances to be spoken for the object. |
1371 |
|
""" |
1372 |
|
|
1373 |
9 |
title = None |
1374 |
9 |
frame = self._script.getFrame(obj) |
1375 |
9 |
if frame: |
1376 |
9 |
title = frame.name |
1377 |
9 |
if not title: |
1378 |
0 |
title = self._script.getDisplayedLabel(obj) |
1379 |
|
|
1380 |
9 |
utterances = [title] |
1381 |
|
|
1382 |
9 |
self._debugGenerator("_getSpeechForTerminal", |
1383 |
9 |
obj, |
1384 |
9 |
already_focused, |
1385 |
9 |
utterances) |
1386 |
|
|
1387 |
9 |
return utterances |
1388 |
|
|
1389 |
1 |
def _getSpeechForToggleButton(self, obj, already_focused): |
1390 |
|
"""Get the speech for a toggle button. If the toggle button already |
1391 |
|
had focus, then only the state is spoken. |
1392 |
|
|
1393 |
|
Arguments: |
1394 |
|
- obj: the check box |
1395 |
|
- already_focused: False if object just received focus |
1396 |
|
|
1397 |
|
Returns a list of utterances to be spoken for the object. |
1398 |
|
""" |
1399 |
|
|
1400 |
10 |
utterances = [] |
1401 |
10 |
if obj.state.count(atspi.Accessibility.STATE_CHECKED): |
1402 |
2 |
checkedState = _("pressed") |
1403 |
|
else: |
1404 |
8 |
checkedState = _("not pressed") |
1405 |
|
|
1406 |
|
# If it's not already focused, say it's name |
1407 |
|
# |
1408 |
10 |
if not already_focused: |
1409 |
10 |
label = self._getSpeechForObjectLabel(obj) |
1410 |
10 |
utterances.extend(label) |
1411 |
10 |
name = self._getSpeechForObjectName(obj) |
1412 |
10 |
if name != label: |
1413 |
8 |
utterances.extend(name) |
1414 |
10 |
utterances.extend(self._getSpeechForObjectRole(obj)) |
1415 |
10 |
utterances.append(checkedState) |
1416 |
10 |
utterances.extend(self._getSpeechForObjectAvailability(obj)) |
1417 |
|
else: |
1418 |
0 |
utterances.append(checkedState) |
1419 |
|
|
1420 |
10 |
self._debugGenerator("_getSpeechForToggleButton", |
1421 |
10 |
obj, |
1422 |
10 |
already_focused, |
1423 |
10 |
utterances) |
1424 |
|
|
1425 |
10 |
return utterances |
1426 |
|
|
1427 |
1 |
def _getSpeechForToolBar(self, obj, already_focused): |
1428 |
|
"""Get the speech for a tool bar |
1429 |
|
|
1430 |
|
Arguments: |
1431 |
|
- obj: the tool bar |
1432 |
|
- already_focused: False if object just received focus |
1433 |
|
|
1434 |
|
Returns a list of utterances to be spoken for the object. |
1435 |
|
""" |
1436 |
|
|
1437 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
1438 |
|
|
1439 |
0 |
self._debugGenerator("_getSpeechForToolBar", |
1440 |
0 |
obj, |
1441 |
0 |
already_focused, |
1442 |
0 |
utterances) |
1443 |
|
|
1444 |
0 |
return utterances |
1445 |
|
|
1446 |
1 |
def _getSpeechForTree(self, obj, already_focused): |
1447 |
|
"""Get the speech for a tree |
1448 |
|
|
1449 |
|
Arguments: |
1450 |
|
- obj: the tree |
1451 |
|
- already_focused: False if object just received focus |
1452 |
|
|
1453 |
|
Returns a list of utterances to be spoken for the object. |
1454 |
|
""" |
1455 |
|
|
1456 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
1457 |
|
|
1458 |
0 |
self._debugGenerator("_getSpeechForTree", |
1459 |
0 |
obj, |
1460 |
0 |
already_focused, |
1461 |
0 |
utterances) |
1462 |
|
|
1463 |
0 |
return utterances |
1464 |
|
|
1465 |
1 |
def _getSpeechForTreeTable(self, obj, already_focused): |
1466 |
|
"""Get the speech for a tree table |
1467 |
|
|
1468 |
|
Arguments: |
1469 |
|
- obj: the tree table |
1470 |
|
- already_focused: False if object just received focus |
1471 |
|
|
1472 |
|
Returns a list of utterances to be spoken for the object. |
1473 |
|
""" |
1474 |
|
|
1475 |
0 |
utterances = self._getDefaultSpeech(obj, already_focused) |
1476 |
|
|
1477 |
0 |
self._debugGenerator("_getSpeechForTreeTable", |
1478 |
0 |
obj, |
1479 |
0 |
already_focused, |
1480 |
0 |
utterances) |
1481 |
|
|
1482 |
0 |
return utterances |
1483 |
|
|
1484 |
1 |
def _getSpeechForWindow(self, obj, already_focused): |
1485 |
|
"""Get the speech for a window |
1486 |
|
|
1487 |
|
Arguments: |
1488 |
|
- obj: the window |
1489 |
|
- already_focused: False if object just received focus |
1490 |
|
|
1491 |
|
Returns a list of utterances to be spoken for the object. |
1492 |
|
""" |
1493 |
|
|
1494 |
2 |
utterances = self._getDefaultSpeech(obj, already_focused) |
1495 |
|
|
1496 |
2 |
self._debugGenerator("_getSpeechForWindow", |
1497 |
2 |
obj, |
1498 |
2 |
already_focused, |
1499 |
2 |
utterances) |
1500 |
|
|
1501 |
2 |
return utterances |
1502 |
|
|
1503 |
1 |
def getSpeech(self, obj, already_focused): |
1504 |
|
"""Get the speech for an Accessible object. This will look |
1505 |
|
first to the specific speech generators and then to the |
1506 |
|
default speech generator. This method is the primary method |
1507 |
|
that external callers of this class should use. |
1508 |
|
|
1509 |
|
Arguments: |
1510 |
|
- obj: the object |
1511 |
|
- already_focused: False if object just received focus |
1512 |
|
|
1513 |
|
Returns a list of utterances to be spoken. |
1514 |
|
""" |
1515 |
|
|
1516 |
799 |
if self.speechGenerators.has_key(obj.role): |
1517 |
792 |
generator = self.speechGenerators[obj.role] |
1518 |
|
else: |
1519 |
7 |
generator = self._getDefaultSpeech |
1520 |
|
|
1521 |
799 |
return [" ".join(generator(obj, already_focused))] |
1522 |
|
|
1523 |
1 |
def getSpeechContext(self, obj, stopAncestor=None): |
1524 |
|
"""Get the speech that describes the names and role of |
1525 |
|
the container hierarchy of the object, stopping at and |
1526 |
|
not including the stopAncestor. |
1527 |
|
|
1528 |
|
Arguments: |
1529 |
|
- obj: the object |
1530 |
|
- stopAncestor: the anscestor to stop at and not include (None |
1531 |
|
means include all ancestors) |
1532 |
|
|
1533 |
|
Returns a list of utterances to be spoken. |
1534 |
|
""" |
1535 |
|
|
1536 |
725 |
utterances = [] |
1537 |
|
|
1538 |
725 |
if not obj: |
1539 |
0 |
return utterances |
1540 |
|
|
1541 |
725 |
if obj is stopAncestor: |
1542 |
15 |
return utterances |
1543 |
|
|
1544 |
|
# We try to ignore fillers and panels without names. |
1545 |
|
# [[[TODO: WDW - HACK sometimes table cells can be children |
1546 |
|
# of table cells (see the "Browse" dialog of gnome-terminal |
1547 |
|
# via "Edit" -> "Current Profile" -> "General" Tab -> |
1548 |
|
# "Profile icon:" button -> "Browse..." button - each element |
1549 |
|
# in the list is a compound table cell where the icon and |
1550 |
|
# text are child table cells of the table cell). So... |
1551 |
|
# we happily ignore those as well. One thing we might |
1552 |
|
# want to do is treat the parent as a compound object. |
1553 |
|
# Logged as bugzilla bug 319751.]]] |
1554 |
|
# |
1555 |
710 |
parent = obj.parent |
1556 |
710 |
if parent \ |
1557 |
|
and (obj.role == rolenames.ROLE_TABLE_CELL) \ |
1558 |
|
and (parent.role == rolenames.ROLE_TABLE_CELL): |
1559 |
0 |
parent = parent.parent |
1560 |
|
|
1561 |
1267 |
while parent and (parent.parent != parent): |
1562 |
1267 |
if parent == stopAncestor: |
1563 |
710 |
break |
1564 |
557 |
if (parent.role != rolenames.ROLE_FILLER) \ |
1565 |
|
and (parent.role != rolenames.ROLE_SECTION) \ |
1566 |
|
and (parent.role != rolenames.ROLE_LAYERED_PANE) \ |
1567 |
|
and (parent.role != rolenames.ROLE_SPLIT_PANE) \ |
1568 |
|
and (parent.role != rolenames.ROLE_SCROLL_PANE) \ |
1569 |
|
and (parent.role != rolenames.ROLE_UNKNOWN) \ |
1570 |
|
and (not self._script.isLayoutOnly(parent)): |
1571 |
|
|
1572 |
|
# Announce the label and text of the object in the hierarchy. |
1573 |
|
# |
1574 |
153 |
text = self._script.getDisplayedText(parent) |
1575 |
153 |
label = self._script.getDisplayedLabel(parent) |
1576 |
|
|
1577 |
|
# Push announcement of cell after text and label. |
1578 |
|
# |
1579 |
153 |
if parent.role != rolenames.ROLE_TABLE_CELL: |
1580 |
153 |
utterances.append(rolenames.getSpeechForRoleName(parent)) |
1581 |
|
|
1582 |
153 |
if text and len(text): |
1583 |
74 |
utterances.append(text) |
1584 |
153 |
if label and len(label): |
1585 |
2 |
utterances.append(label) |
1586 |
|
|
1587 |
153 |
if parent.role == rolenames.ROLE_TABLE_CELL: |
1588 |
0 |
utterances.append(rolenames.getSpeechForRoleName(parent)) |
1589 |
|
|
1590 |
|
# [[[TODO: HACK - we've discovered oddness in hierarchies |
1591 |
|
# such as the gedit Edit->Preferences dialog. In this |
1592 |
|
# dialog, we have labeled groupings of objects. The |
1593 |
|
# grouping is done via a FILLER with two children - one |
1594 |
|
# child is the overall label, and the other is the |
1595 |
|
# container for the grouped objects. When we detect this, |
1596 |
|
# we add the label to the overall context.]]] |
1597 |
|
# |
1598 |
557 |
if parent.role == rolenames.ROLE_FILLER: |
1599 |
236 |
label = self._script.getDisplayedLabel(parent) |
1600 |
236 |
if label and len (label): |
1601 |
48 |
utterances.append(label) |
1602 |
|
|
1603 |
557 |
parent = parent.parent |
1604 |
|
|
1605 |
710 |
utterances.reverse() |
1606 |
|
|
1607 |
710 |
return utterances |