I implemented the remaining stubs in AccessibleJTable. This is quite a
monster. While experimenting with AccessibleJTable in BeanShell I
noticed that the RI has a couple more inner classes
AccessibleJTableHeader and AccessibleJTableHeaderCell in there, which
are created by a couple of methods in AccessibleJTable. I also created
such classes but don't feel motivated enough now the fill in all the new
stubbies of them (does anybody use this anyway??).

2006-06-01  Roman Kennke <[EMAIL PROTECTED]>

        * javax/swing/JTable.java
        (AccessibleJTableCell.getAccessibleRow): Added comment explaining
        why the behaviour is like it is.
        (AccessibleJTableCell.getAccessibleStateSet): Implemented.
        (AccessibleJTableHeader): New inner class.
        (AccessibleJTableHeaderCell): New inner class.
        (AccessibleJTable.lastSelectedRow): New field.
        (AccessibleJTable.lastSelectedColumn): New field.
        (AccessibleJTable.caption): New field.
        (AccessibleJTable.summary): New field.
        (AccessibleJTable.rowDescriptions): New field.
        (AccessibleJTable.columnDescriptions): New field.
        (AccessibleJTable): Initialize lastSelectedRow and lastSelectedColumn.
        (AccessibleJTable.getAccessibleSelection(int)): Implemented.
        (AccessibleJTable.isAccessibleChildSelected): Implemented.
        (AccessibleJTable.addAccessibleSelection): Implemented.
        (AccessibleJTable.removeAccessibleSelection): Implemented.
        (AccessibleJTable.clearAccessibleSelection): Implemented.
        (AccessibleJTable.selectAllAccessibleSelection): Implemented.
        (AccessibleJTable.valueChange): Implemented.
        (AccessibleJTable.tableRowsInserted): Implemented.
        (AccessibleJTable.tableRowsDeleted): Implemented.
        (AccessibleJTable.handleRowChange): New helper method.
        (AccessibleJTable.columnAdded): Implemented.
        (AccessibleJTable.columnMarginChanged): Implemented.
        (AccessibleJTable.columnMoved): Implemented.
        (AccessibleJTable.columnRemoved): Implemented.
        (AccessibleJTable.columnSelectionChanged): Implemented.
        (AccessibleJTable.handleColumnChange): New helper method.
        (AccessibleJTable.editingCanceled): Implemented.
        (AccessibleJTable.editingStopped): Implemented.
        (AccessibleJTable.getAccessibleRow): Implemented.
        (AccessibleJTable.getAccessibleColumn): Implemented.
        (AccessibleJTable.getAccessibleIndex): Implemented.
        (AccessibleJTable.getAccessibleCaption): Implemented.
        (AccessibleJTable.setAccessibleCaption): Implemented.
        (AccessibleJTable.getAccessibleSummary): Implemented.
        (AccessibleJTable.setAccessibleSummary): Implemented.
        (AccessibleJTable.getAccessibleRowCount): Implemented.
        (AccessibleJTable.getAccessibleColumnCount): Implemented.
        (AccessibleJTable.getAccessibleAt): Implemented.
        (AccessibleJTable.getAccessibleRowExtentAt): Implemented.
        (AccessibleJTable.getAccessibleColumnExtentAt): Implemented.
        (AccessibleJTable.getAccessibleRowHeader): Implemented.
        (AccessibleJTable.setAccessibleRowHeader): Implemented.
        (AccessibleJTable.getAccessibleColumnHeader): Implemented.
        (AccessibleJTable.setAccessibleColumnHeader): Implemented.
        (AccessibleJTable.getAccessibleRowDescription): Implemented.
        (AccessibleJTable.setAccessibleRowDescription): Implemented.
        (AccessibleJTable.getAccessibleColumnDescription): Implemented.
        (AccessibleJTable.setAccessibleColumnDescription): Implemented.
        (AccessibleJTable.isAccessibleSelected): Implemented.
        (AccessibleJTable.isAccessibleRowSelected): Implemented.
        (AccessibleJTable.isAccessibleColumnSelected): Implemented.
        (AccessibleJTable.getSelectedAccessibleRows): Implemented.
        (AccessibleJTable.getSelectedAccessibleColumns): Implemented.
        (getAccessibleContext): Register listeners for the accessibility
        class on the JTable.

/Roman

Index: javax/swing/JTable.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JTable.java,v
retrieving revision 1.112
diff -u -1 -0 -r1.112 JTable.java
--- javax/swing/JTable.java	31 May 2006 16:16:30 -0000	1.112
+++ javax/swing/JTable.java	1 Jun 2006 14:12:18 -0000
@@ -31,22 +31,20 @@
 independent module, the terms and conditions of the license of that
 module.  An independent module is a module which is not derived from
 or based on this library.  If you modify this library, you may extend
 this exception to your version of the library, but you are not
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
 
 package javax.swing;
 
-import gnu.classpath.NotImplementedException;
-
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Cursor;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.FontMetrics;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.event.FocusListener;
 import java.beans.PropertyChangeEvent;
@@ -58,20 +56,21 @@
 import java.util.Hashtable;
 import java.util.Locale;
 import java.util.Vector;
 
 import javax.accessibility.Accessible;
 import javax.accessibility.AccessibleComponent;
 import javax.accessibility.AccessibleContext;
 import javax.accessibility.AccessibleExtendedTable;
 import javax.accessibility.AccessibleRole;
 import javax.accessibility.AccessibleSelection;
+import javax.accessibility.AccessibleState;
 import javax.accessibility.AccessibleStateSet;
 import javax.accessibility.AccessibleTable;
 import javax.accessibility.AccessibleTableModelChange;
 import javax.swing.event.CellEditorListener;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 import javax.swing.event.TableColumnModelEvent;
 import javax.swing.event.TableColumnModelListener;
 import javax.swing.event.TableModelEvent;
@@ -158,36 +157,55 @@
         column = c;
         index = i;
       }
 
       /**
        * Returns the accessible row for the table cell.
        *
        * @return the accessible row for the table cell
        */
       public AccessibleRole getAccessibleRole()
-        throws NotImplementedException
       {
         // TODO: What is the role of the table cell?
+        // Seems like the RI returns UNKNOWN here for 'normal' cells, might
+        // be different for special renderers though (not tested yet).
         return AccessibleRole.UNKNOWN;
       }
 
       /**
        * Returns the accessible state set of this accessible table cell.
        *
        * @return the accessible state set of this accessible table cell
        */
       public AccessibleStateSet getAccessibleStateSet()
-        throws NotImplementedException
       {
-        // TODO: What state shoiuld be returned here?
-        return new AccessibleStateSet();
+        AccessibleStateSet state = new AccessibleStateSet();
+
+        // Figure out the SHOWING state.
+        Rectangle visibleRect = getVisibleRect();
+        Rectangle cellRect = getCellRect(row, column, false);
+        if (visibleRect.intersects(cellRect))
+          state.add(AccessibleState.SHOWING);
+
+        // Figure out SELECTED state.
+        if (isCellSelected(row, column))
+          state.add(AccessibleState.SELECTED);
+
+        // Figure out ACTIVE state.
+        if (row == getSelectedRow() && column == getSelectedColumn())
+          state.add(AccessibleState.ACTIVE);
+
+        // TRANSIENT seems to be always set in the RI.
+        state.add(AccessibleState.TRANSIENT);
+
+        // TODO: Any other state to handle here?
+        return state;
       }
 
       /**
        * Returns the index of this cell in the parent object.
        *
        * @return the index of this cell in the parent object
        */
       public int getAccessibleIndexInParent()
       {
         return index;
@@ -591,31 +609,489 @@
       public int getFirstColumn()
       {
         return firstColumn;
       }
 
       public int getLastColumn()
       {
         return lastColumn;
       }
     }
-   
+
+    /**
+     * The RI returns an instance with this name in
+     * [EMAIL PROTECTED] #getAccessibleColumnHeader()}, this makes sense, so we do the
+     * same.
+     */
+    private class AccessibleTableHeader
+      implements AccessibleTable
+    {
+
+      /**
+       * The JTableHeader wrapped by this class.
+       */
+      private JTableHeader header;
+
+      /**
+       * Creates a new instance.
+       *
+       * @param h the JTableHeader to wrap
+       */
+      private AccessibleTableHeader(JTableHeader h)
+      {
+        header = h;
+      }
+
+      /**
+       * Returns the caption for the table header.
+       *
+       * @return the caption for the table header
+       */
+      public Accessible getAccessibleCaption()
+      {
+        // The RI seems to always return null here, so do we.
+        return null;
+      }
+
+      /**
+       * Sets the caption for the table header.
+       *
+       * @param caption the caption to set
+       */
+      public void setAccessibleCaption(Accessible caption)
+      {
+        // This seems to be a no-op in the RI, so we do the same.
+      }
+
+      /**
+       * Returns the caption for the table header.
+       *
+       * @return the caption for the table header
+       */
+      public Accessible getAccessibleSummary()
+      {
+        // The RI seems to always return null here, so do we.
+        return null;
+      }
+
+      /**
+       * Sets the summary for the table header.
+       *
+       * @param summary the caption to set
+       */
+      public void setAccessibleSummary(Accessible summary)
+      {
+        // This seems to be a no-op in the RI, so we do the same.
+      }
+
+      /**
+       * Returns the number of rows, which is always 1 for the table header.
+       *
+       * @return the number of rows
+       */
+      public int getAccessibleRowCount()
+      {
+        return 1;
+      }
+
+      /**
+       * Returns the number of columns in the table header.
+       *
+       * @return the number of columns in the table header
+       */
+      public int getAccessibleColumnCount()
+      {
+        return header.getColumnModel().getColumnCount();
+      }
+
+      /**
+       * Returns the accessible child at the specified row and column.
+       * The row number is ignored here, and we return an
+       * AccessibleJTableHeaderCell here with the renderer component as
+       * component.
+       *
+       * @param r the row number
+       * @param c the column number
+       *
+       * @return the accessible child at the specified row and column
+       */
+      public Accessible getAccessibleAt(int r, int c)
+      {
+        TableColumn column = header.getColumnModel().getColumn(c);
+        TableCellRenderer rend = column.getHeaderRenderer();
+        if (rend == null)
+          rend = header.getDefaultRenderer();
+        Component comp =
+          rend.getTableCellRendererComponent(header.getTable(),
+                                             column.getHeaderValue(), false,
+                                             false, -1, c);
+        return new AccessibleJTableHeaderCell(header, comp, r, c);
+      }
+
+      public int getAccessibleRowExtentAt(int r, int c)
+      {
+        // TODO Auto-generated method stub
+        return 0;
+      }
+
+      public int getAccessibleColumnExtentAt(int r, int c)
+      {
+        // TODO Auto-generated method stub
+        return 0;
+      }
+
+      public AccessibleTable getAccessibleRowHeader()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setAccessibleRowHeader(AccessibleTable header)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public AccessibleTable getAccessibleColumnHeader()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setAccessibleColumnHeader(AccessibleTable header)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public Accessible getAccessibleRowDescription(int r)
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setAccessibleRowDescription(int r, Accessible description)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public Accessible getAccessibleColumnDescription(int c)
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setAccessibleColumnDescription(int c, Accessible description)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public boolean isAccessibleSelected(int r, int c)
+      {
+        // TODO Auto-generated method stub
+        return false;
+      }
+
+      public boolean isAccessibleRowSelected(int r)
+      {
+        // TODO Auto-generated method stub
+        return false;
+      }
+
+      public boolean isAccessibleColumnSelected(int c)
+      {
+        // TODO Auto-generated method stub
+        return false;
+      }
+
+      public int[] getSelectedAccessibleRows()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public int[] getSelectedAccessibleColumns()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+        
+    }
+
+    /**
+     * The RI returns an instance of such class for table header cells. This
+     * makes sense so I added this class. This still needs to be fully
+     * implemented, I just don't feel motivated enough to do so just now.
+     */
+    private class AccessibleJTableHeaderCell
+      extends AccessibleContext
+      implements Accessible, AccessibleComponent
+    {
+
+      private AccessibleJTableHeaderCell(JTableHeader h, Component comp, int r,
+                                         int c)
+      {
+        
+      }
+
+      public AccessibleRole getAccessibleRole()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public AccessibleStateSet getAccessibleStateSet()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public int getAccessibleIndexInParent()
+      {
+        // TODO Auto-generated method stub
+        return 0;
+      }
+
+      public int getAccessibleChildrenCount()
+      {
+        // TODO Auto-generated method stub
+        return 0;
+      }
+
+      public Accessible getAccessibleChild(int i)
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public Locale getLocale()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public AccessibleContext getAccessibleContext()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public Color getBackground()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setBackground(Color color)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public Color getForeground()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setForeground(Color color)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public Cursor getCursor()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setCursor(Cursor cursor)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public Font getFont()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setFont(Font font)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public FontMetrics getFontMetrics(Font font)
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public boolean isEnabled()
+      {
+        // TODO Auto-generated method stub
+        return false;
+      }
+
+      public void setEnabled(boolean b)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public boolean isVisible()
+      {
+        // TODO Auto-generated method stub
+        return false;
+      }
+
+      public void setVisible(boolean b)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public boolean isShowing()
+      {
+        // TODO Auto-generated method stub
+        return false;
+      }
+
+      public boolean contains(Point point)
+      {
+        // TODO Auto-generated method stub
+        return false;
+      }
+
+      public Point getLocationOnScreen()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public Point getLocation()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setLocation(Point point)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public Rectangle getBounds()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setBounds(Rectangle rectangle)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public Dimension getSize()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public void setSize(Dimension dimension)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public Accessible getAccessibleAt(Point point)
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      public boolean isFocusTraversable()
+      {
+        // TODO Auto-generated method stub
+        return false;
+      }
+
+      public void requestFocus()
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public void addFocusListener(FocusListener listener)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+
+      public void removeFocusListener(FocusListener listener)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+    }
+
+    /**
+     * The last selected row. This is needed to track the selection in
+     * [EMAIL PROTECTED] #valueChanged(ListSelectionEvent)}.
+     */
+    private int lastSelectedRow;
+
+    /**
+     * The last selected column. This is needed to track the selection in
+     * [EMAIL PROTECTED] #valueChanged(ListSelectionEvent)}.
+     */
+    private int lastSelectedColumn;
+
+    /**
+     * The caption of the table.
+     */
+    private Accessible caption;
+
+    /**
+     * The summary of the table.
+     */
+    private Accessible summary;
+
+    /**
+     * Accessible descriptions for rows.
+     */
+    private Accessible[] rowDescriptions;
+
+    /**
+     * Accessible descriptions for columns.
+     */
+    private Accessible[] columnDescriptions;
+
     /**
      * Creates a new <code>AccessibleJTable</code>.
      *
      * @since JDK1.5
      */
     protected AccessibleJTable()
     {
       getModel().addTableModelListener(this);
       getSelectionModel().addListSelectionListener(this);
       getColumnModel().addColumnModelListener(this);
+      lastSelectedRow = getSelectedRow();
+      lastSelectedColumn = getSelectedColumn();
       TableCellEditor editor = getCellEditor();
       if (editor != null)
         editor.addCellEditorListener(this);
     }
 
     /**
      * Returns the accessible role for the <code>JTable</code> component.
      *
      * @return [EMAIL PROTECTED] AccessibleRole#TABLE}.
      */
@@ -635,62 +1111,211 @@
     }
     
     /**
      * Returns the number of selected items in this table.
      */
     public int getAccessibleSelectionCount()
     {
       return getSelectedColumnCount();
     }
 
+    /**
+     * Returns the selected accessible object with the specified index
+     * <code>i</code>. This basically returns the i-th selected cell in the
+     * table when going though it row-wise, and inside the rows, column-wise.
+     *
+     * @param i the index of the selected object to find
+     *
+     * @return the selected accessible object with the specified index
+     *         <code>i</code>
+     */
     public Accessible getAccessibleSelection(int i)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return null;
+      Accessible found = null;
+
+      int[] selectedRows = getSelectedRows();
+      int[] selectedColumns = getSelectedColumns();
+      int numCols = getColumnCount();
+      int numRows = getRowCount();
+
+      // We have to go through every selected row and column and count until we
+      // find the specified index. This is potentially inefficient, but I can't
+      // think of anything better atm.
+      if (getRowSelectionAllowed() && getColumnSelectionAllowed())
+        {
+          int current = -1;
+          int newIndex = current;
+          int lastSelectedRow = -1;
+          // Go through the selected rows array, don't forget the selected
+          // cells inside the not-selected rows' columns.
+          for (int j = 0; i < selectedRows.length; i++)
+            {
+              // Handle unselected rows between this selected and the last
+              // selected row, if any.
+              int selectedRow = selectedRows[j];
+              int r = -1;
+              int ci = -1;
+              for (r = lastSelectedRow + 1;
+                   r < selectedRow && current < i; r++)
+                {
+                  for (ci = 0; ci < selectedColumns.length && current < i;
+                       ci++)
+                    {
+                      current++;
+                    }
+                }
+              if (current == i)
+                {
+                  // We found the cell in the above loops, now get out of here.
+                  found = getAccessibleChild(r * numCols
+                                             + selectedColumns[ci]);
+                  break;
+                }
+
+              // If we're still here, handle the current selected row.
+              if (current < i && current + numCols >= i)
+                {
+                  // The cell must be in that row, which one is it?
+                  found = getAccessibleChild(r * numCols + (i - current));
+                  break;
+                }
+              current += numCols;
+            }
+          if (found == null)
+            {
+              // The cell can still be in the last couple of unselected rows.
+              int r = 0;
+              int ci = 0;
+              for (r = lastSelectedRow + 1;
+                   r < numRows && current < i; r++)
+                {
+                  for (ci = 0; ci < selectedColumns.length && current < i;
+                       ci++)
+                    {
+                      current++;
+                    }
+                }
+              if (current == i)
+                {
+                  // We found the cell in the above loops, now get out of here.
+                  found = getAccessibleChild(r * numCols
+                                             + selectedColumns[ci]);
+                }
+            }
+        }
+      // One or more rows can be completely selected.
+      else if (getRowSelectionAllowed())
+        {
+          int c = i % numCols;
+          int r = selectedRows[i / numCols];
+          found = getAccessibleChild(r * numCols + c);
+        }
+      // One or more columns can be completely selected.
+      else if (getRowSelectionAllowed())
+        {
+          int numSelectedColumns = selectedColumns.length;
+          int c = selectedColumns[i % numSelectedColumns];
+          int r = i / numSelectedColumns;
+          found = getAccessibleChild(r * numCols + c);
+        }
+
+      return found;
     }
 
+    /**
+     * Returns <code>true</code> if the accessible child with the index
+     * <code>i</code> is selected, <code>false</code> otherwise.
+     *
+     * @param i the index of the accessible to check
+     *
+     * @return <code>true</code> if the accessible child with the index
+     *         <code>i</code> is selected, <code>false</code> otherwise
+     */
     public boolean isAccessibleChildSelected(int i)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return false;
+      int r = getAccessibleRowAtIndex(i);
+      int c = getAccessibleColumnAtIndex(i);
+      return isCellSelected(r, c);
     }
 
+    /**
+     * Adds the accessible child with the specified index <code>i</code> to the
+     * selection.
+     *
+     * @param i the index of the accessible child to add to the selection
+     */
     public void addAccessibleSelection(int i)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub    
+      int r = getAccessibleRowAtIndex(i);
+      int c = getAccessibleColumnAtIndex(i);
+      changeSelection(r, c, true, false);
     }
 
+    /**
+     * Removes the accessible child with the specified index <code>i</code>
+     * from the current selection. This will only work on tables that have
+     * cell selection enabled (<code>rowSelectionAllowed == false &&
+     * columnSelectionAllowed == false</code>).
+     *
+     * @param i the index of the accessible to be removed from the selection
+     */
     public void removeAccessibleSelection(int i)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub    
+      if (! getRowSelectionAllowed() && ! getColumnSelectionAllowed())
+        {
+          int r = getAccessibleRowAtIndex(i);
+          int c = getAccessibleColumnAtIndex(i);
+          removeRowSelectionInterval(r, r);
+          removeColumnSelectionInterval(c, c);
+        }
     }
 
+    /**
+     * Deselects all selected accessible children.
+     */
     public void clearAccessibleSelection()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
+      clearSelection();
     }
 
+    /**
+     * Selects all accessible children that can be selected. This will only
+     * work on tables that support multiple selections and that have individual
+     * cell selection enabled.
+     */
     public void selectAllAccessibleSelection()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
+      selectAll();
     }
 
+    /**
+     * Receives notification when the row selection changes and fires
+     * appropriate property change events.
+     *
+     * @param event the list selection event
+     */
     public void valueChanged(ListSelectionEvent event)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub 
+      firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
+                         Boolean.FALSE, Boolean.TRUE);
+      int r = getSelectedRow();
+      int c = getSelectedColumn();
+      if (r != lastSelectedRow || c != lastSelectedColumn)
+        {
+          Accessible o = getAccessibleAt(lastSelectedRow,
+                                         lastSelectedColumn);
+          Accessible n = getAccessibleAt(r, c);
+          firePropertyChange(AccessibleContext
+                             .ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY, o, n);
+          lastSelectedRow = r;
+          lastSelectedColumn = c;
+        }
     }
 
     /**
      * Receives notification when the table model changes. Depending on the
      * type of change, this method calls [EMAIL PROTECTED] #tableRowsInserted} or
      * [EMAIL PROTECTED] #tableRowsDeleted}.
      *
      * @param event the table model event
      */
     public void tableChanged(TableModelEvent event)
@@ -701,84 +1326,124 @@
           tableRowsInserted(event);
           break;
         case TableModelEvent.DELETE:
           tableRowsDeleted(event);
           break;
         }
     }
 
     /**
      * Receives notification when one or more rows have been inserted into the
-     * table.
+     * table and fires appropriate property change events.
      *
      * @param event the table model event
      */
     public void tableRowsInserted(TableModelEvent event)
-      throws NotImplementedException
     {
-      // TODO: What to do here, if anything? This might be a hook method for
-      // subclasses...
+      handleRowChange(event);
     }
 
     /**
      * Receives notification when one or more rows have been deleted from the
      * table.
      *
      * @param event the table model event
      */
     public void tableRowsDeleted(TableModelEvent event)
-      throws NotImplementedException
     {
-      // TODO: What to do here, if anything? This might be a hook method for
-      // subclasses...
+      handleRowChange(event);
+    }
+
+    /**
+     * Fires a PropertyChangeEvent for inserted or deleted rows.
+     *
+     * @param event the table model event
+     */
+    private void handleRowChange(TableModelEvent event)
+    {
+      firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
+                         null, null);
+      int firstColumn = event.getColumn();
+      int lastColumn = event.getColumn();
+      if (firstColumn == TableModelEvent.ALL_COLUMNS)
+        {
+          firstColumn = 0;
+          lastColumn = getColumnCount() - 1;
+        }
+      AccessibleJTableModelChange change = new AccessibleJTableModelChange
+         (event.getType(), event.getFirstRow(), event.getLastRow(),
+          firstColumn, lastColumn);
+      firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
+                         null, change);
     }
 
     public void columnAdded(TableColumnModelEvent event)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub    
+      firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
+                         null, null);
+      handleColumnChange(AccessibleTableModelChange.INSERT,
+                         event.getFromIndex(), event.getToIndex());
     }
 
-    public void columnMarginChanged(ChangeEvent event)
-      throws NotImplementedException
+    public void columnRemoved(TableColumnModelEvent event)
     {
-      // TODO Auto-generated method stub
+      firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
+                         null, null);
+      handleColumnChange(AccessibleTableModelChange.DELETE,
+                         event.getFromIndex(), event.getToIndex());
     }
 
     public void columnMoved(TableColumnModelEvent event)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
+      firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
+                         null, null);
+      handleColumnChange(AccessibleTableModelChange.DELETE,
+                         event.getFromIndex(), event.getFromIndex());
+      handleColumnChange(AccessibleTableModelChange.INSERT,
+                         event.getFromIndex(), event.getToIndex());
     }
 
-    public void columnRemoved(TableColumnModelEvent event)
-      throws NotImplementedException
+    /**
+     * Fires a PropertyChangeEvent for inserted or deleted columns.
+     *
+     * @param type the type of change
+     * @param from the start of the change
+     * @param to the target of the change
+     */
+    private void handleColumnChange(int type, int from, int to)
+    {
+      AccessibleJTableModelChange change =
+        new AccessibleJTableModelChange(type, 0, 0, from, to);
+      firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
+                         null, change);
+    }
+
+    public void columnMarginChanged(ChangeEvent event)
     {
-      // TODO Auto-generated method stub
+      firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
+                         null, null);
     }
 
     public void columnSelectionChanged(ListSelectionEvent event)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
+      // AFAICS, nothing is done here.
     }
 
     public void editingCanceled(ChangeEvent event)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
+      // AFAICS, nothing is done here.
     }
 
     public void editingStopped(ChangeEvent event)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
+      firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
+                         null, null);
     }
 
     /**
      * Receives notification when any of the JTable's properties changes. This
      * is used to replace the listeners on the table's model, selection model,
      * column model and cell editor.
      *
      * @param e the property change event
      */
     public void propertyChange(PropertyChangeEvent e)
@@ -807,188 +1472,338 @@
         }
       else if (propName.equals("cellEditor"))
         {
           CellEditor oldEd = (CellEditor) e.getOldValue();
           oldEd.removeCellEditorListener(this);
           CellEditor newEd = (CellEditor) e.getNewValue();
           newEd.addCellEditorListener(this);
         }
     }
 
+    /**
+     * Returns the row number of an accessible child (cell) with the specified
+     * index.
+     *
+     * @param index the index of the cell of which the row number is queried
+     * 
+     * @return the row number of an accessible child (cell) with the specified
+     *         index 
+     */
     public int getAccessibleRow(int index)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return 0;
+      return getAccessibleRowAtIndex(index);
     }
 
+    /**
+     * Returns the column number of an accessible child (cell) with the
+     * specified index.
+     *
+     * @param index the index of the cell of which the column number is queried
+     * 
+     * @return the column number of an accessible child (cell) with the
+     *         specified index 
+     */
     public int getAccessibleColumn(int index)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return 0;
+      return getAccessibleColumnAtIndex(index);
     }
 
+    /**
+     * Returns the index of the accessible child at the specified row and
+     * column.
+     *
+     * @param r the row number
+     * @param c the column number
+     *
+     * @return the index of the accessible child at the specified row and
+     *         column
+     */
     public int getAccessibleIndex(int r, int c)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return 0;
+      return getAccessibleIndexAt(r, c);
     }
 
+    /**
+     * Returns the caption of the table.
+     *
+     * @return the caption of the table
+     *
+     * @see #setAccessibleCaption(Accessible)
+     */
     public Accessible getAccessibleCaption()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return null;
+      return caption;
     }
 
-    public void setAccessibleCaption(Accessible caption)
-      throws NotImplementedException
+    /**
+     * Sets the caption for the table.
+     *
+     * @param c the caption to set
+     */
+    public void setAccessibleCaption(Accessible c)
     {
-      // TODO Auto-generated method stub
+      caption = c;
     }
 
+    /**
+     * Returns the summary for the table.
+     *
+     * @return the summary for the table
+     */
     public Accessible getAccessibleSummary()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return null;
+      return summary;
     }
 
-    public void setAccessibleSummary(Accessible summary)
-      throws NotImplementedException
+    /**
+     * Sets the summary for the table.
+     *
+     * @param s the summary to set
+     */
+    public void setAccessibleSummary(Accessible s)
     {
-      // TODO Auto-generated method stub
+      summary = s;
     }
 
+    /**
+     * Returns the number of rows in the table.
+     *
+     * @return the number of rows in the table
+     */
     public int getAccessibleRowCount()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return 0;
+      return getRowCount();
     }
 
+    /**
+     * Returns the number of columns in the table.
+     *
+     * @return the number of columns in the table
+     */
     public int getAccessibleColumnCount()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return 0;
+      return getColumnCount();
     }
 
+    /**
+     * Returns the accessible child (table cell) at the specified row and
+     * column.
+     *
+     * @param r the row number
+     * @param c the column number
+     *
+     * @return the accessible child (table cell) at the specified row and
+     *         column
+     */
     public Accessible getAccessibleAt(int r, int c)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return null;
+      return getAccessibleChild(r * getAccessibleColumnCount() + c);
     }
 
+    /**
+     * Returns the number of rows that the specified cell occupies. The
+     * standard table cells only occupy one row, so we return <code>1</code>
+     * here.
+     *
+     * @param r the row number
+     * @param c the column number
+     *
+     * @return the number of rows that the specified cell occupies
+     */
     public int getAccessibleRowExtentAt(int r, int c)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return 0;
+      return 1;
     }
 
+    /**
+     * Returns the number of columns that the specified cell occupies. The
+     * standard table cells only occupy one column, so we return <code>1</code>
+     * here.
+     *
+     * @param r the row number
+     * @param c the column number
+     *
+     * @return the number of rows that the specified cell occupies
+     */
     public int getAccessibleColumnExtentAt(int r, int c)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return 0;
+      return 1;
     }
 
+    /**
+     * Returns the accessible row header.
+     *
+     * @return the accessible row header
+     */
     public AccessibleTable getAccessibleRowHeader()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
+      // The RI seems to always return null here, so do we.
       return null;
     }
 
+    /**
+     * Sets the accessible row header.
+     *
+     * @param header the header to set
+     */
     public void setAccessibleRowHeader(AccessibleTable header)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub    
+      // In the RI this seems to be a no-op.    
     }
 
+    /**
+     * Returns the column header.
+     *
+     * @return the column header, or <code>null</code> if there is no column
+     *         header
+     */
     public AccessibleTable getAccessibleColumnHeader()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return null;
+      JTableHeader h = getTableHeader();
+      AccessibleTable header = null;
+      if (h != null)
+        header = new AccessibleTableHeader(h);
+      return header;
     }
 
+    /**
+     * Sets the accessible column header. The default implementation doesn't
+     * allow changing the header this way, so this is a no-op.
+     *
+     * @param header the accessible column header to set
+     */
     public void setAccessibleColumnHeader(AccessibleTable header)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub    
+      // The RI doesn't seem to do anything, so we also do nothing.
     }
 
+    /**
+     * Returns the accessible description for the row with the specified index,
+     * or <code>null</code> if no description has been set.
+     *
+     * @param r the row for which the description is queried
+     *
+     * @return the accessible description for the row with the specified index,
+     *         or <code>null</code> if no description has been set
+     */
     public Accessible getAccessibleRowDescription(int r)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return null;
+      Accessible descr = null;
+      if (rowDescriptions != null)
+        descr = rowDescriptions[r];
+      return descr;
     }
 
+    /**
+     * Sets the accessible description for the row with the specified index.
+     *
+     * @param r the row number for which to set the description
+     * @param description the description to set
+     */
     public void setAccessibleRowDescription(int r, Accessible description)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub    
+      if (rowDescriptions == null)
+        rowDescriptions = new Accessible[getAccessibleRowCount()];
+      rowDescriptions[r] = description;
     }
 
+    /**
+     * Returns the accessible description for the column with the specified
+     * index, or <code>null</code> if no description has been set.
+     *
+     * @param c the column for which the description is queried
+     *
+     * @return the accessible description for the column with the specified
+     *         index, or <code>null</code> if no description has been set
+     */
     public Accessible getAccessibleColumnDescription(int c)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return null;
+      Accessible descr = null;
+      if (columnDescriptions != null)
+        descr = columnDescriptions[c];
+      return descr;
     }
 
+    /**
+     * Sets the accessible description for the column with the specified index.
+     *
+     * @param c the column number for which to set the description
+     * @param description the description to set
+     */
     public void setAccessibleColumnDescription(int c, Accessible description)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      
+      if (columnDescriptions == null)
+        columnDescriptions = new Accessible[getAccessibleRowCount()];
+      columnDescriptions[c] = description;
     }
 
+    /**
+     * Returns <code>true</code> if the accessible child at the specified
+     * row and column is selected, <code>false</code> otherwise.
+     *
+     * @param r the row number of the child
+     * @param c the column number of the child
+     *
+     * @return <code>true</code> if the accessible child at the specified
+     *         row and column is selected, <code>false</code> otherwise
+     */
     public boolean isAccessibleSelected(int r, int c)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return false;
+      return isCellSelected(r, c);
     }
 
+    /**
+     * Returns <code>true</code> if the row with the specified index is
+     * selected, <code>false</code> otherwise.
+     *
+     * @param r the row number
+     *
+     * @return <code>true</code> if the row with the specified index is
+     *        selected, <code>false</code> otherwise
+     */
     public boolean isAccessibleRowSelected(int r)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return false;
+      return isRowSelected(r);
     }
 
+    /**
+     * Returns <code>true</code> if the column with the specified index is
+     * selected, <code>false</code> otherwise.
+     *
+     * @param c the column number
+     *
+     * @return <code>true</code> if the column with the specified index is
+     *        selected, <code>false</code> otherwise
+     */
     public boolean isAccessibleColumnSelected(int c)
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return false;
+      return isColumnSelected(c);
     }
 
+    /**
+     * Returns the indices of all selected rows.
+     *
+     * @return the indices of all selected rows
+     */
     public int[] getSelectedAccessibleRows()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return null;
+      return getSelectedRows();
     }
 
+    /**
+     * Returns the indices of all selected columns.
+     *
+     * @return the indices of all selected columns
+     */
     public int[] getSelectedAccessibleColumns()
-      throws NotImplementedException
     {
-      // TODO Auto-generated method stub
-      return null;
+      return getSelectedColumns();
     }
 
     /**
      * Returns the accessible row at the specified index.
      *
      * @param index the index for which to query the row
      *
      * @return the row number at the specified table index
      */
     public int getAccessibleRowAtIndex(int index)
@@ -2758,21 +3573,30 @@
   }
 
   /**
    * Get the value of the [EMAIL PROTECTED] #accessibleContext} property.
    *
    * @return The current value of the property
    */
   public AccessibleContext getAccessibleContext()
   {
     if (accessibleContext == null)
-      accessibleContext = new AccessibleJTable();
+      {
+        AccessibleJTable ctx = new AccessibleJTable();
+        addPropertyChangeListener(ctx);
+        TableColumnModel tcm = getColumnModel();
+        tcm.addColumnModelListener(ctx);
+        tcm.getSelectionModel().addListSelectionListener(ctx);
+        getSelectionModel().addListSelectionListener(ctx);
+        
+        accessibleContext = ctx;
+      }
     return accessibleContext;
   }
 
   /**
    * Get the value of the [EMAIL PROTECTED] #cellEditor} property.
    *
    * @return The current value of the property
    */
   public TableCellEditor getCellEditor()
   {
@@ -4060,12 +4884,11 @@
           {
             setRowHeight(((Integer) value).intValue());
             clientRowHeightSet = false;
           }
       }
     else
       {
         super.setUIProperty(propertyName, value);
       }
   }
-
 }

Reply via email to