[orca] Fix for bug #543157 - It is not always possible to distinguish on-screen text from Orca's "system" m
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Fix for bug #543157 - It is not always possible to distinguish on-screen text from Orca's "system" m
- Date: Mon, 16 Aug 2010 09:07:50 +0000 (UTC)
commit dbc8d2c388d721c30506bc5cdca97719b228e349
Author: Joanmarie Diggs <joanmarie diggs gmail com>
Date: Sat Aug 14 22:05:10 2010 -0400
Fix for bug #543157 - It is not always possible to distinguish on-screen text from Orca's "system" messages.
Also fixes bug #412656 - Refactor speech generators to provide ACSS per string.
src/orca/default.py | 44 ++-
src/orca/orca-setup.ui | 3 +
src/orca/orca.py | 2 +-
src/orca/orca_console_prefs.py | 4 +-
src/orca/orca_gui_prefs.py | 54 +++-
.../scripts/apps/evolution/speech_generator.py | 5 +
.../scripts/apps/gcalctool/speech_generator.py | 11 +-
src/orca/scripts/apps/soffice/speech_generator.py | 29 ++
.../scripts/toolkits/Gecko/speech_generator.py | 29 ++-
.../J2SE-access-bridge/speech_generator.py | 5 +-
src/orca/settings.py | 4 +-
src/orca/speech.py | 7 +-
src/orca/speech_generator.py | 296 ++++++++++++++++++--
13 files changed, 424 insertions(+), 69 deletions(-)
---
diff --git a/src/orca/default.py b/src/orca/default.py
index 83eab99..6655ad6 100644
--- a/src/orca/default.py
+++ b/src/orca/default.py
@@ -1921,6 +1921,7 @@ class Script(script.Script):
obj = orca_state.locusOfFocus
self.updateBraille(obj)
+ voice = self.voices[settings.DEFAULT_VOICE]
frame, dialog = self.utilities.frameAndDialog(obj)
if frame:
@@ -1932,19 +1933,20 @@ class Script(script.Script):
#
msg = self.speechGenerator.generateStatusBar(frame)
if msg:
- self.presentMessage(msg)
+ self.presentMessage(msg, voice=voice)
window = dialog or frame
if window:
msg = self.speechGenerator.generateDefaultButton(window)
if msg:
- self.presentMessage(msg)
+ self.presentMessage(msg, voice=voice)
def presentTitle(self, inputEvent):
"""Speaks and brailles the title of the window with focus."""
- self.presentMessage(self.speechGenerator.generateTitle(
- orca_state.locusOfFocus))
+ title = self.speechGenerator.generateTitle(orca_state.locusOfFocus)
+ for (string, voice) in title:
+ self.presentMessage(string, voice=voice)
def readCharAttributes(self, inputEvent=None):
"""Reads the attributes associated with the current text character.
@@ -3295,18 +3297,19 @@ class Script(script.Script):
announceState = True
if announceState:
+ voice = self.voices.get(settings.SYSTEM_VOICE)
if event.detail1:
# Translators: this object is now selected.
# Let the user know this.
#
#
- speech.speak(C_("text", "selected"), None, False)
+ speech.speak(C_("text", "selected"), voice, False)
else:
# Translators: this object is now unselected.
# Let the user know this.
#
#
- speech.speak(C_("text", "unselected"), None, False)
+ speech.speak(C_("text", "unselected"), voice, False)
return
if event.type.startswith("object:state-changed:focused"):
@@ -5277,17 +5280,18 @@ class Script(script.Script):
except:
debug.printException(debug.LEVEL_FINEST)
+ voice = self.voices.get(settings.SYSTEM_VOICE)
if self.utilities.isTextSelected(obj, startOffset, endOffset):
# Translators: when the user selects (highlights) text in
# a document, Orca lets them know this.
#
- speech.speak(C_("text", "selected"), None, False)
+ speech.speak(C_("text", "selected"), voice, False)
elif len(text.getText(startOffset, endOffset)):
# Translators: when the user unselects
# (unhighlights) text in a document, Orca lets
# them know this.
#
- speech.speak(C_("text", "unselected"), None, False)
+ speech.speak(C_("text", "unselected"), voice, False)
self._saveLastTextSelections(text)
@@ -5355,8 +5359,7 @@ class Script(script.Script):
# #
############################################################################
- @staticmethod
- def presentMessage(fullMessage, briefMessage=None):
+ def presentMessage(self, fullMessage, briefMessage=None, voice=None):
"""Convenience method to speak a message and 'flash' it in braille.
Arguments:
@@ -5368,6 +5371,8 @@ class Script(script.Script):
brief. Note that providing no briefMessage will result in the full
message being used for either. Callers wishing to present nothing as
the briefMessage should set briefMessage to an empty string.
+ - voice: The voice to use when speaking this message. By default, the
+ "system" voice will be used.
"""
if not fullMessage:
@@ -5382,7 +5387,8 @@ class Script(script.Script):
else:
message = fullMessage
if message:
- speech.speak(message)
+ voice = voice or self.voices.get(settings.SYSTEM_VOICE)
+ speech.speak(message, voice)
if (settings.enableBraille or settings.enableBrailleMonitor) \
and settings.enableFlashMessages:
@@ -5396,6 +5402,7 @@ class Script(script.Script):
if isinstance(message[0], list):
message = message[0]
if isinstance(message, list):
+ message = filter(lambda i: isinstance(i, str), message)
message = " ".join(message)
if settings.flashIsPersistent:
@@ -5724,12 +5731,19 @@ class Script(script.Script):
# #
########################################################################
- @staticmethod
- def speakMessage(string, interrupt=True):
+ def speakMessage(self, string, voice=None, interrupt=True):
"""Method to speak a single string. Scripts should use this
- method rather than calling speech.speak directly."""
+ method rather than calling speech.speak directly.
+
+ - string: The string to be spoken.
+ - voice: The voice to use. By default, the "system" voice will
+ be used.
+ - interrupt: If True, any current speech should be interrupted
+ prior to speaking the new text.
+ """
- speech.speak(string, interrupt=interrupt)
+ voice = voice or self.voices.get(settings.SYSTEM_VOICE)
+ speech.speak(string, voice, interrupt)
@staticmethod
def presentItemsInSpeech(items):
diff --git a/src/orca/orca-setup.ui b/src/orca/orca-setup.ui
index ccb9957..c5b8429 100644
--- a/src/orca/orca-setup.ui
+++ b/src/orca/orca-setup.ui
@@ -113,6 +113,9 @@
<row>
<col id="0" translatable="yes">Hyperlink</col>
</row>
+ <row>
+ <col id="0" translatable="yes">System</col>
+ </row>
</data>
</object>
<object class="GtkListStore" id="model2">
diff --git a/src/orca/orca.py b/src/orca/orca.py
index 8a139e2..330bc5a 100644
--- a/src/orca/orca.py
+++ b/src/orca/orca.py
@@ -2100,7 +2100,7 @@ def main():
try:
message = _("Welcome to Orca.")
- speech.speak(message)
+ speech.speak(message, settings.voices.get(settings.SYSTEM_VOICE))
braille.displayMessage(message)
except:
debug.printException(debug.LEVEL_SEVERE)
diff --git a/src/orca/orca_console_prefs.py b/src/orca/orca_console_prefs.py
index b6839d2..c70d150 100644
--- a/src/orca/orca_console_prefs.py
+++ b/src/orca/orca_console_prefs.py
@@ -308,11 +308,13 @@ def setupSpeech(prefsDict):
defaultACSS[acss.ACSS.AVERAGE_PITCH] = 5
uppercaseACSS = acss.ACSS({acss.ACSS.AVERAGE_PITCH : 6})
hyperlinkACSS = acss.ACSS({})
+ systemACSS = acss.ACSS({})
voices = {
settings.DEFAULT_VOICE : defaultACSS,
settings.UPPERCASE_VOICE : uppercaseACSS,
- settings.HYPERLINK_VOICE : hyperlinkACSS
+ settings.HYPERLINK_VOICE : hyperlinkACSS,
+ settings.SYSTEM_VOICE : systemACSS
}
prefsDict["enableSpeech"] = True
diff --git a/src/orca/orca_gui_prefs.py b/src/orca/orca_gui_prefs.py
index d1cf63a..1132b35 100644
--- a/src/orca/orca_gui_prefs.py
+++ b/src/orca/orca_gui_prefs.py
@@ -75,7 +75,7 @@ from orca_i18n import C_ # to provide qualified translatable strings
# Must match the order of voice types in the GtkBuilder file.
#
-(DEFAULT, UPPERCASE, HYPERLINK) = range(3)
+(DEFAULT, UPPERCASE, HYPERLINK, SYSTEM) = range(4)
# Must match the order that the timeFormatCombo is populated.
#
@@ -168,6 +168,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
self.speechSystemsChoice = None
self.speechSystemsChoices = None
self.speechSystemsModel = None
+ self.systemVoice = None
self.uppercaseVoice = None
self.window = None
self.workingFactories = None
@@ -469,7 +470,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""Return the ACSS value for the the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
Returns the voice dictionary for the given voice type.
"""
@@ -480,6 +481,8 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
voiceACSS = self.uppercaseVoice
elif voiceType == HYPERLINK:
voiceACSS = self.hyperlinkVoice
+ elif voiceType == SYSTEM:
+ voiceACSS = self.systemVoice
else:
voiceACSS = self.defaultVoice
@@ -502,7 +505,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
for the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
- key: the key to look for in the voice dictionary.
- useDefault: if True, and the key isn't found for the given voice
type, the look for it in the default voice dictionary
@@ -525,6 +528,12 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
if not useDefault:
return None
voice = self.defaultVoice
+ elif voiceType == SYSTEM:
+ voice = self.systemVoice
+ if key not in voice:
+ if not useDefault:
+ return None
+ voice = self.defaultVoice
else:
voice = self.defaultVoice
@@ -537,7 +546,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""Gets the name of the voice family for the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
Returns the name of the voice family for the given voice type,
or None if not set.
@@ -555,7 +564,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""Sets the name of the voice family for the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
- name: the name of the voice family to set.
- language: the locale of the voice family to set.
"""
@@ -580,7 +589,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""Gets the speaking rate value for the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
Returns the rate value for the given voice type, or None if
not set.
@@ -592,7 +601,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""Sets the speaking rate value for the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
- value: the rate value to set.
"""
@@ -604,7 +613,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""Gets the pitch value for the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
Returns the pitch value for the given voice type, or None if
not set.
@@ -617,7 +626,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""Sets the pitch value for the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
- value: the pitch value to set.
"""
@@ -629,7 +638,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""Gets the volume (gain) value for the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
Returns the volume (gain) value for the given voice type, or
None if not set.
@@ -641,7 +650,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""Sets the volume (gain) value for the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
- value: the volume (gain) value to set.
"""
@@ -654,7 +663,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
on the given voice type.
Arguments:
- - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK
+ - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
"""
familyName = self._getFamilyNameForVoiceType(voiceType)
@@ -752,6 +761,16 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
# hyperlink.
#
types.append(C_("VoiceType", "Hyperlink"))
+ # Translators: This refers to the voice used by Orca when
+ # presenting information which is not displayed on the screen
+ # as text, but is still being communicated by the system in
+ # some visual fashion. For instance, Orca says "misspelled"
+ # to indicate the presence of the red squiggly line found
+ # under a spelling error; Orca might say "3 of 6" when a
+ # user Tabs into a list of six items and the third item is
+ # selected. And so on.
+ #
+ types.append(C_("VoiceType", "System"))
self.populateComboBox(comboBox, types)
comboBox.set_active(DEFAULT)
voiceType = comboBox.get_active()
@@ -910,9 +929,10 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
"""
voices = self.prefsDict["voices"]
- self.defaultVoice = acss.ACSS(voices[settings.DEFAULT_VOICE])
- self.uppercaseVoice = acss.ACSS(voices[settings.UPPERCASE_VOICE])
- self.hyperlinkVoice = acss.ACSS(voices[settings.HYPERLINK_VOICE])
+ self.defaultVoice = acss.ACSS(voices.get(settings.DEFAULT_VOICE))
+ self.uppercaseVoice = acss.ACSS(voices.get(settings.UPPERCASE_VOICE))
+ self.hyperlinkVoice = acss.ACSS(voices.get(settings.HYPERLINK_VOICE))
+ self.systemVoice = acss.ACSS(voices.get(settings.SYSTEM_VOICE))
# Just a note on general naming pattern:
#
@@ -2612,6 +2632,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
del self.defaultVoice[acss.ACSS.FAMILY]
del self.uppercaseVoice[acss.ACSS.FAMILY]
del self.hyperlinkVoice[acss.ACSS.FAMILY]
+ del self.systemVoice[acss.ACSS.FAMILY]
except:
pass
@@ -4199,7 +4220,8 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
self.prefsDict["voices"] = {
settings.DEFAULT_VOICE : acss.ACSS(self.defaultVoice),
settings.UPPERCASE_VOICE : acss.ACSS(self.uppercaseVoice),
- settings.HYPERLINK_VOICE : acss.ACSS(self.hyperlinkVoice)
+ settings.HYPERLINK_VOICE : acss.ACSS(self.hyperlinkVoice),
+ settings.SYSTEM_VOICE : acss.ACSS(self.systemVoice),
}
settings.setGKSUGrabDisabled(self.disableKeyGrabPref)
diff --git a/src/orca/scripts/apps/evolution/speech_generator.py b/src/orca/scripts/apps/evolution/speech_generator.py
index f41f0c3..ebdbebd 100644
--- a/src/orca/scripts/apps/evolution/speech_generator.py
+++ b/src/orca/scripts/apps/evolution/speech_generator.py
@@ -85,6 +85,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
# toggle columns. That's really the difference here.]]]
#
result = []
+ acss = self.voice(speech_generator.SYSTEM)
try:
parentTable = obj.parent.queryTable()
except NotImplementedError:
@@ -129,6 +130,8 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
text = _("Read")
result.append(text)
+ if result:
+ result.extend(acss)
return result
def _generateUnrelatedLabels(self, obj, **args):
@@ -143,6 +146,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
_generateUnrelatedLabels(self, obj, **args)
result = []
+ acss = self.voice(speech_generator.DEFAULT)
labels = self._script.utilities.unrelatedLabels(obj)
for label in labels:
name = self._generateName(label, **args)
@@ -164,4 +168,5 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
#
name = [_("%s screen") % name]
result.extend(name)
+ result.extend(acss)
return result
diff --git a/src/orca/scripts/apps/gcalctool/speech_generator.py b/src/orca/scripts/apps/gcalctool/speech_generator.py
index 6e9925d..ea038ea 100644
--- a/src/orca/scripts/apps/gcalctool/speech_generator.py
+++ b/src/orca/scripts/apps/gcalctool/speech_generator.py
@@ -46,14 +46,17 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
return speech_generator.SpeechGenerator._generateName(\
self, obj)
+ result = []
+ acss = self.voice(speech_generator.DEFAULT)
if obj.name:
name = obj.name
else:
name = self._script.utilities.displayedText(obj)
if name:
- return [name]
+ result.append(name)
elif obj.description:
- return [obj.description]
- else:
- return []
+ result.append(obj.description)
+ if result:
+ result.extend(acss)
+ return result
diff --git a/src/orca/scripts/apps/soffice/speech_generator.py b/src/orca/scripts/apps/soffice/speech_generator.py
index 7a5f470..c89e358 100644
--- a/src/orca/scripts/apps/soffice/speech_generator.py
+++ b/src/orca/scripts/apps/soffice/speech_generator.py
@@ -96,16 +96,20 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
and an empty array will be returned if no label can be found.
"""
result = []
+ acss = self.voice(speech_generator.DEFAULT)
override = self.__overrideParagraph(obj, **args)
label = self._script.utilities.displayedLabel(obj) or ""
if not label and override:
label = self._script.utilities.displayedLabel(obj.parent) or ""
result.append(label.strip())
+ if result:
+ result.extend(acss)
return result
def _generateLabelOrName(self, obj, **args):
"""Gets the label or the name if the label is not preset."""
result = []
+ acss = self.voice(speech_generator.DEFAULT)
override = self.__overrideParagraph(obj, **args)
# Treat a paragraph which is serving as a text entry in a dialog
# as a text object.
@@ -125,6 +129,8 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
#
if not parentLabel and obj.name and len(obj.name):
result.append(obj.name)
+ if result:
+ result.extend(acss)
else:
result.extend(speech_generator.SpeechGenerator._generateLabelOrName(
self, obj, **args))
@@ -151,6 +157,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
label.
"""
result = []
+ acss = self.voice(speech_generator.SYSTEM)
if obj.description:
# The description of some OOo paragraphs consists of the name
# and the displayed text, with punctuation added. Try to spot
@@ -165,6 +172,8 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
result.append(obj.description)
break
+ if result:
+ result.extend(acss)
return result
def _generateToggleState(self, obj, **args):
@@ -196,6 +205,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
row header(s).
"""
result = []
+ acss = self.voice(speech_generator.DEFAULT)
try:
table = obj.parent.queryTable()
except:
@@ -220,10 +230,13 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
text = self._script.utilities.substring(header, 0, -1)
if text:
result.append(text)
+ if result:
+ result.extend(acss)
return result
def _generateNewRowHeader(self, obj, **args):
result = []
+ acss = self.voice(speech_generator.DEFAULT)
# Check to see if this spread sheet cell has either a dynamic
# row heading associated with it.
#
@@ -253,6 +266,8 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
text = self._script.utilities.substring(header, 0, -1)
if text:
result.append(text)
+ if result:
+ result.extend(acss)
return result
def _generateColumnHeader(self, obj, **args):
@@ -263,6 +278,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
column header(s).
"""
result = []
+ acss = self.voice(speech_generator.DEFAULT)
try:
table = obj.parent.queryTable()
except:
@@ -287,10 +303,13 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
text = self._script.utilities.substring(header, 0, -1)
if text:
result.append(text)
+ if result:
+ result.extend(acss)
return result
def _generateNewColumnHeader(self, obj, **args):
result = []
+ acss = self.voice(speech_generator.DEFAULT)
# Check to see if this spread sheet cell has either a dynamic
# row heading associated with it.
#
@@ -320,6 +339,8 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
text = self._script.utilities.substring(header, 0, -1)
if text:
result.append(text)
+ if result:
+ result.extend(acss)
return result
def _generateTooLong(self, obj, **args):
@@ -331,6 +352,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
of the spread sheet cell, or None if the message fits.
"""
result = []
+ acss = self.voice(speech_generator.SYSTEM)
try:
text = obj.queryText()
objectText = \
@@ -355,10 +377,13 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
result = [ngettext("%d character too long",
"%d characters too long",
tooLongCount) % tooLongCount]
+ if result:
+ result.extend(acss)
return result
def _generateSpreadSheetCell(self, obj, **args):
result = []
+ acss = self.voice(speech_generator.DEFAULT)
if self._script.inputLineForCell == None:
self._script.inputLineForCell = \
self._script.locateInputLine(obj)
@@ -373,6 +398,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
#
objectText = _("blank")
result.append(objectText)
+ result.extend(acss)
except NotImplementedError:
pass
@@ -391,6 +417,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
result.append(name)
break
+ if result:
+ result.extend(acss)
+
tooLong = self._generateTooLong(obj, **args)
if tooLong and len(tooLong):
result.extend(self._generatePause(obj, **args))
diff --git a/src/orca/scripts/toolkits/Gecko/speech_generator.py b/src/orca/scripts/toolkits/Gecko/speech_generator.py
index 27ab914..bff614d 100644
--- a/src/orca/scripts/toolkits/Gecko/speech_generator.py
+++ b/src/orca/scripts/toolkits/Gecko/speech_generator.py
@@ -54,6 +54,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
def _generateName(self, obj, **args):
result = []
+ acss = self.voice(speech_generator.DEFAULT)
role = args.get('role', obj.getRole())
if role == pyatspi.ROLE_COMBO_BOX:
# With Gecko, a combo box has a menu as a child. The text being
@@ -87,12 +88,16 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
break
if child and child.name:
result.append(child.name)
+ if result:
+ result.extend(acss)
+
else:
result.extend(speech_generator.SpeechGenerator._generateName(
self, obj, **args))
if not result and role == pyatspi.ROLE_LIST_ITEM:
result.append(self._script.utilities.expandEOCs(obj))
+ acss = self.voice(speech_generator.HYPERLINK)
link = None
if role == pyatspi.ROLE_LINK:
link = obj
@@ -106,6 +111,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
basename = self._script.getLinkBasename(link)
if basename:
result.append(basename)
+ result.extend(acss)
return result
@@ -132,6 +138,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
return result
def _generateLabel(self, obj, **args):
+ acss = self.voice(speech_generator.DEFAULT)
result = speech_generator.SpeechGenerator._generateLabel(self,
obj,
**args)
@@ -162,6 +169,8 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
and not self._script.inDocumentContent():
result.append(obj.name)
+ if result:
+ result.extend(acss)
return result
def _generateLabelAndName(self, obj, **args):
@@ -196,6 +205,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
def _generateRoleName(self, obj, **args):
"""Prevents some roles from being spoken."""
result = []
+ acss = self.voice(speech_generator.DEFAULT)
role = args.get('role', obj.getRole())
force = args.get('force', False)
@@ -252,12 +262,17 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
else:
result.append(rolenames.getSpeechForRoleName(obj, role))
+ if result:
+ result.extend(acss)
+
if role == pyatspi.ROLE_LINK \
and obj.childCount and obj[0].getRole() == pyatspi.ROLE_IMAGE:
# If this is a link with a child which is an image, we
# want to indicate that.
#
+ acss = self.voice(speech_generator.HYPERLINK)
result.append(rolenames.getSpeechForRoleName(obj[0]))
+ result.extend(acss)
return result
@@ -271,6 +286,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
def _generateNumberOfChildren(self, obj, **args):
result = []
+ acss = self.voice(speech_generator.SYSTEM)
role = args.get('role', obj.getRole())
if role == pyatspi.ROLE_LIST:
# Translators: this represents a list in HTML.
@@ -278,6 +294,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
result.append(ngettext("List with %d item",
"List with %d items",
obj.childCount) % obj.childCount)
+ result.extend(acss)
else:
result.extend(
speech_generator.SpeechGenerator._generateNumberOfChildren(
@@ -387,17 +404,24 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
text = self._script.utilities.displayedText(parent)
label = self._script.utilities.displayedLabel(parent)
newResult = []
+ acss = self.voice(speech_generator.DEFAULT)
if text and (text != label) and len(text.strip()) \
and (not text.startswith("chrome://")):
+ newResult.extend(acss)
newResult.append(text)
if label and len(label.strip()):
+ newResult.extend(acss)
newResult.append(label)
# Finally add the role if it's not among the roles we don't
# wish to speak.
#
+ acss = self.voice(speech_generator.SYSTEM)
if not (role in dontSpeakRoles) and len(newResult):
- result.append(rolenames.getSpeechForRoleName(parent))
+ roleInfo = rolenames.getSpeechForRoleName(parent)
+ if roleInfo:
+ result.extend(acss)
+ result.append(roleInfo)
# If this object is an ARIA widget with STATE_REQUIRED, add
# that. (Note that for the most part, the ARIA widget itself
@@ -448,6 +472,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
containing obj.
"""
result = []
+ acss = self.voice(speech_generator.DEFAULT)
headings, forms, tables, vlinks, uvlinks, percent = \
self._script.getPageSummary(obj)
if headings:
@@ -489,6 +514,8 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
'%d percent of document read',
percent) % percent)
+ if result:
+ result.extend(acss)
return result
def generateSpeech(self, obj, **args):
diff --git a/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py b/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py
index ef871cd..453691e 100644
--- a/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py
+++ b/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py
@@ -85,6 +85,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
object has."""
result = []
+ acss = self.voice(speech_generator.SYSTEM)
if obj and obj.getState().contains(pyatspi.STATE_EXPANDED) \
and obj.getRole() == pyatspi.ROLE_LABEL and obj.childCount:
children = obj.childCount
@@ -93,6 +94,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
#
items = ngettext("%d item", "%d items", children) % children
result.append(items)
+ result.extend(acss)
else:
result.extend(speech_generator.SpeechGenerator.\
_generateNumberOfChildren(self, obj, **args))
@@ -117,6 +119,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
self, obj, **args)
result = []
+ acss = self.voice(speech_generator.SYSTEM)
name = self._generateName(obj)
position = -1
index = total = 0
@@ -138,7 +141,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
result.append(self._script.formatting.getString(
mode='speech', stringType='groupindex') \
% {"index" : position, "total" : total})
-
+ result.extend(acss)
return result
def generateSpeech(self, obj, **args):
diff --git a/src/orca/settings.py b/src/orca/settings.py
index 74ec1e1..07abc5f 100644
--- a/src/orca/settings.py
+++ b/src/orca/settings.py
@@ -373,11 +373,13 @@ speechServerInfo = None # None means let the factory decide.
DEFAULT_VOICE = "default"
UPPERCASE_VOICE = "uppercase"
HYPERLINK_VOICE = "hyperlink"
+SYSTEM_VOICE = "system"
voices = {
DEFAULT_VOICE : ACSS({}),
UPPERCASE_VOICE : ACSS({ACSS.AVERAGE_PITCH : 5.6}),
- HYPERLINK_VOICE : ACSS({})
+ HYPERLINK_VOICE : ACSS({}),
+ SYSTEM_VOICE : ACSS({}),
}
# If True, enable speaking of speech indentation and justification.
diff --git a/src/orca/speech.py b/src/orca/speech.py
index 28798e3..1d0c28b 100644
--- a/src/orca/speech.py
+++ b/src/orca/speech.py
@@ -233,12 +233,13 @@ def speak(content, acss=None, interrupt=True):
continue
elif isinstance(element, ACSS):
newVoice.update(element)
- if newVoice and newVoice == activeVoice:
+ if newVoice == activeVoice:
continue
newItemsToSpeak.append(toSpeak.pop())
- string = " ".join(toSpeak)
- _speak(string, activeVoice, interrupt)
+ if toSpeak:
+ string = " ".join(toSpeak)
+ _speak(string, activeVoice, interrupt)
activeVoice = newVoice
toSpeak = newItemsToSpeak
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index 01bed32..b816bde 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -63,6 +63,22 @@ LINE_BREAK = [LineBreak()]
#
METHOD_PREFIX = "_generate"
+DEFAULT = "default"
+UPPERCASE = "uppercase"
+HYPERLINK = "hyperlink"
+SYSTEM = "system"
+STATE = "state" # Candidate for sound
+VALUE = "value" # Candidate for sound
+
+voiceType = {
+ DEFAULT : settings.DEFAULT_VOICE,
+ UPPERCASE : settings.UPPERCASE_VOICE,
+ HYPERLINK : settings.HYPERLINK_VOICE,
+ SYSTEM : settings.SYSTEM_VOICE,
+ STATE : settings.SYSTEM_VOICE, # Users may prefer DEFAULT_VOICE here
+ VALUE : settings.SYSTEM_VOICE, # Users may prefer DEFAULT_VOICE here
+}
+
class SpeechGenerator(generator.Generator):
"""Takes accessible objects and produces a string to speak for
those objects. See the generateSpeech method, which is the primary
@@ -105,6 +121,63 @@ class SpeechGenerator(generator.Generator):
# #
#####################################################################
+ def _generateName(self, obj, **args):
+ """Returns an array of strings for use by speech and braille that
+ represent the name of the object. If the object is directly
+ displaying any text, that text will be treated as the name.
+ Otherwise, the accessible name of the object will be used. If
+ there is no accessible name, then the description of the
+ object will be used. This method will return an empty array
+ if nothing can be found. [[[WDW - I wonder if we should just
+ have _generateName, _generateDescription,
+ _generateDisplayedText, etc., that don't do any fallback.
+ Then, we can allow the formatting to do the fallback (e.g.,
+ 'displayedText or name or description'). [[[JD to WDW - I
+ needed a _generateDescription for whereAmI. :-) See below.
+ """
+ acss = self.voice(DEFAULT)
+ result = generator.Generator._generateName(self, obj, **args)
+ if result:
+ result.extend(acss)
+ return result
+
+ def _generateLabel(self, obj, **args):
+ """Returns the label for an object as an array of strings for use by
+ speech and braille. The label is determined by the displayedLabel
+ method of the script utility, and an empty array will be returned if
+ no label can be found.
+ """
+ acss = self.voice(DEFAULT)
+ result = generator.Generator._generateLabel(self, obj, **args)
+ if result:
+ result.extend(acss)
+ return result
+
+ def _generateLabelOrName(self, obj, **args):
+ """Returns the label as an array of strings for speech and braille.
+ If the label cannot be found, the name will be used instead.
+ If the name cannot be found, an empty array will be returned.
+ """
+ result = []
+ acss = self.voice(DEFAULT)
+ result.extend(self._generateLabel(obj, **args))
+ if not result:
+ if obj.name and (len(obj.name)):
+ result.append(obj.name)
+ result.extend(acss)
+ return result
+
+ def _generateDescription(self, obj, **args):
+ """Returns an array of strings fo use by speech and braille that
+ represent the description of the object, if that description
+ is different from that of the name and label.
+ """
+ acss = self.voice(SYSTEM)
+ result = generator.Generator._generateDescription(self, obj, **args)
+ if result:
+ result.extend(acss)
+ return result
+
def _generateTextRole(self, obj, **args):
"""A convenience method to prevent the pyatspi.ROLE_PARAGRAPH role
from being spoken. In the case of a pyatspi.ROLE_PARAGRAPH
@@ -118,9 +191,11 @@ class SpeechGenerator(generator.Generator):
override.]]]
"""
result = []
+ acss = self.voice(SYSTEM)
role = args.get('role', obj.getRole())
if role != pyatspi.ROLE_PARAGRAPH:
result.extend(self._generateRoleName(obj, **args))
+ result.extend(acss)
return result
def _generateRoleName(self, obj, **args):
@@ -131,9 +206,11 @@ class SpeechGenerator(generator.Generator):
accessible role of the obj.
"""
result = []
+ acss = self.voice(SYSTEM)
role = args.get('role', obj.getRole())
if (role != pyatspi.ROLE_UNKNOWN):
result.append(rolenames.getSpeechForRoleName(obj, role))
+ result.extend(acss)
return result
def getRoleName(self, obj, **args):
@@ -152,11 +229,14 @@ class SpeechGenerator(generator.Generator):
hierarchy and which are not in a label for or labelled by
relation.
"""
- labels = self._script.utilities.unrelatedLabels(obj)
result = []
+ acss = self.voice(DEFAULT)
+ labels = self._script.utilities.unrelatedLabels(obj)
for label in labels:
name = self._generateName(label, **args)
result.extend(name)
+ if result:
+ result.extend(acss)
return result
def _generateEmbedded(self, obj, **args):
@@ -165,12 +245,15 @@ class SpeechGenerator(generator.Generator):
This either is the label or name of the object or the name of
the application for the object.
"""
+ acss = self.voice(DEFAULT)
result = self._generateLabelOrName(obj, **args)
if not result:
try:
result.append(obj.getApplication().name)
except:
pass
+ if result:
+ result.extend(acss)
return result
#####################################################################
@@ -179,6 +262,42 @@ class SpeechGenerator(generator.Generator):
# #
#####################################################################
+ def _generateCheckedState(self, obj, **args):
+ """Returns an array of strings for use by speech and braille that
+ represent the checked state of the object. This is typically
+ for check boxes. [[[WDW - should we return an empty array if
+ we can guarantee we know this thing is not checkable?]]]
+ """
+ acss = self.voice(STATE)
+ result = generator.Generator._generateCheckedState(self, obj, **args)
+ if result:
+ result.extend(acss)
+ return result
+
+ def _generateExpandableState(self, obj, **args):
+ """Returns an array of strings for use by speech and braille that
+ represent the expanded/collapsed state of an object, such as a
+ tree node. If the object is not expandable, an empty array
+ will be returned.
+ """
+ acss = self.voice(STATE)
+ result = generator.Generator._generateExpandableState(self, obj, **args)
+ if result:
+ result.extend(acss)
+ return result
+
+ def _generateMenuItemCheckedState(self, obj, **args):
+ """Returns an array of strings for use by speech and braille that
+ represent the checked state of the menu item, only if it is
+ checked. Otherwise, and empty array will be returned.
+ """
+ acss = self.voice(STATE)
+ result = generator.Generator.\
+ _generateMenuItemCheckedState(self, obj, **args)
+ if result:
+ result.extend(acss)
+ return result
+
def _generateMultiselectableState(self, obj, **args):
"""Returns an array of strings (and possibly voice and audio
specifications) that represent the multiselectable state of
@@ -186,6 +305,7 @@ class SpeechGenerator(generator.Generator):
is not multiselectable, an empty array will be returned.
"""
result = []
+ acss = self.voice(STATE)
if obj.getState().contains(pyatspi.STATE_MULTISELECTABLE):
# Translators: "multi-select" refers to a web form list
# in which more than one item can be selected at a time.
@@ -193,6 +313,31 @@ class SpeechGenerator(generator.Generator):
result.append(self._script.formatting.getString(
mode='speech',
stringType='multiselect'))
+ result.extend(acss)
+ return result
+
+ def _generateRadioState(self, obj, **args):
+ """Returns an array of strings for use by speech and braille that
+ represent the checked state of the object. This is typically
+ for check boxes. [[[WDW - should we return an empty array if
+ we can guarantee we know this thing is not checkable?]]]
+ """
+ acss = self.voice(STATE)
+ result = generator.Generator._generateRadioState(self, obj, **args)
+ if result:
+ result.extend(acss)
+ return result
+
+ def _generateToggleState(self, obj, **args):
+ """Returns an array of strings for use by speech and braille that
+ represent the checked state of the object. This is typically
+ for check boxes. [[[WDW - should we return an empty array if
+ we can guarantee we know this thing is not checkable?]]]
+ """
+ acss = self.voice(STATE)
+ result = generator.Generator._generateToggleState(self, obj, **args)
+ if result:
+ result.extend(acss)
return result
#####################################################################
@@ -207,6 +352,7 @@ class SpeechGenerator(generator.Generator):
the link associated with obj.
"""
result = []
+ acss = self.voice(HYPERLINK)
# Get the URI for the link of interest and parse it. The parsed
# URI is returned as a tuple containing six components:
# scheme://netloc/path;parameters?query#fragment.
@@ -250,6 +396,8 @@ class SpeechGenerator(generator.Generator):
result.append(linkOutput)
if obj.childCount and obj[0].getRole() == pyatspi.ROLE_IMAGE:
result.extend(self._generateRoleName(obj[0]))
+ if result:
+ result.extend(acss)
return result
def _generateSiteDescription(self, obj, **args):
@@ -258,6 +406,7 @@ class SpeechGenerator(generator.Generator):
pointed to by the URI of the link associated with obj.
"""
result = []
+ acss = self.voice(HYPERLINK)
link_uri = self._script.utilities.uri(obj)
if link_uri:
link_uri_info = urlparse.urlparse(link_uri)
@@ -297,6 +446,8 @@ class SpeechGenerator(generator.Generator):
# site than that of the link.
#
result.append(_("different site"))
+ if result:
+ result.extend(acss)
return result
def _generateFileSize(self, obj, **args):
@@ -306,6 +457,7 @@ class SpeechGenerator(generator.Generator):
obj.
"""
result = []
+ acss = self.voice(HYPERLINK)
sizeString = ""
uri = self._script.utilities.uri(obj)
if not uri:
@@ -332,6 +484,8 @@ class SpeechGenerator(generator.Generator):
# Translators: This is the size of a file in megabytes
#
result.append(_("%.2f megabytes") % (float(size) * .000001))
+ if result:
+ result.extend(acss)
return result
#####################################################################
@@ -346,6 +500,7 @@ class SpeechGenerator(generator.Generator):
it exists. Otherwise, an empty array is returned.
"""
result = []
+ acss = self.voice(DEFAULT)
try:
image = obj.queryImage()
except:
@@ -353,6 +508,7 @@ class SpeechGenerator(generator.Generator):
else:
args['role'] = pyatspi.ROLE_IMAGE
result.extend(self.generate(obj, **args))
+ result.extend(acss)
return result
#####################################################################
@@ -372,6 +528,7 @@ class SpeechGenerator(generator.Generator):
previous object with focus.
"""
result = []
+ acss = self.voice(DEFAULT)
if obj:
priorObj = args.get('priorObj', None)
try:
@@ -405,6 +562,8 @@ class SpeechGenerator(generator.Generator):
and ((newRow != oldRow) \
or (obj.parent != priorParent)):
result = self._generateRowHeader(obj, **args)
+ if result:
+ result.extend(acss)
return result
def _generateNewColumnHeader(self, obj, **args):
@@ -418,6 +577,7 @@ class SpeechGenerator(generator.Generator):
previous object with focus.
"""
result = []
+ acss = self.voice(DEFAULT)
if obj and not args.get('readingRow', False):
priorObj = args.get('priorObj', None)
try:
@@ -451,6 +611,8 @@ class SpeechGenerator(generator.Generator):
and ((newCol != oldCol) \
or (obj.parent != priorParent)):
result = self._generateColumnHeader(obj, **args)
+ if result:
+ result.extend(acss)
return result
def _generateRealTableCell(self, obj, **args):
@@ -461,6 +623,7 @@ class SpeechGenerator(generator.Generator):
cell itself. The string, 'blank', is added for empty cells.
"""
result = []
+ acss = self.voice(DEFAULT)
oldRole = self._overrideRole('REAL_ROLE_TABLE_CELL', args)
result.extend(self.generate(obj, **args))
self._restoreRole(oldRole, args)
@@ -470,6 +633,9 @@ class SpeechGenerator(generator.Generator):
# user has navigated to an empty line.
#
result.append(_("blank"))
+ if result:
+ result.extend(acss)
+
return result
def _generateUnselectedCell(self, obj, **args):
@@ -481,7 +647,7 @@ class SpeechGenerator(generator.Generator):
settings.py.]]]
"""
result = []
-
+ acss = self.voice(STATE)
# If this is an icon within an layered pane or a table cell
# within a table or a tree table and the item is focused but not
# selected, let the user know. See bug #486908 for more details.
@@ -517,6 +683,7 @@ class SpeechGenerator(generator.Generator):
# selected or not.
#
result.append(C_("tablecell", "not selected"))
+ result.extend(acss)
return result
@@ -525,6 +692,7 @@ class SpeechGenerator(generator.Generator):
specifications) reflecting the column number of a cell.
"""
result = []
+ acss = self.voice(SYSTEM)
col = -1
if obj.parent.getRole() == pyatspi.ROLE_TABLE_CELL:
obj = obj.parent
@@ -541,6 +709,8 @@ class SpeechGenerator(generator.Generator):
# Translators: this is in references to a column in a
# table.
result.append(_("column %d") % (col + 1))
+ if result:
+ result.extend(acss)
return result
def _generateRow(self, obj, **args):
@@ -548,6 +718,7 @@ class SpeechGenerator(generator.Generator):
specifications) reflecting the row number of a cell.
"""
result = []
+ acss = self.voice(SYSTEM)
row = -1
if obj.parent.getRole() == pyatspi.ROLE_TABLE_CELL:
obj = obj.parent
@@ -564,6 +735,8 @@ class SpeechGenerator(generator.Generator):
# Translators: this is in references to a row in a table.
#
result.append(_("row %d") % (row + 1))
+ if result:
+ result.extend(acss)
return result
def _generateColumnAndRow(self, obj, **args):
@@ -573,6 +746,7 @@ class SpeechGenerator(generator.Generator):
and the total number of rows.
"""
result = []
+ acss = self.voice(SYSTEM)
if obj.parent.getRole() == pyatspi.ROLE_TABLE_CELL:
obj = obj.parent
parent = obj.parent
@@ -594,6 +768,8 @@ class SpeechGenerator(generator.Generator):
result.append(_("row %(index)d of %(total)d") \
% {"index" : (row + 1),
"total" : table.nRows})
+ if result:
+ result.extend(acss)
return result
def _generateEndOfTableIndicator(self, obj, **args):
@@ -602,6 +778,7 @@ class SpeechGenerator(generator.Generator):
in the table.
"""
result = []
+ acss = self.voice(SYSTEM)
if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE:
if obj.getRole() == pyatspi.ROLE_TABLE_CELL:
cell = obj
@@ -621,6 +798,8 @@ class SpeechGenerator(generator.Generator):
# he/she is in the last cell of a table in a document.
#
result.append(_("End of table"))
+ if result:
+ result.extend(acss)
return result
#####################################################################
@@ -637,6 +816,7 @@ class SpeechGenerator(generator.Generator):
to return an empty array if this is not a terminal.]]]
"""
result = []
+ acss = self.voice(DEFAULT)
title = None
frame = self._script.utilities.ancestorWithRole(
obj, [pyatspi.ROLE_FRAME], [])
@@ -645,6 +825,8 @@ class SpeechGenerator(generator.Generator):
if not title:
title = self._script.utilities.displayedLabel(obj)
result.append(title)
+ if result:
+ result.extend(acss)
return result
#####################################################################
@@ -653,6 +835,18 @@ class SpeechGenerator(generator.Generator):
# #
#####################################################################
+ def _generateCurrentLineText(self, obj, **args):
+ """Returns an array of strings for use by speech and braille
+ that represents the current line of text, if
+ this is a text object. [[[WDW - consider returning an empty
+ array if this is not a text object.]]]
+ """
+ acss = self.voice(DEFAULT)
+ result = generator.Generator._generateCurrentLineText(self, obj, **args)
+ if result:
+ result.extend(acss)
+ return result
+
def _getCharacterAttributes(self,
obj,
text,
@@ -792,15 +986,19 @@ class SpeechGenerator(generator.Generator):
except NotImplementedError:
return []
+ result = []
+ acss = self.voice(DEFAULT)
[line, startOffset, endOffset, selected] = \
self._getTextInformation(obj)
# The empty string seems to be messing with using 'or' in
# formatting strings.
#
- if line == '':
- return []
- return [line]
+ if line:
+ result.append(line)
+ result.extend(acss)
+
+ return result
def _generateTextContentWithAttributes(self, obj, **args):
"""Returns an array of strings (and possibly voice and audio
@@ -809,11 +1007,13 @@ class SpeechGenerator(generator.Generator):
mixed in. This requires _generateTextInformation to have been
called prior to this method.
"""
+
try:
text = obj.queryText()
except NotImplementedError:
return []
+ acss = self.voice(DEFAULT)
[line, startOffset, endOffset, selected] = \
self._getTextInformation(obj)
@@ -842,7 +1042,9 @@ class SpeechGenerator(generator.Generator):
newLine += " ; "
newLine += attribs
- return [newLine]
+ result = [newline]
+ result.extend(acss)
+ return result
def _generateAnyTextSelection(self, obj, **args):
"""Returns an array of strings (and possibly voice and audio
@@ -851,6 +1053,7 @@ class SpeechGenerator(generator.Generator):
moved to settings.py.]]]
"""
result = []
+ acss = self.voice(SYSTEM)
[line, startOffset, endOffset, selected] = \
self._getTextInformation(obj)
@@ -861,6 +1064,7 @@ class SpeechGenerator(generator.Generator):
#
text = C_("text", "selected")
result.append(text)
+ result.extend(acss)
return result
def _generateAllTextSelection(self, obj, **args):
@@ -870,6 +1074,7 @@ class SpeechGenerator(generator.Generator):
moved to settings.py.]]]
"""
result = []
+ acss = self.voice(SYSTEM)
try:
textObj = obj.queryText()
except:
@@ -884,6 +1089,7 @@ class SpeechGenerator(generator.Generator):
# a document, Orca lets them know this.
#
result = [C_("text", "selected")]
+ result.extend(acss)
return result
def generateTextIndentation(self, obj, **args):
@@ -897,6 +1103,7 @@ class SpeechGenerator(generator.Generator):
- obj: the text object.
- line: the string to check for spaces and tabs.
"""
+ acss = self.voice(SYSTEM)
if not settings.enableSpeechIndentation:
return []
line = args.get('alreadyFocused', "")
@@ -941,9 +1148,10 @@ class SpeechGenerator(generator.Generator):
break
spaceCount = tabCount = 0
- if len(utterance):
- return [utterance]
- return []
+ result = [utterance]
+ if result and result[0]:
+ result.extend(acss)
+ return result
#####################################################################
# #
@@ -961,10 +1169,12 @@ class SpeechGenerator(generator.Generator):
focus.
"""
result = []
+ acss = self.voice(SYSTEM)
oldLevel = self._script.utilities.nodeLevel(args.get('priorObj', None))
newLevel = self._script.utilities.nodeLevel(obj)
if (oldLevel != newLevel) and (newLevel >= 0):
result.extend(self._generateNodeLevel(obj, **args))
+ result.extend(acss)
return result
#####################################################################
@@ -980,6 +1190,7 @@ class SpeechGenerator(generator.Generator):
should consider returning an empty array if there is no value.
"""
result = []
+ acss = self.voice(SYSTEM)
try:
value = obj.queryValue()
except NotImplementedError:
@@ -995,6 +1206,8 @@ class SpeechGenerator(generator.Generator):
"%d percent",
percentValue) % percentValue
result.append(percentage)
+ if result:
+ result.extend(acss)
return result
#####################################################################
@@ -1017,6 +1230,7 @@ class SpeechGenerator(generator.Generator):
# AT-SPI method calls.]]]
#
result = []
+ acss = self.voice(DEFAULT)
priorObj = args.get('priorObj', None)
if obj and obj.getRole() == pyatspi.ROLE_RADIO_BUTTON:
radioGroupLabel = None
@@ -1038,6 +1252,7 @@ class SpeechGenerator(generator.Generator):
if (not inSameGroup) and radioGroupLabel:
result.append(self._script.utilities.\
displayedText(radioGroupLabel))
+ result.extend(acss)
return result
def _generateNumberOfChildren(self, obj, **args):
@@ -1048,6 +1263,7 @@ class SpeechGenerator(generator.Generator):
be moved to settings.py.]]]
"""
result = []
+ acss = self.voice(SYSTEM)
childNodes = self._script.utilities.childNodes(obj)
children = len(childNodes)
if children:
@@ -1056,6 +1272,7 @@ class SpeechGenerator(generator.Generator):
#
itemString = ngettext("%d item", "%d items", children) % children
result.append(itemString)
+ result.extend(acss)
return result
def _generateNoShowingChildren(self, obj, **args):
@@ -1067,6 +1284,7 @@ class SpeechGenerator(generator.Generator):
settings.py.]]]
"""
result = []
+ acss = self.voice(SYSTEM)
hasItems = False
for child in obj:
state = child.getState()
@@ -1078,6 +1296,7 @@ class SpeechGenerator(generator.Generator):
# or table.
#
result.append(_("0 items"))
+ result.extend(acss)
return result
def _generateNoChildren(self, obj, **args ):
@@ -1089,11 +1308,13 @@ class SpeechGenerator(generator.Generator):
settings.py.]]]
"""
result = []
+ acss = self.voice(SYSTEM)
if not obj.childCount:
# Translators: this is the number of items in a layered pane
# or table.
#
result.append(_("0 items"))
+ result.extend(acss)
return result
def _generateSelectedItemCount(self, obj, **args):
@@ -1103,6 +1324,7 @@ class SpeechGenerator(generator.Generator):
panel or a layered pane.
"""
result = []
+ acss = self.voice(SYSTEM)
# TODO - JD: Is there a better way to do this other than
# hard-coding it in?
#
@@ -1129,13 +1351,13 @@ class SpeechGenerator(generator.Generator):
% {"index" : totalSelectedItems,
"total" : childCount}
result.append(countString)
-
+ result.extend(acss)
result.append(self._script.formatting.getString(
mode='speech',
stringType='iconindex') \
% {"index" : currentItem,
"total" : childCount})
-
+ result.extend(acss)
return result
def _generateSelectedItems(self, obj, **args):
@@ -1162,6 +1384,7 @@ class SpeechGenerator(generator.Generator):
settings.py.]]]
"""
result = []
+ acss = self.voice(SYSTEM)
# If this application has more than one unfocused alert or
# dialog window, then speak '<m> unfocused dialogs'
# to let the user know.
@@ -1175,6 +1398,7 @@ class SpeechGenerator(generator.Generator):
result.append(ngettext("%d unfocused dialog",
"%d unfocused dialogs",
alertAndDialogCount) % alertAndDialogCount)
+ result.extend(acss)
return result
def _generateAncestors(self, obj, **args):
@@ -1189,6 +1413,7 @@ class SpeechGenerator(generator.Generator):
previous object with focus.
"""
result = []
+ acss = self.voice(DEFAULT)
priorObj = args.get('priorObj', None)
requireText = args.get('requireText', True)
commonAncestor = self._script.utilities.commonAncestor(priorObj, obj)
@@ -1209,16 +1434,21 @@ class SpeechGenerator(generator.Generator):
and 'Text' in pyatspi.listInterfaces(parent))):
text = self._script.utilities.displayedText(parent)
if text and len(text.strip()):
+ roleInfo = self._generateRoleName(parent)
+ if roleInfo:
+ roleInfo.reverse()
# Push announcement of cell to the end
#
if parent.getRole() not in [pyatspi.ROLE_TABLE_CELL,
pyatspi.ROLE_FILLER]:
- result.extend(self._generateRoleName(parent))
+ result.extend(roleInfo)
+ result.extend(acss)
result.append(text)
if parent.getRole() == pyatspi.ROLE_TABLE_CELL:
- result.extend(self._generateRoleName(parent))
+ result.extend(roleInfo)
parent = parent.parent
- return result.reverse() or result
+ result.reverse()
+ return result
def _generateNewAncestors(self, obj, **args):
"""Returns an array of strings (and possibly voice and audio
@@ -1271,6 +1501,7 @@ class SpeechGenerator(generator.Generator):
object in a group.
"""
result = []
+ acss = self.voice(SYSTEM)
position = -1
total = -1
@@ -1294,7 +1525,7 @@ class SpeechGenerator(generator.Generator):
stringType='groupindex') \
% {"index" : position,
"total" : total})
-
+ result.extend(acss)
return result
def _generatePositionInList(self, obj, **args):
@@ -1303,6 +1534,7 @@ class SpeechGenerator(generator.Generator):
object in a list.
"""
result = []
+ acss = self.voice(SYSTEM)
position = -1
index = 0
total = 0
@@ -1376,7 +1608,7 @@ class SpeechGenerator(generator.Generator):
stringType='groupindex') \
% {"index" : position,
"total" : total})
-
+ result.extend(acss)
return result
def _generateDefaultButton(self, obj, **args):
@@ -1433,6 +1665,7 @@ class SpeechGenerator(generator.Generator):
any unfocused dialog boxes.
"""
result = []
+ acss = self.voice(DEFAULT)
frame, dialog = self._script.utilities.frameAndDialog(obj)
if frame:
result.append(self._generateLabelAndName(frame))
@@ -1444,9 +1677,12 @@ class SpeechGenerator(generator.Generator):
# Translators: this tells the user how many unfocused
# alert and dialog windows that this application has.
#
- result.append(ngettext("%d unfocused dialog",
- "%d unfocused dialogs",
- alertAndDialogCount) % alertAndDialogCount)
+ dialogs = []
+ dialogs.append(ngettext("%d unfocused dialog",
+ "%d unfocused dialogs",
+ alertAndDialogCount) % alertAndDialogCount)
+ dialogs.extend(acss)
+ result.append(dialogs)
return result
#####################################################################
@@ -1461,10 +1697,13 @@ class SpeechGenerator(generator.Generator):
or an empty array if no accelerator can be found.
"""
result = []
+ acss = self.voice(SYSTEM)
[mnemonic, shortcut, accelerator] = \
self._script.utilities.mnemonicShortcutAccelerator(obj)
if accelerator:
result.append(accelerator)
+ result.extend(acss)
+
return result
def _generateMnemonic(self, obj, **args):
@@ -1473,6 +1712,7 @@ class SpeechGenerator(generator.Generator):
an empty array if no mnemonic can be found.
"""
result = []
+ acss = self.voice(SYSTEM)
if settings.enableMnemonicSpeaking or args.get('forceMnemonic', False):
[mnemonic, shortcut, accelerator] = \
self._script.utilities.mnemonicShortcutAccelerator(obj)
@@ -1482,6 +1722,8 @@ class SpeechGenerator(generator.Generator):
mnemonic = shortcut
if mnemonic:
result = [mnemonic]
+ result.extend(acss)
+
return result
#####################################################################
@@ -1499,6 +1741,7 @@ class SpeechGenerator(generator.Generator):
'forceTutorial' attribute of the args dictionary to True.
"""
result = []
+ acss = self.voice(SYSTEM)
alreadyFocused = args.get('alreadyFocused', False)
forceTutorial = args.get('forceTutorial', False)
result.extend(self._script.tutorialGenerator.getTutorial(
@@ -1513,6 +1756,8 @@ class SpeechGenerator(generator.Generator):
frame,
alreadyFocused,
forceTutorial))
+ if result and result[0]:
+ result.extend(acss)
return result
#####################################################################
@@ -1527,13 +1772,12 @@ class SpeechGenerator(generator.Generator):
def _generateLineBreak(self, obj, **args):
return LINE_BREAK
- def voice(self, key=None):
+ def voice(self, key=None, **args):
"""Returns an array containing a voice. The key is a value
to be used to look up the voice in the settings.py:voices
- dictionary.
+ dictionary. Other arguments can be passed in for future
+ decision making.
"""
- try:
- voice = settings.voices[key]
- except:
- voice = settings.voices[settings.DEFAULT_VOICE]
- return [voice]
+
+ voicename = voiceType.get(key) or voiceType.get(DEFAULT)
+ return [settings.voices.get(voicename)]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]