1# Orca
2#
3# Copyright 2005-2009 Sun Microsystems Inc.
4# Copyright 2010 Joanmarie Diggs
5#
6# This library is free software; you can redistribute it and/or
7# modify it under the terms of the GNU Lesser General Public
8# License as published by the Free Software Foundation; either
9# version 2.1 of the License, or (at your option) any later version.
10#
11# This library is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14# Lesser General Public License for more details.
15#
16# You should have received a copy of the GNU Lesser General Public
17# License along with this library; if not, write to the
18# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
19# Boston MA  02110-1301 USA.
20
21__id__        = "$Id$"
22__version__   = "$Revision$"
23__date__      = "$Date$"
24__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc., " \
25                "Copyright (c) 2010 Joanmarie Diggs"
26__license__   = "LGPL"
27
28import pyatspi
29
30import orca.messages as messages
31import orca.settings as settings
32import orca.settings_manager as settings_manager
33import orca.speech_generator as speech_generator
34
35_settingsManager = settings_manager.getManager()
36
37########################################################################
38#                                                                      #
39# Speech Generator                                                     #
40#                                                                      #
41########################################################################
42
43class SpeechGenerator(speech_generator.SpeechGenerator):
44
45    # pylint: disable-msg=W0142
46
47    def __init__(self, script):
48        speech_generator.SpeechGenerator.__init__(self, script)
49
50    def _generateAncestors(self, obj, **args):
51        """The Swing toolkit has labelled panels that do not implement the
52        AccessibleText interface, but displayedText returns a meaningful
53        string that needs to be used if displayedLabel returns None.
54        """
55        args['requireText'] = False
56        result = speech_generator.SpeechGenerator._generateAncestors(
57            self, obj, **args)
58        del args['requireText']
59        return result
60
61    def _generateNewAncestors(self, obj, **args):
62        """Returns an array of strings (and possibly voice and audio
63        specifications) that represent the text of the ancestors for
64        the object.  This is typically used to present the context for
65        an object (e.g., the names of the window, the panels, etc.,
66        that the object is contained in).  If the 'priorObj' attribute
67        of the args dictionary is set, only the differences in
68        ancestry between the 'priorObj' and the current obj will be
69        computed.  Otherwise, no ancestry will be computed.  The
70        'priorObj' is typically set by Orca to be the previous object
71        with focus.
72        """
73        result = []
74        if args.get('role', obj.getRole()) == pyatspi.ROLE_MENU:
75            # We're way too chatty here -- at least with the Swing2
76            # demo. Users entering a menu want to know they've gone
77            # into a menu; not a huge ancestry.
78            #
79            return result
80        result.extend(speech_generator.SpeechGenerator.\
81                          _generateNewAncestors(self, obj, **args))
82        return result
83
84    def _generateNumberOfChildren(self, obj, **args):
85        """Returns an array of strings (and possibly voice and audio
86        specifications) that represents the number of children the
87        object has."""
88
89        if _settingsManager.getSetting('onlySpeakDisplayedText') \
90           or _settingsManager.getSetting('speechVerbosityLevel') == settings.VERBOSITY_LEVEL_BRIEF:
91            return []
92
93        result = []
94        acss = self.voice(speech_generator.SYSTEM)
95        if obj and obj.getState().contains(pyatspi.STATE_EXPANDED) \
96           and obj.getRole() == pyatspi.ROLE_LABEL and obj.childCount:
97            result.append(messages.itemCount(obj.childCount))
98            result.extend(acss)
99        else:
100            result.extend(speech_generator.SpeechGenerator.\
101                          _generateNumberOfChildren(self, obj, **args))
102
103        return result
104
105    def _generatePositionInList(self, obj, **args):
106        """Returns an array of strings (and possibly voice and audio
107        specifications) that represent the relative position of an
108        object in a list.
109        """
110
111        if _settingsManager.getSetting('onlySpeakDisplayedText'):
112            return []
113
114        listObj = None
115        if obj and obj.getRole() == pyatspi.ROLE_COMBO_BOX:
116            hasRole = lambda x: x and x.getRole() == pyatspi.ROLE_LIST
117            allLists = pyatspi.findAllDescendants(obj, hasRole)
118            if len(allLists) == 1:
119                listObj = allLists[0]
120
121        if not listObj:
122            return speech_generator.SpeechGenerator._generatePositionInList(
123                self, obj, **args)
124
125        result = []
126        acss = self.voice(speech_generator.SYSTEM)
127        name = self._generateName(obj)
128        position = -1
129        index = total = 0
130
131        for child in listObj:
132            nextName = self._generateName(child)
133            if not nextName or nextName[0] in ["", "Empty", "separator"] \
134               or not child.getState().contains(pyatspi.STATE_VISIBLE):
135                continue
136
137            index += 1
138            total += 1
139
140            if nextName == name:
141                position = index
142
143        if (_settingsManager.getSetting('enablePositionSpeaking') \
144            or args.get('forceList', False)) \
145           and position >= 0:
146            result.append(self._script.formatting.getString(
147                              mode='speech', stringType='groupindex') \
148                              %  {"index" : position, "total" : total})
149            result.extend(acss)
150        return result
151
152    def generateSpeech(self, obj, **args):
153        result = []
154        if obj.getRole() == pyatspi.ROLE_CHECK_BOX \
155           and obj.parent.getRole() == pyatspi.ROLE_MENU:
156            oldRole = self._overrideRole(pyatspi.ROLE_CHECK_MENU_ITEM, args)
157            result.extend(speech_generator.SpeechGenerator.\
158                                           generateSpeech(self, obj, **args))
159            self._restoreRole(oldRole, args)
160
161        if args.get('formatType', 'unfocused') == 'basicWhereAmI' \
162           and obj.getRole() == pyatspi.ROLE_TEXT:
163            spinbox = self._script.utilities.ancestorWithRole(
164                obj, [pyatspi.ROLE_SPIN_BUTTON], None)
165            if spinbox:
166                obj = spinbox
167        result.extend(speech_generator.SpeechGenerator.\
168                                       generateSpeech(self, obj, **args))
169        return result
170