Index: test/keystrokes/oowriter/bug_382415.py
===================================================================
--- test/keystrokes/oowriter/bug_382415.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_382415.py	(working copy)
@@ -44,9 +44,9 @@
     "Down arrow to move to the Mon table column header",
     ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Mon Paragraph") + "'",
      "     VISIBLE:  'Mon Paragraph', cursor=1",
-     "SPEECH OUTPUT: 'Cell B1'",
+     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.",
      "SPEECH OUTPUT: 'Mon'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Cell B1'"]))
 
 ######################################################################
 # 5. Type a down arrow to move to the blank table cell on the next row.
@@ -56,15 +56,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Down arrow to move to the blank table cell on the next row",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Mon Paragraph") + "'",
-     "     VISIBLE:  'Mon Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Paragraph") + "'",
      "     VISIBLE:  'Paragraph', cursor=1",
-     "SPEECH OUTPUT: 'Mon'",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell B2'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'blank'",
+     "SPEECH OUTPUT: 'Cell B2'"]))
 
 ######################################################################
 # 6. Type a down arrow to move to the "4" table cell on the next row.
@@ -74,15 +69,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Down arrow to move to the '4' table cell on the next row",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Paragraph") + "'",
-     "     VISIBLE:  'Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
      "     VISIBLE:  '4 Paragraph', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell B3'",
      "SPEECH OUTPUT: '4'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Cell B3'"]))
 
 ######################################################################
 # 7. Type a down arrow to move to the "11" table cell on the next row.
@@ -92,15 +82,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Down arrow to move to the '11' table cell on the next row",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
-     "     VISIBLE:  '4 Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 11 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 11 Paragraph") + "'",
      "     VISIBLE:  '11 Paragraph', cursor=1",
-     "SPEECH OUTPUT: '4'",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell B4'",
      "SPEECH OUTPUT: '11'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Cell B4'"]))
 
 ######################################################################
 # 8. Enter Alt-f, Alt-c to close this Writer application.
Index: test/keystrokes/oowriter/bug_435201.py
===================================================================
--- test/keystrokes/oowriter/bug_435201.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_435201.py	(working copy)
@@ -17,118 +17,83 @@
 
 ######################################################################
 # 2. Type Control-Home to position the text caret to the left of the
-#    first character on the first line.
+#    first character on the first line. Then Down Arrow and Up Arrow
+#    once because our caret-moved events seem to initially be AWOL in
+#    m29 and m30.
 #
 sequence.append(KeyComboAction("<Control>Home"))
-sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
+sequence.append(KeyComboAction("Down"))
+sequence.append(KeyComboAction("Up"))
 
 ######################################################################
 # 3. Type Control-down to move to the next paragraph.
 #
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Down"))
-sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type Control-down to move to the next paragraph [1]",
-    ["BUG: speaks the paragraph three times",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "NOBODY expects the Spanish Inquisition! Our chief weapon is surprise. Surprise and  \$l") + "'",
-     "     VISIBLE:  'NOBODY expects the Spanish Inqui', cursor=2",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "NOBODY expects the Spanish Inquisition! Our chief weapon is surprise. Surprise and  \$l") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse  \$l") + "'",
      "     VISIBLE:  'NOBODY expects the Spanish Inqui', cursor=1",
-     "BRAILLE LINE:  'NOBODY expects the Spanish Inquisition! Our chief weapon is surprise. Surprise and  $l'",
+     "BRAILLE LINE:  'NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse  \$l",
      "     VISIBLE:  'NOBODY expects the Spanish Inqui', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse  \$l") + "'",
-     "     VISIBLE:  'NOBODY expects the Spanish Inqui', cursor=1",
-     "SPEECH OUTPUT: 'NOBODY expects the Spanish Inquisition! Our chief weapon is surprise. Surprise and '",
-     "SPEECH OUTPUT: 'NOBODY expects the Spanish Inquisition! Our chief weapon is surprise. Surprise and '",
-     "SPEECH OUTPUT: 'NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse '"]))
+     "SPEECH OUTPUT: 'NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse elements as: fear, surprise, ruthless efficiency, an almost fanatical devotion to the Pope, and nice red uniforms - Oh damn!'"]))
 
 ######################################################################
 # 4. Type Control-down to move to the next paragraph.
 #
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Down"))
-sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type Control-down to move to the next paragraph [2]",
-    ["BUG: speaks the paragraph two times",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse  \$l") + "'",
-     "     VISIBLE:  'NOBODY expects the Spanish Inqui', cursor=2",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse  \$l") + "'",
-     "     VISIBLE:  'NOBODY expects the Spanish Inqui', cursor=1",
-     "BRAILLE LINE:  'NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse  $l'",
-     "     VISIBLE:  'NOBODY expects the Spanish Inqui', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", " \$l") + "'",
-     "     VISIBLE:  ' $l', cursor=1",
-     "SPEECH OUTPUT: 'NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse '",
-     "SPEECH OUTPUT: 'NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse '",
-     "SPEECH OUTPUT: 'blank'"]))
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", " \$l") + "'",
+     "     VISIBLE:  ' \$l', cursor=1",
+     "BRAILLE LINE:  ' \$l'",
+     "     VISIBLE:  ' \$l', cursor=1",
+     "SPEECH OUTPUT: 'blank'",
+     "SPEECH OUTPUT: ''"]))
 
 ######################################################################
 # 5. Type Control-down to move to the next paragraph.
 #
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Down"))
-sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type Control-down to move to the next paragraph [3]",
-    ["BUG: speaks the paragraph two times",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Now old lady, you have one last chance.  Confess the heinous sin of heresy, reject  \$l") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Now old lady, you have one last chance. Confess the heinous sin of heresy, reject  \$l") + "'",
      "     VISIBLE:  'Now old lady, you have one last ', cursor=1",
-     "BRAILLE LINE:  'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject  $l'",
+     "BRAILLE LINE:  'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject  \$l'",
      "     VISIBLE:  'Now old lady, you have one last ', cursor=1",
      "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", " \$l") + "'",
-     "     VISIBLE:  ' $l', cursor=1",
-     "BRAILLE LINE:  ' $l'",
-     "     VISIBLE:  ' $l', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Now old lady, you have one last chance.  Confess the heinous sin of heresy, reject  \$l") + "'",
-     "     VISIBLE:  'Now old lady, you have one last ', cursor=1",
-     "SPEECH OUTPUT: 'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject '",
-     "SPEECH OUTPUT: 'blank'",
-     "SPEECH OUTPUT: 'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject '"]))
+     "     VISIBLE:  ' \$l', cursor=1",
+     "SPEECH OUTPUT: 'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject the works of the ungodly. Two last chances. And you shall be free. Three last chances. You have three last chances, the nature of which I have divulged in my previous utterance.'"]))
 
 ######################################################################
 # 6. Type Control-down to move to the next paragraph.
 #
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Down"))
-sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type Control-down to move to the next paragraph [4]",
-    ["BUG: speaks the paragraph two times",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Now old lady, you have one last chance.  Confess the heinous sin of heresy, reject  \$l") + "'",
-     "     VISIBLE:  'Now old lady, you have one last ', cursor=2",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Now old lady, you have one last chance.  Confess the heinous sin of heresy, reject  \$l") + "'",
-     "     VISIBLE:  'Now old lady, you have one last ', cursor=1",
-     "BRAILLE LINE:  'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject  $l'",
-     "     VISIBLE:  'Now old lady, you have one last ', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", " \$l") + "'",
-     "     VISIBLE:  ' $l', cursor=1",
-     "SPEECH OUTPUT: 'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject '",
-     "SPEECH OUTPUT: 'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject '",
-     "SPEECH OUTPUT: 'blank'"]))
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", " \$l") + "'",
+     "     VISIBLE:  ' \$l', cursor=1",
+     "BRAILLE LINE:  ' \$l'",
+     "     VISIBLE:  ' \$l', cursor=1",
+     "SPEECH OUTPUT: 'blank'",
+     "SPEECH OUTPUT: ''"]))
 
 ######################################################################
 # 7. Type Control-down to move to the next paragraph.
 #
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Down"))
-sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type Control-down to move to the next paragraph [5]",
-    ["BUG: speaks the paragraph two times",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR! \$l") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR! \$l") + "'",
      "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=1",
-     "BRAILLE LINE:  'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR! $l'",
+     "BRAILLE LINE:  'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR! \$l'",
      "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=1",
      "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", " \$l") + "'",
-     "     VISIBLE:  ' $l', cursor=1",
-     "BRAILLE LINE:  ' $l'",
-     "     VISIBLE:  ' $l', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR! \$l") + "'",
-     "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=1",
-     "SPEECH OUTPUT: 'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR!'",
-     "SPEECH OUTPUT: 'blank'",
+     "     VISIBLE:  ' \$l', cursor=1",
      "SPEECH OUTPUT: 'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR!'"]))
 
 ######################################################################
Index: test/keystrokes/oowriter/bug_342602.py
===================================================================
--- test/keystrokes/oowriter/bug_342602.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_342602.py	(working copy)
@@ -61,17 +61,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Move to cell B1",
-    ["BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Table1-1 Table A Paragraph'",
-     "     VISIBLE:  'A Paragraph', cursor=1",
-     "BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Table1-1 Table Paragraph'",     
+    ["BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Table1-1 Table Paragraph'",     
      "     VISIBLE:  'Paragraph', cursor=1",
-     "SPEECH OUTPUT: 'A'",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'table with 2 rows and 2 columns.'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell B1'",
-     "SPEECH OUTPUT: 'blank'"]))
+     "SPEECH OUTPUT: 'blank'",
+     "SPEECH OUTPUT: 'Cell B1'"]))
 
 ######################################################################
 # 6. Enter Shift-Tab (Returns to cell A1).
@@ -81,15 +74,9 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Move back to cell A1",
-    ["BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Table1-1 Table Paragraph'",
-     "     VISIBLE:  'Paragraph', cursor=1",
-     "BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Table1-1 Table A Paragraph'",
+    ["BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Table1-1 Table A Paragraph'",
      "     VISIBLE:  'A Paragraph', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'table with 2 rows and 2 columns.'",
      "SPEECH OUTPUT: 'A'",
-     "SPEECH OUTPUT: ' not selected'",
      "SPEECH OUTPUT: 'Cell A1'"]))
 
 ######################################################################
Index: test/keystrokes/oowriter/bug_350219.py
===================================================================
--- test/keystrokes/oowriter/bug_350219.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_350219.py	(working copy)
@@ -30,15 +30,14 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "New text document",
-    ["BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame'",
+    ["BUG? - The braille context doesn't include the Frame",
+     "BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame'",
      "     VISIBLE:  'Untitled[ ]*2 - *",
-     "BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane Panel'",
-     "     VISIBLE:  'Panel', cursor=1",
      "BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view  \$l'",
      "     VISIBLE:  ' $l', cursor=1",
      "SPEECH OUTPUT: 'Untitled[ ]*2 - " + utils.getOOoName("Writer") + " frame'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'panel'"]))
+     "SPEECH OUTPUT: 'blank'",
+     "SPEECH OUTPUT: ''"]))
 
 ######################################################################
 # 3. Enter Alt-f, Alt-c to close the Writer application.
Index: test/keystrokes/oowriter/bug_382408.py
===================================================================
--- test/keystrokes/oowriter/bug_382408.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_382408.py	(working copy)
@@ -51,8 +51,8 @@
     "Type a down arrow to move to the Mon table column header",
     ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Sun Mon Tue Wed Thu Fri Sat") + "'",
      "     VISIBLE:  'Mon Tue Wed Thu Fri Sat', cursor=1",
-     "SPEECH OUTPUT: 'Sun Mon Tue Wed Thu Fri Sat'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'table with 7 rows and 7 columns",
+     "SPEECH OUTPUT: 'Sun Mon Tue Wed Thu Fri Sat'"]))
 
 ######################################################################
 # 6. Enter Alt-f, Alt-c to close this Writer application.
Index: test/keystrokes/oowriter/bug_382418.py
===================================================================
--- test/keystrokes/oowriter/bug_382418.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_382418.py	(working copy)
@@ -58,19 +58,16 @@
 # 6. Type Control-Home to move the text caret to the start of the
 #    document (and leave the table).
 #
+sequence.append(PauseAction(3000))
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type Control-Home to move to start of document",
-    ["BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Table1-1 Table Paragraph'",
-     "     VISIBLE:  'Paragraph', cursor=1",
-     "BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Line 1 \$l'",
+    ["BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Line 1 \$l'",
      "     VISIBLE:  'Line 1 $l', cursor=1",
      "BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Line 1 \$l'",
      "     VISIBLE:  'Line 1 $l', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ' not selected'",
 # [[[TODO: WDW - StarOffice 8 gives us this.  DEV300_m25 does not.]]]
 #
 #     "SPEECH OUTPUT: 'leaving table.'",
@@ -86,7 +83,10 @@
     "Type a down arrow to enter the table",
 # [[[TODO: WDW - StarOffice 8 gives us this.  DEV300_m25 does not.]]]
 #
-    ["SPEECH OUTPUT: 'table with 2 rows and 2 columns.'",
+    ["BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view Table1-1 Table Paragraph'",
+     "     VISIBLE:  'Paragraph', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows and 2 columns.'",
+     "SPEECH OUTPUT: 'blank'",
      "SPEECH OUTPUT: 'Cell A1'"]))
 
 ######################################################################
Index: test/keystrokes/oowriter/bug_382880.py
===================================================================
--- test/keystrokes/oowriter/bug_382880.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_382880.py	(working copy)
@@ -44,9 +44,9 @@
     "Type a down arrow to move to the Mon table column header",
     ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Mon Paragraph") + "'",
      "     VISIBLE:  'Mon Paragraph', cursor=1",
-     "SPEECH OUTPUT: 'Cell B1'",
+     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.",
      "SPEECH OUTPUT: 'Mon'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Cell B1'"]))
 
 ######################################################################
 # 5. Type a Tab to move to the Tue table column header.
@@ -56,17 +56,9 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a Tab to move to the Tue table column header",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Mon Paragraph") + "'",
-     "     VISIBLE:  'Mon Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Tue Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Tue Paragraph") + "'",
      "     VISIBLE:  'Tue Paragraph', cursor=1",
-     "SPEECH OUTPUT: 'Mon'",
-     "SPEECH OUTPUT: ' not selected'",
-# [[[TODO: WDW - StarOffice 8 gives us this.  DEV300_m25 does not.]]]
-#
-#     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.'",
      "SPEECH OUTPUT: 'Tue'",
-     "SPEECH OUTPUT: ' not selected'",
      "SPEECH OUTPUT: 'Cell C1'"]))
 
 ######################################################################
@@ -77,15 +69,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a down arrow to move to the blank cell C2",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Tue Paragraph") + "'",
-     "     VISIBLE:  'Tue Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Paragraph") + "'",
      "     VISIBLE:  'Paragraph', cursor=1",
-     "SPEECH OUTPUT: 'Tue'",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell C2'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'blank'",
+     "SPEECH OUTPUT: 'Cell C2'"]))
 
 ######################################################################
 # 7. Type a down arrow to move to cell C3 containing "5".
@@ -95,15 +82,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a down arrow to move to cell C3 containing '5'",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Paragraph") + "'",
-     "     VISIBLE:  'Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 5 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 5 Paragraph") + "'",
      "     VISIBLE:  '5 Paragraph', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell C3'",
      "SPEECH OUTPUT: '5'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Cell C3'"]))
 
 ######################################################################
 # 8. Type a Shift-Tab to move to cell B3 containing "4".
@@ -113,17 +95,9 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a Shift-Tab to move to cell B3 containing '4'",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 5 Paragraph") + "'",
-     "     VISIBLE:  '5 Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
      "     VISIBLE:  '4 Paragraph', cursor=1",
-     "SPEECH OUTPUT: '5'",
-     "SPEECH OUTPUT: ' not selected'",
-# [[[TODO: WDW - StarOffice 8 gives us this.  DEV300_m25 does not.]]]
-#
-#     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.'",
      "SPEECH OUTPUT: '4'",
-     "SPEECH OUTPUT: ' not selected'",
      "SPEECH OUTPUT: 'Cell B3'"]))
 
 ######################################################################
@@ -134,15 +108,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a down arrow to move to cell B4 containing '11'",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
-     "     VISIBLE:  '4 Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 11 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 11 Paragraph") + "'",
      "     VISIBLE:  '11 Paragraph', cursor=1",
-     "SPEECH OUTPUT: '4'",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell B4'",
      "SPEECH OUTPUT: '11'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Cell B4'"]))
 
 ######################################################################
 # 10. Type an up arrow to move to cell B3 containing "4".
@@ -152,17 +121,9 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type an up arrow to move to cell B3 containing '4'",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 11 Paragraph") + "'",
-     "     VISIBLE:  '11 Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
      "     VISIBLE:  '4 Paragraph', cursor=1",
-     "SPEECH OUTPUT: '11'",
-     "SPEECH OUTPUT: ' not selected'",
-# [[[TODO: WDW - StarOffice 8 gives us this.  DEV300_m25 does not.]]]
-#
-#     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.'",
      "SPEECH OUTPUT: '4'",
-     "SPEECH OUTPUT: ' not selected'",
      "SPEECH OUTPUT: 'Cell B3'"]))
 
 ######################################################################
Index: test/keystrokes/oowriter/bug_364765.py
===================================================================
--- test/keystrokes/oowriter/bug_364765.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_364765.py	(working copy)
@@ -30,13 +30,9 @@
 sequence.append(WaitForFocus("Letter...", acc_role=pyatspi.ROLE_MENU_ITEM))
 sequence.append(utils.AssertPresentationAction(
     "Press W to open the Wizards submenu",
-    ["BRAILLE LINE:  'soffice Application Untitled[ ]*1 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*1 - " + utils.getOOoName("Writer") + " RootPane MenuBar Wizards Menu'",
-     "     VISIBLE:  'Wizards Menu', cursor=1",
-     "BRAILLE LINE:  'soffice Application Untitled[ ]*1 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*1 - " + utils.getOOoName("Writer") + " RootPane MenuBar File Menu Letter...'",
+    ["BRAILLE LINE:  'soffice Application Untitled[ ]*1 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*1 - " + utils.getOOoName("Writer") + " RootPane MenuBar File Menu Letter...'",
      "     VISIBLE:  'Letter...', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Wizards menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Letter...'"]))
 
 ######################################################################
Index: test/keystrokes/oowriter/bug_362979.py
===================================================================
--- test/keystrokes/oowriter/bug_362979.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_362979.py	(working copy)
@@ -79,8 +79,6 @@
     "Move cursor to start of document",
     ["BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view •Line 1 \$l'",
      "     VISIBLE:  '•Line 1 \$l', cursor=2",
-     "BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view •Line 1 \$l'",
-     "     VISIBLE:  '•Line 1 \$l', cursor=2",
      "SPEECH OUTPUT: '•Line 1'"]))
 
 ######################################################################
Index: test/keystrokes/oowriter/bug_382888.py
===================================================================
--- test/keystrokes/oowriter/bug_382888.py	(revision 4139)
+++ test/keystrokes/oowriter/bug_382888.py	(working copy)
@@ -44,9 +44,9 @@
     "Type a down arrow to move to the Mon table column header",
     ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Mon Paragraph") + "'",
      "     VISIBLE:  'Mon Paragraph', cursor=1",
-     "SPEECH OUTPUT: 'Cell B1'",
+     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.'",
      "SPEECH OUTPUT: 'Mon'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Cell B1'"]))
 
 ######################################################################
 # 5. Type a Tab to move to the Tue table column header.
@@ -56,17 +56,9 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a Tab to move to the Tue table column header",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Mon Paragraph") + "'",
-     "     VISIBLE:  'Mon Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Tue Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Tue Paragraph") + "'",
      "     VISIBLE:  'Tue Paragraph', cursor=1",
-     "SPEECH OUTPUT: 'Mon'",
-     "SPEECH OUTPUT: ' not selected'",
-# [[[TODO: WDW - StarOffice 8 gives us this.  DEV300_m25 does not.]]]
-#
-#     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.'",
      "SPEECH OUTPUT: 'Tue'",
-     "SPEECH OUTPUT: ' not selected'",
      "SPEECH OUTPUT: 'Cell C1'"]))
 
 ######################################################################
@@ -77,15 +69,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a down arrow to move to the blank cell C2",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Tue Paragraph") + "'",
-     "     VISIBLE:  'Tue Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Paragraph") + "'",
      "     VISIBLE:  'Paragraph', cursor=1",
-     "SPEECH OUTPUT: 'Tue'",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell C2'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'blank'",
+     "SPEECH OUTPUT: 'Cell C2'"]))
 
 ######################################################################
 # 7. Type a down arrow to move to cell C3 containing "5".
@@ -95,15 +82,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a down arrow to move to cell C3 containing '5'",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Paragraph") + "'",
-     "     VISIBLE:  'Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 5 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 5 Paragraph") + "'",
      "     VISIBLE:  '5 Paragraph', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell C3'",
      "SPEECH OUTPUT: '5'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Cell C3'"]))
 
 ######################################################################
 # 8. Type a Shift-Tab to move to cell B3 containing "4".
@@ -113,17 +95,9 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a Shift-Tab to move to cell B3 containing '4'",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 5 Paragraph") + "'",
-     "     VISIBLE:  '5 Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
      "     VISIBLE:  '4 Paragraph', cursor=1",
-     "SPEECH OUTPUT: '5'",
-     "SPEECH OUTPUT: ' not selected'",
-# [[[TODO: WDW - StarOffice 8 gives us this.  DEV300_m25 does not.]]]
-#
-#     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.'",
      "SPEECH OUTPUT: '4'",
-     "SPEECH OUTPUT: ' not selected'",
      "SPEECH OUTPUT: 'Cell B3'"]))
 
 ######################################################################
@@ -134,15 +108,10 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type a down arrow to move to cell B4 containing '11'",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
-     "     VISIBLE:  '4 Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 11 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 11 Paragraph") + "'",
      "     VISIBLE:  '11 Paragraph', cursor=1",
-     "SPEECH OUTPUT: '4'",
-     "SPEECH OUTPUT: ' not selected'",
-     "SPEECH OUTPUT: 'Cell B4'",
      "SPEECH OUTPUT: '11'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Cell B4'"]))
 
 ######################################################################
 # 10. Type an up arrow to move to cell B3 containing "4".
@@ -152,17 +121,9 @@
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_PARAGRAPH))
 sequence.append(utils.AssertPresentationAction(
     "Type an up arrow to move to cell B3 containing '4'",
-    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 11 Paragraph") + "'",
-     "     VISIBLE:  '11 Paragraph', cursor=1",
-     "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
+    ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table 4 Paragraph") + "'",
      "     VISIBLE:  '4 Paragraph', cursor=1",
-     "SPEECH OUTPUT: '11'",
-     "SPEECH OUTPUT: ' not selected'",
-# [[[TODO: WDW - StarOffice 8 gives us this.  DEV300_m25 does not.]]]
-#
-#     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.'",
      "SPEECH OUTPUT: '4'",
-     "SPEECH OUTPUT: ' not selected'",
      "SPEECH OUTPUT: 'Cell B3'"]))
 
 ######################################################################
Index: src/orca/scripts/apps/soffice/script.py
===================================================================
--- src/orca/scripts/apps/soffice/script.py	(revision 4139)
+++ src/orca/scripts/apps/soffice/script.py	(working copy)
@@ -17,6 +17,18 @@
 # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
 # Boston MA  02110-1301 USA.
 
+# [[[TODO: JD - Pylint is giving us a number of errors along these
+# lines throughout this file:
+#
+# E1103:690:Script.presentTableInfo: Instance of 'list' has no
+# 'queryTable' member (but some types could not be inferred)
+#
+# In each case, we're not querying the table interface (or asking
+# for the name) of a list, but rather of an accessible. Pylint is
+# correct about it's suggestion that it cannot infer types.]]]
+#
+# pylint: disable-msg=E1103
+
 """Custom script for StarOffice and OpenOffice."""
 
 __id__        = "$Id$"
@@ -67,9 +79,10 @@
         #
         self.debugLevel = debug.LEVEL_FINEST
 
-        # A handle to the last spread sheet cell encountered.
+        # A handle to the last Writer table or Calc spread sheet cell
+        # encountered and its caret offset.
         #
-        self.lastCell = None
+        self.lastCell = [None, -1]
 
         # The spreadsheet input line.
         #
@@ -648,45 +661,118 @@
                     return root_pane
         return parent
 
-    def checkForTableBoundry(self, oldFocus, newFocus):
-        """Check to see if we've entered or left a table.
-        When entering a table, announce the table dimensions.
-        When leaving a table, announce that the table has been exited.
+    def presentTableInfo(self, oldFocus, newFocus):
+        """Presents information relevant to a table that was just entered
+        (primarily) or exited.
 
         Arguments:
-        - oldFocus: Accessible that is the old locus of focus
-        - newFocus: Accessible that is the new locus of focus
+        - oldFocus: the first accessible to check (usually the previous
+          locusOfFocus)
+        - newFocus: the second accessible to check (usually the current
+          locusOfFocus)
+
+        Returns True if table info was presented.
         """
 
-        if oldFocus == None or newFocus == None:
-            return
+        oldAncestor = self.getAncestor(oldFocus,
+                                       [pyatspi.ROLE_TABLE,
+                                        pyatspi.ROLE_UNKNOWN,
+                                        pyatspi.ROLE_DOCUMENT_FRAME],
+                                       [pyatspi.ROLE_FRAME])
+        newAncestor = self.getAncestor(newFocus,
+                                       [pyatspi.ROLE_TABLE,
+                                        pyatspi.ROLE_UNKNOWN,
+                                        pyatspi.ROLE_DOCUMENT_FRAME],
+                                       [pyatspi.ROLE_FRAME])
 
-        oldFocusIsTable = None
-        while oldFocus.getRole() != pyatspi.ROLE_APPLICATION:
-            if oldFocus.getRole() == pyatspi.ROLE_TABLE:
-                oldFocusIsTable = oldFocus
-                break
-            oldFocus = oldFocus.parent
+        if not (oldAncestor and newAncestor):
+            # At least one of the objects not only is not in a table, but is
+            # is not in a document either.
+            #
+            return False
+        elif self.isSpreadSheetCell(oldAncestor, True) \
+             or self.isSpreadSheetCell(newAncestor, True):
+            # One or both objects is a table in a spreadsheet; we just want
+            # to handle tables in documents (definitely Writer; maybe also
+            # Impress).
+            #
+            return False
 
-        newFocusIsTable = None
-        while newFocus.getRole() != pyatspi.ROLE_APPLICATION:
-            if newFocus.getRole() == pyatspi.ROLE_TABLE:
-                newFocusIsTable = newFocus
-                break
-            newFocus = newFocus.parent
+        try:
+            oldTable = oldAncestor.queryTable()
+        except:
+            oldTable = None
 
-        if oldFocusIsTable == None and newFocusIsTable != None:
-            rows = newFocusIsTable.queryTable().nRows
-            columns = newFocusIsTable.queryTable().nColumns
-            # We've entered a table.  Announce the dimensions.
+        try:
+            newTable = newAncestor.queryTable()
+        except:
+            newTable = None
+
+        if oldTable == newTable == None:
+            # We're in a document, but apparently have not entered or left
+            # a table.
             #
-            line = _("table with %d rows and %d columns.") % (rows, columns)
-            speech.speak(line)
-        elif oldFocusIsTable != None and newFocusIsTable == None:
-            # We've left a table.  Announce this fact.
+            return False
+
+        if not self.isSameObject(oldAncestor, newAncestor):
+            if oldTable:
+                # We've left a table.  Announce this fact.
+                #
+                speech.speak(_("leaving table."))
+            if newTable:
+                # We've entered a table.  Announce the dimensions.
+                #
+                line = _("table with %d rows and %d columns.") % \
+                        (newTable.nRows, newTable.nColumns)
+                speech.speak(line)
+
+        if not newTable:
+            self.lastCell = [None, -1]
+            return True
+
+        try:
+            text = newFocus.queryText()
+        except:
+            offset = -1
+        else:
+            offset = text.caretOffset
+
+        cell = self.getAncestor(newFocus,
+                                [pyatspi.ROLE_TABLE_CELL],
+                                [pyatspi.ROLE_TABLE])
+        if not cell or self.lastCell[0] == cell:
+            # If we haven't found a cell, who knows what's going on? If
+            # the cell is the same as our last location, odds are that
+            # there are multiple paragraphs in this cell and a focus:
+            # and/or object:state-changed:focused event was emitted.
+            # If we haven't changed cells, we'll just treat this as any
+            # other paragraph and let the caret-moved events do their
+            # thing.
             #
-            speech.speak(_("leaving table."))
+            return False
 
+        self.updateBraille(cell)
+        utterances = self.speechGenerator.getSpeech(cell, False)
+        if not len(utterances[0]) and self.speakBlankLine(newFocus):
+            # Translators: "blank" is a short word to mean the
+            # user has navigated to an empty line.
+            #
+            speech.speak(_("blank"), None, False)
+        else:
+            speech.speakUtterances(utterances)
+
+        if not settings.readTableCellRow:
+            self.speakCellName(cell.name)
+
+        self.lastCell = [cell, offset]
+        index = self.getCellIndex(cell)
+        column = newTable.getColumnAtIndex(index)
+        self.pointOfReference['lastColumn'] = column
+        row = newTable.getRowAtIndex(index)
+        self.pointOfReference['lastRow'] = row
+
+        return True
+
     def speakInputLine(self, inputEvent):
         """Speak the contents of the spread sheet input line (assuming we
         have a handle to it - generated when we first focus on a spread
@@ -1165,6 +1251,12 @@
         - textToSpeak: the text to speak
         """
 
+        if not textToSpeak and event and self.speakBlankLine(event.source):
+            # Translators: "blank" is a short word to mean the
+            # user has navigated to an empty line.
+            #
+            speech.speak(_("blank"), None, False)
+
         # Check to see if there are any hypertext links in this paragraph.
         # If no, then just speak the whole line. Otherwise, split the text
         # to speak into words and call sayWriterWord() to speak that token
@@ -1206,13 +1298,14 @@
 
     # This method tries to detect and handle the following cases:
     # 0) Writer: find command.
-    # 1) Writer: text paragraph.
-    # 2) Welcome to StarOffice dialog.
-    # 3) Calc: cell editor.
-    # 4) Calc: name box.
-    # 5) Calc: spreadsheet cell.
-    # 6) Impress: scroll pane.
-    # 7) Presentation: scroll pane: place holder
+    # 1) Writer: table cell..
+    # 2) Writer: text paragraph.
+    # 3) Welcome to StarOffice dialog.
+    # 4) Calc: cell editor.
+    # 5) Calc: name box.
+    # 6) Calc: spreadsheet cell.
+    # 7) Impress: scroll pane.
+    # 8) Presentation: scroll pane: place holder
 
     def locusOfFocusChanged(self, event, oldLocusOfFocus, newLocusOfFocus):
         """Called when the visual object with focus changes.
@@ -1242,19 +1335,18 @@
             self.find()
             return
 
-        # 1) Writer: text paragraph.
+        # 1) Writer: Table cell.
         #
-        # We need to handle two things here:
+        # If we are FOCUSED on a paragraph inside a table cell (in Writer),
+        # then speak/braille that parent table cell (see bug #382415). Also
+        # announce that a table has been entered or left.
         #
-        # If the old locus of focus was on the File->New->Text Document
-        # menu item and we are currently have focus on an empty text
-        # paragraph, then we've just created the first new text document
-        # in Writer. Announce it by doing a "where am I".
-        #
-        # Also, when the focus is on a paragraph in the Document view of
-        # the Writer, then just speak/braille the current line (rather than
-        # speaking a bogus initial "paragraph" utterance as well).
+        if event.source.getRole() == pyatspi.ROLE_PARAGRAPH:
+            if self.presentTableInfo(oldLocusOfFocus, newLocusOfFocus):
+                return
 
+        # 2) Writer: text paragraph.
+        #
         rolesList = [pyatspi.ROLE_PARAGRAPH,
                      [pyatspi.ROLE_UNKNOWN, pyatspi.ROLE_DOCUMENT_FRAME],
                      pyatspi.ROLE_SCROLL_PANE,
@@ -1267,25 +1359,24 @@
 
             result = self.getTextLineAtCaret(event.source)
             textToSpeak = result[0].decode("UTF-8")
+            self._speakWriterText(event, textToSpeak)
 
-            # Translators: this is the name of the menu item people
-            # use in StarOffice to create a new text document.  It's
-            # at File->New->Text Document.  The translated form has to
-            # match what StarOffice/OpenOffice is using. We hate
-            # keying off stuff like this, but we're forced to do so in
-            # this case.
+            # For multiline text areas, we only show the context if we
+            # are on the very first line.  Otherwise, we show only the
+            # line. The default script's updateBraille does that, but
+            # it makes it's decision based on the caret offset rather
+            # than also looking at the child count. [[[TODO - JD: Might
+            # be cool to have a method which says "am I the start?" in
+            # the default script.]]]
             #
-            if oldLocusOfFocus and \
-               oldLocusOfFocus.getRole() == pyatspi.ROLE_MENU_ITEM and \
-               oldLocusOfFocus.name == _("Text Document") and \
-               len(textToSpeak) == 0:
-                self.whereAmI.whereAmI(None)
-
-            self._speakWriterText(event, textToSpeak)
-            braille.displayRegions(brailleGen.getBrailleRegions(event.source))
+            if event.source.getIndexInParent == 0:
+                self.updateBraille(event.source)
+            else:
+                braille.displayRegions(\
+                    brailleGen.getBrailleRegions(event.source))
             return
 
-        # 2) Welcome to StarOffice dialog.
+        # 3) Welcome to StarOffice dialog.
         #
         # Check to see if the object that just got focus is in the Setup
         # dialog. If it is, then check for a variety of scenerios.
@@ -1382,7 +1473,7 @@
                     + "Registration: Register Now radio button.")
                 self.handleSetupPanel(event.source.parent)
 
-        # 3) Calc: cell editor.
+        # 4) Calc: cell editor.
         #
         # Check to see if we are editing a spread sheet cell. If so, just
         # return to avoid uttering something like "Paragraph 0 paragraph".
@@ -1400,7 +1491,7 @@
                           + "Calc: cell editor.")
             return
 
-        # 4) Calc: name box
+        # 5) Calc: name box
         #
         # Check to see if the focus has just moved to the Name Box combo
         # box in Calc. If so, then replace the non-existent name with a
@@ -1430,7 +1521,7 @@
             speech.speak(_("Move to cell"))
             return
 
-        # 5) Calc: spreadsheet cell.
+        # 6) Calc: spreadsheet cell.
         #
         # Check to see if this is a Calc: spread sheet cell. If it is then
         # we don't want to speak "not selected" after giving the cell
@@ -1459,7 +1550,7 @@
                     self.pointOfReference['lastRow'] = row
                 return
 
-        # 6) Impress: scroll pane.
+        # 7) Impress: scroll pane.
         #
         # If we are in the slide presentation scroll pane, also announce
         # the current page tab. See bug #538056 for more details.
@@ -1485,7 +1576,7 @@
                             speech.speakUtterances(utterances)
             # Fall-thru to process the event with the default handler.
 
-        # 7) Presentation: scroll pane: place holder
+        # 8) Presentation: scroll pane: place holder
         #
         # If we are focused on a place holder element in the slide
         # presentation scroll pane, first present the object, then
@@ -1622,18 +1713,6 @@
             orca.setLocusOfFocus(event, event.source, True)
             return
 
-        # If we are FOCUSED on a paragraph inside a table cell (in Writer),
-        # then speak/braille that parent table cell (see bug #382415).
-        #
-        if event.source.getRole() == pyatspi.ROLE_PARAGRAPH and \
-           event.source.parent.getRole() == pyatspi.ROLE_TABLE_CELL and \
-           event.source.getState().contains(pyatspi.STATE_FOCUSED):
-            if self.lastCell != event.source.parent:
-                default.Script.locusOfFocusChanged(self, event,
-                                                   None, event.source.parent)
-                self.lastCell = event.source.parent
-            return
-
         default.Script.onFocus(self, event)
 
     def onActiveDescendantChanged(self, event):
@@ -1684,8 +1763,9 @@
         # If this is state change "focused" event and event.source isn't a
         # focused object, then just return. See bug #517502 for more details.
         #
-        if event.type.startswith("object:state-changed:focused") and \
-           not event.source.getState().contains(pyatspi.STATE_FOCUSED):
+        if event.type.startswith("object:state-changed:focused") \
+           and (not event.source.getState().contains(pyatspi.STATE_FOCUSED) \
+                or event.detail1 == 0):
             return
 
         # Check to see if we are in the Presentation startup wizard. If so,
@@ -1711,27 +1791,6 @@
                     break
                 current = current.parent
 
-        # If this is a state change "focused" event that we care about, and
-        # we are in Writer, check to see if we are entering or leaving a table.
-        #
-        if event.type.startswith("object:state-changed:focused") and \
-           event.detail1 == 1:
-            current = event.source.parent
-            while current.getRole() != pyatspi.ROLE_APPLICATION:
-                # Translators: this is the title of the window that
-                # you get when using StarOffice Writer.  The
-                # translated form has to match what
-                # StarOffice/OpenOffice is using.  We hate keying off
-                # stuff like this, but we're forced to do so in this
-                # case.
-                #
-                if current.getRole() == pyatspi.ROLE_FRAME and \
-                   (current.name and current.name.endswith(_("Writer"))):
-                    self.checkForTableBoundry(orca_state.locusOfFocus,
-                                              event.source)
-                    break
-                current = current.parent
-
         # Prevent  "object:state-changed:active" events from activating
         # the find operation. See comment #18 of bug #354463.
         #
@@ -1764,35 +1823,6 @@
                 speech.speakUtterances(self.speechGenerator.getSpeech( \
                                        event.source, False))
 
-        # If we are FOCUSED on a paragraph inside a table cell (in Writer),
-        # then speak/braille that parent table cell (see bug #382415).
-        #
-        if event.type.startswith("object:state-changed:focused") and \
-           event.source.getRole() == pyatspi.ROLE_PARAGRAPH and \
-           event.source.parent.getRole() == pyatspi.ROLE_TABLE_CELL and \
-           event.detail1 == 0 and \
-           event.source.getState().contains(pyatspi.STATE_FOCUSED):
-
-            # Check to see if the last input event was "Up" or "Down".
-            # If it was, and we are in the same table cell as last time,
-            # and if that table cell has more than one child, then just
-            # get the speech for that single child, otherwise speak/braille
-            # the parent table cell.
-            #
-            event_string = None
-            if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
-                event_string = orca_state.lastNonModifierKeyEvent.event_string
-            if (event_string == "Up" or event_string == "Down") and \
-               event.source.parent == self.lastCell and \
-               event.source.parent.childCount > 1:
-                default.Script.locusOfFocusChanged(self, event,
-                                                   None, event.source)
-            else:
-                default.Script.locusOfFocusChanged(self, event,
-                                                   None, event.source.parent)
-            self.lastCell = event.source.parent
-            return
-
         # When a new paragraph receives focus, we get a caret-moved event and
         # two focus events (the first being object:state-changed:focused).
         # The caret-moved event will cause us to present the text at the new
@@ -1810,12 +1840,10 @@
                          pyatspi.ROLE_PANEL,
                          pyatspi.ROLE_ROOT_PANE,
                          pyatspi.ROLE_FRAME]
-            if self.isDesiredFocusedItem(event.source, rolesList) \
-               and event.source != self.currentParagraph \
-               and event.detail1 == 1:
-                self.currentParagraph = event.source
+            if self.isDesiredFocusedItem(event.source, rolesList):
                 orca.setLocusOfFocus(event, event.source, False)
-                self.updateBraille(event.source)
+                if event.source != self.currentParagraph:
+                    self.updateBraille(event.source)
                 return
 
         # If we are in the sbase Table Wizard, try to reduce the numerous
@@ -1878,8 +1906,8 @@
                 # appending "has formula" twice, we only do it if the last
                 # cell is different from this one.
                 #
-                if cell != self.lastCell:
-                    self.lastCell = cell
+                if cell != self.lastCell[0]:
+                    self.lastCell[0] = cell
 
                     try:
                         if cell.queryText():
@@ -2007,6 +2035,19 @@
         if event.detail1 == -1:
             return
 
+        if self.lastCell[0] == event.source.parent:
+            if self.lastCell[1] == event.detail1:
+                # We took care of this in a focus event (our position has not
+                # changed within the cell)
+                #
+                return
+            else:
+                # We're in the same cell, but at a different position. Update
+                # our stored location and then let the normal caret-moved
+                # processing take place.
+                #
+                self.lastCell[1] = event.detail1
+
         if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
            and orca_state.lastNonModifierKeyEvent:
             event_string = orca_state.lastNonModifierKeyEvent.event_string
@@ -2017,92 +2058,47 @@
         isControlKey = mods & settings.CTRL_MODIFIER_MASK
         isShiftKey = mods & settings.SHIFT_MODIFIER_MASK
 
-        # If we are FOCUSED on a paragraph inside a table cell (in Writer),
-        # then just return (modulo the special cases below). Speaking and
-        # brailling will have been done in the onStateChanged() routine
-        # (see bug #382415).
+        # If the last input event was a keyboard event of Control-Up or
+        # Control-Down, we want to speak the whole paragraph rather than
+        # just the current line. In addition, we need to filter out some
+        # creative uses of the caret-moved event on the part of the OOo
+        # guys.
         #
-        if event.source.getRole() == pyatspi.ROLE_PARAGRAPH and \
-           event.source.parent.getRole() == pyatspi.ROLE_TABLE_CELL and \
-           event.source.getState().contains(pyatspi.STATE_FOCUSED):
-
-            # If we are moving up and down, and we are speaking-by-cell
-            # (as opposed to by-row), then speak the cell name. Otherwise
-            # just return.
+        if event_string in ["Up", "Down"] and isControlKey and not isShiftKey:
+            # If we moved to the next paragraph, the event.source index should
+            # be larger than the current paragraph's index. If we moved to the
+            # previous paragraph it should be smaller. Otherwise, it's bogus.
             #
-            if (event_string == "Up" or event_string == "Down"):
-                if not settings.readTableCellRow:
-                    if event.detail1 != -1:
-                        self.speakCellName(event.source.parent.name)
-                return
+            eventIndex = event.source.getIndexInParent()
+            if self.currentParagraph:
+                paraIndex = self.currentParagraph.getIndexInParent()
+            else:
+                paraIndex = eventIndex
 
-            # If we are moving left or right and we are in a new cell, just
-            # return.
-            #
-            if (event_string == "Left" or event_string == "Right") and \
-               self.lastCell != event.source.parent:
+            if (event_string == "Down" and (eventIndex - paraIndex <= 0)) \
+               or (event_string == "Up" and (eventIndex - paraIndex >= 0)):
                 return
 
-            caretOffset = event.source.queryText().caretOffset
-            charLen = event.source.queryText().characterCount
-
-            # If you are in a table cell and you arrow Right, the caret
-            # will focus at the end of the current paragraph before moving
-            # into the next cell. To be similar to the way that caret
-            # navigation works in other paragraphs in OOo, just return.
-            #
-            if event_string == "Right" and caretOffset == charLen:
-                return
-
-            # If we have moved left and the caret position is at the end of
-            # the paragraph or if we have moved right and the caret position
-            # is at the start of the text string, or the last key input was
-            # Tab or Shift-Tab, and if we are speaking-by-cell (as opposed
-            # to by-row), then speak the cell name, otherwise just return
-            # (see bug #382418).
-            #
-            if (event_string == "Left" and caretOffset == charLen) or \
-               (event_string == "Right" and caretOffset == 0) or \
-               (event_string == "Tab" or event_string == "ISO_Left_Tab"):
-                if not settings.readTableCellRow:
-                    if event.detail1 != -1:
-                        self.speakCellName(event.source.parent.name)
-
-                # Speak a blank line, if appropriate.
-                if self.speakBlankLine(event.source):
-                    # Translators: "blank" is a short word to mean the
-                    # user has navigated to an empty line.
-                    #
-                    speech.speak(_("blank"), None, False)
-                return
-
-        # Remove possible extra utterances of the current paragraph by
-        # stopping any pending speech. See bug #435201 for more details.
-        #
-        if (event_string == "Up" or event_string == "Down") and not isShiftKey:
-            speech.stop()
-
-        # Speak a blank line, if appropriate.
-        if self.speakBlankLine(event.source):
-            # Translators: "blank" is a short word to mean the
-            # user has navigated to an empty line.
-            #
-            speech.speak(_("blank"), None, False)
-
-        # If the last input event was a keyboard event of Control-Up or
-        # Control-Down, we want to speak the whole paragraph rather than
-        # just the current line.
-        #
-        if (event_string == "Up" or event_string == "Down") and \
-            isControlKey and not isShiftKey:
             result = self.getText(event.source, 0, -1)
             textToSpeak = result.decode("UTF-8")
             self._speakWriterText(event, textToSpeak)
             braille.displayRegions( \
                 self.brailleGenerator.getBrailleRegions(event.source))
         else:
+            # Speak a blank line, if appropriate.
+            if self.speakBlankLine(event.source):
+                # Translators: "blank" is a short word to mean the
+                # user has navigated to an empty line.
+                #
+                speech.speak(_("blank"), None, False)
+
             default.Script.onCaretMoved(self, event)
 
+        # If we're still here, we must be convinced that this paragraph
+        # coincides with our actual location.
+        #
+        self.currentParagraph = event.source
+
     def speakBlankLine(self, obj):
         """Returns True if a blank line should be spoken.
         Otherwise, returns False.
