[orca/570658-whereami] Begin implementing text where am I code
- From: William Walker <wwalker src gnome org>
- To: svn-commits-list gnome org
- Subject: [orca/570658-whereami] Begin implementing text where am I code
- Date: Thu, 4 Jun 2009 18:29:43 -0400 (EDT)
commit 4ed5b29a1d0c1309c927b32e1ac84f8c019785fd
Author: Willie Walker <william walker sun com>
Date: Thu Jun 4 18:27:28 2009 -0400
Begin implementing text where am I code
This moves a lot of stuff to speech_generator. Seems to work nicely,
but I'm not ready to throw the switch yet. Most of the code in
where_am_I.py can be deleted once more testing has been done.
---
src/orca/formatting.py | 12 ++-
src/orca/speech_generator.py | 202 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 211 insertions(+), 3 deletions(-)
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index 0696c1b..7215249 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -118,7 +118,9 @@ formatting = {
},
pyatspi.ROLE_PASSWORD_TEXT: {
'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
- 'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection + mnemonic'
+ 'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection + mnemonic',
+ 'basicWhereAmI': 'label + readOnly + textRole + textContent + anyTextSelection + mnemonic + tutorial',
+ 'detailedWhereAmI': 'label + readOnly + textRole + textContentWithAttributes + anyTextSelection + mnemonic + tutorial'
},
pyatspi.ROLE_PROGRESS_BAR: {
'focused': 'percentage',
@@ -204,7 +206,9 @@ formatting = {
},
pyatspi.ROLE_TEXT: {
'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
- 'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection + mnemonic'
+ 'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection + mnemonic',
+ 'basicWhereAmI': 'label + readOnly + textRole + textContent + anyTextSelection + mnemonic + tutorial',
+ 'detailedWhereAmI': 'label + readOnly + textRole + textContentWithAttributes + anyTextSelection + mnemonic + tutorial'
},
pyatspi.ROLE_TOGGLE_BUTTON: {
'focused': 'toggleState',
@@ -217,7 +221,9 @@ formatting = {
},
pyatspi.ROLE_PARAGRAPH: {
'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
- 'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection + mnemonic'
+ 'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection + mnemonic',
+ 'basicWhereAmI': 'label + readOnly + textRole + textContent + anyTextSelection + mnemonic + tutorial',
+ 'detailedWhereAmI': 'label + readOnly + textRole + textContentWithAttributes + anyTextSelection + mnemonic + tutorial'
},
pyatspi.ROLE_EMBEDDED: {
'focused': 'embedded',
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index 8b19957..b9bdc70 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -36,6 +36,7 @@ import orca_state
import pyatspi
import rolenames
import settings
+import text_attribute_names
from orca_i18n import _ # for gettext support
from orca_i18n import ngettext # for ngettext support
@@ -95,6 +96,11 @@ class SpeechGenerator:
name = name[0].lower() + name[1:]
self._methodsDict[name] = method
+ # Something to help us retain things we've computed while
+ # generating speech so we don't need to keep recomputing them.
+ #
+ self._valueCache = {}
+
# Verify the formatting strings are OK. This is only
# for verification and does not effect the function of
# Orca at all.
@@ -1148,6 +1154,180 @@ class SpeechGenerator:
# #
#####################################################################
+ def _getCharacterAttributes(self,
+ obj,
+ text,
+ textOffset,
+ lineIndex,
+ keys=["style", "weight", "underline"]):
+ """Helper function that returns a string containing the
+ given attributes from keys for the given character.
+ """
+ attribStr = ""
+
+ defaultAttributes = text.getDefaultAttributes()
+ attributesDictionary = \
+ self._script.attributeStringToDictionary(defaultAttributes)
+
+ charAttributes = text.getAttributes(textOffset)
+ if charAttributes[0]:
+ charDict = \
+ self._script.attributeStringToDictionary(charAttributes[0])
+ for key in charDict.keys():
+ attributesDictionary[key] = charDict[key]
+
+ if attributesDictionary:
+ for key in keys:
+ localizedKey = text_attribute_names.getTextAttributeName(key)
+ if key in attributesDictionary:
+ attribute = attributesDictionary[key]
+ localizedValue = \
+ text_attribute_names.getTextAttributeName(attribute)
+ if attribute:
+ # If it's the 'weight' attribute and greater than 400,
+ # just speak it as bold, otherwise speak the weight.
+ #
+ if key == "weight":
+ if int(attribute) > 400:
+ attribStr += " "
+ # Translators: bold as in the font sense.
+ #
+ attribStr += _("bold")
+ elif key == "underline":
+ if attribute != "none":
+ attribStr += " "
+ attribStr += localizedKey
+ elif key == "style":
+ if attribute != "normal":
+ attribStr += " "
+ attribStr += localizedValue
+ else:
+ attribStr += " "
+ attribStr += (localizedKey + " " + localizedValue)
+
+ # Also check to see if this is a hypertext link.
+ #
+ if self._script.getLinkIndex(obj, textOffset) >= 0:
+ attribStr += " "
+ # Translators: this indicates that this piece of
+ # text is a hypertext link.
+ #
+ attribStr += _("link")
+
+ return attribStr
+
+ def _getTextInformation(self, obj, **args):
+ """Returns an empty array, but sets up a 'textInformation' attribute
+ in self._valueCache for other methods to use. The information
+ is either:
+
+ A. if no text on the current line is selected, the current line
+ B. if text is selected, the selected text
+ C. if the current line is blank/empty, 'blank'
+
+ For all the above, we'll get a 'textInformation' entry in
+ self._valueCache that is the following list:
+
+ [textContents, startOffset, endOffset, selected]
+ """
+
+ textObj = obj.queryText()
+ caretOffset = textObj.caretOffset
+ textContents = ""
+ selected = False
+
+ nSelections = textObj.getNSelections()
+
+ [current, other] = self._script.hasTextSelections(obj)
+ if current or other:
+ selected = True
+ [textContents, startOffset, endOffset] = \
+ self._script.getAllSelectedText(obj)
+ else:
+ # Get the line containing the caret
+ #
+ [line, startOffset, endOffset] = textObj.getTextAtOffset(
+ textObj.caretOffset,
+ pyatspi.TEXT_BOUNDARY_LINE_START)
+ if len(line):
+ line = self._script.adjustForRepeats(line)
+ textContents = line
+ else:
+ char = textObj.getTextAtOffset(caretOffset,
+ pyatspi.TEXT_BOUNDARY_CHAR)
+ if char[0] == "\n" and startOffset == caretOffset \
+ and settings.speakBlankLines:
+ # Translators: "blank" is a short word to mean the
+ # user has navigated to an empty line.
+ #
+ textContents = (_("blank"))
+
+ self._valueCache['textInformation'] = \
+ [textContents, startOffset, endOffset, selected]
+
+ return []
+
+ def _getTextContent(self, obj, **args):
+ """Returns an array of strings (and possibly voice and audio
+ specifications) containing the text content. This requires
+ _getTextInformation to have been called prior to this method.
+ """
+ try:
+ text = obj.queryText()
+ except NotImplementedError:
+ return []
+
+ if not self._valueCache.has_key('textInformation'):
+ self._getTextInformation(obj, **args)
+ [line, startOffset, endOffset, selected] = \
+ self._valueCache['textInformation']
+
+ return [line]
+
+ def _getTextContentWithAttributes(self, obj, **args):
+ """Returns an array of strings (and possibly voice and audio
+ specifications) containing the text content, obtained from the
+ 'textInformation' value of self._valueCache, with character
+ attribute information mixed in. This requires
+ _getTextInformation to have been called prior to this method.
+ """
+ try:
+ text = obj.queryText()
+ except NotImplementedError:
+ return []
+
+ if not self._valueCache.has_key('textInformation'):
+ self._getTextInformation(obj, **args)
+ [line, startOffset, endOffset, selected] = \
+ self._valueCache['textInformation']
+
+ newLine = ""
+ lastAttribs = None
+ textOffset = startOffset
+ for i in range(0, len(line)):
+ attribs = self._getCharacterAttributes(obj, text, textOffset, i)
+ if attribs and attribs != lastAttribs:
+ if newLine:
+ newLine += " ; "
+ newLine += attribs
+ newLine += " "
+ lastAttribs = attribs
+ newLine += line[i]
+ textOffset += 1
+
+ attribs = self._getCharacterAttributes(obj,
+ text,
+ startOffset,
+ 0,
+ ["paragraph-style"])
+
+ if attribs:
+ if newLine:
+ newLine += " ; "
+ newLine += attribs
+
+ return [newLine]
+
def _getCurrentLineText(self, obj, **args ):
"""Returns an array of strings (and possibly voice and audio
specifications) that represents the current line of text, if
@@ -1165,6 +1345,27 @@ class SpeechGenerator:
"""
return [self._script.getDisplayedText(obj)]
+ def _getAnyTextSelection(self, obj, **args):
+ """Returns an array of strings (and possibly voice and audio
+ specifications) that says if any of the text for the entire
+ object is selected. [[[WDW - I wonder if this string should be
+ moved to settings.py.]]]
+ """
+ result = []
+
+ if not self._valueCache.has_key('textInformation'):
+ self._getTextInformation(obj, **args)
+ [line, startOffset, endOffset, selected] = \
+ self._valueCache['textInformation']
+
+ if selected:
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca lets them know this.
+ #
+ text = C_("text", "selected")
+ result.append(text)
+ return result
+
def _getAllTextSelection(self, obj, **args):
"""Returns an array of strings (and possibly voice and audio
specifications) that says if all the text for the entire
@@ -1901,6 +2102,7 @@ class SpeechGenerator:
# we've been called.
#
if not args.get('recursing', False):
+ self._valueCache = {}
if args.get('includeContext', True):
prefix = self._script.formatting.getPrefix(**args)
suffix = self._script.formatting.getSuffix(**args)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]