Index: test/keystrokes/gtk-demo/role_column_header.py
===================================================================
--- test/keystrokes/gtk-demo/role_column_header.py	(revision 3583)
+++ test/keystrokes/gtk-demo/role_column_header.py	(working copy)
@@ -109,16 +109,42 @@
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
-    "Normal cell Where Am I",
+    "Normal cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Severity ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  'Normal scrollable notebooks and ', cursor=1",
-     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'table'",
+     "SPEECH OUTPUT: 'Severity'",
      "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'Normal'",
+     "SPEECH OUTPUT: 'row 1 of 14'"]))
+
+########################################################################
+# Do a detailed "Where Am I" via KP_Enter.
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(PauseAction(3000))
+sequence.append(utils.AssertPresentationAction(
+    "Normal cell detailed Where Am I",
+    ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Severity ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
+     "     VISIBLE:  'Normal scrollable notebooks and ', cursor=1",
+     "BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Severity ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
+     "     VISIBLE:  'Normal scrollable notebooks and ', cursor=1",
+     "SPEECH OUTPUT: 'table'",
+     "SPEECH OUTPUT: 'Severity'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'Normal'",
+     "SPEECH OUTPUT: 'row 1 of 14'",
+     "SPEECH OUTPUT: 'table'",
+     "SPEECH OUTPUT: 'Severity'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'Normal'",
+     "SPEECH OUTPUT: 'row 1 of 14'",
      "SPEECH OUTPUT: 'check box not checked'",
      "SPEECH OUTPUT: '60482'",
      "SPEECH OUTPUT: 'Normal'",
-     "SPEECH OUTPUT: 'scrollable notebooks and hidden tabs'",
-     "SPEECH OUTPUT: 'row 1 of 14'"]))
+     "SPEECH OUTPUT: 'scrollable notebooks and hidden tabs'"]))
 
 ########################################################################
 # Now move to the cell to the left containing the number "60482".
@@ -163,16 +189,42 @@
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
-    "Checkbox cell Where Am I",
+    "Checkbox cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Fixed? ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  '< > Fixed? 60482 Normal scrollab', cursor=1",
-     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'table'",
+     "SPEECH OUTPUT: 'Fixed?'",
      "SPEECH OUTPUT: 'cell'",
      "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'row 1 of 14'"]))
+
+########################################################################
+# Do a detailed "Where Am I" via KP_Enter.
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(PauseAction(3000))
+sequence.append(utils.AssertPresentationAction(
+    "Checkbox cell detailed Where Am I",
+    ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Fixed? ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
+     "     VISIBLE:  '< > Fixed? 60482 Normal scrollab', cursor=1",
+     "BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Fixed? ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
+     "     VISIBLE:  '< > Fixed? 60482 Normal scrollab', cursor=1",
+     "SPEECH OUTPUT: 'table'",
+     "SPEECH OUTPUT: 'Fixed?'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'row 1 of 14'",
+     "SPEECH OUTPUT: 'table'",
+     "SPEECH OUTPUT: 'Fixed?'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'row 1 of 14'",
+     "SPEECH OUTPUT: 'check box not checked'",
      "SPEECH OUTPUT: '60482'",
      "SPEECH OUTPUT: 'Normal'",
-     "SPEECH OUTPUT: 'scrollable notebooks and hidden tabs'",
-     "SPEECH OUTPUT: 'row 1 of 14'"]))
+     "SPEECH OUTPUT: 'scrollable notebooks and hidden tabs'"]))
  
 ########################################################################
 # Close the GtkListStore demo
Index: test/keystrokes/gtk-demo/role_tree_table.py
===================================================================
--- test/keystrokes/gtk-demo/role_tree_table.py	(revision 3583)
+++ test/keystrokes/gtk-demo/role_tree_table.py	(working copy)
@@ -84,14 +84,52 @@
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
-    "January cell Where Am I",
-    ["BUG? - we're on the January cell",
-     "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable'",
-     "     VISIBLE:  'TreeTable', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'tree table'"]))
+    "January cell basic Where Am I",
+    ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January expanded < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
+     "     VISIBLE:  'January expanded < > Alex < > Ha', cursor=1",
+     "SPEECH OUTPUT: 'tree table'",
+     "SPEECH OUTPUT: 'Holiday'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'January'",
+     "SPEECH OUTPUT: 'row 1 of 53'",
+     "SPEECH OUTPUT: 'expanded'",
+     "SPEECH OUTPUT: 'tree level 1'"]))
 
 ########################################################################
+# Do a detailed "Where Am I" via KP_Enter.
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(PauseAction(3000))
+sequence.append(utils.AssertPresentationAction(
+    "January cell detailed Where Am I",
+    ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January expanded < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
+     "     VISIBLE:  'January expanded < > Alex < > Ha', cursor=1",
+     "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January expanded < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
+     "     VISIBLE:  'January expanded < > Alex < > Ha', cursor=1",
+     "SPEECH OUTPUT: 'tree table'",
+     "SPEECH OUTPUT: 'Holiday'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'January'",
+     "SPEECH OUTPUT: 'row 1 of 53'",
+     "SPEECH OUTPUT: 'expanded'",
+     "SPEECH OUTPUT: 'tree level 1'",
+     "SPEECH OUTPUT: 'tree table'",
+     "SPEECH OUTPUT: 'Holiday'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'January'",
+     "SPEECH OUTPUT: 'row 1 of 53'",
+     "SPEECH OUTPUT: 'January'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'expanded'",
+     "SPEECH OUTPUT: 'tree level 1'"]))
+
+########################################################################
 # Collapse the cell.
 #
 sequence.append(utils.StartRecordingAction())
@@ -114,14 +152,52 @@
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
-    "January cell collapsed Where Am I",
-    ["BUG? - we're on the January cell",
-     "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable'",
-     "     VISIBLE:  'TreeTable', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'tree table'"]))
+    "January cell collapsed basic Where Am I",
+    ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January collapsed < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
+     "     VISIBLE:  'January collapsed < > Alex < > H', cursor=1",
+     "SPEECH OUTPUT: 'tree table'",
+     "SPEECH OUTPUT: 'Holiday'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'January'",
+     "SPEECH OUTPUT: 'row 1 of 50'",
+     "SPEECH OUTPUT: 'collapsed'",
+     "SPEECH OUTPUT: 'tree level 1'"]))
 
 ########################################################################
+# Do a detailed "Where Am I" via KP_Enter.
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(PauseAction(3000))
+sequence.append(utils.AssertPresentationAction(
+    "January cell collapsed detailed Where Am I",
+    ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January collapsed < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
+     "     VISIBLE:  'January collapsed < > Alex < > H', cursor=1",
+     "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January collapsed < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
+     "     VISIBLE:  'January collapsed < > Alex < > H', cursor=1",
+     "SPEECH OUTPUT: 'tree table'",
+     "SPEECH OUTPUT: 'Holiday'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'January'",
+     "SPEECH OUTPUT: 'row 1 of 50'",
+     "SPEECH OUTPUT: 'collapsed'",
+     "SPEECH OUTPUT: 'tree level 1'",
+     "SPEECH OUTPUT: 'tree table'",
+     "SPEECH OUTPUT: 'Holiday'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'January'",
+     "SPEECH OUTPUT: 'row 1 of 50'",
+     "SPEECH OUTPUT: 'January'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'check box not checked'",
+     "SPEECH OUTPUT: 'collapsed'",
+     "SPEECH OUTPUT: 'tree level 1'"]))
+
+########################################################################
 # Expand the cell again.
 #
 sequence.append(utils.StartRecordingAction())
@@ -184,18 +260,44 @@
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
-    "Alex checkbox cell Where Am I",
+    "Alex checkbox cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Alex ColumnHeader <x> Alex'",
      "     VISIBLE:  '<x> Alex', cursor=1",
-     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'tree table'",
+     "SPEECH OUTPUT: 'Alex'",
      "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'check box checked'",
+     "SPEECH OUTPUT: 'row 2 of 53'"]))
+
+########################################################################
+# Do a detailed "Where Am I" via KP_Enter.
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(PauseAction(3000))
+sequence.append(utils.AssertPresentationAction(
+    "Alex checkbox cell detailed Where Am I",
+    ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Alex ColumnHeader <x> Alex'",
+     "     VISIBLE:  '<x> Alex', cursor=1",
+     "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Alex ColumnHeader <x> Alex'",
+     "     VISIBLE:  '<x> Alex', cursor=1",
+     "SPEECH OUTPUT: 'tree table'",
+     "SPEECH OUTPUT: 'Alex'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'check box checked'",
+     "SPEECH OUTPUT: 'row 2 of 53'",
+     "SPEECH OUTPUT: 'tree table'",
+     "SPEECH OUTPUT: 'Alex'",
+     "SPEECH OUTPUT: 'cell'",
+     "SPEECH OUTPUT: 'check box checked'",
+     "SPEECH OUTPUT: 'row 2 of 53'",
      "SPEECH OUTPUT: 'New Years Day'",
      "SPEECH OUTPUT: 'check box checked'",
      "SPEECH OUTPUT: 'check box checked'",
      "SPEECH OUTPUT: 'check box checked'",
      "SPEECH OUTPUT: 'check box checked'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'row 2 of 53'"]))
+     "SPEECH OUTPUT: 'check box not checked'"]))
 
 ########################################################################
 # Change the state of the checkbox.
Index: src/orca/scripts/StarOffice.py
===================================================================
--- src/orca/scripts/StarOffice.py	(revision 3583)
+++ src/orca/scripts/StarOffice.py	(working copy)
@@ -85,11 +85,51 @@
                (table.getColumnAtIndex(obj.getIndexInParent()) + 1)
         utterances.append(text)
 
+        # Speak the dynamic column header (if any).
+        #
+        if self._script.dynamicColumnHeaders.has_key(table):
+            row = self._script.dynamicColumnHeaders[table]
+            header = self._script.getDynamicRowHeaderCell(obj, row)
+            try:
+                headerText = header.queryText()
+            except:
+                headerText = None
+
+            if header.childCount > 0:
+                for child in header:
+                    text = self._script.getText(child, 0, -1)
+                    if text:
+                        utterances.append(text)
+            elif headerText:
+                text = self._script.getText(header, 0, -1)
+                if text:
+                    utterances.append(text)
+
         # Translators: this represents the row number of a table.
         #
         text = _("row %d") % (table.getRowAtIndex(obj.getIndexInParent()) + 1)
         utterances.append(text)
 
+        # Speak the dynamic row header (if any).
+        #
+        if self._script.dynamicRowHeaders.has_key(table):
+            column = self._script.dynamicRowHeaders[table]
+            header = self._script.getDynamicColumnHeaderCell(obj, column)
+            try:
+                headerText = header.queryText()
+            except:
+                headerText = None
+
+            if header.childCount > 0:
+                for child in header:
+                    text = self._script.getText(child, 0, -1)
+                    if text:
+                        utterances.append(text)
+            elif headerText:
+                text = self._script.getText(header, 0, -1)
+                if text:
+                    utterances.append(text)
+
         text = obj.queryText().getText(0, -1)
         utterances.append(text)
 
Index: src/orca/where_am_I.py
===================================================================
--- src/orca/where_am_I.py	(revision 3583)
+++ src/orca/where_am_I.py	(working copy)
@@ -495,34 +495,61 @@
         """Tree Tables present the following information (an example is
         'Tree table, Mike Pedersen, item 8 of 10, tree level 2'):
 
-        1. label, if any
-        2. role
-        3. current row (regardless of speak cell/row setting)
-        4. relative position
-        5. if expandable/collapsible: expanded/collapsed
-        6. if applicable, the level
+        1. parent's role
+        2. column header of object
+        3. row header of object
+        4. object's role
+        5. object's contents, if there are multiple columns
+        6. current row (regardless of speak cell/row setting), if
+           performing a detailed whereAmI.
+        7. relative position
+        8. if expandable/collapsible: expanded/collapsed
+        9. if applicable, the level
 
         Nautilus and Gaim
         """
 
-        # Speak the first two items (and possibly the position)
         utterances = []
         if obj.parent.getRole() == pyatspi.ROLE_TABLE_CELL:
             obj = obj.parent
         parent = obj.parent
 
-        text = self._getObjLabel(obj)
+        text = rolenames.getSpeechForRoleName(parent)
         utterances.append(text)
 
+        try:
+            table = parent.queryTable()
+        except:
+            table = None
+            nColumns = 0
+        else:
+            nColumns = table.nColumns
+
+            column = table.getColumnAtIndex(obj.getIndexInParent())
+            header = table.getColumnHeader(column)
+            if header:
+                text = self._getObjName(header)
+                utterances.append(text)
+
+            row = table.getRowAtIndex(obj.getIndexInParent())
+            header = table.getRowHeader(row)
+            if header:
+                text = self._getObjName(header)
+                utterances.append(text)
+
         text = rolenames.getSpeechForRoleName(obj)
         utterances.append(text)
+
+        if nColumns > 1:
+            text = self._getTableCell(obj)
+            utterances.append(text)
+
         debug.println(self._debugLevel, "first table cell utterances=%s" % \
                       utterances)
         speech.speakUtterances(utterances)
 
         utterances = []
-        if not basicOnly:
-            table = parent.queryTable()
+        if not basicOnly and table:
             row = table.getRowAtIndex(
               orca_state.locusOfFocus.getIndexInParent())
             # Translators: this in reference to a row in a table.
@@ -531,11 +558,14 @@
             utterances.append(text)
             speech.speakUtterances(utterances)
 
-        # Speak the current row
-        utterances = self._getTableRow(obj)
-        debug.println(self._debugLevel, "second table cell utterances=%s" % \
-                      utterances)
-        speech.speakUtterances(utterances)
+        # Speak the current row if performing a "detailed" whereAmI.
+        #
+        if not basicOnly:
+            utterances = self._getTableRow(obj)
+            debug.println(self._debugLevel, \
+                          "second table cell utterances=%s" % \
+                          utterances)
+            speech.speakUtterances(utterances)
 
         # Speak the remaining items.
         utterances = []
