Coverage Report - orca.where_am_I

ModuleCoverage %
orca.where_am_I
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 1
"""Speaks information about the current object of interest."""
21
22 1
__id__        = "$Id: where_am_I.py 2514 2007-07-03 13:15:24Z shaeger $"
23 1
__version__   = "$Revision: 2514 $"
24 1
__date__      = "$Date: 2007-07-03 09:15:24 -0400 (Tue, 03 Jul 2007) $"
25 1
__copyright__ = "Copyright (c) 2005-2007 Sun Microsystems Inc."
26 1
__license__   = "LGPL"
27
28 1
import atspi
29 1
import debug
30 1
import orca_state
31 1
import rolenames
32 1
import settings
33 1
import speech
34 1
import urlparse, urllib2
35
36 1
from orca_i18n import _ # for gettext support
37 1
from orca_i18n import ngettext  # for ngettext support
38
39 2
class WhereAmI:
40
41 1
    def __init__(self, script):
42
        """Create a new WhereAmI that will be used to speak information
43
        about the current object of interest.
44
        """
45
46 79
        self._script = script
47 79
        self._debugLevel = debug.LEVEL_FINEST
48 79
        self._statusBar = None
49 79
        self._lastAttributeString = ""
50
51 1
    def whereAmI(self, obj, doubleClick, orcaKey):
52
        """Speaks information about the current object of interest, including
53
        the object itself, which window it is in, which application, which
54
        workspace, etc.
55
56
        The object of interest can vary depending upon the mode the user
57
        is using at the time. For example, in focus tracking mode, the
58
        object of interest is the object with keyboard focus. In review
59
        mode, the object of interest is the object currently being visited,
60
        whether it has keyboard focus or not.
61
        """
62
63 94
        if (not obj):
64 0
            return False
65
66 94
        debug.println(self._debugLevel,
67
            "whereAmI: \
68
           \n  label=%s \
69
           \n  name=%s \
70
           \n  role=%s \
71
           \n  mnemonics=%s \
72
           \n  parent label= %s \
73
           \n  parent name=%s \
74
           \n  parent role=%s \
75
           \n  double-click=%s \
76 94
           \n  orca-key=%s" % \
77 94
            (self._getObjLabel(obj),
78 94
             self._getObjName(obj),
79 94
             obj.role,
80 94
             self._script.getAcceleratorAndShortcut(obj),
81 94
             self._getObjLabel(obj.parent),
82 94
             self._getObjName(obj.parent),
83 94
             obj.parent.role,
84 94
             doubleClick,
85 94
             orcaKey))
86
87 94
        role = obj.role
88
89 94
        if orcaKey:
90 1
            self._processOrcaKey(obj, doubleClick)
91
92 93
        elif role == rolenames.ROLE_CHECK_BOX:
93 2
            self._speakCheckBox(obj, doubleClick)
94
95 91
        elif role == rolenames.ROLE_RADIO_BUTTON:
96 6
            self._speakRadioButton(obj, doubleClick)
97
98 85
        elif role == rolenames.ROLE_COMBO_BOX:
99 20
            self._speakComboBox(obj, doubleClick)
100
101 65
        elif role == rolenames.ROLE_SPIN_BUTTON:
102 3
            self._speakSpinButton(obj, doubleClick)
103
104 62
        elif role == rolenames.ROLE_PUSH_BUTTON:
105 1
            self._speakPushButton(obj, doubleClick)
106
107 61
        elif role == rolenames.ROLE_SLIDER:
108 0
            self._speakSlider(obj, doubleClick)
109
110 61
        elif role == rolenames.ROLE_MENU or \
111 61
             role == rolenames.ROLE_MENU_ITEM or \
112 58
             role == rolenames.ROLE_CHECK_MENU or \
113 58
             role == rolenames.ROLE_CHECK_MENU_ITEM or \
114 55
             role == rolenames.ROLE_RADIO_MENU or \
115 55
             role == rolenames.ROLE_RADIO_MENU_ITEM:
116 6
            self._speakMenuItem(obj, doubleClick)
117
118 55
        elif role == rolenames.ROLE_PAGE_TAB:
119 6
            self._speakPageTab(obj, doubleClick)
120
121 49
        elif role == rolenames.ROLE_TEXT or \
122 40
             role == rolenames.ROLE_TERMINAL:
123 9
            self._speakText(obj, doubleClick)
124
125 40
        elif role == rolenames.ROLE_TABLE_CELL:
126 25
            self._speakTableCell(obj, doubleClick)
127
128 15
        elif role == rolenames.ROLE_PARAGRAPH:
129 0
            self._speakParagraph(obj, doubleClick)
130
131 15
        elif role == rolenames.ROLE_ICON:
132 8
            self._speakIconPanel(obj, doubleClick)
133
134 7
        elif role == rolenames.ROLE_LINK:
135 0
            self._speakLink(obj, doubleClick)
136
137
        else:
138 7
            self._speakGenericObject(obj, doubleClick)
139
140 94
        return True
141
142 1
    def _processOrcaKey(self, obj, doubleClick):
143
        """Test to see if the Orca modifier key has been pressed.
144
        """
145
146 1
        self._handleOrcaKey(obj, doubleClick)
147
148 1
    def _speakCheckBox(self, obj, doubleClick):
149
        """Checkboxes present the following information
150
        (an example is 'Enable speech, checkbox checked, Alt E'):
151
        1. label
152
        2. role
153
        3. state
154
        4. mnemonic (i.e. Alt plus the underlined letter), if any
155
        """
156
157 2
        utterances = []
158 2
        text = self._getObjLabelAndName(obj)
159 2
        utterances.append(text)
160
161 2
        text = rolenames.getSpeechForRoleName(obj)
162 2
        utterances.append(text)
163
164 2
        if obj.state.count(atspi.Accessibility.STATE_CHECKED):
165
            # Translators: this represents the state of a checkbox.
166
            #
167 1
            text = _("checked")
168
        else:
169
            # Translators: this represents the state of a checkbox.
170
            #
171 1
            text = _("not checked")
172 2
        utterances.append(text)
173
174 2
        text = self._getObjMnemonic(obj)
175 2
        utterances.append(text)
176
177 2
        debug.println(self._debugLevel, "check box utterances=%s" \
178 2
                      % utterances)
179 2
        speech.speakUtterances(utterances)
180
181 1
    def _speakRadioButton(self, obj, doubleClick):
182
        """Radio Buttons present the following information (an example is
183
        'Punctuation Level, Some, Radio button, selected, item 2 of 4, Alt M'):
184
185
        1. group name
186
        2. label
187
        3. role
188
        4. state
189
        5. relative position
190
        6. mnemonic (i.e. Alt plus the underlined letter), if any
191
        """
192
193 6
        utterances = []
194 6
        text = self._getGroupLabel(obj)
195 6
        utterances.append(text)
196
197 6
        if doubleClick:
198 2
            text = self._getPositionInGroup(obj)
199 2
            utterances.append(text)
200
201 6
        text = self._getObjLabelAndName(obj)
202 6
        utterances.append(text)
203
204 6
        text = rolenames.getSpeechForRoleName(obj)
205 6
        utterances.append(text)
206
207 6
        if obj.state.count(atspi.Accessibility.STATE_CHECKED):
208
            # Translators: this represents the state of a checkbox.
209
            #
210 6
            text = _("checked")
211
        else:
212
            # Translators: this represents the state of a checkbox.
213
            #
214 0
            text = _("not checked")
215 6
        utterances.append(text)
216
217 6
        if not doubleClick:
218 4
            text = self._getPositionInGroup(obj)
219 4
            utterances.append(text)
220
221 6
        text = self._getObjMnemonic(obj)
222 6
        utterances.append(text)
223
224 6
        debug.println(self._debugLevel, "radio button utterances=%s" % \
225 6
                      utterances)
226 6
        speech.speakUtterances(utterances)
227
228 1
    def _speakComboBox(self, obj, doubleClick):
229
        """Comboboxes present the following information (an example is
230
        'Speech system: combo box, GNOME Speech Services, item 1 of 1,
231
        Alt S'):
232
        1. label
233
        2. role
234
        3. current value
235
        4. relative position
236
        5. mnemonic (i.e. Alt plus the underlined letter), if any
237
        """
238
239 20
        utterances = []
240 20
        text = self._getObjLabel(obj)
241 20
        utterances.append(text)
242
243 20
        text = rolenames.getSpeechForRoleName(obj)
244 20
        utterances.append(text)
245
246 20
        if doubleClick:
247
            # child(0) is the popup list
248 6
            name = self._getObjName(obj)
249 6
            text = self._getPositionInList(obj.child(0), name)
250 6
            utterances.append(text)
251
252 6
            utterances.append(name)
253
        else:
254 14
            name = self._getObjName(obj)
255 14
            utterances.append(name)
256
257
            # child(0) is the popup list
258 14
            text = self._getPositionInList(obj.child(0), name)
259 14
            utterances.append(text)
260
261 20
        text = self._getObjMnemonic(obj)
262 20
        utterances.append(text)
263
264 20
        debug.println(self._debugLevel, "combo box utterances=%s" % \
265 20
                      utterances)
266 20
        speech.speakUtterances(utterances)
267
268 1
    def _speakSpinButton(self, obj, doubleClick):
269
        """Spin Buttons present the following information (an example is
270
        'Scale factor: spin button, 4.00, Alt F'):
271
272
        1. label
273
        2. role
274
        3. current value
275
        4. mnemonic (i.e. Alt plus the underlined letter), if any
276
        """
277
278 3
        utterances = []
279 3
        text = self._getObjLabelAndName(obj)
280 3
        utterances.append(text)
281
282 3
        text = rolenames.getSpeechForRoleName(obj)
283 3
        utterances.append(text)
284
285 3
        value = obj.value
286 3
        if value:
287 3
            text = "%.1f" % value.currentValue
288 3
            utterances.append(text)
289
290 3
        text = self._getObjMnemonic(obj)
291 3
        utterances.append(text)
292
293 3
        debug.println(self._debugLevel, "spin button utterances=%s" % \
294 3
                      utterances)
295 3
        speech.speakUtterances(utterances)
296
297 1
    def _speakPushButton(self, obj, doubleClick):
298
        """ Push Buttons present the following information (an example is
299
        'Apply button, Alt A'):
300
301
        1. label
302
        2. role
303
        3. mnemonic (i.e. Alt plus the underlined letter), if any
304
        """
305
306 1
        utterances = []
307 1
        text = self._getObjLabelAndName(obj)
308 1
        utterances.append(text)
309
310 1
        text = rolenames.getSpeechForRoleName(obj)
311 1
        utterances.append(text)
312
313 1
        text = self._getObjMnemonic(obj)
314 1
        utterances.append(text)
315
316 1
        debug.println(self._debugLevel, "push button utterances=%s" % \
317 1
                      utterances)
318 1
        speech.speakUtterances(utterances)
319
320 1
    def _speakSlider(self, obj, doubleClick):
321
        """Sliders present the following information (examples include
322
        'Pitch slider, 5.0, 56%'; 'Volume slider, 9.0, 100%'):
323
324
        1. label
325
        2. role
326
        3. value
327
        4. percentage (if possible)
328
        5. mnemonic (i.e. Alt plus the underlined letter), if any
329
        """
330
331 0
        utterances = []
332 0
        text = self._getObjLabel(obj)
333 0
        utterances.append(text)
334
335 0
        text = rolenames.getSpeechForRoleName(obj)
336 0
        utterances.append(text)
337
338 0
        values = self._getSliderValues(obj)
339 0
        utterances.append(values[0])
340
        # Translators: this is the percentage value of a slider.
341
        #
342 0
        utterances.append(_("%s percent") % values[1])
343
344 0
        text = self._getObjMnemonic(obj)
345 0
        utterances.append(text)
346
347 0
        debug.println(self._debugLevel, "slider utterances=%s" % \
348 0
                      utterances)
349 0
        speech.speakUtterances(utterances)
350
351 1
    def _speakMenuItem(self, obj, doubleClick):
352
        """Menu items present the following information (examples include
353
        'File menu, Open..., Control + O, item 2 of 20, O', 'File menu,
354
        Wizards Menu, item 4 of 20, W'):
355
356
        1. Name of the menu containing the item, followed by its role
357
        2. item name, followed by its role (if a menu) followed by its
358
        accelerator key, if any
359
        3. relative position
360
        4. mnemonic (i.e. Alt plus the underlined letter), if any
361
        """
362
363 6
        utterances = []
364 6
        text = self._getObjLabelAndName(obj.parent)
365 6
        utterances.append(text)
366
367 6
        if doubleClick:
368
            # parent is the page tab list
369 2
            name = self._getObjName(obj)
370 2
            text = self._getPositionInList(obj.parent, name)
371 2
            utterances.append(text)
372
373 6
        text = self._getObjLabelAndName(obj)
374 6
        utterances.append(text)
375
376 6
        text = self._getObjAccelerator(obj)
377 6
        utterances.append(text)
378
379 6
        text = rolenames.getSpeechForRoleName(obj)
380 6
        utterances.append(text)
381
382 6
        if not doubleClick:
383
            # parent is the page tab list
384 4
            name = self._getObjName(obj)
385 4
            text = self._getPositionInList(obj.parent, name)
386 4
            utterances.append(text)
387
388 6
        text = self._getObjShortcut(obj)
389 6
        utterances.append(text)
390
391 6
        debug.println(self._debugLevel, "menu item utterances=%s" % \
392 6
                      utterances)
393 6
        speech.speakUtterances(utterances)
394
395 1
    def _speakPageTab(self, obj, doubleClick):
396
        """Tabs in a Tab List present the following information (an example
397
        is 'Tab list, braille page, item 2 of 5'):
398
399
        1. role
400
        2. label + 'page'
401
        3. relative position
402
        4. mnemonic (i.e. Alt plus the underlined letter), if any
403
        """
404
405 6
        utterances = []
406 6
        text = rolenames.getSpeechForRoleName(obj)
407 6
        utterances.append(text)
408
409 6
        if doubleClick:
410
            # Translators: "page" is the word for a page tab in a tab list.
411
            #
412 2
            text = _("%s page") % self._getObjLabelAndName(obj)
413 2
            utterances.append(text)
414
415 2
            name = self._getObjName(obj)
416 2
            text = self._getPositionInList(obj.parent, name)
417 2
            utterances.append(text)
418
        else:
419 4
            name = self._getObjName(obj)
420 4
            text = self._getPositionInList(obj.parent, name)
421 4
            utterances.append(text)
422
423
            # Translators: "page" is the word for a page tab in a tab list.
424
            #
425 4
            text = _("%s page") % self._getObjLabelAndName(obj)
426 4
            utterances.append(text)
427
428 6
        text = self._getObjMnemonic(obj)
429 6
        utterances.append(text)
430
431 6
        debug.println(self._debugLevel, "page utterances=%s" % \
432 6
                      utterances)
433 6
        speech.speakUtterances(utterances)
434
435 1
    def _speakText(self, obj, doubleClick):
436
        """Text boxes present the following information (an example is
437
        'Source display: text, blank, Alt O'):
438
439
        1. label, if any
440
        2. role
441
        3. contents
442
            A. if no text on the current line is selected, the current line
443
            B. if text is selected on the current line, that text, followed
444
            attibute information before  (bold "text")
445
            by 'selected' (single press)
446
            C. if the current line is blank/empty, 'blank'
447
        4. mnemonic (i.e. Alt plus the underlined letter), if any
448
449
        Gaim, gedit, OpenOffice Writer and Terminal
450
        """
451
452 9
        utterances = []
453 9
        text = self._getObjLabel(obj)
454 9
        utterances.append(text)
455
456 9
        text = rolenames.getSpeechForRoleName(obj)
457 9
        utterances.append(text)
458
459
        [textContents, startOffset, endOffset, selected] = \
460 9
                       self._getTextContents(obj, doubleClick)
461 9
        if doubleClick:
462
            # Speak character attributes.
463
            textContents = \
464 2
                self._insertAttributes(obj, startOffset,
465 2
                                       endOffset, textContents)
466 2
            savedStyle = settings.verbalizePunctuationStyle
467 2
            settings.verbalizePunctuationStyle = settings.PUNCTUATION_STYLE_SOME
468
469 9
        text = textContents
470 9
        utterances.append(text)
471 9
        debug.println(self._debugLevel, "first text utterances=%s" % \
472 9
                      utterances)
473 9
        speech.speakUtterances(utterances)
474
475 9
        if doubleClick:
476 2
            verbalizePunctuationStyle = savedStyle
477
478 9
        utterances = []
479 9
        if selected:
480 3
            text = _("selected")
481 3
            utterances.append(text)
482
483 9
        text = self._getObjMnemonic(obj)
484 9
        utterances.append(text)
485
486 9
        debug.println(self._debugLevel, "text utterances=%s" % \
487 9
                      utterances)
488 9
        speech.speakUtterances(utterances)
489
490 1
    def _speakTableCell(self, obj, doubleClick):
491
        """Tree Tables present the following information (an example is
492
        'Tree table, Mike Pedersen, item 8 of 10, tree level 2'):
493
494
        1. label, if any
495
        2. role
496
        3. current row (regardless of speak cell/row setting)
497
        4. relative position
498
        5. if expandable/collapsible: expanded/collapsed
499
        6. if applicable, the level
500
501
        Nautilus and Gaim
502
        """
503
504
        # Speak the first two items (and possibly the position)
505 25
        utterances = []
506 25
        if obj.parent.role == rolenames.ROLE_TABLE_CELL:
507 0
            obj = obj.parent
508 25
        parent = obj.parent
509
510 25
        text = self._getObjLabel(obj)
511 25
        utterances.append(text)
512
513 25
        text = rolenames.getSpeechForRoleName(obj)
514 25
        utterances.append(text)
515 25
        debug.println(self._debugLevel, "first table cell utterances=%s" % \
516 25
                      utterances)
517 25
        speech.speakUtterances(utterances)
518
519 25
        utterances = []
520 25
        if doubleClick:
521 4
            table = parent.table
522 4
            row = table.getRowAtIndex(orca_state.locusOfFocus.index)
523
            # Translators: this in reference to a row in a table.
524
            #
525 4
            text = _("row %d of %d") % ((row+1), parent.table.nRows)
526 4
            utterances.append(text)
527 4
            speech.speakUtterances(utterances)
528
529
        # Speak the current row
530 25
        utterances = self._getTableRow(obj)
531 25
        debug.println(self._debugLevel, "second table cell utterances=%s" % \
532 25
                      utterances)
533 25
        speech.speakUtterances(utterances)
534
535
        # Speak the remaining items.
536 25
        utterances = []
537
538 25
        if not doubleClick:
539 21
            table = parent.table
540 21
            if not table:
541 0
                debug.println(self._debugLevel, "??? parent=%s" % parent.role)
542 0
                return
543
544 21
            row = table.getRowAtIndex(orca_state.locusOfFocus.index)
545
            # Translators: this in reference to a row in a table.
546
            #
547 21
            text = _("row %d of %d") % ((row+1), parent.table.nRows)
548 21
            utterances.append(text)
549
550 25
        if obj.state.count(atspi.Accessibility.STATE_EXPANDABLE):
551 3
            if obj.state.count(atspi.Accessibility.STATE_EXPANDED):
552
                # Translators: this represents the state of a node in a tree.
553
                # 'expanded' means the children are showing.
554
                # 'collapsed' means the children are not showing.
555
                #
556 2
                text = _("expanded")
557
            else:
558
                # Translators: this represents the state of a node in a tree.
559
                # 'expanded' means the children are showing.
560
                # 'collapsed' means the children are not showing.
561
                #
562 1
                text = _("collapsed")
563 1
                utterances.append(text)
564
565 25
        level = self._script.getNodeLevel(orca_state.locusOfFocus)
566 25
        if level >= 0:
567
            # Translators: this represents the depth of a node in a tree
568
            # view (i.e., how many ancestors a node has).
569
            #
570 11
            utterances.append(_("tree level %d") % (level + 1))
571
572 25
        debug.println(self._debugLevel, "third table cell utterances=%s" % \
573 25
                      utterances)
574 25
        speech.speakUtterances(utterances)
575
576 1
    def _speakParagraph(self, obj, doubleClick):
577
        """Speak a paragraph object.
578
        """
579
580 0
        self._speakText(obj, doubleClick)
581
582 1
    def _speakIconPanel(self, obj, doubleClick):
583
        """Speak the contents of the pane containing this icon. The
584
        number of icons in the pane is spoken. Plus the total number of
585
        selected icons. Plus the name of each of the selected icons.
586
587
        Arguments:
588
        - obj: the icon object that currently has focus.
589
        """
590
591 8
        utterances = []
592 8
        panel = obj.parent
593 8
        childCount = panel.childCount
594
595 8
        utterances.append(_("Icon panel"))
596 8
        utterances.append(self._getObjLabelAndName(obj))
597 8
        utterances.append(rolenames.getSpeechForRoleName(obj))
598
599 8
        selectedItems = []
600 8
        totalSelectedItems = 0
601 200
        for i in range(0, childCount):
602 192
            child = panel.child(i)
603 192
            if child.state.count(atspi.Accessibility.STATE_SELECTED):
604 0
                totalSelectedItems += 1
605 0
                selectedItems.append(child)
606
607
        # Translators: this is a count of the number of selected icons 
608
        # and the count of the total number of icons within an icon panel. 
609
        # An example of an icon panel is the Nautilus folder view.
610
        #
611 8
        itemString = ngettext("%d of %d item selected",
612 8
                              "%d of %d items selected",
613 8
                              childCount) % \
614 8
                              (totalSelectedItems, childCount)
615 8
        utterances.append(itemString)
616
617 8
        if doubleClick:
618 2
            for i in range(0, len(selectedItems)):
619 0
                utterances.append(self._getObjLabelAndName(selectedItems[i]))
620
621 8
        speech.speakUtterances(utterances)
622
623 1
    def _speakLink(self, obj, doubleClick):
624
        """Speaks information about a link including protocol, domain 
625
        comparisons and size of file if possible
626
627
        Arguments:
628
        - obj: the icon object that currently has focus.
629
        - doubleClick: was it a doubleclick event?
630
        """
631
632
        # get the URI for the link of interest and parse it.
633
        # parsed URI is returned as a tuple containing six components: 
634
        # scheme://netloc/path;parameters?query#fragment.
635 0
        link_uri = self._script.getURI(obj)
636 0
        if link_uri:
637 0
            link_uri_info = urlparse.urlparse(link_uri)
638
        else:
639
            # something is wrong, just return
640 0
            return
641
642
        # Try to get the URI of the active document and parse it
643 0
        doc_uri = self._script.getDocumentFrameURI()
644 0
        if doc_uri:
645 0
            doc_uri_info = urlparse.urlparse(doc_uri)
646
        else:
647 0
            doc_uri_info = None
648
649
        # initialize our three outputs.  Output may change below for some 
650
        # protocols.
651
        # Translators: this is the protocol of a link eg. http, mailto.
652
        #
653 0
        linkoutput = _('%s link') %link_uri_info[0]
654 0
        domainoutput = ''
655 0
        sizeoutput = ''
656
657
        # get size and other protocol specific information
658 0
        if link_uri_info[0] == 'ftp' or \
659 0
           link_uri_info[0] == 'ftps' or \
660 0
           link_uri_info[0] == 'file':
661
            # change link output message to include filename
662 0
            filename = link_uri_info[2].split('/')
663 0
            linkoutput = _('%s link to %s') %(link_uri_info[0], filename[-1])
664 0
            sizestr = self.__extractSize(link_uri)
665 0
            sizeoutput = self.__formatSizeOutput(sizestr)
666
667
        # determine location differences if doc uri info is available
668 0
        if doc_uri_info:
669 0
            if link_uri_info[1] == doc_uri_info[1]:
670 0
                if link_uri_info[2] == doc_uri_info[2]:
671
                    # Translators: this is the domain relationship of a given
672
                    # link to the current page.  eg. same page, same site.
673 0
                    domainoutput = _('same page')
674
                else:
675 0
                    domainoutput = _('same site')
676
            else:
677
                # check for different machine name on same site
678 0
                linkdomain = link_uri_info[1].split('.')
679 0
                docdomain = doc_uri_info[1].split('.')
680 0
                if len(linkdomain) > 1 and docdomain > 1  \
681 0
                    and linkdomain[-1] == docdomain[-1]  \
682 0
                    and linkdomain[-2] == docdomain[-2]:
683 0
                    domainoutput = _('same site') 
684
                else:
685 0
                    domainoutput = _('different site')
686
687 0
        speech.speakUtterances([linkoutput, domainoutput, sizeoutput])
688
689 1
    def __extractSize(self, uri):
690
        '''
691
        Get the http header for a given uri and try to extract the size (Content-length).
692
        '''
693 0
        try:
694 0
            x=urllib2.urlopen(uri)
695 0
            try:
696 0
                return x.info()['Content-length']
697 0
            except KeyError:
698 0
                return None
699 0
        except (ValueError, urllib2.URLError, OSError):
700 0
            return None
701
702 1
    def __formatSizeOutput(self, sizestr):
703
        '''
704
        Format the size output announcement.  Changes wording based on size.
705
        '''
706
        # sanity check
707 0
        if sizestr is None or sizestr == '':
708 0
            return ''
709 0
        size = int(sizestr)
710 0
        if size < 10000:
711
            # Translators: This is the size of a file in bytes
712
            #
713 0
            return ngettext('%d byte', '%d bytes', size) % size
714 0
        elif size < 1000000:
715
            # Translators: This is the size of a file in kilobytes
716
            #
717 0
            return _('%.2f kilobytes') % (float(size) * .001)
718 0
        elif size >= 1000000:
719
            # Translators: This is the size of a file in megabytes
720
            #
721 0
            return _('%.2f megabytes') % (float(size) * .000001) 
722
723 1
    def _speakGenericObject(self, obj, doubleClick):
724
        """Speak a generic object; one not specifically handled by
725
        other methods.
726
        """
727
728 7
        utterances = []
729 7
        text = self._getObjLabelAndName(obj)
730 7
        utterances.append(text)
731
732 7
        text = rolenames.getSpeechForRoleName(obj)
733 7
        utterances.append(text)
734 7
        speech.speakUtterances(utterances)
735
736 1
    def _getObjName(self, obj):
737
        """Returns the name to speak for an object.
738
        """
739
740 449
        text = ""
741 449
        name = self._script.getDisplayedText(obj)
742 449
        if not name:
743 113
            name = obj.description
744
745 449
        if name and name != "None":
746 336
            text = name
747
        # debug.println(self._debugLevel, "%s name=<%s>" % (obj.role, text))
748
749 449
        return text
750
751 1
    def _getObjLabel(self, obj):
752
        """Returns the label to speak for an object.
753
        """
754
755 300
        text = ""
756 300
        label = self._script.getDisplayedLabel(obj)
757
758 300
        if label and label != "None":
759 16
            text = label
760
        # debug.println(self._debugLevel, "%s label=<%s>" % (obj.role, text))
761
762 300
        return text
763
764 1
    def _getObjLabelAndName(self, obj):
765
        """Returns the object label plus the object name.
766
        """
767
768 58
        name = self._getObjName(obj)
769 58
        label = self._getObjLabel(obj)
770 58
        if name != label:
771 44
            text = label + " " + name
772
        else:
773 14
            text = label
774
775 58
        if obj.text:
776 43
            [string, startOffset, endOffset] = obj.text.getTextAtOffset(0,
777 43
                atspi.Accessibility.TEXT_BOUNDARY_LINE_START)
778
779 43
            debug.println(self._debugLevel, "%s text=<%s>" % (obj.role, string))
780
781 58
        return text.strip()
782
783 1
    def _getGroupLabel(self, obj):
784
        """Returns the label for a group of components.
785
        """
786
787 6
        text = ""
788 6
        labelledBy = None
789
790 6
        relations = obj.relations
791 12
        for relation in relations:
792 6
            if relation.getRelationType() ==  \
793 6
                   atspi.Accessibility.RELATION_LABELLED_BY:
794 0
                labelledBy = atspi.Accessible.makeAccessible( \
795 0
                                                      relation.getTarget(0))
796 0
                break
797
798 6
        if labelledBy:
799 0
            text = self._getObjLabelAndName(labelledBy)
800
        else:
801 6
            parent = obj.parent
802 6
            while parent and (parent.parent != parent):
803 66
                if parent.role == rolenames.ROLE_PANEL:
804 12
                    label = self._getObjLabelAndName(parent)
805 12
                    if label and label != "":
806 0
                        text = label
807 0
                        break
808 66
                parent = parent.parent
809
810 6
        return text
811
812 1
    def _getPositionInGroup(self, obj):
813
        """Returns the relative position of an object in a group.
814
        """
815
816 6
        text = ""
817 6
        position = -1
818 6
        total = -1
819
820 6
        relations = obj.relations
821 12
        for relation in relations:
822 6
            if relation.getRelationType() == atspi.Accessibility.RELATION_MEMBER_OF:
823 6
                total = relation.getNTargets()
824 12
                for i in range(0, total):
825 12
                    target = atspi.Accessible.makeAccessible( \
826 12
                                                     relation.getTarget(i))
827 12
                    if target == obj:
828 6
                        position = total - i
829 6
                        break
830
831 6
        if position >= 0:
832
            # Translators: this is an item in a list.
833
            #
834 6
            text += _("item %d of %d") % (position, total)
835
836 6
        return text
837
838 1
    def _getPositionInList(self, obj, name):
839
        """Returns the relative position of an object in a list.
840
        """
841
842 32
        text = ""
843 32
        position = -1
844 32
        index = 0
845 32
        total = 0
846
847 32
        debug.println(self._debugLevel, "obj=%s, count=%d, name=%s" % \
848 32
                      (obj.role, obj.childCount, name))
849
850 203
        for i in range(0, obj.childCount):
851 171
            next = self._getObjName(obj.child(i))
852 171
            if next == "" or next == "Empty" or next == "separator":
853 21
                continue
854
855 150
            index += 1
856 150
            total += 1
857
858 150
            if next == name:
859 29
                position = index
860
861 32
        if position >= 0:
862
            # Translators: this is an item in a list.
863
            #
864 29
            text = _("item %d of %d") % (position, total)
865
866 32
        return text
867
868 1
    def _getObjMnemonic(self, obj):
869
        """Returns the accellerator and/or shortcut for the object,
870
        if either exists.
871
        """
872
873 47
        list = self._script.getAcceleratorAndShortcut(obj)
874
875 47
        text = ""
876 47
        if not list[1]:
877 35
            text = list[0]
878
        else:
879 12
            text = list[0] + " " +  list[1]
880
881 47
        return text
882
883 1
    def _getObjAccelerator(self, obj):
884
        """Returns the accelerator for the object, if it exists.
885
        """
886
887 6
        list = self._script.getAcceleratorAndShortcut(obj)
888
889 6
        text = ""
890 6
        if list[0]:
891 6
            text = list[0]
892
893 6
        return text
894
895 1
    def _getObjShortcut(self, obj):
896
        """Returns the shortcut for the object, if it exists.
897
        """
898
899 6
        list = self._script.getAcceleratorAndShortcut(obj)
900
901 6
        text = ""
902 6
        if list[1]:
903 6
            text = list[1]
904
905 6
        return text
906
907 1
    def _getSliderValues(self, obj):
908
        """Returns the slider's current value and percentage.
909
        """
910
911 0
        value = obj.value
912
913 0
        currentValue = "%.1f" % value.currentValue
914 0
        percent = value.currentValue / value.maximumValue * 100
915 0
        rounded = "%d" % round(percent, 5)
916
917 0
        debug.println(self._debugLevel,
918 0
            "_getSliderValues: min=%f, cur=%f, max=%f, str=%s, percent=%s" % \
919 0
            (value.minimumValue, value.currentValue, value.maximumValue, \
920 0
             currentValue, rounded))
921
922 0
        return [currentValue, rounded]
923
924 1
    def _getTableRow(self, obj):
925
        """Get the speech for a table cell row or a single table cell
926
        if settings.readTableCellRow is False.
927
928
        Arguments:
929
        - obj: the table
930
        - already_focused: False if object just received focus
931
932
        Returns a list of utterances to be spoken for the object.
933
        """
934
935 25
        utterances = []
936
937 25
        parent = obj.parent
938 25
        table = parent.table
939 25
        if not table:
940 0
            debug.println(self._debugLevel, "??? parent=%s" % parent.role)
941 0
            return []
942
943 25
        row = parent.table.getRowAtIndex(obj.index)
944
945 133
        for i in range(0, parent.table.nColumns):
946 108
            cell = parent.table.getAccessibleAt(row, i)
947 108
            acc = atspi.Accessible.makeAccessible(cell)
948 108
            utterances.append(self._getTableCell(acc))
949
950 25
        debug.println(self._debugLevel, "row=<%s>" % utterances)
951
952 25
        return utterances
953
954 1
    def _getTableCell(self, obj):
955
        """Get the speech utterances for a single table cell.
956
        """
957
958
        # Don't speak check box cells that area not checked.
959 108
        notChecked = False
960 108
        action = obj.action
961 108
        if action:
962 164
            for i in range(0, action.nActions):
963 125
                if action.getName(i) == "toggle":
964 55
                    obj.role = rolenames.ROLE_CHECK_BOX
965 55
                    if not obj.state.count(atspi.Accessibility.STATE_CHECKED):
966 33
                        notChecked = True
967 55
                    obj.role = rolenames.ROLE_TABLE_CELL
968 55
                    break
969
970 108
        if notChecked:
971 33
            return ""
972
973 75
        descendant = self._script.getRealActiveDescendant(obj)
974 75
        text = self._script.getDisplayedText(descendant)
975
976 75
        debug.println(self._debugLevel, "cell=<%s>" % text)
977
978 75
        return text
979
980 1
    def _getTextSelection(self, obj):
981
        """Get the text selection for the given object.
982
983
        Arguments:
984
        - obj: the text object to extract the selected text from.
985
986
        Returns: the selected text contents plus the start and end 
987
        offsets within the text.
988
        """
989
990 3
        textContents = ""
991 3
        textObj = obj.text
992 3
        nSelections = textObj.getNSelections()
993 6
        for i in range(0, nSelections):
994 3
            [startOffset, endOffset] = textObj.getSelection(i)
995
996 3
            debug.println(self._debugLevel,
997 3
                "_getTextSelection: selection start=%d, end=%d" % \
998 3
                (startOffset, endOffset))
999
1000 3
            selectedText = textObj.getText(startOffset, endOffset)
1001 3
            debug.println(self._debugLevel,
1002 3
                "_getTextSelection: selected text=<%s>" % selectedText)
1003
1004 3
            if i > 0:
1005 0
                textContents += " "
1006 3
            textContents += selectedText
1007
1008 3
        return [textContents, startOffset, endOffset]
1009
1010 1
    def _getTextSelections(self, obj, doubleClick):
1011
        """Get all the text applicable text selections for the given object.
1012
        If the user doubleclicked, look to see if there are any previous 
1013
        or next text objects that also have selected text and add in their 
1014
        text contents.
1015
1016
        Arguments:
1017
        - obj: the text object to start extracting the selected text from.
1018
        - doubleClick: True if the user double-clicked the "where am I" key.
1019
1020
        Returns: all the selected text contents plus the start and end
1021
        offsets within the text for the given object.
1022
        """
1023
1024 3
        textContents = ""
1025 3
        startOffset = 0
1026 3
        endOffset = 0
1027 3
        if obj.text.getNSelections() > 0:
1028
            [textContents, startOffset, endOffset] = \
1029 3
                                            self._getTextSelection(obj)
1030
1031 3
        if doubleClick:
1032 0
            current = obj
1033 0
            morePossibleSelections = True
1034 0
            while morePossibleSelections:
1035 0
                morePossibleSelections = False
1036 0
                for relation in current.relations:
1037 0
                    if relation.getRelationType() == \
1038 0
                           atspi.Accessibility.RELATION_FLOWS_FROM:
1039 0
                        prevObj = atspi.Accessible.makeAccessible( \
1040 0
                                                  relation.getTarget(0))
1041 0
                        if prevObj.text.getNSelections() > 0:
1042
                            [newTextContents, start, end] = \
1043 0
                                         self._getTextSelection(prevObj)
1044 0
                            textContents = newTextContents + textContents
1045 0
                            current = prevObj
1046 0
                            morePossibleSelections = True
1047
                        else:
1048 0
                            displayedText = prevObj.text.getText(0, -1)
1049 0
                            if len(displayedText) == 0:
1050 0
                                current = prevObj
1051 0
                                morePossibleSelections = True
1052 0
                        break
1053
1054 0
            current = obj
1055 0
            morePossibleSelections = True
1056 0
            while morePossibleSelections:
1057 0
                morePossibleSelections = False
1058 0
                for relation in current.relations:
1059 0
                    if relation.getRelationType() == \
1060 0
                           atspi.Accessibility.RELATION_FLOWS_TO:
1061 0
                        nextObj = atspi.Accessible.makeAccessible( \
1062 0
                                                  relation.getTarget(0))
1063 0
                        if nextObj.text.getNSelections() > 0:
1064
                            [newTextContents, start, end] = \
1065 0
                                         self._getTextSelection(nextObj)
1066 0
                            textContents += newTextContents
1067 0
                            current = nextObj
1068 0
                            morePossibleSelections = True
1069
                        else:
1070 0
                            displayedText = nextObj.text.getText(0, -1)
1071 0
                            if len(displayedText) == 0:
1072 0
                                current = nextObj
1073 0
                                morePossibleSelections = True
1074 0
                        break
1075
1076 3
        return [textContents, startOffset, endOffset]
1077
1078 1
    def _hasTextSelections(self, obj):
1079
        """Return an indication of whether this object has selected text.
1080
        Note that it's possible that this object has no text, but is part
1081
        of a selected text area. Because of this, we need to check the
1082
        objects on either side to see if they are none zero length and
1083
        have text selections.
1084
1085
        Arguments:
1086
        - obj: the text object to start checking for selected text.
1087
1088
        Returns: an indication of whether this object has selected text,
1089
        or adjacent text objects have selected text.
1090
        """
1091
1092 9
        currentSelected = False
1093 9
        otherSelected = False
1094 9
        nSelections = obj.text.getNSelections()
1095 9
        if nSelections:
1096 3
            currentSelected = True
1097
        else:
1098 6
            otherSelected = False
1099 6
            displayedText = obj.text.getText(0, -1)
1100 6
            if len(displayedText) == 0:
1101 0
                current = obj
1102 0
                morePossibleSelections = True
1103 0
                while morePossibleSelections:
1104 0
                    morePossibleSelections = False
1105 0
                    for relation in current.relations:
1106 0
                        if relation.getRelationType() == \
1107 0
                               atspi.Accessibility.RELATION_FLOWS_FROM:
1108 0
                            prevObj = atspi.Accessible.makeAccessible( \
1109 0
                                                      relation.getTarget(0))
1110 0
                            if prevObj.text.getNSelections() > 0:
1111 0
                                otherSelected = True
1112
                            else:
1113 0
                                displayedText = prevObj.text.getText(0, -1)
1114 0
                                if len(displayedText) == 0:
1115 0
                                    current = prevObj
1116 0
                                    morePossibleSelections = True
1117 0
                            break
1118
1119 0
                current = obj
1120 0
                morePossibleSelections = True
1121 0
                while morePossibleSelections:
1122 0
                    morePossibleSelections = False
1123 0
                    for relation in current.relations:
1124 0
                        if relation.getRelationType() == \
1125 0
                               atspi.Accessibility.RELATION_FLOWS_TO:
1126 0
                            nextObj = atspi.Accessible.makeAccessible( \
1127 0
                                                      relation.getTarget(0))
1128 0
                            if nextObj.text.getNSelections() > 0:
1129 0
                                otherSelected = True
1130
                            else:
1131 0
                                displayedText = nextObj.text.getText(0, -1)
1132 0
                                if len(displayedText) == 0:
1133 0
                                    current = nextObj
1134 0
                                    morePossibleSelections = True
1135 0
                            break
1136
1137 9
        return [currentSelected, otherSelected]
1138
1139 1
    def _getTextContents(self, obj, doubleClick):
1140
        """Returns utterences for text.
1141
1142
        A. if no text on the current line is selected, the current line
1143
        B. if text is selected on the current line, that text, followed
1144
        by 'selected'
1145
        C. if the current line is blank/empty, 'blank'
1146
        """
1147
1148 9
        textObj = obj.text
1149 9
        caretOffset = textObj.caretOffset
1150 9
        textContents = ""
1151 9
        selected = False
1152 9
        startSelOffset = -1
1153 9
        endSelOffset = -1
1154
1155 9
        nSelections = textObj.getNSelections()
1156 9
        debug.println(self._debugLevel,
1157 9
            "_getTextContents: caretOffset=%d, nSelections=%d" % \
1158 9
            (caretOffset, nSelections))
1159
1160 9
        [current, other] = self._hasTextSelections(obj)
1161 9
        if (doubleClick and (current or other)) or \
1162 9
           (not doubleClick and current):
1163 3
            selected = True
1164
            [textContents, startOffset, endOffset] = \
1165 3
                                  self._getTextSelections(obj, doubleClick)
1166
        else:
1167
            # Get the line containing the caret
1168
            #
1169 6
            [line, startOffset, endOffset] = textObj.getTextAtOffset(
1170 6
                textObj.caretOffset,
1171 6
                atspi.Accessibility.TEXT_BOUNDARY_LINE_START)
1172 6
            debug.println(self._debugLevel, \
1173 6
                "_getTextContents: len=%d, start=%d, end=%d, line=<%s>" % \
1174 6
                (len(line), startOffset, endOffset, line))
1175
1176 6
            if len(line):
1177 4
                line = self._script.adjustForRepeats(line)
1178 4
                textContents = line
1179
            else:
1180 2
                char = textObj.getTextAtOffset(caretOffset,
1181 2
                    atspi.Accessibility.TEXT_BOUNDARY_CHAR)
1182 2
                debug.println(self._debugLevel,
1183 2
                    "_getTextContents: character=<%s>, start=%d, end=%d" % \
1184 2
                    (char[0], char[1], char[2]))
1185
1186 2
                if char[0] == "\n" and startOffset == caretOffset \
1187 0
                       and settings.speakBlankLines:
1188
                    # Translators: "blank" is a short word to mean the
1189
                    # user has navigated to an empty line.
1190
                    #
1191 0
                    textContents = (_("blank"))
1192
1193 9
        return [textContents, startOffset, endOffset, selected]
1194
1195 1
    def _insertAttributes(self, obj, startOffset, endOffset, line):
1196
        """Adjust line to include attribute information.
1197
        """
1198
1199 2
        text = obj.text
1200 2
        if not text:
1201 0
            return ""
1202
1203 2
        newLine = ""
1204 2
        textOffset = startOffset
1205
1206 17
        for i in range(0, len(line)):
1207 15
            attribs = self._getAttributesForChar(text, textOffset, line, i)
1208 15
            debug.println(self._debugLevel,
1209 15
                          "line attribs <%s>" % (attribs))
1210 15
            if attribs:
1211 0
                newLine += " ; "
1212 0
                newLine += attribs
1213 0
                newLine += " "
1214
1215 15
            newLine += line[i]
1216 15
            textOffset += 1
1217
1218 2
        debug.println(self._debugLevel, "newLine: <%s>" % (newLine))
1219
1220 2
        return newLine
1221
1222 1
    def _getAttributesForChar(self, text, textOffset, line, lineIndex):
1223
1224 15
        keys = [ "style", "weight", "underline" ]
1225 15
        attribStr = ""
1226 15
        charAttributes = text.getAttributes(textOffset)
1227
1228 15
        if charAttributes[0]:
1229 0
            charDict = self._stringToDictionary(charAttributes[0])
1230 0
            debug.println(self._debugLevel,
1231 0
                          "charDict: %s" % (charDict))
1232
1233 0
            for key in keys:
1234 0
                if charDict.has_key(key):
1235 0
                    attribute = charDict[key]
1236 0
                    if attribute:
1237
                        # If it's the 'weight' attribute and greater than 400,
1238
                        # just speak it as bold, otherwise speak the weight.
1239
                        #
1240 0
                        if key == "weight" and int(attribute) > 400:
1241 0
                            attribStr += " "
1242
                            # Translators: bold as in the font sense.
1243
                            #
1244 0
                            attribStr += _("bold")
1245
1246 0
                        elif key == "underline":
1247 0
                            if attribute != "none":
1248 0
                                attribStr += " "
1249 0
                                attribStr += key
1250
1251 0
                        elif key == "style":
1252 0
                            if attribute != "normal":
1253 0
                                attribStr += " "
1254 0
                                attribStr += attribute
1255
                        else:
1256 0
                            attribStr += " "
1257 0
                            attribStr += (key + " " + attribute)
1258
1259 0
            debug.println(self._debugLevel,
1260 0
                          "char <%s>: %s" % (line[lineIndex], attribStr))
1261
1262
        # Only return attributes for the beginning of an attribute run.
1263 15
        if attribStr != self._lastAttributeString:
1264 0
            self._lastAttributeString = attribStr
1265 0
            return attribStr
1266
        else:
1267 15
            return ""
1268
1269 1
    def _stringToDictionary(self, str):
1270
        """Converts a string of text attribute tokens of the form
1271
        <key>:<value>; into a dictionary of keys and values.
1272
        Text before the colon is the key and text afterwards is the
1273
        value. If there is a final semi-colon, then it's ignored.
1274
        """
1275
1276 0
        dictionary = {}
1277 0
        allTokens = str.split(";")
1278 0
        for token in allTokens:
1279 0
            item = token.split(":")
1280 0
            if len(item) == 2:
1281 0
                item[0] = self._removeLeadingSpaces(item[0])
1282 0
                item[1] = self._removeLeadingSpaces(item[1])
1283 0
                dictionary[item[0]] = item[1]
1284
1285 0
        return dictionary
1286
1287 1
    def _removeLeadingSpaces(self, str):
1288
        """Returns a string with the leading space characters removed.
1289
        """
1290
1291 0
        newStr = ""
1292 0
        leadingSpaces = True
1293 0
        for i in range(0, len(str)):
1294 0
            if str[i] == " ":
1295 0
                if leadingSpaces:
1296 0
                    continue
1297
            else:
1298 0
                leadingSpaces = False
1299
1300 0
            newStr += str[i]
1301
1302 0
        return newStr
1303
1304 1
    def _handleOrcaKey(self, obj, doubleClick):
1305
        """Handle the Orca modifier key being pressed.
1306
1307
        When Insert + KP_Enter is pressed a single time, Orca will speak
1308
        and display the following information:
1309
1310
        1. The contents of the title bar of the application main window
1311
        2. If in a dialog box within an application, the contents of the
1312
        title bar of the dialog box.
1313
        3. Orca will pause briefly between these two pieces of information
1314
        so that the speech user can distinguish each.
1315
        """
1316
1317 1
        utterances = []
1318
1319 1
        list = self._getFrameAndDialog(obj)
1320 1
        if doubleClick:
1321 0
            if list[0]:
1322 0
                self._statusBar = None
1323 0
                self._getStatusBar(list[0])
1324 0
                if self._statusBar:
1325 0
                    self._speakStatusBar()
1326
        else:
1327 1
            if list[0]:
1328 1
                text = self._getObjLabelAndName(list[0])
1329 1
                utterances.append(text)
1330 1
            if list[1]:
1331 0
                text = self._getObjLabelAndName(list[1])
1332 0
                utterances.append(text)
1333
1334 1
            debug.println(self._debugLevel, "titlebar utterances=%s" % \
1335 1
                          utterances)
1336 1
            speech.speakUtterances(utterances)
1337
1338 1
    def _getFrameAndDialog(self, obj):
1339
        """Returns the frame and (possibly) the dialog containing
1340
        the object.
1341
        """
1342
1343 1
        list = [None, None]
1344
1345 1
        parent = obj.parent
1346 1
        while parent and (parent.parent != parent):
1347
            #debug.println(self._debugLevel,
1348
            #              "_getFrameAndDialog: parent=%s, %s" % \
1349
            #              (parent.role, self._getObjLabelAndName(parent)))
1350 4
            if parent.role == rolenames.ROLE_FRAME:
1351 1
                list[0] = parent
1352 4
            if parent.role == rolenames.ROLE_DIALOG:
1353 0
                list[1] = parent
1354 4
            parent = parent.parent
1355
1356 1
        return list
1357
1358 1
    def _getStatusBar(self, obj):
1359
        """Gets the status bar.
1360
        """
1361 0
        if self._statusBar:
1362 0
            return
1363
1364
        # debug.println(self._debugLevel, "_findStatusBar: ROOT=%s, %s" % \
1365
        #               (obj.role, self._getObjLabelAndName(obj)))
1366
1367 0
        managesDescendants = obj.state.count(\
1368 0
            atspi.Accessibility.STATE_MANAGES_DESCENDANTS)
1369 0
        if managesDescendants:
1370 0
            return
1371
1372 0
        for i in range(0, obj.childCount):
1373 0
            child = obj.child(i)
1374
            # debug.println(self._debugLevel,
1375
            #               "_findStatusBar: child=%s, %s" % \
1376
            #               (child.role, self._getObjLabelAndName(child)))
1377 0
            if child.role == rolenames.ROLE_STATUSBAR:
1378 0
                self._statusBar = child
1379 0
                return
1380
1381 0
            if child.childCount > 0:
1382 0
                self._getStatusBar(child)
1383
1384 1
    def _speakStatusBar(self):
1385
        """Speaks the status bar.
1386
        """
1387
1388 0
        if not self._statusBar:
1389 0
            return
1390
1391 0
        utterances = []
1392
1393 0
        if self._statusBar.childCount == 0:
1394 0
            text = self._getObjName(self._statusBar)
1395 0
            utterances.append(text)
1396
        else:
1397 0
            for i in range(0, self._statusBar.childCount):
1398 0
                child = self._statusBar.child(i)
1399 0
                text = self._getObjName(child)
1400 0
                utterances.append(text)
1401
1402 0
        debug.println(self._debugLevel, "statusbar utterances=%s" % \
1403 0
                      utterances)
1404 0
        speech.speakUtterances(utterances)