Coverage Report - orca.speechgenerator

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