orca r3909 - in trunk: . src/orca src/orca/scripts/apps/gedit src/orca/scripts/apps/soffice



Author: richb
Date: Tue May 20 20:27:27 2008
New Revision: 3909
URL: http://svn.gnome.org/viewvc/orca?rev=3909&view=rev

Log:
        * src/orca/scripts/apps/gedit/script.py:
          src/orca/scripts/apps/soffice/script.py:
          src/orca/default.py:
          src/orca/where_am_I.py:
          Fixed bug #517048 - Orca does not always speak the correct 
          information when navigating and/or selecting text across 
          object boundaries in OOo Writer.


Modified:
   trunk/ChangeLog
   trunk/src/orca/default.py
   trunk/src/orca/scripts/apps/gedit/script.py
   trunk/src/orca/scripts/apps/soffice/script.py
   trunk/src/orca/where_am_I.py

Modified: trunk/src/orca/default.py
==============================================================================
--- trunk/src/orca/default.py	(original)
+++ trunk/src/orca/default.py	Tue May 20 20:27:27 2008
@@ -3133,8 +3133,81 @@
         self.pointOfReference['oldName'] = event.source.name
         orca.visualAppearanceChanged(event, event.source)
 
-    def _presentTextAtNewCaretPosition(self, event):
+    def _speakContiguousSelection(self, obj, relationship):
+        """Check if the contiguous object has a selection. If it does, then
+        speak it. If the user pressed Shift-Down, then look for an object 
+        with a RELATION_FLOWS_FROM relationship. If they pressed Shift-Up,
+        then look for a RELATION_FLOWS_TO relationship.
+
+        Arguments:
+        - the current text object
+        - the flows relationship (RELATION_FLOWS_FROM or RELATION_FLOWS_TO).
+
+        Returns an indication of whether anything was spoken.
+        """
+
+        lastPos = self.pointOfReference.get("lastCursorPosition")
+
+        # Reasons to NOT speak contiguous selections:
+        #
+        # 1. The new cursor position is in the same object as the old
+        #    cursor position. (The change in selection is all within
+        #    the current object.)
+        # 2. If we are selecting up line by line from the beginning of
+        #    the line and have just crossed into a new object, the change
+        #    in selection is the previous line (which has just become
+        #    selected).  Nothing has changed on the line we came from.
+        #
+        if self.isSameObject(lastPos[0], obj) \
+           or relationship == pyatspi.RELATION_FLOWS_TO and lastPos[1] == 0:
+            return False
+
+        selSpoken = False
+        current = obj
+        for relation in current.getRelationSet():
+            if relation.getRelationType() == relationship:
+                obj = relation.getTarget(0)
+                objText = obj.queryText()
+
+                # When selecting down across paragraph boundaries, what
+                # we've (un)selected on (what is now) the previous line
+                # is from wherever the cursor used to be to the end of 
+                # the line.
+                #
+                if relationship == pyatspi.RELATION_FLOWS_FROM:
+                    start, end = lastPos[1], objText.characterCount
+
+                # When selecting up across paragraph boundaries, what
+                # we've (un)selected on (what is now) the next line is
+                # from the beginning of the line to wherever the cursor
+                # used to be.
+                #
+                else:
+                    start, end = 0, lastPos[1]
 
+                if objText.getNSelections() > 0:
+                    [textContents, startOffset, endOffset] = \
+                        self.whereAmI.getTextSelection(obj)
+
+                    # Now that we have the full selection, adjust based
+                    # on the relation type. (see above comment)
+                    #
+                    startOffset = start or startOffset
+                    endOffset = end or endOffset
+                    self.sayPhrase(obj, startOffset, endOffset)
+                    selSpoken = True
+                else:
+                    # We don't have selections in this object. But we're
+                    # here, which means that something is selected in a
+                    # neighboring object and the text in this object must
+                    # have just become unselected and needs to be spoken.
+                    #
+                    self.sayPhrase(obj, start, end)
+                    selSpoken = True
+
+        return selSpoken
+
+    def _presentTextAtNewCaretPosition(self, event):
         obj = event.source
         text = obj.queryText()
 
@@ -3179,7 +3252,8 @@
         mods = orca_state.lastInputEvent.modifiers
         isControlKey = mods & (1 << pyatspi.MODIFIER_CONTROL)
         isShiftKey = mods & (1 << pyatspi.MODIFIER_SHIFT)
-        hasLastPos = self.pointOfReference.has_key("lastCursorPosition")
+        lastPos = self.pointOfReference.get("lastCursorPosition")
+        hasLastPos = (lastPos != None)
 
         if (keyString == "Up") or (keyString == "Down"):
             # If the user has typed Shift-Up or Shift-Down, then we want
@@ -3188,8 +3262,39 @@
             # currently positioned.
             #
             if hasLastPos and isShiftKey and not isControlKey:
-                [startOffset, endOffset] = self.getOffsetsForPhrase(obj)
-                self.sayPhrase(obj, startOffset, endOffset)
+                if keyString == "Up":
+                    # If we have just crossed a paragraph boundary with
+                    # Shift+Up, what we've selected in this object starts
+                    # with the current offset and goes to the end of the
+                    # paragraph.
+                    # 
+                    if not self.isSameObject(lastPos[0], obj):
+                        [startOffset, endOffset] = \
+                            text.caretOffset, text.characterCount
+                    else:
+                        [startOffset, endOffset] \
+                                             = self.getOffsetsForPhrase(obj)
+                    self.sayPhrase(obj, startOffset, endOffset)
+                    selSpoken = self._speakContiguousSelection(obj,
+                                                   pyatspi.RELATION_FLOWS_TO)
+                else:
+                    selSpoken = self._speakContiguousSelection(obj,
+                                                 pyatspi.RELATION_FLOWS_FROM)
+
+                    # If we have just crossed a paragraph boundary with
+                    # Shift+Down, what we've selected in this object starts
+                    # with the beginning of the paragraph and goes to the
+                    # current offset.
+                    #
+                    if not self.isSameObject(lastPos[0], obj):
+                        [startOffset, endOffset] = 0, text.caretOffset
+                    else:
+                        [startOffset, endOffset] \
+                                             = self.getOffsetsForPhrase(obj)
+
+                    if startOffset != endOffset:
+                        self.sayPhrase(obj, startOffset, endOffset)
+
             else:
                 [startOffset, endOffset] = self.getOffsetsForLine(obj)
                 self.sayLine(obj)
@@ -3201,12 +3306,17 @@
             # or Control-Right, we speak the current word otherwise we speak
             # the character at the text cursor position.
             #
-            if hasLastPos and isShiftKey and isControlKey:
+            inNewObj = hasLastPos and not self.isSameObject(lastPos[0], obj)
+
+            if hasLastPos and not inNewObj and isShiftKey and isControlKey:
                 [startOffset, endOffset] = self.getOffsetsForPhrase(obj)
                 self.sayPhrase(obj, startOffset, endOffset)
-            elif isControlKey:
+            elif isControlKey and not inNewObj:
                 [startOffset, endOffset] = self.getOffsetsForWord(obj)
-                self.sayWord(obj)
+                if startOffset == endOffset:
+                    self.sayCharacter(obj)
+                else:
+                    self.sayWord(obj)
             else:
                 [startOffset, endOffset] = self.getOffsetsForChar(obj)
                 self.sayCharacter(obj)
@@ -3262,7 +3372,7 @@
             startOffset = text.caretOffset
             endOffset = text.caretOffset
 
-        self._saveLastCursorPosition(text)
+        self._saveLastCursorPosition(obj, text.caretOffset)
         self._saveSpokenTextRange(startOffset, endOffset)
 
     def onCaretMoved(self, event):
@@ -3686,7 +3796,8 @@
         """
 
         text = obj.queryText()
-        startOffset = self.pointOfReference["lastCursorPosition"]
+        lastPos = self.pointOfReference.get("lastCursorPosition")
+        startOffset = lastPos[1]
         endOffset = text.caretOffset
 
         # Swap values if in wrong order (StarOffice is fussy about that).
@@ -3750,13 +3861,37 @@
         - event: the Event
         """
 
-        startOffset = 0
-        endOffset = 0
-        if "spokenTextRange" in self.pointOfReference:
-            startOffset = self.pointOfReference["spokenTextRange"][0]
-            endOffset = self.pointOfReference["spokenTextRange"][1]
-        self.speakTextSelectionState(event.source, startOffset, endOffset)
+        obj = event.source
+        spokenRange = self.pointOfReference.get("spokenTextRange") or [0, 0]
+        startOffset, endOffset = spokenRange
+
+        if not obj.getState().contains(pyatspi.STATE_FOCUSED):
+            # If we are selecting text across object boundaries with
+            # Shift+Down and doing so from the very beginning of the
+            # line, we will get an event telling us that the selection
+            # has changed for the line we just left.  Because nothing
+            # is selected on the line which contains the caret, we won't
+            # speak "selected."  So check to see if the event is for the
+            # object we just left and be sure that we don't have a spoken
+            # range (otherwise, we'll say selected twice when we are
+            # selecting across boundaries from the middle of the line).
+            #
+            lastPos = self.pointOfReference.get("lastCursorPosition")
+            if not lastPos or spokenRange != [0, 0]:
+                return
+
+            prevObj = None
+            for relation in lastPos[0].getRelationSet():
+                if relation.getRelationType() == pyatspi.RELATION_FLOWS_FROM:
+                    prevObj = relation.getTarget(0)
+
+            if not self.isSameObject(prevObj, obj):
+                return
+
+            endOffset = obj.queryText().characterCount
 
+        self.speakTextSelectionState(obj, startOffset, endOffset)    
+            
     def onSelectionChanged(self, event):
         """Called when an object's selection changes.
 
@@ -6810,14 +6945,15 @@
 
         self.pointOfReference["spokenTextRange"] = [startOffset, endOffset]
 
-    def _saveLastCursorPosition(self, text):
+    def _saveLastCursorPosition(self, obj, caretOffset):
         """Save away the current text cursor position for next time.
 
         Arguments:
-        - text: the text object.
+        - obj: the current accessible
+        - caretOffset: the cursor position within this object
         """
 
-        self.pointOfReference["lastCursorPosition"] = text.caretOffset
+        self.pointOfReference["lastCursorPosition"] = [obj, caretOffset]
 
     def _saveLastTextSelections(self, text):
         """Save away the list of text selections for next time.
@@ -6848,8 +6984,13 @@
 
         # Handle special cases.
         #
-        # Shift-Page-Down:    speak "page <state> from cursor position".
-        # Shift-Page-Up:      speak "page <state> to cursor position".
+        # Control-Shift-Page_Down:
+        #          speak "line selected to end from previous cursor position".
+        # Control-Shift-Page_Up:
+        #        speak "line selected from start to previous cursor position".
+        #
+        # Shift-Page_Down:    speak "page <state> from cursor position".
+        # Shift-Page_Up:      speak "page <state> to cursor position".
         #
         # Control-Shift-Down: speak "line <state> down from cursor position".
         # Control-Shift-Up:   speak "line <state> up from cursor position".
@@ -6874,7 +7015,23 @@
         selectedText = (text.getNSelections() != 0)
 
         specialCaseFound = False
-        if (eventStr == "Page_Down") and isShiftKey and not isControlKey:
+        if (eventStr == "Page_Down") and isShiftKey and isControlKey:
+            specialCaseFound = True
+            # Translators: when the user selects (highlights) text in
+            # a document, Orca will speak information about what they
+            # have selected.
+            #
+            line = _("line selected to end from previous cursor position")
+
+        elif (eventStr == "Page_Up") and isShiftKey and isControlKey:
+            specialCaseFound = True
+            # Translators: when the user selects (highlights) text in
+            # a document, Orca will speak information about what they
+            # have selected.
+            #
+            line = _("line selected from start to previous cursor position")
+
+        elif (eventStr == "Page_Down") and isShiftKey and not isControlKey:
             specialCaseFound = True
             if selectedText:
                 # Translators: when the user selects (highlights) text in
@@ -6977,6 +7134,8 @@
         if specialCaseFound:
             speech.speak(line, None, False)
             return
+        elif startOffset == endOffset:
+            return
 
         try:
             # If we are selecting by word, then there possibly will be
@@ -7007,6 +7166,7 @@
                         startOffset += 1
                     else:
                         break
+
         except:
             debug.printException(debug.LEVEL_FINEST)
 
@@ -7017,23 +7177,14 @@
             # ONLY TRANSLATE THE PART AFTER THE PIPE CHARACTER |
             #
             speech.speak(Q_("text|selected"), None, False)
-        else:
-            if self.pointOfReference.has_key("lastSelections"):
-                for i in xrange(len(self.pointOfReference["lastSelections"])):
-                    startSelOffset = \
-                        self.pointOfReference["lastSelections"][0][0]
-                    endSelOffset = \
-                        self.pointOfReference["lastSelections"][0][1]
-                    if (startOffset >= startSelOffset) \
-                        and (endOffset <= endSelOffset):
-                        # Translators: when the user unselects
-                        # (unhighlights) text in a document, Orca lets
-                        # them know this.
-                        #
-                        # ONLY TRANSLATE THE PART AFTER THE PIPE CHARACTER |
-                        #
-                        speech.speak(Q_("text|unselected"), None, False)
-                        break
+        elif len(text.getText(startOffset, endOffset)):
+            # Translators: when the user unselects
+            # (unhighlights) text in a document, Orca lets
+            # them know this.
+            #
+            # ONLY TRANSLATE THE PART AFTER THE PIPE CHARACTER |
+            #
+            speech.speak(Q_("text|unselected"), None, False)
 
         self._saveLastTextSelections(text)
 

Modified: trunk/src/orca/scripts/apps/gedit/script.py
==============================================================================
--- trunk/src/orca/scripts/apps/gedit/script.py	(original)
+++ trunk/src/orca/scripts/apps/gedit/script.py	Tue May 20 20:27:27 2008
@@ -291,6 +291,9 @@
         """
 
         obj = orca_state.locusOfFocus
+        if not obj:
+            return False
+
         rolesList1 = [pyatspi.ROLE_PUSH_BUTTON,
                       pyatspi.ROLE_FILLER,
                       pyatspi.ROLE_FILLER,

Modified: trunk/src/orca/scripts/apps/soffice/script.py
==============================================================================
--- trunk/src/orca/scripts/apps/soffice/script.py	(original)
+++ trunk/src/orca/scripts/apps/soffice/script.py	Tue May 20 20:27:27 2008
@@ -1848,6 +1848,11 @@
         - event: the Event
         """
 
+        # If the object is losing focus, then just ignore this event.
+        #
+        if event.detail1 == -1:
+            return
+
         if orca_state.lastNonModifierKeyEvent:
             event_string = orca_state.lastNonModifierKeyEvent.event_string
             isShiftKey = orca_state.lastNonModifierKeyEvent.modifiers \
@@ -1921,10 +1926,6 @@
         if (event_string == "Up" or event_string == "Down") and not isShiftKey:
             speech.stop()
 
-        # Speak a newline, if appropriate.
-        if self.speakNewLine(event.source):
-            speech.speakCharacter("\n", None)
-
         # Speak a blank line, if appropriate.
         if self.speakBlankLine(event.source):
             # Translators: "blank" is a short word to mean the
@@ -1934,63 +1935,6 @@
 
         default.Script.onCaretMoved(self, event)
 
-    def speakNewLine(self, obj):
-        """Returns True if a newline should be spoken.
-           Otherwise, returns False.
-        """
-
-        # Get the the AccessibleText interface.
-        try:
-            text = obj.queryText()
-        except NotImplementedError:
-            return False
-
-        # Was a left or right-arrow key pressed?
-        if not (orca_state.lastInputEvent and \
-                orca_state.lastInputEvent.__dict__.has_key("event_string")):
-            return False
-
-        lastKey = orca_state.lastNonModifierKeyEvent.event_string
-        if lastKey != "Left" and lastKey != "Right":
-            return False
-
-        # Was a control key pressed?
-        mods = orca_state.lastInputEvent.modifiers
-        isControlKey = mods & (1 << pyatspi.MODIFIER_CONTROL)
-
-        # Get the line containing the caret
-        caretOffset = text.caretOffset
-        line = text.getTextAtOffset(caretOffset, \
-            pyatspi.TEXT_BOUNDARY_LINE_START)
-        lineStart = line[1]
-        lineEnd = line[2]
-
-        if isControlKey:  # control-right-arrow or control-left-arrow
-
-            # Get the word containing the caret.
-            word = text.getTextAtOffset(caretOffset, \
-                pyatspi.TEXT_BOUNDARY_WORD_START)
-            wordStart = word[1]
-            wordEnd = word[2]
-
-            if lastKey == "Right":
-                if wordStart == lineStart:
-                    return True
-            else:
-                if wordEnd == lineEnd:
-                    return True
-
-        else:  # right arrow or left arrow
-
-            if lastKey == "Right":
-                if caretOffset == lineStart:
-                    return True
-            else:
-                if caretOffset == lineEnd:
-                    return True
-
-        return False
-
     def speakBlankLine(self, obj):
         """Returns True if a blank line should be spoken.
         Otherwise, returns False.

Modified: trunk/src/orca/where_am_I.py
==============================================================================
--- trunk/src/orca/where_am_I.py	(original)
+++ trunk/src/orca/where_am_I.py	Tue May 20 20:27:27 2008
@@ -1267,7 +1267,7 @@
 
         return text
 
-    def _getTextSelection(self, obj):
+    def getTextSelection(self, obj):
         """Get the text selection for the given object.
 
         Arguments:
@@ -1284,12 +1284,12 @@
             [startOffset, endOffset] = textObj.getSelection(i)
 
             debug.println(self._debugLevel,
-                "_getTextSelection: selection start=%d, end=%d" % \
+                "getTextSelection: selection start=%d, end=%d" % \
                 (startOffset, endOffset))
 
             selectedText = textObj.getText(startOffset, endOffset)
             debug.println(self._debugLevel,
-                "_getTextSelection: selected text=<%s>" % selectedText)
+                "getTextSelection: selected text=<%s>" % selectedText)
 
             if i > 0:
                 textContents += " "
@@ -1317,7 +1317,7 @@
         text = obj.queryText()
         if text.getNSelections() > 0:
             [textContents, startOffset, endOffset] = \
-                                            self._getTextSelection(obj)
+                                            self.getTextSelection(obj)
 
         if not basicOnly:
             current = obj
@@ -1331,7 +1331,7 @@
                         prevObjText = prevObj.queryText()
                         if prevObjText.getNSelections() > 0:
                             [newTextContents, start, end] = \
-                                         self._getTextSelection(prevObj)
+                                         self.getTextSelection(prevObj)
                             textContents = newTextContents + " " + textContents
                             current = prevObj
                             morePossibleSelections = True
@@ -1353,7 +1353,7 @@
                         nextObjText = nextObj.queryText()
                         if nextObjText.getNSelections() > 0:
                             [newTextContents, start, end] = \
-                                         self._getTextSelection(nextObj)
+                                         self.getTextSelection(nextObj)
                             textContents += " " + newTextContents
                             current = nextObj
                             morePossibleSelections = True



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]