Source for javax.swing.JTable

   1: /* JTable.java -- 
   2:    Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Component;
  43: import java.awt.Cursor;
  44: import java.awt.Dimension;
  45: import java.awt.Font;
  46: import java.awt.FontMetrics;
  47: import java.awt.Point;
  48: import java.awt.Rectangle;
  49: import java.awt.event.FocusListener;
  50: import java.beans.PropertyChangeEvent;
  51: import java.beans.PropertyChangeListener;
  52: import java.text.DateFormat;
  53: import java.text.NumberFormat;
  54: import java.util.Date;
  55: import java.util.EventObject;
  56: import java.util.Hashtable;
  57: import java.util.Locale;
  58: import java.util.Vector;
  59: 
  60: import javax.accessibility.Accessible;
  61: import javax.accessibility.AccessibleComponent;
  62: import javax.accessibility.AccessibleContext;
  63: import javax.accessibility.AccessibleExtendedTable;
  64: import javax.accessibility.AccessibleRole;
  65: import javax.accessibility.AccessibleSelection;
  66: import javax.accessibility.AccessibleState;
  67: import javax.accessibility.AccessibleStateSet;
  68: import javax.accessibility.AccessibleTable;
  69: import javax.accessibility.AccessibleTableModelChange;
  70: import javax.swing.event.CellEditorListener;
  71: import javax.swing.event.ChangeEvent;
  72: import javax.swing.event.ListSelectionEvent;
  73: import javax.swing.event.ListSelectionListener;
  74: import javax.swing.event.TableColumnModelEvent;
  75: import javax.swing.event.TableColumnModelListener;
  76: import javax.swing.event.TableModelEvent;
  77: import javax.swing.event.TableModelListener;
  78: import javax.swing.plaf.TableUI;
  79: import javax.swing.table.DefaultTableCellRenderer;
  80: import javax.swing.table.DefaultTableColumnModel;
  81: import javax.swing.table.DefaultTableModel;
  82: import javax.swing.table.JTableHeader;
  83: import javax.swing.table.TableCellEditor;
  84: import javax.swing.table.TableCellRenderer;
  85: import javax.swing.table.TableColumn;
  86: import javax.swing.table.TableColumnModel;
  87: import javax.swing.table.TableModel;
  88: 
  89: /**
  90:  * The table component, displaying information, organized in rows and columns.
  91:  * The table can be placed in the scroll bar and have the optional header
  92:  * that is always visible. Cell values may be editable after double clicking
  93:  * on the cell. Cell columns may have various data types, that are 
  94:  * displayed and edited by the different renderers and editors. It is possible
  95:  * to set different column width. The columns are also resizeable by 
  96:  * dragging the column boundary in the header.
  97:  */
  98: public class JTable
  99:   extends JComponent
 100:   implements TableModelListener, Scrollable, TableColumnModelListener,
 101:              ListSelectionListener, CellEditorListener, Accessible
 102: {
 103:   /**
 104:    * Provides accessibility support for <code>JTable</code>.
 105:    *
 106:    * @author Roman Kennke (kennke@aicas.com)
 107:    */
 108:   protected class AccessibleJTable
 109:     extends AccessibleJComponent
 110:     implements AccessibleSelection, ListSelectionListener, TableModelListener,
 111:     TableColumnModelListener, CellEditorListener, PropertyChangeListener,
 112:     AccessibleExtendedTable
 113:   {
 114: 
 115:     /**
 116:      * Provides accessibility support for table cells.
 117:      *
 118:      * @author Roman Kennke (kennke@aicas.com)
 119:      */
 120:     protected class AccessibleJTableCell
 121:       extends AccessibleContext
 122:       implements Accessible, AccessibleComponent
 123:     {
 124: 
 125:       /**
 126:        * The table of this cell.
 127:        */
 128:       private JTable table;
 129: 
 130:       /**
 131:        * The row index of this cell.
 132:        */
 133:       private int row;
 134: 
 135:       /**
 136:        * The column index of this cell.
 137:        */
 138:       private int column;
 139: 
 140:       /**
 141:        * The index of this cell inside the AccessibleJTable parent.
 142:        */
 143:       private int index;
 144: 
 145:       /**
 146:        * Creates a new <code>AccessibleJTableCell</code>.
 147:        *
 148:        * @param t the table
 149:        * @param r the row
 150:        * @param c the column
 151:        * @param i the index of this cell inside the accessible table parent
 152:        */
 153:       public AccessibleJTableCell(JTable t, int r, int c, int i)
 154:       {
 155:         table = t;
 156:         row = r;
 157:         column = c;
 158:         index = i;
 159:       }
 160: 
 161:       /**
 162:        * Returns the accessible row for the table cell.
 163:        *
 164:        * @return the accessible row for the table cell
 165:        */
 166:       public AccessibleRole getAccessibleRole()
 167:       {
 168:         // TODO: What is the role of the table cell?
 169:         // Seems like the RI returns UNKNOWN here for 'normal' cells, might
 170:         // be different for special renderers though (not tested yet).
 171:         return AccessibleRole.UNKNOWN;
 172:       }
 173: 
 174:       /**
 175:        * Returns the accessible state set of this accessible table cell.
 176:        *
 177:        * @return the accessible state set of this accessible table cell
 178:        */
 179:       public AccessibleStateSet getAccessibleStateSet()
 180:       {
 181:         AccessibleStateSet state = new AccessibleStateSet();
 182: 
 183:         // Figure out the SHOWING state.
 184:         Rectangle visibleRect = getVisibleRect();
 185:         Rectangle cellRect = getCellRect(row, column, false);
 186:         if (visibleRect.intersects(cellRect))
 187:           state.add(AccessibleState.SHOWING);
 188: 
 189:         // Figure out SELECTED state.
 190:         if (isCellSelected(row, column))
 191:           state.add(AccessibleState.SELECTED);
 192: 
 193:         // Figure out ACTIVE state.
 194:         if (row == getSelectedRow() && column == getSelectedColumn())
 195:           state.add(AccessibleState.ACTIVE);
 196: 
 197:         // TRANSIENT seems to be always set in the RI.
 198:         state.add(AccessibleState.TRANSIENT);
 199: 
 200:         // TODO: Any other state to handle here?
 201:         return state;
 202:       }
 203: 
 204:       /**
 205:        * Returns the index of this cell in the parent object.
 206:        *
 207:        * @return the index of this cell in the parent object
 208:        */
 209:       public int getAccessibleIndexInParent()
 210:       {
 211:         return index;
 212:       }
 213: 
 214:       /**
 215:        * Returns the number of children of this object. Table cells cannot have
 216:        * children, so we return <code>0</code> here.
 217:        *
 218:        * @return <code>0</code>
 219:        */
 220:       public int getAccessibleChildrenCount()
 221:       {
 222:         return 0;
 223:       }
 224: 
 225:       /**
 226:        * Returns the accessible child at index <code>i</code>. Table cells
 227:        * don't have children, so we return <code>null</code> here.
 228:        *
 229:        * @return <code>null</code>
 230:        */
 231:       public Accessible getAccessibleChild(int i)
 232:       {
 233:         return null;
 234:       }
 235: 
 236:       /**
 237:        * Returns the locale setting for this accessible table cell.
 238:        *
 239:        * @return the locale setting for this accessible table cell
 240:        */
 241:       public Locale getLocale()
 242:       {
 243:         // TODO: For now, we return english here. This must be fixed as soon
 244:         // as we have a localized Swing.
 245:         return Locale.ENGLISH;
 246:       }
 247: 
 248:       /**
 249:        * Returns the accessible context of this table cell. Since accessible
 250:        * table cells are their own accessible context, we return
 251:        * <code>this</code>.
 252:        *
 253:        * @return the accessible context of this table cell
 254:        */
 255:       public AccessibleContext getAccessibleContext()
 256:       {
 257:         return this;
 258:       }
 259: 
 260:       /**
 261:        * Returns the background color of this cell.
 262:        *
 263:        * @return the background color of this cell
 264:        */
 265:       public Color getBackground()
 266:       {
 267:         return table.getBackground();
 268:       }
 269: 
 270:       /**
 271:        * Sets the background of the cell. Since table cells cannot have
 272:        * individual background colors, this method does nothing. Set the
 273:        * background directly on the table instead.
 274:        * 
 275:        * @param color not used
 276:        */
 277:       public void setBackground(Color color)
 278:       {
 279:         // This method does nothing. See API comments.
 280:       }
 281: 
 282:       /**
 283:        * Returns the foreground color of the table cell.
 284:        *
 285:        * @return the foreground color of the table cell
 286:        */
 287:       public Color getForeground()
 288:       {
 289:         return table.getForeground();
 290:       }
 291: 
 292:       /**
 293:        * Sets the foreground of the cell. Since table cells cannot have
 294:        * individual foreground colors, this method does nothing. Set the
 295:        * foreground directly on the table instead.
 296:        * 
 297:        * @param color not used
 298:        */
 299:       public void setForeground(Color color)
 300:       {
 301:         // This method does nothing. See API comments.
 302:       }
 303: 
 304:       /**
 305:        * Returns the cursor for this table cell.
 306:        *
 307:        * @return the cursor for this table cell
 308:        */
 309:       public Cursor getCursor()
 310:       {
 311:         return table.getCursor();
 312:       }
 313: 
 314:       /**
 315:        * Sets the cursor of the cell. Since table cells cannot have
 316:        * individual cursors, this method does nothing. Set the
 317:        * cursor directly on the table instead.
 318:        * 
 319:        * @param cursor not used
 320:        */
 321:       public void setCursor(Cursor cursor)
 322:       {
 323:         // This method does nothing. See API comments.
 324:       }
 325: 
 326:       /**
 327:        * Returns the font of the table cell.
 328:        *
 329:        * @return the font of the table cell
 330:        */
 331:       public Font getFont()
 332:       {
 333:         return table.getFont();
 334:       }
 335: 
 336:       /**
 337:        * Sets the font of the cell. Since table cells cannot have
 338:        * individual fonts, this method does nothing. Set the
 339:        * font directly on the table instead.
 340:        * 
 341:        * @param font not used
 342:        */
 343:       public void setFont(Font font)
 344:       {
 345:         // This method does nothing. See API comments.
 346:       }
 347: 
 348:       /**
 349:        * Returns the font metrics for a specified font.
 350:        *
 351:        * @param font the font for which we return the metrics
 352:        *
 353:        * @return the font metrics for a specified font
 354:        */
 355:       public FontMetrics getFontMetrics(Font font)
 356:       {
 357:         return table.getFontMetrics(font);
 358:       }
 359: 
 360:       /**
 361:        * Returns <code>true</code> if this table cell is enabled,
 362:        * <code>false</code> otherwise.
 363:        *
 364:        * @return <code>true</code> if this table cell is enabled,
 365:        *         <code>false</code> otherwise
 366:        */
 367:       public boolean isEnabled()
 368:       {
 369:         return table.isEnabled();
 370:       }
 371: 
 372:       /**
 373:        * Table cells cannot be disabled or enabled individually, so this method
 374:        * does nothing. Set the enabled flag on the table itself.
 375:        *
 376:        * @param b not used here
 377:        */
 378:       public void setEnabled(boolean b)
 379:       {
 380:         // This method does nothing. See API comments.
 381:       }
 382: 
 383:       /**
 384:        * Returns <code>true</code> if this cell is visible, <code>false</code>
 385:        * otherwise.
 386:        *
 387:        * @return <code>true</code> if this cell is visible, <code>false</code>
 388:        *         otherwise
 389:        */
 390:       public boolean isVisible()
 391:       {
 392:         return table.isVisible();
 393:       }
 394: 
 395:       /**
 396:        * The visibility cannot be set on individual table cells, so this method
 397:        * does nothing. Set the visibility on the table itself.
 398:        *
 399:        * @param b not used
 400:        */
 401:       public void setVisible(boolean b)
 402:       {
 403:         // This method does nothing. See API comments.
 404:       }
 405: 
 406:       /**
 407:        * Returns <code>true</code> if this table cell is currently showing on
 408:        * screen.
 409:        *
 410:        * @return <code>true</code> if this table cell is currently showing on
 411:        *         screen
 412:        */
 413:       public boolean isShowing()
 414:       {
 415:         return table.isShowing();
 416:       }
 417: 
 418:       /**
 419:        * Returns <code>true</code> if this table cell contains the location
 420:        * at <code>point</code>, <code>false</code> otherwise.
 421:        * <code>point</code> is interpreted as relative to the coordinate system
 422:        * of the table cell.
 423:        *
 424:        * @return <code>true</code> if this table cell contains the location
 425:        *         at <code>point</code>, <code>false</code> otherwise
 426:        */
 427:       public boolean contains(Point point)
 428:       {
 429:         Rectangle cellRect = table.getCellRect(row, column, true);
 430:         cellRect.x = 0;
 431:         cellRect.y = 0;
 432:         return cellRect.contains(point);
 433:       }
 434: 
 435:       /**
 436:        * Returns the screen location of the table cell.
 437:        *
 438:        * @return the screen location of the table cell
 439:        */
 440:       public Point getLocationOnScreen()
 441:       {
 442:         Point tableLoc = table.getLocationOnScreen();
 443:         Rectangle cellRect = table.getCellRect(row, column, true);
 444:         tableLoc.x += cellRect.x;
 445:         tableLoc.y += cellRect.y;
 446:         return tableLoc;
 447:       }
 448: 
 449:       /**
 450:        * Returns the location of this cell relative to the table's bounds.
 451:        *
 452:        * @return the location of this cell relative to the table's bounds
 453:        */
 454:       public Point getLocation()
 455:       {
 456:         Rectangle cellRect = table.getCellRect(row, column, true);
 457:         return new Point(cellRect.x, cellRect.y);
 458:       }
 459: 
 460:       /**
 461:        * The location of the table cells cannot be manipulated directly, so
 462:        * this method does nothing.
 463:        *
 464:        * @param point not used
 465:        */
 466:       public void setLocation(Point point)
 467:       {
 468:         // This method does nothing. See API comments.
 469:       }
 470: 
 471:       /**
 472:        * Returns the bounds of the cell relative to its table.
 473:        *
 474:        * @return the bounds of the cell relative to its table
 475:        */
 476:       public Rectangle getBounds()
 477:       {
 478:         return table.getCellRect(row, column, true);
 479:       }
 480: 
 481:       /**
 482:        * The bounds of the table cells cannot be manipulated directly, so
 483:        * this method does nothing.
 484:        *
 485:        * @param rectangle not used
 486:        */
 487:       public void setBounds(Rectangle rectangle)
 488:       {
 489:         // This method does nothing. See API comments.
 490:       }
 491: 
 492:       /**
 493:        * Returns the size of the table cell.
 494:        *
 495:        * @return the size of the table cell
 496:        */
 497:       public Dimension getSize()
 498:       {
 499:         Rectangle cellRect = table.getCellRect(row, column, true);
 500:         return new Dimension(cellRect.width, cellRect.height);
 501:       }
 502: 
 503:       /**
 504:        * The size cannot be set on table cells directly, so this method does
 505:        * nothing.
 506:        *
 507:        * @param dimension not used
 508:        */
 509:       public void setSize(Dimension dimension)
 510:       {
 511:         // This method does nothing. See API comments.
 512:       }
 513: 
 514:       /**
 515:        * Table cells have no children, so we return <code>null</code> here.
 516:        *
 517:        * @return <code>null</code>
 518:        */
 519:       public Accessible getAccessibleAt(Point point)
 520:       {
 521:         return null;
 522:       }
 523: 
 524:       /**
 525:        * Returns <code>true</code> if this table cell is focus traversable,
 526:        * <code>false</code> otherwise.
 527:        *
 528:        * @return <code>true</code> if this table cell is focus traversable,
 529:        *         <code>false</code> otherwise
 530:        */
 531:       public boolean isFocusTraversable()
 532:       {
 533:         return table.isFocusable();
 534:       }
 535: 
 536:       /**
 537:        * Requests that this table cell gets the keyboard focus.
 538:        */
 539:       public void requestFocus()
 540:       {
 541:         // We first set the selection models' lead selection to this cell.
 542:         table.getColumnModel().getSelectionModel()
 543:         .setLeadSelectionIndex(column);
 544:         table.getSelectionModel().setLeadSelectionIndex(row);
 545:         // Now we request that the table receives focus.
 546:         table.requestFocus();
 547:       }
 548: 
 549:       /**
 550:        * Adds a focus listener to this cell. The focus listener is really
 551:        * added to the table, so there is no way to find out when an individual
 552:        * cell changes the focus.
 553:        *
 554:        * @param listener the focus listener to add
 555:        */
 556:       public void addFocusListener(FocusListener listener)
 557:       {
 558:         table.addFocusListener(listener);
 559:       }
 560: 
 561:       /**
 562:        * Removes a focus listener from the cell. The focus listener is really
 563:        * removed from the table.
 564:        *
 565:        * @param listener the listener to remove
 566:        */
 567:       public void removeFocusListener(FocusListener listener)
 568:       {
 569:         table.removeFocusListener(listener);
 570:       }
 571:         
 572:     }
 573: 
 574:     protected class AccessibleJTableModelChange
 575:       implements AccessibleTableModelChange
 576:     {
 577:       protected int type;
 578:       protected int firstRow;
 579:       protected int lastRow;
 580:       protected int firstColumn;
 581:       protected int lastColumn;
 582: 
 583:       protected AccessibleJTableModelChange(int type, int firstRow,
 584:                                             int lastRow, int firstColumn,
 585:                                             int lastColumn)
 586:       {
 587:         this.type = type;
 588:         this.firstRow = firstRow;
 589:         this.lastRow = lastRow;
 590:         this.firstColumn = firstColumn;
 591:         this.lastColumn = lastColumn;
 592:       }
 593: 
 594:       public int getType()
 595:       {
 596:         return type;
 597:       }
 598: 
 599:       public int getFirstRow()
 600:       {
 601:         return firstRow;
 602:       }
 603: 
 604:       public int getLastRow()
 605:       {
 606:         return lastRow;
 607:       }
 608: 
 609:       public int getFirstColumn()
 610:       {
 611:         return firstColumn;
 612:       }
 613: 
 614:       public int getLastColumn()
 615:       {
 616:         return lastColumn;
 617:       }
 618:     }
 619: 
 620:     /**
 621:      * The RI returns an instance with this name in
 622:      * {@link #getAccessibleColumnHeader()}, this makes sense, so we do the
 623:      * same.
 624:      */
 625:     private class AccessibleTableHeader
 626:       implements AccessibleTable
 627:     {
 628: 
 629:       /**
 630:        * The JTableHeader wrapped by this class.
 631:        */
 632:       private JTableHeader header;
 633: 
 634:       /**
 635:        * Creates a new instance.
 636:        *
 637:        * @param h the JTableHeader to wrap
 638:        */
 639:       private AccessibleTableHeader(JTableHeader h)
 640:       {
 641:         header = h;
 642:       }
 643: 
 644:       /**
 645:        * Returns the caption for the table header.
 646:        *
 647:        * @return the caption for the table header
 648:        */
 649:       public Accessible getAccessibleCaption()
 650:       {
 651:         // The RI seems to always return null here, so do we.
 652:         return null;
 653:       }
 654: 
 655:       /**
 656:        * Sets the caption for the table header.
 657:        *
 658:        * @param caption the caption to set
 659:        */
 660:       public void setAccessibleCaption(Accessible caption)
 661:       {
 662:         // This seems to be a no-op in the RI, so we do the same.
 663:       }
 664: 
 665:       /**
 666:        * Returns the caption for the table header.
 667:        *
 668:        * @return the caption for the table header
 669:        */
 670:       public Accessible getAccessibleSummary()
 671:       {
 672:         // The RI seems to always return null here, so do we.
 673:         return null;
 674:       }
 675: 
 676:       /**
 677:        * Sets the summary for the table header.
 678:        *
 679:        * @param summary the caption to set
 680:        */
 681:       public void setAccessibleSummary(Accessible summary)
 682:       {
 683:         // This seems to be a no-op in the RI, so we do the same.
 684:       }
 685: 
 686:       /**
 687:        * Returns the number of rows, which is always 1 for the table header.
 688:        *
 689:        * @return the number of rows
 690:        */
 691:       public int getAccessibleRowCount()
 692:       {
 693:         return 1;
 694:       }
 695: 
 696:       /**
 697:        * Returns the number of columns in the table header.
 698:        *
 699:        * @return the number of columns in the table header
 700:        */
 701:       public int getAccessibleColumnCount()
 702:       {
 703:         return header.getColumnModel().getColumnCount();
 704:       }
 705: 
 706:       /**
 707:        * Returns the accessible child at the specified row and column.
 708:        * The row number is ignored here, and we return an
 709:        * AccessibleJTableHeaderCell here with the renderer component as
 710:        * component.
 711:        *
 712:        * @param r the row number
 713:        * @param c the column number
 714:        *
 715:        * @return the accessible child at the specified row and column
 716:        */
 717:       public Accessible getAccessibleAt(int r, int c)
 718:       {
 719:         TableColumn column = header.getColumnModel().getColumn(c);
 720:         TableCellRenderer rend = column.getHeaderRenderer();
 721:         if (rend == null)
 722:           rend = header.getDefaultRenderer();
 723:         Component comp =
 724:           rend.getTableCellRendererComponent(header.getTable(),
 725:                                              column.getHeaderValue(), false,
 726:                                              false, -1, c);
 727:         return new AccessibleJTableHeaderCell(header, comp, r, c);
 728:       }
 729: 
 730:       public int getAccessibleRowExtentAt(int r, int c)
 731:       {
 732:         // TODO Auto-generated method stub
 733:         return 0;
 734:       }
 735: 
 736:       public int getAccessibleColumnExtentAt(int r, int c)
 737:       {
 738:         // TODO Auto-generated method stub
 739:         return 0;
 740:       }
 741: 
 742:       public AccessibleTable getAccessibleRowHeader()
 743:       {
 744:         // TODO Auto-generated method stub
 745:         return null;
 746:       }
 747: 
 748:       public void setAccessibleRowHeader(AccessibleTable header)
 749:       {
 750:         // TODO Auto-generated method stub
 751:         
 752:       }
 753: 
 754:       public AccessibleTable getAccessibleColumnHeader()
 755:       {
 756:         // TODO Auto-generated method stub
 757:         return null;
 758:       }
 759: 
 760:       public void setAccessibleColumnHeader(AccessibleTable header)
 761:       {
 762:         // TODO Auto-generated method stub
 763:         
 764:       }
 765: 
 766:       public Accessible getAccessibleRowDescription(int r)
 767:       {
 768:         // TODO Auto-generated method stub
 769:         return null;
 770:       }
 771: 
 772:       public void setAccessibleRowDescription(int r, Accessible description)
 773:       {
 774:         // TODO Auto-generated method stub
 775:         
 776:       }
 777: 
 778:       public Accessible getAccessibleColumnDescription(int c)
 779:       {
 780:         // TODO Auto-generated method stub
 781:         return null;
 782:       }
 783: 
 784:       public void setAccessibleColumnDescription(int c, Accessible description)
 785:       {
 786:         // TODO Auto-generated method stub
 787:         
 788:       }
 789: 
 790:       public boolean isAccessibleSelected(int r, int c)
 791:       {
 792:         // TODO Auto-generated method stub
 793:         return false;
 794:       }
 795: 
 796:       public boolean isAccessibleRowSelected(int r)
 797:       {
 798:         // TODO Auto-generated method stub
 799:         return false;
 800:       }
 801: 
 802:       public boolean isAccessibleColumnSelected(int c)
 803:       {
 804:         // TODO Auto-generated method stub
 805:         return false;
 806:       }
 807: 
 808:       public int[] getSelectedAccessibleRows()
 809:       {
 810:         // TODO Auto-generated method stub
 811:         return null;
 812:       }
 813: 
 814:       public int[] getSelectedAccessibleColumns()
 815:       {
 816:         // TODO Auto-generated method stub
 817:         return null;
 818:       }
 819:         
 820:     }
 821: 
 822:     /**
 823:      * The RI returns an instance of such class for table header cells. This
 824:      * makes sense so I added this class. This still needs to be fully
 825:      * implemented, I just don't feel motivated enough to do so just now.
 826:      */
 827:     private class AccessibleJTableHeaderCell
 828:       extends AccessibleContext
 829:       implements Accessible, AccessibleComponent
 830:     {
 831: 
 832:       JTableHeader header;
 833:       
 834:       int columnIndex;
 835:       
 836:       /**
 837:        * 
 838:        * @param h  the table header.
 839:        * @param comp
 840:        * @param r
 841:        * @param c  the column index.
 842:        */
 843:       private AccessibleJTableHeaderCell(JTableHeader h, Component comp, int r,
 844:                                          int c)
 845:       {
 846:         header = h;
 847:         columnIndex = c;
 848:       }
 849: 
 850:       /**
 851:        * Returns the header renderer.
 852:        * 
 853:        * @return The header renderer.
 854:        */
 855:       Component getColumnHeaderRenderer()
 856:       {
 857:         TableColumn tc = header.getColumnModel().getColumn(columnIndex);
 858:         TableCellRenderer r = tc.getHeaderRenderer();
 859:         if (r == null)
 860:           r = header.getDefaultRenderer();
 861:         return r.getTableCellRendererComponent(header.getTable(), 
 862:             tc.getHeaderValue(), false, false, -1, columnIndex);
 863:       }
 864:       
 865:       /**
 866:        * Returns the accessible role for the table header cell.
 867:        * 
 868:        * @return The accessible role.
 869:        */
 870:       public AccessibleRole getAccessibleRole()
 871:       {
 872:         Component renderer = getColumnHeaderRenderer();
 873:         if (renderer instanceof Accessible)
 874:           {
 875:             Accessible ac = (Accessible) renderer;
 876:             return ac.getAccessibleContext().getAccessibleRole();
 877:           }
 878:         return null;
 879:       }
 880: 
 881:       public AccessibleStateSet getAccessibleStateSet()
 882:       {
 883:         // TODO Auto-generated method stub
 884:         return null;
 885:       }
 886: 
 887:       public int getAccessibleIndexInParent()
 888:       {
 889:         // TODO Auto-generated method stub
 890:         return 0;
 891:       }
 892: 
 893:       public int getAccessibleChildrenCount()
 894:       {
 895:         // TODO Auto-generated method stub
 896:         return 0;
 897:       }
 898: 
 899:       public Accessible getAccessibleChild(int i)
 900:       {
 901:         // TODO Auto-generated method stub
 902:         return null;
 903:       }
 904: 
 905:       public Locale getLocale()
 906:       {
 907:         // TODO Auto-generated method stub
 908:         return null;
 909:       }
 910: 
 911:       /**
 912:        * Returns the accessible context.
 913:        * 
 914:        * @return <code>this</code>.
 915:        */
 916:       public AccessibleContext getAccessibleContext()
 917:       {
 918:         return this;
 919:       }
 920: 
 921:       public Color getBackground()
 922:       {
 923:         // TODO Auto-generated method stub
 924:         return null;
 925:       }
 926: 
 927:       public void setBackground(Color color)
 928:       {
 929:         // TODO Auto-generated method stub
 930:         
 931:       }
 932: 
 933:       public Color getForeground()
 934:       {
 935:         // TODO Auto-generated method stub
 936:         return null;
 937:       }
 938: 
 939:       public void setForeground(Color color)
 940:       {
 941:         // TODO Auto-generated method stub
 942:         
 943:       }
 944: 
 945:       public Cursor getCursor()
 946:       {
 947:         // TODO Auto-generated method stub
 948:         return null;
 949:       }
 950: 
 951:       public void setCursor(Cursor cursor)
 952:       {
 953:         // TODO Auto-generated method stub
 954:         
 955:       }
 956: 
 957:       public Font getFont()
 958:       {
 959:         // TODO Auto-generated method stub
 960:         return null;
 961:       }
 962: 
 963:       public void setFont(Font font)
 964:       {
 965:         // TODO Auto-generated method stub
 966:         
 967:       }
 968: 
 969:       public FontMetrics getFontMetrics(Font font)
 970:       {
 971:         // TODO Auto-generated method stub
 972:         return null;
 973:       }
 974: 
 975:       public boolean isEnabled()
 976:       {
 977:         // TODO Auto-generated method stub
 978:         return false;
 979:       }
 980: 
 981:       public void setEnabled(boolean b)
 982:       {
 983:         // TODO Auto-generated method stub
 984:         
 985:       }
 986: 
 987:       public boolean isVisible()
 988:       {
 989:         // TODO Auto-generated method stub
 990:         return false;
 991:       }
 992: 
 993:       public void setVisible(boolean b)
 994:       {
 995:         // TODO Auto-generated method stub
 996:         
 997:       }
 998: 
 999:       public boolean isShowing()
1000:       {
1001:         // TODO Auto-generated method stub
1002:         return false;
1003:       }
1004: 
1005:       public boolean contains(Point point)
1006:       {
1007:         // TODO Auto-generated method stub
1008:         return false;
1009:       }
1010: 
1011:       public Point getLocationOnScreen()
1012:       {
1013:         // TODO Auto-generated method stub
1014:         return null;
1015:       }
1016: 
1017:       public Point getLocation()
1018:       {
1019:         // TODO Auto-generated method stub
1020:         return null;
1021:       }
1022: 
1023:       public void setLocation(Point point)
1024:       {
1025:         // TODO Auto-generated method stub
1026:         
1027:       }
1028: 
1029:       public Rectangle getBounds()
1030:       {
1031:         // TODO Auto-generated method stub
1032:         return null;
1033:       }
1034: 
1035:       public void setBounds(Rectangle rectangle)
1036:       {
1037:         // TODO Auto-generated method stub
1038:         
1039:       }
1040: 
1041:       public Dimension getSize()
1042:       {
1043:         // TODO Auto-generated method stub
1044:         return null;
1045:       }
1046: 
1047:       public void setSize(Dimension dimension)
1048:       {
1049:         // TODO Auto-generated method stub
1050:         
1051:       }
1052: 
1053:       public Accessible getAccessibleAt(Point point)
1054:       {
1055:         // TODO Auto-generated method stub
1056:         return null;
1057:       }
1058: 
1059:       public boolean isFocusTraversable()
1060:       {
1061:         // TODO Auto-generated method stub
1062:         return false;
1063:       }
1064: 
1065:       public void requestFocus()
1066:       {
1067:         // TODO Auto-generated method stub
1068:         
1069:       }
1070: 
1071:       public void addFocusListener(FocusListener listener)
1072:       {
1073:         // TODO Auto-generated method stub
1074:         
1075:       }
1076: 
1077:       public void removeFocusListener(FocusListener listener)
1078:       {
1079:         // TODO Auto-generated method stub
1080:         
1081:       }
1082:       
1083:     }
1084: 
1085:     /**
1086:      * The last selected row. This is needed to track the selection in
1087:      * {@link #valueChanged(ListSelectionEvent)}.
1088:      */
1089:     private int lastSelectedRow;
1090: 
1091:     /**
1092:      * The last selected column. This is needed to track the selection in
1093:      * {@link #valueChanged(ListSelectionEvent)}.
1094:      */
1095:     private int lastSelectedColumn;
1096: 
1097:     /**
1098:      * The caption of the table.
1099:      */
1100:     private Accessible caption;
1101: 
1102:     /**
1103:      * The summary of the table.
1104:      */
1105:     private Accessible summary;
1106: 
1107:     /**
1108:      * Accessible descriptions for rows.
1109:      */
1110:     private Accessible[] rowDescriptions;
1111: 
1112:     /**
1113:      * Accessible descriptions for columns.
1114:      */
1115:     private Accessible[] columnDescriptions;
1116: 
1117:     /**
1118:      * Creates a new <code>AccessibleJTable</code>.
1119:      *
1120:      * @since JDK1.5
1121:      */
1122:     protected AccessibleJTable()
1123:     {
1124:       getModel().addTableModelListener(this);
1125:       getSelectionModel().addListSelectionListener(this);
1126:       getColumnModel().addColumnModelListener(this);
1127:       lastSelectedRow = getSelectedRow();
1128:       lastSelectedColumn = getSelectedColumn();
1129:       TableCellEditor editor = getCellEditor();
1130:       if (editor != null)
1131:         editor.addCellEditorListener(this);
1132:     }
1133: 
1134:     /**
1135:      * Returns the accessible role for the <code>JTable</code> component.
1136:      *
1137:      * @return {@link AccessibleRole#TABLE}.
1138:      */
1139:     public AccessibleRole getAccessibleRole()
1140:     {
1141:       return AccessibleRole.TABLE;
1142:     }
1143:     
1144:     /**
1145:      * Returns the accessible table.
1146:      * 
1147:      * @return <code>this</code>.
1148:      */
1149:     public AccessibleTable getAccessibleTable()
1150:     {
1151:       return this;
1152:     }
1153:     
1154:     /**
1155:      * Returns the number of selected items in this table.
1156:      */
1157:     public int getAccessibleSelectionCount()
1158:     {
1159:       return getSelectedColumnCount();
1160:     }
1161: 
1162:     /**
1163:      * Returns the selected accessible object with the specified index
1164:      * <code>i</code>. This basically returns the i-th selected cell in the
1165:      * table when going though it row-wise, and inside the rows, column-wise.
1166:      *
1167:      * @param i the index of the selected object to find
1168:      *
1169:      * @return the selected accessible object with the specified index
1170:      *         <code>i</code>
1171:      */
1172:     public Accessible getAccessibleSelection(int i)
1173:     {
1174:       Accessible found = null;
1175: 
1176:       int[] selectedRows = getSelectedRows();
1177:       int[] selectedColumns = getSelectedColumns();
1178:       int numCols = getColumnCount();
1179:       int numRows = getRowCount();
1180: 
1181:       // We have to go through every selected row and column and count until we
1182:       // find the specified index. This is potentially inefficient, but I can't
1183:       // think of anything better atm.
1184:       if (getRowSelectionAllowed() && getColumnSelectionAllowed())
1185:         {
1186:           int current = -1;
1187:           int newIndex = current;
1188:           int lastSelectedRow = -1;
1189:           // Go through the selected rows array, don't forget the selected
1190:           // cells inside the not-selected rows' columns.
1191:           for (int j = 0; i < selectedRows.length; i++)
1192:             {
1193:               // Handle unselected rows between this selected and the last
1194:               // selected row, if any.
1195:               int selectedRow = selectedRows[j];
1196:               int r = -1;
1197:               int ci = -1;
1198:               for (r = lastSelectedRow + 1;
1199:                    r < selectedRow && current < i; r++)
1200:                 {
1201:                   for (ci = 0; ci < selectedColumns.length && current < i;
1202:                        ci++)
1203:                     {
1204:                       current++;
1205:                     }
1206:                 }
1207:               if (current == i)
1208:                 {
1209:                   // We found the cell in the above loops, now get out of here.
1210:                   found = getAccessibleChild(r * numCols
1211:                                              + selectedColumns[ci]);
1212:                   break;
1213:                 }
1214: 
1215:               // If we're still here, handle the current selected row.
1216:               if (current < i && current + numCols >= i)
1217:                 {
1218:                   // The cell must be in that row, which one is it?
1219:                   found = getAccessibleChild(r * numCols + (i - current));
1220:                   break;
1221:                 }
1222:               current += numCols;
1223:             }
1224:           if (found == null)
1225:             {
1226:               // The cell can still be in the last couple of unselected rows.
1227:               int r = 0;
1228:               int ci = 0;
1229:               for (r = lastSelectedRow + 1;
1230:                    r < numRows && current < i; r++)
1231:                 {
1232:                   for (ci = 0; ci < selectedColumns.length && current < i;
1233:                        ci++)
1234:                     {
1235:                       current++;
1236:                     }
1237:                 }
1238:               if (current == i)
1239:                 {
1240:                   // We found the cell in the above loops, now get out of here.
1241:                   found = getAccessibleChild(r * numCols
1242:                                              + selectedColumns[ci]);
1243:                 }
1244:             }
1245:         }
1246:       // One or more rows can be completely selected.
1247:       else if (getRowSelectionAllowed())
1248:         {
1249:           int c = i % numCols;
1250:           int r = selectedRows[i / numCols];
1251:           found = getAccessibleChild(r * numCols + c);
1252:         }
1253:       // One or more columns can be completely selected.
1254:       else if (getRowSelectionAllowed())
1255:         {
1256:           int numSelectedColumns = selectedColumns.length;
1257:           int c = selectedColumns[i % numSelectedColumns];
1258:           int r = i / numSelectedColumns;
1259:           found = getAccessibleChild(r * numCols + c);
1260:         }
1261: 
1262:       return found;
1263:     }
1264: 
1265:     /**
1266:      * Returns <code>true</code> if the accessible child with the index
1267:      * <code>i</code> is selected, <code>false</code> otherwise.
1268:      *
1269:      * @param i the index of the accessible to check
1270:      *
1271:      * @return <code>true</code> if the accessible child with the index
1272:      *         <code>i</code> is selected, <code>false</code> otherwise
1273:      */
1274:     public boolean isAccessibleChildSelected(int i)
1275:     {
1276:       int r = getAccessibleRowAtIndex(i);
1277:       int c = getAccessibleColumnAtIndex(i);
1278:       return isCellSelected(r, c);
1279:     }
1280: 
1281:     /**
1282:      * Adds the accessible child with the specified index <code>i</code> to the
1283:      * selection.
1284:      *
1285:      * @param i the index of the accessible child to add to the selection
1286:      */
1287:     public void addAccessibleSelection(int i)
1288:     {
1289:       int r = getAccessibleRowAtIndex(i);
1290:       int c = getAccessibleColumnAtIndex(i);
1291:       changeSelection(r, c, true, false);
1292:     }
1293: 
1294:     /**
1295:      * Removes the accessible child with the specified index <code>i</code>
1296:      * from the current selection. This will only work on tables that have
1297:      * cell selection enabled (<code>rowSelectionAllowed == false &&
1298:      * columnSelectionAllowed == false</code>).
1299:      *
1300:      * @param i the index of the accessible to be removed from the selection
1301:      */
1302:     public void removeAccessibleSelection(int i)
1303:     {
1304:       if (! getRowSelectionAllowed() && ! getColumnSelectionAllowed())
1305:         {
1306:           int r = getAccessibleRowAtIndex(i);
1307:           int c = getAccessibleColumnAtIndex(i);
1308:           removeRowSelectionInterval(r, r);
1309:           removeColumnSelectionInterval(c, c);
1310:         }
1311:     }
1312: 
1313:     /**
1314:      * Deselects all selected accessible children.
1315:      */
1316:     public void clearAccessibleSelection()
1317:     {
1318:       clearSelection();
1319:     }
1320: 
1321:     /**
1322:      * Selects all accessible children that can be selected. This will only
1323:      * work on tables that support multiple selections and that have individual
1324:      * cell selection enabled.
1325:      */
1326:     public void selectAllAccessibleSelection()
1327:     {
1328:       selectAll();
1329:     }
1330: 
1331:     /**
1332:      * Receives notification when the row selection changes and fires
1333:      * appropriate property change events.
1334:      *
1335:      * @param event the list selection event
1336:      */
1337:     public void valueChanged(ListSelectionEvent event)
1338:     {
1339:       firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
1340:                          Boolean.FALSE, Boolean.TRUE);
1341:       int r = getSelectedRow();
1342:       int c = getSelectedColumn();
1343:       if (r != lastSelectedRow || c != lastSelectedColumn)
1344:         {
1345:           Accessible o = getAccessibleAt(lastSelectedRow,
1346:                                          lastSelectedColumn);
1347:           Accessible n = getAccessibleAt(r, c);
1348:           firePropertyChange(AccessibleContext
1349:                              .ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY, o, n);
1350:           lastSelectedRow = r;
1351:           lastSelectedColumn = c;
1352:         }
1353:     }
1354: 
1355:     /**
1356:      * Receives notification when the table model changes. Depending on the
1357:      * type of change, this method calls {@link #tableRowsInserted} or
1358:      * {@link #tableRowsDeleted}.
1359:      *
1360:      * @param event the table model event
1361:      */
1362:     public void tableChanged(TableModelEvent event)
1363:     {
1364:       switch (event.getType())
1365:         {
1366:         case TableModelEvent.INSERT:
1367:           tableRowsInserted(event);
1368:           break;
1369:         case TableModelEvent.DELETE:
1370:           tableRowsDeleted(event);
1371:           break;
1372:         }
1373:     }
1374: 
1375:     /**
1376:      * Receives notification when one or more rows have been inserted into the
1377:      * table and fires appropriate property change events.
1378:      *
1379:      * @param event the table model event
1380:      */
1381:     public void tableRowsInserted(TableModelEvent event)
1382:     {
1383:       handleRowChange(event);
1384:     }
1385: 
1386:     /**
1387:      * Receives notification when one or more rows have been deleted from the
1388:      * table.
1389:      *
1390:      * @param event the table model event
1391:      */
1392:     public void tableRowsDeleted(TableModelEvent event)
1393:     {
1394:       handleRowChange(event);
1395:     }
1396: 
1397:     /**
1398:      * Fires a PropertyChangeEvent for inserted or deleted rows.
1399:      *
1400:      * @param event the table model event
1401:      */
1402:     private void handleRowChange(TableModelEvent event)
1403:     {
1404:       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1405:                          null, null);
1406:       int firstColumn = event.getColumn();
1407:       int lastColumn = event.getColumn();
1408:       if (firstColumn == TableModelEvent.ALL_COLUMNS)
1409:         {
1410:           firstColumn = 0;
1411:           lastColumn = getColumnCount() - 1;
1412:         }
1413:       AccessibleJTableModelChange change = new AccessibleJTableModelChange
1414:          (event.getType(), event.getFirstRow(), event.getLastRow(),
1415:           firstColumn, lastColumn);
1416:       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
1417:                          null, change);
1418:     }
1419: 
1420:     public void columnAdded(TableColumnModelEvent event)
1421:     {
1422:       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1423:                          null, null);
1424:       handleColumnChange(AccessibleTableModelChange.INSERT,
1425:                          event.getFromIndex(), event.getToIndex());
1426:     }
1427: 
1428:     public void columnRemoved(TableColumnModelEvent event)
1429:     {
1430:       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1431:                          null, null);
1432:       handleColumnChange(AccessibleTableModelChange.DELETE,
1433:                          event.getFromIndex(), event.getToIndex());
1434:     }
1435: 
1436:     public void columnMoved(TableColumnModelEvent event)
1437:     {
1438:       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1439:                          null, null);
1440:       handleColumnChange(AccessibleTableModelChange.DELETE,
1441:                          event.getFromIndex(), event.getFromIndex());
1442:       handleColumnChange(AccessibleTableModelChange.INSERT,
1443:                          event.getFromIndex(), event.getToIndex());
1444:     }
1445: 
1446:     /**
1447:      * Fires a PropertyChangeEvent for inserted or deleted columns.
1448:      *
1449:      * @param type the type of change
1450:      * @param from the start of the change
1451:      * @param to the target of the change
1452:      */
1453:     private void handleColumnChange(int type, int from, int to)
1454:     {
1455:       AccessibleJTableModelChange change =
1456:         new AccessibleJTableModelChange(type, 0, 0, from, to);
1457:       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
1458:                          null, change);
1459:     }
1460: 
1461:     public void columnMarginChanged(ChangeEvent event)
1462:     {
1463:       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1464:                          null, null);
1465:     }
1466: 
1467:     public void columnSelectionChanged(ListSelectionEvent event)
1468:     {
1469:       // AFAICS, nothing is done here.
1470:     }
1471: 
1472:     public void editingCanceled(ChangeEvent event)
1473:     {
1474:       // AFAICS, nothing is done here.
1475:     }
1476: 
1477:     public void editingStopped(ChangeEvent event)
1478:     {
1479:       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1480:                          null, null);
1481:     }
1482: 
1483:     /**
1484:      * Receives notification when any of the JTable's properties changes. This
1485:      * is used to replace the listeners on the table's model, selection model,
1486:      * column model and cell editor.
1487:      *
1488:      * @param e the property change event
1489:      */
1490:     public void propertyChange(PropertyChangeEvent e)
1491:     {
1492:       String propName = e.getPropertyName(); 
1493:       if (propName.equals("tableModel"))
1494:         {
1495:           TableModel oldModel = (TableModel) e.getOldValue();
1496:           oldModel.removeTableModelListener(this);
1497:           TableModel newModel = (TableModel) e.getNewValue();
1498:           newModel.addTableModelListener(this);
1499:         }
1500:       else if (propName.equals("columnModel"))
1501:         {
1502:           TableColumnModel oldModel = (TableColumnModel) e.getOldValue();
1503:           oldModel.removeColumnModelListener(this);
1504:           TableColumnModel newModel = (TableColumnModel) e.getNewValue();
1505:           newModel.addColumnModelListener(this);
1506:         }
1507:       else if (propName.equals("selectionModel"))
1508:         {
1509:           ListSelectionModel oldModel = (ListSelectionModel) e.getOldValue();
1510:           oldModel.removeListSelectionListener(this);
1511:           ListSelectionModel newModel = (ListSelectionModel) e.getNewValue();
1512:           newModel.addListSelectionListener(this);
1513:         }
1514:       else if (propName.equals("cellEditor"))
1515:         {
1516:           CellEditor oldEd = (CellEditor) e.getOldValue();
1517:           oldEd.removeCellEditorListener(this);
1518:           CellEditor newEd = (CellEditor) e.getNewValue();
1519:           newEd.addCellEditorListener(this);
1520:         }
1521:     }
1522: 
1523:     /**
1524:      * Returns the row number of an accessible child (cell) with the specified
1525:      * index.
1526:      *
1527:      * @param index the index of the cell of which the row number is queried
1528:      * 
1529:      * @return the row number of an accessible child (cell) with the specified
1530:      *         index 
1531:      */
1532:     public int getAccessibleRow(int index)
1533:     {
1534:       return getAccessibleRowAtIndex(index);
1535:     }
1536: 
1537:     /**
1538:      * Returns the column number of an accessible child (cell) with the
1539:      * specified index.
1540:      *
1541:      * @param index the index of the cell of which the column number is queried
1542:      * 
1543:      * @return the column number of an accessible child (cell) with the
1544:      *         specified index 
1545:      */
1546:     public int getAccessibleColumn(int index)
1547:     {
1548:       return getAccessibleColumnAtIndex(index);
1549:     }
1550: 
1551:     /**
1552:      * Returns the index of the accessible child at the specified row and
1553:      * column.
1554:      *
1555:      * @param r the row number
1556:      * @param c the column number
1557:      *
1558:      * @return the index of the accessible child at the specified row and
1559:      *         column
1560:      */
1561:     public int getAccessibleIndex(int r, int c)
1562:     {
1563:       return getAccessibleIndexAt(r, c);
1564:     }
1565: 
1566:     /**
1567:      * Returns the caption of the table.
1568:      *
1569:      * @return the caption of the table
1570:      *
1571:      * @see #setAccessibleCaption(Accessible)
1572:      */
1573:     public Accessible getAccessibleCaption()
1574:     {
1575:       return caption;
1576:     }
1577: 
1578:     /**
1579:      * Sets the caption for the table.
1580:      *
1581:      * @param c the caption to set
1582:      */
1583:     public void setAccessibleCaption(Accessible c)
1584:     {
1585:       caption = c;
1586:     }
1587: 
1588:     /**
1589:      * Returns the summary for the table.
1590:      *
1591:      * @return the summary for the table
1592:      */
1593:     public Accessible getAccessibleSummary()
1594:     {
1595:       return summary;
1596:     }
1597: 
1598:     /**
1599:      * Sets the summary for the table.
1600:      *
1601:      * @param s the summary to set
1602:      */
1603:     public void setAccessibleSummary(Accessible s)
1604:     {
1605:       summary = s;
1606:     }
1607: 
1608:     /**
1609:      * Returns the number of rows in the table.
1610:      *
1611:      * @return the number of rows in the table
1612:      */
1613:     public int getAccessibleRowCount()
1614:     {
1615:       return getRowCount();
1616:     }
1617: 
1618:     /**
1619:      * Returns the number of columns in the table.
1620:      *
1621:      * @return the number of columns in the table
1622:      */
1623:     public int getAccessibleColumnCount()
1624:     {
1625:       return getColumnCount();
1626:     }
1627: 
1628:     /**
1629:      * Returns the accessible child at the given index.
1630:      *
1631:      * @param index  the child index.
1632:      * 
1633:      * @return The accessible child.
1634:      */
1635:     public Accessible getAccessibleChild(int index)
1636:     {
1637:       int r = getAccessibleRow(index);
1638:       int c = getAccessibleColumn(index);
1639:       return getAccessibleAt(r, c);  
1640:     }
1641:     
1642:     /**
1643:      * Returns the accessible child (table cell) at the specified row and
1644:      * column.
1645:      *
1646:      * @param r the row number
1647:      * @param c the column number
1648:      *
1649:      * @return the accessible child (table cell) at the specified row and
1650:      *         column
1651:      */
1652:     public Accessible getAccessibleAt(int r, int c)
1653:     {
1654:       TableCellRenderer cellRenderer = getCellRenderer(r, c);
1655:       Component renderer = cellRenderer.getTableCellRendererComponent(
1656:           JTable.this, getValueAt(r, c), isCellSelected(r, c), false, r, c);
1657:       if (renderer instanceof Accessible)
1658:         return (Accessible) renderer;
1659:       return null;
1660:     }
1661: 
1662:     /**
1663:      * Returns the number of rows that the specified cell occupies. The
1664:      * standard table cells only occupy one row, so we return <code>1</code>
1665:      * here.
1666:      *
1667:      * @param r the row number
1668:      * @param c the column number
1669:      *
1670:      * @return the number of rows that the specified cell occupies
1671:      */
1672:     public int getAccessibleRowExtentAt(int r, int c)
1673:     {
1674:       return 1;
1675:     }
1676: 
1677:     /**
1678:      * Returns the number of columns that the specified cell occupies. The
1679:      * standard table cells only occupy one column, so we return <code>1</code>
1680:      * here.
1681:      *
1682:      * @param r the row number
1683:      * @param c the column number
1684:      *
1685:      * @return the number of rows that the specified cell occupies
1686:      */
1687:     public int getAccessibleColumnExtentAt(int r, int c)
1688:     {
1689:       return 1;
1690:     }
1691: 
1692:     /**
1693:      * Returns the accessible row header.
1694:      *
1695:      * @return the accessible row header
1696:      */
1697:     public AccessibleTable getAccessibleRowHeader()
1698:     {
1699:       // The RI seems to always return null here, so do we.
1700:       return null;
1701:     }
1702: 
1703:     /**
1704:      * Sets the accessible row header.
1705:      *
1706:      * @param header the header to set
1707:      */
1708:     public void setAccessibleRowHeader(AccessibleTable header)
1709:     {
1710:       // In the RI this seems to be a no-op.    
1711:     }
1712: 
1713:     /**
1714:      * Returns the column header.
1715:      *
1716:      * @return the column header, or <code>null</code> if there is no column
1717:      *         header
1718:      */
1719:     public AccessibleTable getAccessibleColumnHeader()
1720:     {
1721:       JTableHeader h = getTableHeader();
1722:       AccessibleTable header = null;
1723:       if (h != null)
1724:         header = new AccessibleTableHeader(h);
1725:       return header;
1726:     }
1727: 
1728:     /**
1729:      * Sets the accessible column header. The default implementation doesn't
1730:      * allow changing the header this way, so this is a no-op.
1731:      *
1732:      * @param header the accessible column header to set
1733:      */
1734:     public void setAccessibleColumnHeader(AccessibleTable header)
1735:     {
1736:       // The RI doesn't seem to do anything, so we also do nothing.
1737:     }
1738: 
1739:     /**
1740:      * Returns the accessible description for the row with the specified index,
1741:      * or <code>null</code> if no description has been set.
1742:      *
1743:      * @param r the row for which the description is queried
1744:      *
1745:      * @return the accessible description for the row with the specified index,
1746:      *         or <code>null</code> if no description has been set
1747:      */
1748:     public Accessible getAccessibleRowDescription(int r)
1749:     {
1750:       Accessible descr = null;
1751:       if (rowDescriptions != null)
1752:         descr = rowDescriptions[r];
1753:       return descr;
1754:     }
1755: 
1756:     /**
1757:      * Sets the accessible description for the row with the specified index.
1758:      *
1759:      * @param r the row number for which to set the description
1760:      * @param description the description to set
1761:      */
1762:     public void setAccessibleRowDescription(int r, Accessible description)
1763:     {
1764:       if (rowDescriptions == null)
1765:         rowDescriptions = new Accessible[getAccessibleRowCount()];
1766:       rowDescriptions[r] = description;
1767:     }
1768: 
1769:     /**
1770:      * Returns the accessible description for the column with the specified
1771:      * index, or <code>null</code> if no description has been set.
1772:      *
1773:      * @param c the column for which the description is queried
1774:      *
1775:      * @return the accessible description for the column with the specified
1776:      *         index, or <code>null</code> if no description has been set
1777:      */
1778:     public Accessible getAccessibleColumnDescription(int c)
1779:     {
1780:       Accessible descr = null;
1781:       if (columnDescriptions != null)
1782:         descr = columnDescriptions[c];
1783:       return descr;
1784:     }
1785: 
1786:     /**
1787:      * Sets the accessible description for the column with the specified index.
1788:      *
1789:      * @param c the column number for which to set the description
1790:      * @param description the description to set
1791:      */
1792:     public void setAccessibleColumnDescription(int c, Accessible description)
1793:     {
1794:       if (columnDescriptions == null)
1795:         columnDescriptions = new Accessible[getAccessibleRowCount()];
1796:       columnDescriptions[c] = description;
1797:     }
1798: 
1799:     /**
1800:      * Returns <code>true</code> if the accessible child at the specified
1801:      * row and column is selected, <code>false</code> otherwise.
1802:      *
1803:      * @param r the row number of the child
1804:      * @param c the column number of the child
1805:      *
1806:      * @return <code>true</code> if the accessible child at the specified
1807:      *         row and column is selected, <code>false</code> otherwise
1808:      */
1809:     public boolean isAccessibleSelected(int r, int c)
1810:     {
1811:       return isCellSelected(r, c);
1812:     }
1813: 
1814:     /**
1815:      * Returns <code>true</code> if the row with the specified index is
1816:      * selected, <code>false</code> otherwise.
1817:      *
1818:      * @param r the row number
1819:      *
1820:      * @return <code>true</code> if the row with the specified index is
1821:      *        selected, <code>false</code> otherwise
1822:      */
1823:     public boolean isAccessibleRowSelected(int r)
1824:     {
1825:       return isRowSelected(r);
1826:     }
1827: 
1828:     /**
1829:      * Returns <code>true</code> if the column with the specified index is
1830:      * selected, <code>false</code> otherwise.
1831:      *
1832:      * @param c the column number
1833:      *
1834:      * @return <code>true</code> if the column with the specified index is
1835:      *        selected, <code>false</code> otherwise
1836:      */
1837:     public boolean isAccessibleColumnSelected(int c)
1838:     {
1839:       return isColumnSelected(c);
1840:     }
1841: 
1842:     /**
1843:      * Returns the indices of all selected rows.
1844:      *
1845:      * @return the indices of all selected rows
1846:      */
1847:     public int[] getSelectedAccessibleRows()
1848:     {
1849:       return getSelectedRows();
1850:     }
1851: 
1852:     /**
1853:      * Returns the indices of all selected columns.
1854:      *
1855:      * @return the indices of all selected columns
1856:      */
1857:     public int[] getSelectedAccessibleColumns()
1858:     {
1859:       return getSelectedColumns();
1860:     }
1861: 
1862:     /**
1863:      * Returns the accessible row at the specified index.
1864:      *
1865:      * @param index the index for which to query the row
1866:      *
1867:      * @return the row number at the specified table index
1868:      */
1869:     public int getAccessibleRowAtIndex(int index)
1870:     {
1871:       // TODO: Back this up by a Mauve test and update API docs accordingly.
1872:       return index / getColumnCount();
1873:     }
1874: 
1875:     /**
1876:      * Returns the accessible column at the specified index.
1877:      *
1878:      * @param index the index for which to query the column
1879:      *
1880:      * @return the column number at the specified table index
1881:      */
1882:     public int getAccessibleColumnAtIndex(int index)
1883:     {
1884:       // TODO: Back this up by a Mauve test and update API docs accordingly.
1885:       return index % getColumnCount();
1886:     }
1887: 
1888:     /**
1889:      * Returns the accessible child index at the specified column and row.
1890:      *
1891:      * @param row the row
1892:      * @param column the column
1893:      *
1894:      * @return the index of the accessible child at the specified row and
1895:      *         column
1896:      */
1897:     public int getAccessibleIndexAt(int row, int column)
1898:     {
1899:       // TODO: Back this up by a Mauve test and update API docs accordingly.
1900:       return row * getColumnCount() + column;
1901:     }
1902:   }
1903:   /**
1904:    * Handles property changes from the <code>TableColumn</code>s of this
1905:    * <code>JTable</code>.
1906:    *
1907:    * More specifically, this triggers a {@link #revalidate()} call if the
1908:    * preferredWidth of one of the observed columns changes.
1909:    */
1910:   class TableColumnPropertyChangeHandler implements PropertyChangeListener
1911:   {
1912:     /**
1913:      * Receives notification that a property of the observed TableColumns has
1914:      * changed.
1915:      * 
1916:      * @param ev the property change event
1917:      */
1918:     public void propertyChange(PropertyChangeEvent ev)
1919:     {
1920:       if (ev.getPropertyName().equals("preferredWidth"))
1921:         {
1922:           JTableHeader header = getTableHeader();
1923:           if (header != null)
1924:             // Do nothing if the table is in the resizing mode.
1925:             if (header.getResizingColumn() == null)
1926:               {
1927:                 TableColumn col = (TableColumn) ev.getSource();
1928:                 header.setResizingColumn(col);
1929:                 doLayout();
1930:                 header.setResizingColumn(null);
1931:               }
1932:         }
1933:     }
1934:   }
1935: 
1936:   /**
1937:    * A cell renderer for boolean values.
1938:    */
1939:   private class BooleanCellRenderer
1940:     extends DefaultTableCellRenderer
1941:   {
1942:     /**
1943:      * The CheckBox that is used for rendering.
1944:      */
1945:     private final JCheckBox checkBox;
1946:     
1947:     /**
1948:      * Creates a new checkbox based boolean cell renderer. The checkbox is
1949:      * centered by default.
1950:      */
1951:     BooleanCellRenderer()
1952:     {
1953:        checkBox = new JCheckBox();
1954:        checkBox.setHorizontalAlignment(SwingConstants.CENTER);
1955:     }
1956:    
1957:     /**
1958:      * Get the check box.
1959:      */
1960:     JCheckBox getCheckBox()
1961:     {
1962:       return checkBox;
1963:     }
1964: 
1965:     /**
1966:      * Returns the component that is used for rendering the value.
1967:      * 
1968:      * @param table the JTable
1969:      * @param value the value of the object
1970:      * @param isSelected is the cell selected?
1971:      * @param hasFocus has the cell the focus?
1972:      * @param row the row to render
1973:      * @param column the cell to render
1974:      * @return this component (the default table cell renderer)
1975:      */
1976:     public Component getTableCellRendererComponent(JTable table, Object value,
1977:                                                    boolean isSelected,
1978:                                                    boolean hasFocus, int row,
1979:                                                    int column)
1980:     {
1981:       if (isSelected)
1982:         {
1983:           checkBox.setBackground(table.getSelectionBackground());
1984:           checkBox.setForeground(table.getSelectionForeground());
1985:         }
1986:       else
1987:         {
1988:           checkBox.setBackground(table.getBackground());
1989:           checkBox.setForeground(table.getForeground());
1990:         }
1991: 
1992:       if (hasFocus)
1993:         {
1994:           checkBox.setBorder(
1995:             UIManager.getBorder("Table.focusCellHighlightBorder"));
1996:           if (table.isCellEditable(row, column))
1997:             {
1998:               checkBox.setBackground(
1999:                 UIManager.getColor("Table.focusCellBackground"));
2000:               checkBox.setForeground(
2001:                 UIManager.getColor("Table.focusCellForeground"));
2002:             }
2003:         }
2004:       else
2005:         checkBox.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
2006: 
2007:       // Null is rendered as false.
2008:       if (value == null)
2009:         checkBox.setSelected(false);
2010:       else
2011:         {
2012:           Boolean boolValue = (Boolean) value;
2013:           checkBox.setSelected(boolValue.booleanValue());
2014:         }
2015:       return checkBox;
2016:     }
2017:   }
2018: 
2019:   /**
2020:    * A cell renderer for Date values.
2021:    */
2022:   private class DateCellRenderer
2023:     extends DefaultTableCellRenderer
2024:   {
2025:     /**
2026:      * Returns the component that is used for rendering the value.
2027:      *
2028:      * @param table the JTable
2029:      * @param value the value of the object
2030:      * @param isSelected is the cell selected?
2031:      * @param hasFocus has the cell the focus?
2032:      * @param row the row to render
2033:      * @param column the cell to render
2034:      * 
2035:      * @return this component (the default table cell renderer)
2036:      */
2037:     public Component getTableCellRendererComponent(JTable table, Object value,
2038:                                                    boolean isSelected,
2039:                                                    boolean hasFocus, int row,
2040:                                                    int column)
2041:     {
2042:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
2043:                                           row, column);
2044:       if (value instanceof Date)
2045:         {
2046:           Date dateValue = (Date) value;
2047:           DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
2048:           setText(df.format(dateValue));
2049:         }
2050:       return this;
2051:     }
2052:   }
2053: 
2054:   /**
2055:    * A cell renderer for Double values.
2056:    */
2057:   private class DoubleCellRenderer
2058:     extends DefaultTableCellRenderer
2059:   {
2060:     /**
2061:      * Creates a new instance of NumberCellRenderer.
2062:      */
2063:     public DoubleCellRenderer()
2064:     {
2065:       setHorizontalAlignment(JLabel.RIGHT);
2066:     }
2067: 
2068:     /**
2069:      * Returns the component that is used for rendering the value.
2070:      *
2071:      * @param table the JTable
2072:      * @param value the value of the object
2073:      * @param isSelected is the cell selected?
2074:      * @param hasFocus has the cell the focus?
2075:      * @param row the row to render
2076:      * @param column the cell to render
2077:      * 
2078:      * @return this component (the default table cell renderer)
2079:      */
2080:     public Component getTableCellRendererComponent(JTable table, Object value,
2081:                                                    boolean isSelected,
2082:                                                    boolean hasFocus, int row,
2083:                                                    int column)
2084:     {
2085:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
2086:                                           row, column);
2087:       if (value instanceof Double)
2088:         {
2089:           Double doubleValue = (Double) value;
2090:           NumberFormat nf = NumberFormat.getInstance();
2091:           setText(nf.format(doubleValue.doubleValue()));
2092:         }
2093:       return this;
2094:     }
2095:   }
2096: 
2097:   /**
2098:    * A cell renderer for Float values.
2099:    */
2100:   private class FloatCellRenderer
2101:     extends DefaultTableCellRenderer
2102:   {
2103:     /**
2104:      * Creates a new instance of NumberCellRenderer.
2105:      */
2106:     public FloatCellRenderer()
2107:     {
2108:       setHorizontalAlignment(JLabel.RIGHT);
2109:     }
2110: 
2111:     /**
2112:      * Returns the component that is used for rendering the value.
2113:      *
2114:      * @param table the JTable
2115:      * @param value the value of the object
2116:      * @param isSelected is the cell selected?
2117:      * @param hasFocus has the cell the focus?
2118:      * @param row the row to render
2119:      * @param column the cell to render
2120:      * 
2121:      * @return this component (the default table cell renderer)
2122:      */
2123:     public Component getTableCellRendererComponent(JTable table, Object value,
2124:                                                    boolean isSelected,
2125:                                                    boolean hasFocus, int row,
2126:                                                    int column)
2127:     {
2128:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
2129:                                           row, column);
2130:       if (value instanceof Float)
2131:         {
2132:           Float floatValue = (Float) value;
2133:           NumberFormat nf = NumberFormat.getInstance();
2134:           setText(nf.format(floatValue.floatValue()));
2135:         }
2136:       return this;
2137:     }
2138:   }
2139: 
2140:   /**
2141:    * A cell renderer for Number values.
2142:    */
2143:   private class NumberCellRenderer
2144:     extends DefaultTableCellRenderer
2145:   {
2146:     /**
2147:      * Creates a new instance of NumberCellRenderer.
2148:      */
2149:     public NumberCellRenderer()
2150:     {
2151:       setHorizontalAlignment(JLabel.RIGHT);
2152:     }
2153:   }
2154: 
2155:   /**
2156:    * A cell renderer for Icon values.
2157:    */
2158:   private class IconCellRenderer
2159:     extends DefaultTableCellRenderer
2160:   {
2161:     IconCellRenderer()
2162:     {
2163:       setHorizontalAlignment(SwingConstants.CENTER);
2164:     }
2165:     
2166:     
2167:     /**
2168:      * Returns the component that is used for rendering the value.
2169:      *
2170:      * @param table the JTable
2171:      * @param value the value of the object
2172:      * @param isSelected is the cell selected?
2173:      * @param hasFocus has the cell the focus?
2174:      * @param row the row to render
2175:      * @param column the cell to render
2176:      * 
2177:      * @return this component (the default table cell renderer)
2178:      */
2179:     public Component getTableCellRendererComponent(JTable table, Object value,
2180:                                                    boolean isSelected,
2181:                                                    boolean hasFocus, int row,
2182:                                                    int column)
2183:     {
2184:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
2185:                                           row, column);
2186:       if (value instanceof Icon)
2187:         {
2188:           Icon iconValue = (Icon) value;
2189:           setIcon(iconValue);
2190:         }
2191:       else
2192:         {
2193:           setIcon(null);
2194:         }
2195:       setText("");
2196:       return this;
2197:     }
2198:   }
2199:   
2200:     /**
2201:      * The JTable text component (used in editing) always has the table
2202:      * as its parent. The scrollRectToVisible must be adjusted taking the
2203:      * relative component position.
2204:      *
2205:      * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
2206:      */
2207:     private class TableTextField extends JTextField
2208:     {
2209:       /**
2210:        * Create the text field without the border.
2211:        */
2212:       TableTextField()
2213:       {
2214:         setBorder(BorderFactory.createLineBorder(getGridColor(), 2));
2215:       }
2216:     }    
2217:   
2218: 
2219:   private static final long serialVersionUID = 3876025080382781659L;
2220:   
2221:   /**
2222:    * This table, for referring identically name methods from inner classes.
2223:    */
2224:   final JTable this_table = this;
2225: 
2226: 
2227:   /**
2228:    * When resizing columns, do not automatically change any columns. In this
2229:    * case the table should be enclosed in a {@link JScrollPane} in order to
2230:    * accomodate cases in which the table size exceeds its visible area.
2231:    */
2232:   public static final int AUTO_RESIZE_OFF = 0;
2233: 
2234:   /**
2235:    * When resizing column <code>i</code>, automatically change only the
2236:    * single column <code>i+1</code> to provide or absorb excess space
2237:    * requirements.
2238:    */
2239:   public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
2240: 
2241:   /**
2242:    * When resizing column <code>i</code> in a table of <code>n</code>
2243:    * columns, automatically change all columns in the range <code>[i+1,
2244:    * n)</code>, uniformly, to provide or absorb excess space requirements.
2245:    */
2246:   public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
2247:   
2248:   /**
2249:    * When resizing column <code>i</code> in a table of <code>n</code>
2250:    * columns, automatically change all columns in the range <code>[0,
2251:    * n)</code> (with the exception of column i) uniformly, to provide or
2252:    * absorb excess space requirements.
2253:    */
2254:   public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
2255: 
2256:   /**
2257:    * When resizing column <code>i</code> in a table of <code>n</code>
2258:    * columns, automatically change column <code>n-1</code> (the last column
2259:    * in the table) to provide or absorb excess space requirements.
2260:    */
2261:   public static final int AUTO_RESIZE_LAST_COLUMN = 3;
2262: 
2263:   /**
2264:    * A table mapping {@link java.lang.Class} objects to 
2265:    * {@link TableCellEditor} objects. This table is consulted by the 
2266:    * FIXME
2267:    */
2268:   protected Hashtable defaultEditorsByColumnClass = new Hashtable();
2269: 
2270:   /**
2271:    * A table mapping {@link java.lang.Class} objects to 
2272:    * {@link TableCellEditor} objects. This table is consulted by the 
2273:    * FIXME
2274:    */
2275:   protected Hashtable defaultRenderersByColumnClass = new Hashtable();
2276: 
2277:   /**
2278:    * The column that is edited, -1 if the table is not edited currently.
2279:    */
2280:   protected int editingColumn;
2281: 
2282:   /**
2283:    * The row that is edited, -1 if the table is not edited currently.
2284:    */
2285:   protected int editingRow;
2286: 
2287:   /**
2288:    * The component that is used for editing.
2289:    * <code>null</code> if the table is not editing currently.
2290:    *
2291:    */
2292:   protected transient Component editorComp;
2293: 
2294: 
2295:   /**
2296:    * Whether or not the table should automatically compute a matching
2297:    * {@link TableColumnModel} and assign it to the {@link #columnModel}
2298:    * property when the {@link #dataModel} property is changed. 
2299:    *
2300:    * @see #setModel(TableModel)
2301:    * @see #createDefaultColumnsFromModel()
2302:    * @see #setColumnModel(TableColumnModel)
2303:    * @see #setAutoCreateColumnsFromModel(boolean)
2304:    * @see #getAutoCreateColumnsFromModel()
2305:    */
2306:   protected boolean autoCreateColumnsFromModel;
2307: 
2308:   /**
2309:    * A numeric code specifying the resizing behavior of the table. Must be
2310:    * one of {@link #AUTO_RESIZE_ALL_COLUMNS} (the default), {@link
2311:    * #AUTO_RESIZE_LAST_COLUMN}, {@link #AUTO_RESIZE_NEXT_COLUMN}, {@link
2312:    * #AUTO_RESIZE_SUBSEQUENT_COLUMNS}, or {@link #AUTO_RESIZE_OFF}.
2313:    * 
2314:    * @see #doLayout()
2315:    * @see #setAutoResizeMode(int)
2316:    * @see #getAutoResizeMode()
2317:    */
2318:   protected int autoResizeMode;
2319: 
2320:   /**
2321:    * The height in pixels of any row of the table. All rows in a table are
2322:    * of uniform height. This differs from column width, which varies on a
2323:    * per-column basis, and is stored in the individual columns of the
2324:    * {@link #columnModel}.
2325:    * 
2326:    * @see #getRowHeight()
2327:    * @see #setRowHeight(int)
2328:    * @see TableColumn#getWidth()
2329:    * @see TableColumn#setWidth(int)
2330:    */
2331:   protected int rowHeight;
2332: 
2333:   /**
2334:    * The height in pixels of the gap left between any two rows of the table. 
2335:    * 
2336:    * @see #setRowMargin(int)
2337:    * @see #getRowHeight()
2338:    * @see #getIntercellSpacing()
2339:    * @see #setIntercellSpacing(Dimension)
2340:    * @see TableColumnModel#getColumnMargin()
2341:    * @see TableColumnModel#setColumnMargin(int)
2342:    */
2343:   protected int rowMargin;
2344: 
2345:   /**
2346:    * Whether or not the table should allow row selection. If the table
2347:    * allows both row <em>and</em> column selection, it is said to allow
2348:    * "cell selection". Previous versions of the JDK supported cell
2349:    * selection as an independent concept, but it is now represented solely
2350:    * in terms of simultaneous row and column selection.
2351:    *
2352:    * @see TableColumnModel#getColumnSelectionAllowed()
2353:    * @see #setRowSelectionAllowed(boolean)
2354:    * @see #getRowSelectionAllowed()
2355:    * @see #getCellSelectionEnabled()
2356:    * @see #setCellSelectionEnabled(boolean)
2357:    */
2358:   protected boolean rowSelectionAllowed;
2359: 
2360:   /**
2361:    * Obsolete. Use {@link #rowSelectionAllowed}, {@link 
2362:    * #getColumnSelectionAllowed}, or the combined methods {@link
2363:    * #getCellSelectionEnabled} and {@link #setCellSelectionEnabled(boolean)}.
2364:    */
2365:   protected boolean cellSelectionEnabled;
2366:   
2367:   /**
2368:    * The model for data stored in the table. Confusingly, the published API
2369:    * requires that this field be called <code>dataModel</code>, despite its
2370:    * property name. The table listens to its model as a {@link
2371:    * TableModelListener}.
2372:    *
2373:    * @see #tableChanged(TableModelEvent)
2374:    * @see TableModel#addTableModelListener(TableModelListener)
2375:    */
2376:   protected TableModel dataModel;
2377: 
2378:   /**
2379:    * <p>A model of various aspects of the columns of the table, <em>not
2380:    * including</em> the data stored in them. The {@link TableColumnModel}
2381:    * is principally concerned with holding a set of {@link TableColumn}
2382:    * objects, each of which describes the display parameters of a column
2383:    * and the numeric index of the column from the data model which the
2384:    * column is presenting.</p>
2385:    *
2386:    * <p>The TableColumnModel also contains a {@link ListSelectionModel} which
2387:    * indicates which columns are currently selected. This selection model
2388:    * works in combination with the {@link #selectionModel} of the table
2389:    * itself to specify a <em>table selection</em>: a combination of row and
2390:    * column selections.</p>
2391:    *
2392:    * <p>Most application programmers do not need to work with this property
2393:    * at all: setting {@link #autoCreateColumnsFromModel} will construct the
2394:    * columnModel automatically, and the table acts as a facade for most of
2395:    * the interesting properties of the columnModel anyways.</p>
2396:    * 
2397:    * @see #setColumnModel(TableColumnModel)
2398:    * @see #getColumnModel()
2399:    */
2400:   protected TableColumnModel columnModel;
2401: 
2402:   /**
2403:    * A model of the rows of this table which are currently selected. This
2404:    * model is used in combination with the column selection model held as a
2405:    * member of the {@link #columnModel} property, to represent the rows and
2406:    * columns (or both: cells) of the table which are currently selected.
2407:    *
2408:    * @see #rowSelectionAllowed
2409:    * @see #setSelectionModel(ListSelectionModel)
2410:    * @see #getSelectionModel()
2411:    * @see TableColumnModel#getSelectionModel()
2412:    * @see ListSelectionModel#addListSelectionListener(ListSelectionListener)   
2413:    */
2414:   protected ListSelectionModel selectionModel;
2415: 
2416:   /**
2417:    * The current cell editor. 
2418:    */
2419:   protected TableCellEditor cellEditor;
2420: 
2421:   /**
2422:    * Whether or not drag-and-drop is enabled on this table.
2423:    *
2424:    * @see #setDragEnabled(boolean)
2425:    * @see #getDragEnabled()
2426:    */
2427:   private boolean dragEnabled;
2428: 
2429:   /**
2430:    * The color to paint the grid lines of the table, when either {@link
2431:    * #showHorizontalLines} or {@link #showVerticalLines} is set.
2432:    *
2433:    * @see #setGridColor(Color)
2434:    * @see #getGridColor()
2435:    */
2436:   protected Color gridColor;
2437: 
2438:   /**
2439:    * The size this table would prefer its viewport assume, if it is
2440:    * contained in a {@link JScrollPane}.
2441:    *
2442:    * @see #setPreferredScrollableViewportSize(Dimension)
2443:    * @see #getPreferredScrollableViewportSize()
2444:    */
2445:   protected Dimension preferredViewportSize;
2446: 
2447:   /**
2448:    * The color to paint the background of selected cells. Fires a property
2449:    * change event with name {@link #SELECTION_BACKGROUND_CHANGED_PROPERTY}
2450:    * when its value changes.
2451:    *
2452:    * @see #setSelectionBackground(Color)
2453:    * @see #getSelectionBackground()
2454:    */
2455:   protected Color selectionBackground;
2456: 
2457:   /**
2458:    * The name carried in property change events when the {@link
2459:    * #selectionBackground} property changes.
2460:    */
2461:   private static final String SELECTION_BACKGROUND_CHANGED_PROPERTY = "selectionBackground";
2462: 
2463:   /**
2464:    * The color to paint the foreground of selected cells. Fires a property
2465:    * change event with name {@link #SELECTION_FOREGROUND_CHANGED_PROPERTY}
2466:    * when its value changes.
2467:    *
2468:    * @see #setSelectionForeground(Color)
2469:    * @see #getSelectionForeground()
2470:    */
2471:   protected Color selectionForeground;
2472: 
2473:   /**
2474:    * The name carried in property change events when the
2475:    * {@link #selectionForeground} property changes.
2476:    */
2477:   private static final String SELECTION_FOREGROUND_CHANGED_PROPERTY = "selectionForeground";
2478: 
2479:   /**
2480:    * The showHorizontalLines property.
2481:    */
2482:   protected boolean showHorizontalLines;
2483: 
2484:   /**
2485:    * The showVerticalLines property.
2486:    */
2487:   protected boolean showVerticalLines;
2488: 
2489:   /**
2490:    * The tableHeader property.
2491:    */
2492:   protected JTableHeader tableHeader;
2493: 
2494:   /**
2495:    * The property handler for this table's columns.
2496:    */
2497:   TableColumnPropertyChangeHandler tableColumnPropertyChangeHandler =
2498:     new TableColumnPropertyChangeHandler();
2499: 
2500:   /**
2501:    * Whether cell editors should receive keyboard focus when the table is
2502:    * activated.
2503:    */
2504:   private boolean surrendersFocusOnKeystroke = false;
2505: 
2506:   /**
2507:    * A Rectangle object to be reused in {@link #getCellRect}. 
2508:    */
2509:   private Rectangle rectCache = new Rectangle();
2510: 
2511:   /**
2512:    * Indicates if the rowHeight property has been set by a client program or by
2513:    * the UI.
2514:    *
2515:    * @see #setUIProperty(String, Object)
2516:    * @see LookAndFeel#installProperty(JComponent, String, Object)
2517:    */
2518:   private boolean clientRowHeightSet = false;
2519: 
2520:   /**
2521:    * Stores the sizes and positions of each row, when using non-uniform row
2522:    * heights. Initially the height of all rows is equal and stored in
2523:    * {link #rowHeight}. However, when an application calls
2524:    * {@link #setRowHeight(int,int)}, the table switches to non-uniform
2525:    * row height mode which stores the row heights in the SizeSequence
2526:    * object instead.
2527:    *
2528:    * @see #setRowHeight(int)
2529:    * @see #getRowHeight()
2530:    * @see #getRowHeight(int)
2531:    * @see #setRowHeight(int, int)
2532:    */
2533:   private SizeSequence rowHeights;
2534:   
2535:   /**
2536:    * This editor serves just a marker that the value must be simply changed to
2537:    * the opposite one instead of starting the editing session.
2538:    */
2539:   private transient TableCellEditor booleanInvertingEditor; 
2540:   
2541:   /**
2542:    * Creates a new <code>JTable</code> instance.
2543:    */
2544:   public JTable ()
2545:   {
2546:     this(null, null, null);
2547:   }
2548: 
2549:   /**
2550:    * Creates a new <code>JTable</code> instance with the given number
2551:    * of rows and columns.
2552:    *
2553:    * @param numRows an <code>int</code> value
2554:    * @param numColumns an <code>int</code> value
2555:    */
2556:   public JTable (int numRows, int numColumns)
2557:   {
2558:     this(new DefaultTableModel(numRows, numColumns));
2559:   }
2560: 
2561:   /**
2562:    * Creates a new <code>JTable</code> instance, storing the given data 
2563:    * array and heaving the given column names. To see the column names,
2564:    * you must place the JTable into the {@link JScrollPane}.
2565:    *
2566:    * @param data an <code>Object[][]</code> the table data
2567:    * @param columnNames an <code>Object[]</code> the column headers
2568:    */
2569:   public JTable(Object[][] data, Object[] columnNames)
2570:   {
2571:     this(new DefaultTableModel(data, columnNames));
2572:   }
2573: 
2574:   /**
2575:    * Creates a new <code>JTable</code> instance, using the given data model
2576:    * object that provides information about the table content. The table model
2577:    * object is asked for the table size, other features and also receives
2578:    * notifications in the case when the table has been edited by the user.
2579:    * 
2580:    * @param model
2581:    *          the table model.
2582:    */
2583:   public JTable (TableModel model)
2584:   {
2585:     this(model, null, null);
2586:   }
2587: 
2588:   /**
2589:    * Creates a new <code>JTable</code> instance, using the given model object
2590:    * that provides information about the table content. The table data model
2591:    * object is asked for the table size, other features and also receives
2592:    * notifications in the case when the table has been edited by the user. The
2593:    * table column model provides more detailed control on the table column
2594:    * related features.
2595:    * 
2596:    * @param dm
2597:    *          the table data mode
2598:    * @param cm
2599:    *          the table column model
2600:    */
2601:   public JTable (TableModel dm, TableColumnModel cm)
2602:   {
2603:     this(dm, cm, null);
2604:   }
2605: 
2606:   /**
2607:    * Creates a new <code>JTable</code> instance, providing data model,
2608:    * column model and list selection model. The list selection model
2609:    * manages the selections.
2610:    *
2611:    * @param dm data model (manages table data)
2612:    * @param cm column model (manages table columns)
2613:    * @param sm list selection model (manages table selections)
2614:    */
2615:   public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm)
2616:   {
2617:     boolean autoCreate = false;
2618:     TableColumnModel columnModel;
2619:     if (cm != null)
2620:         columnModel = cm;
2621:     else 
2622:       {
2623:         columnModel = createDefaultColumnModel();
2624:         autoCreate = true;
2625:       }
2626:     
2627:     // Initialise the intercelar spacing before setting the column model to
2628:     // avoid firing unnecessary events.
2629:     // The initial incellar spacing is new Dimenstion(1,1). 
2630:     rowMargin = 1;
2631:     columnModel.setColumnMargin(1);
2632:     setColumnModel(columnModel);
2633:     
2634:     setSelectionModel(sm == null ? createDefaultSelectionModel() : sm);
2635:     setModel(dm == null ? createDefaultDataModel() : dm);
2636:     setAutoCreateColumnsFromModel(autoCreate);
2637:     initializeLocalVars();
2638:     
2639:     // The following four lines properly set the lead selection indices.
2640:     // After this, the UI will handle the lead selection indices.
2641:     // FIXME: this should probably not be necessary, if the UI is installed
2642:     // before the TableModel is set then the UI will handle things on its
2643:     // own, but certain variables need to be set before the UI can be installed
2644:     // so we must get the correct order for all the method calls in this
2645:     // constructor.
2646:     // These four lines are not needed.  A Mauve test that shows this is
2647:     // gnu.testlet.javax.swing.JTable.constructors(linesNotNeeded).
2648:     // selectionModel.setAnchorSelectionIndex(-1);
2649:     // selectionModel.setLeadSelectionIndex(-1);
2650:     // columnModel.getSelectionModel().setAnchorSelectionIndex(-1);
2651:     // columnModel.getSelectionModel().setLeadSelectionIndex(-1);
2652:     updateUI(); 
2653:   }
2654:   
2655:   /**
2656:    * Creates a new <code>JTable</code> instance that uses data and column
2657:    * names, stored in {@link Vector}s.
2658:    *
2659:    * @param data the table data
2660:    * @param columnNames the table column names.
2661:    */
2662:   public JTable(Vector data, Vector columnNames)
2663:   {
2664:     this(new DefaultTableModel(data, columnNames));
2665:   }  
2666:   
2667:   /**
2668:    * Initialize local variables to default values.
2669:    */
2670:   protected void initializeLocalVars()
2671:   {
2672:     setTableHeader(createDefaultTableHeader());
2673:     if (autoCreateColumnsFromModel)
2674:       createDefaultColumnsFromModel();
2675:     this.columnModel.addColumnModelListener(this);
2676: 
2677:     this.autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
2678:     setRowHeight(16);
2679:     this.rowMargin = 1;
2680:     this.rowSelectionAllowed = true;
2681:     
2682:     // this.accessibleContext = new AccessibleJTable();
2683:     this.cellEditor = null;
2684:     
2685:     // COMPAT: Both Sun and IBM have drag enabled
2686:     this.dragEnabled = false;
2687:     this.preferredViewportSize = new Dimension(450,400);
2688:     this.showHorizontalLines = true;
2689:     this.showVerticalLines = true;
2690:     this.editingColumn = -1;
2691:     this.editingRow = -1;
2692:   }
2693:   
2694:   /**
2695:    * Add the new table column. The table column class allows to specify column
2696:    * features more precisely, setting the preferred width, column data type
2697:    * (column class) and table headers.
2698:    * 
2699:    * There is no need the add columns to the table if the default column 
2700:    * handling is sufficient.
2701:    * 
2702:    * @param column
2703:    *          the new column to add.
2704:    */
2705:   public void addColumn(TableColumn column)
2706:   {
2707:     if (column.getHeaderValue() == null)
2708:       {
2709:         String name = dataModel.getColumnName(column.getModelIndex());
2710:         column.setHeaderValue(name);
2711:       }
2712:     
2713:     columnModel.addColumn(column);
2714:     column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
2715:   }
2716:   
2717:   /**
2718:    * Create the default editors for this table. The default method creates
2719:    * the editor for Booleans.
2720:    * 
2721:    * Other fields are edited as strings at the moment.
2722:    */
2723:   protected void createDefaultEditors()
2724:   {
2725:     JCheckBox box = new BooleanCellRenderer().getCheckBox();
2726:     box.setBorder(BorderFactory.createLineBorder(getGridColor(), 2));
2727:     box.setBorderPainted(true);
2728:     booleanInvertingEditor = new DefaultCellEditor(box);    
2729:     setDefaultEditor(Boolean.class, booleanInvertingEditor);
2730:   }
2731:   
2732:   /**
2733:    * Create the default renderers for this table. The default method creates
2734:    * renderers for Boolean, Number, Double, Date, Icon and ImageIcon.
2735:    *
2736:    */
2737:   protected void createDefaultRenderers()
2738:   {
2739:     setDefaultRenderer(Boolean.class, new BooleanCellRenderer());
2740:     setDefaultRenderer(Number.class, new NumberCellRenderer());
2741:     setDefaultRenderer(Double.class, new DoubleCellRenderer());
2742:     setDefaultRenderer(Double.class, new FloatCellRenderer());
2743:     setDefaultRenderer(Date.class, new DateCellRenderer());
2744:     setDefaultRenderer(Icon.class, new IconCellRenderer());
2745:     setDefaultRenderer(ImageIcon.class, new IconCellRenderer());    
2746:   }
2747:   
2748:   /**
2749:    * @deprecated 1.0.2, replaced by <code>new JScrollPane(JTable)</code>
2750:    */
2751:   public static JScrollPane createScrollPaneForTable(JTable table)
2752:   {
2753:     return new JScrollPane(table);
2754:   }
2755:   
2756:   /**
2757:    * Create the default table column model that is used if the user-defined
2758:    * column model is not provided. The default method creates
2759:    * {@link DefaultTableColumnModel}.
2760:    * 
2761:    * @return the created table column model.
2762:    */
2763:   protected TableColumnModel createDefaultColumnModel()
2764:   {
2765:     return new DefaultTableColumnModel();
2766:   }
2767: 
2768:   /**
2769:    * Create the default table data model that is used if the user-defined
2770:    * data model is not provided. The default method creates
2771:    * {@link DefaultTableModel}.
2772:    * 
2773:    * @return the created table data model.
2774:    */
2775:   protected TableModel createDefaultDataModel()
2776:   {
2777:     return new DefaultTableModel();
2778:   }
2779: 
2780:   /**
2781:    * Create the default table selection model that is used if the user-defined
2782:    * selection model is not provided. The default method creates
2783:    * {@link DefaultListSelectionModel}.
2784:    * 
2785:    * @return the created table data model.
2786:    */
2787:   protected ListSelectionModel createDefaultSelectionModel()
2788:   {
2789:     return new DefaultListSelectionModel();
2790:   }
2791:   
2792:   /**
2793:    * Create the default table header, if the user - defined table header is not
2794:    * provided.
2795:    * 
2796:    * @return the default table header.
2797:    */
2798:   protected JTableHeader createDefaultTableHeader()
2799:   {
2800:     return new JTableHeader(columnModel);
2801:   }
2802:   
2803:   /**
2804:    * Invoked when the column is added. Revalidates and repains the table.
2805:    */
2806:   public void columnAdded (TableColumnModelEvent event)
2807:   {
2808:     revalidate();
2809:     repaint();
2810:   }
2811: 
2812:   /**
2813:    * Invoked when the column margin is changed. 
2814:    * Revalidates and repains the table.
2815:    */
2816:   public void columnMarginChanged (ChangeEvent event)
2817:   {
2818:     revalidate();
2819:     repaint();
2820:   }
2821: 
2822:   /**
2823:    * Invoked when the column is moved. Revalidates and repains the table.
2824:    */
2825:   public void columnMoved (TableColumnModelEvent event)
2826:   {
2827:     if (isEditing())
2828:       editingCanceled(null);
2829:     revalidate();
2830:     repaint();
2831:   }
2832: 
2833:   /**
2834:    * Invoked when the column is removed. Revalidates and repains the table.
2835:    */
2836:   public void columnRemoved (TableColumnModelEvent event)
2837:   {
2838:     revalidate();
2839:     repaint();
2840:   }
2841:   
2842:   /**
2843:    * Invoked when the the column selection changes, repaints the changed
2844:    * columns. It is not recommended to override this method, register the
2845:    * listener instead.
2846:    */
2847:   public void columnSelectionChanged (ListSelectionEvent event)
2848:   {
2849:     // We must limit the indices to the bounds of the JTable's model, because
2850:     // we might get values of -1 or greater then columnCount in the case
2851:     // when columns get removed.
2852:     int idx0 = Math.max(0, Math.min(getColumnCount() - 1,
2853:                                     event.getFirstIndex()));
2854:     int idxn = Math.max(0, Math.min(getColumnCount() - 1,
2855:                                     event.getLastIndex()));
2856: 
2857:     int minRow = 0;
2858:     int maxRow = getRowCount() - 1;
2859:     if (getRowSelectionAllowed())
2860:       {
2861:         minRow = selectionModel.getMinSelectionIndex();
2862:         maxRow = selectionModel.getMaxSelectionIndex();
2863:         int leadRow = selectionModel.getLeadSelectionIndex();
2864:         if (minRow == -1 && maxRow == -1)
2865:           {
2866:             minRow = leadRow;
2867:             maxRow = leadRow;
2868:           }
2869:         else
2870:           {
2871:             // In this case we need to repaint also the range to leadRow, not
2872:             // only between min and max.
2873:             if (leadRow != -1)
2874:               {
2875:                 minRow = Math.min(minRow, leadRow);
2876:                 maxRow = Math.max(maxRow, leadRow);
2877:               }
2878:           }
2879:       }
2880:     if (minRow != -1 && maxRow != -1)
2881:       {
2882:         Rectangle first = getCellRect(minRow, idx0, false);
2883:         Rectangle last = getCellRect(maxRow, idxn, false);
2884:         Rectangle dirty = SwingUtilities.computeUnion(first.x, first.y,
2885:                                                       first.width,
2886:                                                       first.height, last);
2887:         repaint(dirty);
2888:       }
2889:   }
2890:  
2891:   /**
2892:    * Invoked when the editing is cancelled.
2893:    */
2894:   public void editingCanceled (ChangeEvent event)
2895:   {
2896:     if (editorComp!=null)
2897:       {
2898:         remove(editorComp);
2899:         repaint(editorComp.getBounds());        
2900:         editorComp = null;
2901:       }
2902:   }
2903:   
2904:   /**
2905:    * Finish the current editing session and update the table with the
2906:    * new value by calling {@link #setValueAt}.
2907:    * 
2908:    * @param event the change event
2909:    */
2910:   public void editingStopped (ChangeEvent event)
2911:   {
2912:     if (editorComp!=null)
2913:       {
2914:         remove(editorComp);        
2915:         setValueAt(cellEditor.getCellEditorValue(), editingRow, editingColumn);            
2916:         repaint(editorComp.getBounds());
2917:         editorComp = null;
2918:       }
2919:     requestFocusInWindow();
2920:   }
2921: 
2922:   /**
2923:    * Invoked when the table changes.
2924:    * <code>null</code> means everything changed.
2925:    */
2926:   public void tableChanged (TableModelEvent event)
2927:   {
2928:     // update the column model from the table model if the structure has
2929:     // changed and the flag autoCreateColumnsFromModel is set
2930:     if (event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW))
2931:       handleCompleteChange(event);
2932:     else if (event.getType() == TableModelEvent.INSERT)
2933:       handleInsert(event);
2934:     else if (event.getType() == TableModelEvent.DELETE)
2935:       handleDelete(event);
2936:     else
2937:       handleUpdate(event);
2938:   }
2939: 
2940:   /**
2941:    * Handles a request for complete relayout. This is the case when
2942:    * event.getFirstRow() == TableModelEvent.HEADER_ROW.
2943:    *
2944:    * @param ev the table model event
2945:    */
2946:   private void handleCompleteChange(TableModelEvent ev)
2947:   {
2948:     clearSelection();
2949:     checkSelection();
2950:     rowHeights = null;
2951:     if (getAutoCreateColumnsFromModel())
2952:       createDefaultColumnsFromModel();
2953:     else
2954:       resizeAndRepaint();
2955:   }
2956: 
2957:   /**
2958:    * Handles table model insertions.
2959:    *
2960:    * @param ev the table model event
2961:    */
2962:   private void handleInsert(TableModelEvent ev)
2963:   {
2964:     // Sync selection model with data model.
2965:     int first = ev.getFirstRow();
2966:     if (first < 0)
2967:       first = 0;
2968:     int last = ev.getLastRow();
2969:     if (last < 0)
2970:       last = getRowCount() - 1;
2971:     selectionModel.insertIndexInterval(first, last - first + 1, true);
2972:     checkSelection();
2973: 
2974:     // For variable height rows we must update the SizeSequence thing.
2975:     if (rowHeights != null)
2976:       {
2977:         rowHeights.insertEntries(first, last - first + 1, rowHeight);
2978:         // TODO: We repaint the whole thing when the rows have variable
2979:         // heights. We might want to handle this better though.
2980:         repaint();
2981:       }
2982:     else
2983:       {
2984:         // Repaint the dirty region and revalidate.
2985:         int rowHeight = getRowHeight();
2986:         Rectangle dirty = new Rectangle(0, first * rowHeight,
2987:                                         getColumnModel().getTotalColumnWidth(),
2988:                                         (getRowCount() - first) * rowHeight);
2989:         repaint(dirty);
2990:       }
2991:     revalidate();
2992:   }
2993: 
2994:   /**
2995:    * Handles table model deletions.
2996:    *
2997:    * @param ev the table model event
2998:    */
2999:   private void handleDelete(TableModelEvent ev)
3000:   {
3001:     // Sync selection model with data model.
3002:     int first = ev.getFirstRow();
3003:     if (first < 0)
3004:       first = 0;
3005:     int last = ev.getLastRow();
3006:     if (last < 0)
3007:       last = getRowCount() - 1;
3008: 
3009:     selectionModel.removeIndexInterval(first, last);
3010: 
3011:     checkSelection();
3012: 
3013:     if (dataModel.getRowCount() == 0)
3014:       clearSelection();
3015: 
3016:     // For variable height rows we must update the SizeSequence thing.
3017:     if (rowHeights != null)
3018:       {
3019:         rowHeights.removeEntries(first, last - first + 1);
3020:         // TODO: We repaint the whole thing when the rows have variable
3021:         // heights. We might want to handle this better though.
3022:         repaint();
3023:       }
3024:     else
3025:       {
3026:         // Repaint the dirty region and revalidate.
3027:         int rowHeight = getRowHeight();
3028:         int oldRowCount = getRowCount() + last - first + 1;
3029:         Rectangle dirty = new Rectangle(0, first * rowHeight,
3030:                                         getColumnModel().getTotalColumnWidth(),
3031:                                         (oldRowCount - first) * rowHeight);
3032:         repaint(dirty);
3033:       }
3034:     revalidate();
3035:   }
3036: 
3037:   /**
3038:    * Handles table model updates without structural changes.
3039:    *
3040:    * @param ev the table model event
3041:    */
3042:   private void handleUpdate(TableModelEvent ev)
3043:   {
3044:     if (rowHeights == null)
3045:       {
3046:         // Some cells have been changed without changing the structure.
3047:         // Figure out the dirty rectangle and repaint.
3048:         int firstRow = ev.getFirstRow();
3049:         int lastRow = ev.getLastRow();
3050:         int col = ev.getColumn();
3051:         Rectangle dirty;
3052:         if (col == TableModelEvent.ALL_COLUMNS)
3053:           {
3054:             // All columns changed. 
3055:             dirty = new Rectangle(0, firstRow * getRowHeight(),
3056:                                   getColumnModel().getTotalColumnWidth(), 0);
3057:           }
3058:         else
3059:           {
3060:             // Only one cell or column of cells changed.
3061:             // We need to convert to view column first.
3062:             int column = convertColumnIndexToModel(col);
3063:             dirty = getCellRect(firstRow, column, false);
3064:           }
3065: 
3066:         // Now adjust the height of the dirty region.
3067:         dirty.height = (lastRow + 1) * getRowHeight();
3068:         // .. and repaint.
3069:         repaint(dirty);
3070:       }
3071:     else
3072:       {
3073:         // TODO: We repaint the whole thing when the rows have variable
3074:         // heights. We might want to handle this better though.
3075:         repaint();
3076:       }
3077:   }
3078: 
3079:   /**
3080:    * Helper method for adjusting the lead and anchor indices when the
3081:    * table structure changed. This sets the lead and anchor to -1 if there's
3082:    * no more rows, or set them to 0 when they were at -1 and there are actually
3083:    * some rows now.
3084:    */
3085:   private void checkSelection()
3086:   {
3087:     TableModel m = getModel();
3088:     ListSelectionModel sm = selectionModel;
3089:     if (m != null)
3090:       {
3091:         int lead = sm.getLeadSelectionIndex();
3092:         int c = m.getRowCount();
3093:         if (c == 0 && lead != -1)
3094:           {
3095:             // No rows in the model, reset lead and anchor to -1.
3096:             sm.setValueIsAdjusting(true);
3097:             sm.setAnchorSelectionIndex(-1);
3098:             sm.setLeadSelectionIndex(-1);
3099:             sm.setValueIsAdjusting(false);
3100:           }
3101:         else if (c != 0 && lead == -1)
3102:           {
3103:             // We have rows, but no lead/anchor. Set them to 0. We
3104:             // do a little trick here so that the actual selection is not
3105:             // touched.
3106:             if (sm.isSelectedIndex(0))
3107:               sm.addSelectionInterval(0, 0);
3108:             else
3109:               sm.removeSelectionInterval(0, 0);
3110:           }
3111:         // Nothing to do in the other cases.
3112:       }
3113:   }
3114: 
3115:   /**
3116:    * Invoked when another table row is selected. It is not recommended
3117:    * to override thid method, register the listener instead.
3118:    */
3119:   public void valueChanged (ListSelectionEvent event)
3120:   {
3121:     // If we are in the editing process, end the editing session.
3122:     if (isEditing())
3123:       editingStopped(null);
3124:     
3125:     // Repaint the changed region.
3126:     int first = Math.max(0, Math.min(getRowCount() - 1, event.getFirstIndex()));
3127:     int last = Math.max(0, Math.min(getRowCount() - 1, event.getLastIndex()));
3128:     Rectangle rect1 = getCellRect(first, 0, false);
3129:     Rectangle rect2 = getCellRect(last, getColumnCount() - 1, false);
3130:     Rectangle dirty = SwingUtilities.computeUnion(rect2.x, rect2.y,
3131:                                                   rect2.width, rect2.height,
3132:                                                   rect1);
3133:     repaint(dirty);
3134:   }
3135: 
3136:  /**
3137:    * Returns index of the column that contains specified point 
3138:    * or -1 if this table doesn't contain this point.
3139:    *
3140:    * @param point point to identify the column
3141:    * @return index of the column that contains specified point or 
3142:    * -1 if this table doesn't contain this point.
3143:    */
3144:   public int columnAtPoint(Point point)
3145:   {
3146:     int ncols = getColumnCount();
3147:     Dimension gap = getIntercellSpacing();
3148:     TableColumnModel cols = getColumnModel();
3149:     int x = point.x;
3150: 
3151:     for (int i = 0; i < ncols; ++i)
3152:       {
3153:         int width = cols.getColumn(i).getWidth()
3154:                     + (gap == null ? 0 : gap.width);
3155:         if (0 <= x && x < width)
3156:           return i;
3157:         x -= width;
3158:       }
3159:     return -1;
3160:   }
3161: 
3162:   /**
3163:    * Returns index of the row that contains specified point or -1 if this table
3164:    * doesn't contain this point.
3165:    * 
3166:    * @param point point to identify the row
3167:    * @return index of the row that contains specified point or -1 if this table
3168:    *         doesn't contain this point.
3169:    */
3170:   public int rowAtPoint(Point point)
3171:   {
3172:     if (point != null)
3173:       {
3174:         int nrows = getRowCount();
3175:         int r;
3176:         int y = point.y;
3177:         if (rowHeights == null)
3178:           {
3179:             int height = getRowHeight();
3180:             r = y / height;
3181:           }
3182:         else
3183:           r = rowHeights.getIndex(y);
3184: 
3185:         if (r < 0 || r >= nrows)
3186:           return -1;
3187:         else
3188:           return r;
3189:       }
3190:     else
3191:       return -1;
3192:   }
3193: 
3194:   /** 
3195:    * Calculate the visible rectangle for a particular row and column. The
3196:    * row and column are specified in visual terms; the column may not match
3197:    * the {@link #dataModel} column.
3198:    *
3199:    * @param row the visible row to get the cell rectangle of
3200:    *
3201:    * @param column the visible column to get the cell rectangle of, which may
3202:    * differ from the {@link #dataModel} column
3203:    *
3204:    * @param includeSpacing whether or not to include the cell margins in the
3205:    * resulting cell. If <code>false</code>, the result will only contain the
3206:    * inner area of the target cell, not including its margins.
3207:    *
3208:    * @return a rectangle enclosing the specified cell
3209:    */
3210:   public Rectangle getCellRect(int row,
3211:                                int column,
3212:                                boolean includeSpacing)
3213:   {
3214:     Rectangle cellRect = new Rectangle(0, 0, 0, 0);
3215: 
3216:     // Check for valid range vertically.
3217:     if (row >= getRowCount())
3218:       {
3219:         cellRect.height = getHeight();
3220:       }
3221:     else if (row >= 0)
3222:       {
3223:         cellRect.height = getRowHeight(row);
3224:         if (rowHeights == null)
3225:           cellRect.y = row * cellRect.height;
3226:         else
3227:           cellRect.y = rowHeights.getPosition(row);
3228: 
3229:         if (! includeSpacing)
3230:           {
3231:             // The rounding here is important.
3232:             int rMargin = getRowMargin();
3233:             cellRect.y += rMargin / 2;
3234:             cellRect.height -= rMargin;
3235:           }
3236:       }
3237:     // else row < 0, y = height = 0
3238: 
3239:     // Check for valid range horizontally.
3240:     if (column < 0)
3241:       {
3242:         if (! getComponentOrientation().isLeftToRight())
3243:           {
3244:             cellRect.x = getWidth();
3245:           }
3246:       }
3247:     else if (column >= getColumnCount())
3248:       {
3249:         if (getComponentOrientation().isLeftToRight())
3250:           {
3251:             cellRect.x = getWidth();
3252:           }
3253:       }
3254:     else
3255:       {
3256:         TableColumnModel tcm = getColumnModel();
3257:         if (getComponentOrientation().isLeftToRight())
3258:           {
3259:             for (int i = 0; i < column; i++)
3260:               cellRect.x += tcm.getColumn(i).getWidth();
3261:           }
3262:         else
3263:           {
3264:             for (int i = tcm.getColumnCount() - 1; i > column; i--)
3265:               cellRect.x += tcm.getColumn(i).getWidth();
3266:           }
3267:         cellRect.width = tcm.getColumn(column).getWidth();
3268:         if (! includeSpacing)
3269:           {
3270:             // The rounding here is important.
3271:             int cMargin = tcm.getColumnMargin();
3272:             cellRect.x += cMargin / 2;
3273:             cellRect.width -= cMargin;
3274:           }
3275:       } 
3276: 
3277:     return cellRect;
3278:   }
3279: 
3280:   public void clearSelection()
3281:   {
3282:     selectionModel.clearSelection();
3283:     getColumnModel().getSelectionModel().clearSelection();
3284:   }
3285: 
3286:   /**
3287:    * Get the value of the selectedRow property by delegation to
3288:    * the {@link ListSelectionModel#getMinSelectionIndex} method of the
3289:    * {@link #selectionModel} field.
3290:    *
3291:    * @return The current value of the selectedRow property
3292:    */
3293:   public int getSelectedRow ()
3294:   {    
3295:     return selectionModel.getMinSelectionIndex();
3296:   }
3297:   
3298:   /**
3299:    * Get the value of the {@link #selectionModel} property.
3300:    *
3301:    * @return The current value of the property
3302:    */
3303:   public ListSelectionModel getSelectionModel()
3304:   {
3305:     //Neither Sun nor IBM returns null if rowSelection not allowed
3306:     return selectionModel;
3307:   }
3308:   
3309:   public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
3310:   {
3311:     int block;
3312:     if (orientation == SwingConstants.HORIZONTAL)
3313:       {
3314:         block = visibleRect.width;
3315:       }
3316:     else
3317:       {
3318:         int rowHeight = getRowHeight();
3319:         if (rowHeight > 0)
3320:           block = Math.max(rowHeight, // Little hack for useful rounding.
3321:                            (visibleRect.height / rowHeight) * rowHeight);
3322:         else
3323:           block = visibleRect.height;
3324:       }
3325:     return block;
3326:   }
3327: 
3328:   /**
3329:    * Get the value of the <code>scrollableTracksViewportHeight</code> property.
3330:    *
3331:    * @return The constant value <code>false</code>
3332:    */
3333:   public boolean getScrollableTracksViewportHeight()
3334:   {
3335:     return false;
3336:   }
3337:   
3338:   /**
3339:    * Get the value of the <code>scrollableTracksViewportWidth</code> property.
3340:    *
3341:    * @return <code>true</code> unless the {@link #autoResizeMode} property is
3342:    * <code>AUTO_RESIZE_OFF</code>
3343:    */
3344:   public boolean getScrollableTracksViewportWidth()
3345:   {
3346:     if (autoResizeMode == AUTO_RESIZE_OFF)
3347:       return false;
3348:     else
3349:       return true;
3350:   }
3351:   
3352:   /**
3353:    * Return the preferred scrolling amount (in pixels) for the given scrolling
3354:    * direction and orientation. This method handles a partially exposed row by
3355:    * returning the distance required to completely expose the item. When
3356:    * scrolling the top item is completely exposed.
3357:    * 
3358:    * @param visibleRect the currently visible part of the component.
3359:    * @param orientation the scrolling orientation
3360:    * @param direction the scrolling direction (negative - up, positive -down).
3361:    *          The values greater than one means that more mouse wheel or similar
3362:    *          events were generated, and hence it is better to scroll the longer
3363:    *          distance.
3364:    *          
3365:    * @author Roman Kennke (kennke@aicas.com)
3366:    */
3367:   public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
3368:                                         int direction)
3369:   {
3370:     int unit;
3371:     if (orientation == SwingConstants.HORIZONTAL)
3372:       unit = 100;
3373:     else
3374:       {
3375:         unit = getRowHeight();
3376:         // The following adjustment doesn't work for variable height rows.
3377:         // It fully exposes partially visible rows in the scrolling direction.
3378:         if (rowHeights == null)
3379:           {
3380:             if (direction > 0)
3381:               {
3382:                 // Scroll down.
3383:                 // How much pixles are exposed from the last item?
3384:                 int exposed = (visibleRect.y + visibleRect.height) % unit;
3385:                 if (exposed > 0 && exposed < unit - 1)
3386:                   unit = unit - exposed - 1;
3387:               }
3388:             else
3389:               {
3390:                 // Scroll up.
3391:                 int exposed = visibleRect.y % unit;
3392:                 if (exposed > 0 && exposed < unit)
3393:                   unit = exposed;
3394:               }
3395:           }
3396:       }
3397:     return unit;
3398:   }
3399: 
3400:   /**
3401:    * Get the cell editor, suitable for editing the given cell. The default
3402:    * method requests the editor from the column model. If the column model does
3403:    * not provide the editor, the call is forwarded to the
3404:    * {@link #getDefaultEditor(Class)} with the parameter, obtained from
3405:    * {@link TableModel#getColumnClass(int)}.
3406:    * 
3407:    * @param row the cell row
3408:    * @param column the cell column
3409:    * @return the editor to edit that cell
3410:    */
3411:   public TableCellEditor getCellEditor(int row, int column)
3412:   {
3413:     TableCellEditor editor = columnModel.getColumn(column).getCellEditor();
3414: 
3415:     if (editor == null)
3416:       {
3417:         int mcolumn = convertColumnIndexToModel(column);
3418:         editor = getDefaultEditor(dataModel.getColumnClass(mcolumn));
3419:       }
3420: 
3421:     return editor;
3422:   }
3423:   
3424:   /**
3425:    * Get the default editor for editing values of the given type
3426:    * (String, Boolean and so on).
3427:    * 
3428:    * @param columnClass the class of the value that will be edited.
3429:    * 
3430:    * @return the editor, suitable for editing this data type
3431:    */
3432:   public TableCellEditor getDefaultEditor(Class<?> columnClass)
3433:   {
3434:     if (defaultEditorsByColumnClass.containsKey(columnClass))
3435:       return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass);
3436:     else
3437:       {
3438:         JTextField t = new TableTextField();        
3439:         TableCellEditor r = new DefaultCellEditor(t);
3440:         defaultEditorsByColumnClass.put(columnClass, r);
3441:         return r;
3442:       }
3443:   }
3444: 
3445:   /**
3446:    * Get the cell renderer for rendering the given cell.
3447:    * 
3448:    * @param row the cell row
3449:    * @param column the cell column
3450:    * @return the cell renderer to render that cell.
3451:    */
3452:   public TableCellRenderer getCellRenderer(int row, int column)
3453:   {
3454:     TableCellRenderer renderer = null;
3455:     if (columnModel.getColumnCount() > 0)
3456:       renderer = columnModel.getColumn(column).getCellRenderer();
3457:     if (renderer == null)
3458:       {
3459:         int mcolumn = convertColumnIndexToModel(column);
3460:         renderer = getDefaultRenderer(dataModel.getColumnClass(mcolumn));
3461:       }
3462:     return renderer;
3463:   }
3464: 
3465:   /**
3466:    * Set default renderer for rendering the given data type.
3467:    * 
3468:    * @param columnClass the data type (String, Boolean and so on) that must be
3469:    *          rendered.
3470:    * @param rend the renderer that will rend this data type
3471:    */
3472:   public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer rend)
3473:   {
3474:     defaultRenderersByColumnClass.put(columnClass, rend);
3475:   }
3476: 
3477:   /**
3478:    * Get the default renderer for rendering the given data type.
3479:    * 
3480:    * @param columnClass the data that must be rendered
3481:    * 
3482:    * @return the appropriate defauld renderer for rendering that data type.
3483:    */
3484:   public TableCellRenderer getDefaultRenderer(Class<?> columnClass)
3485:   {
3486:     if (defaultRenderersByColumnClass.containsKey(columnClass))
3487:       return (TableCellRenderer) defaultRenderersByColumnClass.get(columnClass);
3488:     else
3489:       {
3490:         TableCellRenderer r = new DefaultTableCellRenderer();
3491:         defaultRenderersByColumnClass.put(columnClass, r);
3492:         return r;
3493:       }
3494:   }
3495:   
3496:   /**
3497:    * Convert the table model index into the table column number.
3498:    * The model number need not match the real column position. The columns
3499:    * may be rearranged by the user with mouse at any time by dragging the
3500:    * column headers.
3501:    *
3502:    * @param vc the column number (0=first).
3503:    * 
3504:    * @return the table column model index of this column.
3505:    * 
3506:    * @see TableColumn#getModelIndex()
3507:    */
3508:   public int convertColumnIndexToModel(int vc)
3509:   {
3510:     if (vc < 0)
3511:       return vc;
3512:     else
3513:       return columnModel.getColumn(vc).getModelIndex();
3514:   }
3515:   
3516:   /**
3517:    * Convert the table column number to the table column model index.
3518:    * The model number need not match the real column position. The columns
3519:    * may be rearranged by the user with mouse at any time by dragging the
3520:    * column headers.
3521:    *  
3522:    * @param mc the table column index (0=first).
3523:    * 
3524:    * @return the table column number in the model
3525:    * 
3526:    * @see TableColumn#getModelIndex() 
3527:    */
3528:   public int convertColumnIndexToView(int mc)
3529:   {
3530:     if (mc < 0)
3531:       return mc;
3532:     int ncols = getColumnCount();
3533:     for (int vc = 0; vc < ncols; ++vc)
3534:       {
3535:         if (columnModel.getColumn(vc).getModelIndex() == mc)
3536:           return vc;
3537:       }
3538:     return -1;
3539:   }
3540:   
3541:   /**
3542:    * Prepare the renderer for rendering the given cell.
3543:    * 
3544:    * @param renderer the renderer being prepared
3545:    * @param row the row of the cell being rendered
3546:    * @param column the column of the cell being rendered
3547:    * 
3548:    * @return the component which .paint() method will paint the cell.
3549:    */
3550:   public Component prepareRenderer(TableCellRenderer renderer,
3551:                                    int row,
3552:                                    int column)
3553:   {
3554:     boolean rowSelAllowed = getRowSelectionAllowed();
3555:     boolean colSelAllowed = getColumnSelectionAllowed();
3556:     boolean isSel = false;
3557:     if (rowSelAllowed && colSelAllowed || !rowSelAllowed && !colSelAllowed)
3558:       isSel = isCellSelected(row, column);
3559:     else
3560:       isSel = isRowSelected(row) && getRowSelectionAllowed()
3561:            || isColumnSelected(column) && getColumnSelectionAllowed();
3562: 
3563:     // Determine the focused cell. The focused cell is the cell at the
3564:     // leadSelectionIndices of the row and column selection model.
3565:     ListSelectionModel rowSel = getSelectionModel();
3566:     ListSelectionModel colSel = getColumnModel().getSelectionModel();
3567:     boolean hasFocus = hasFocus() && isEnabled()
3568:                        && rowSel.getLeadSelectionIndex() == row
3569:                        && colSel.getLeadSelectionIndex() == column;
3570: 
3571:     return renderer.getTableCellRendererComponent(this,
3572:                                                   dataModel.getValueAt(row, 
3573:                                                                        convertColumnIndexToModel(column)),
3574:                                                   isSel,
3575:                                                   hasFocus,
3576:                                                   row, column);
3577:   }
3578: 
3579: 
3580:   /**
3581:    * Get the value of the {@link #autoCreateColumnsFromModel} property.
3582:    *
3583:    * @return The current value of the property
3584:    */
3585:   public boolean getAutoCreateColumnsFromModel()
3586:   {
3587:     return autoCreateColumnsFromModel;
3588:   }
3589: 
3590:   /**
3591:    * Get the value of the {@link #autoResizeMode} property.
3592:    *
3593:    * @return The current value of the property
3594:    */
3595:   public int getAutoResizeMode()
3596:   {
3597:     return autoResizeMode;
3598:   }
3599: 
3600:   /**
3601:    * Get the value of the {@link #rowHeight} property.
3602:    *
3603:    * @return The current value of the property
3604:    */
3605:   public int getRowHeight()
3606:   {
3607:     return rowHeight;
3608:   }
3609: 
3610:   /**
3611:    * Get the height of the specified row.
3612:    *
3613:    * @param row the row whose height to return
3614:    */
3615:   public int getRowHeight(int row)
3616:   {
3617:     int rh = rowHeight;
3618:     if (rowHeights != null)
3619:       rh = rowHeights.getSize(row);
3620:     return rh;
3621:   }
3622: 
3623: 
3624:   /**
3625:    * Get the value of the {@link #rowMargin} property.
3626:    *
3627:    * @return The current value of the property
3628:    */
3629:   public int getRowMargin()
3630:   {
3631:     return rowMargin;
3632:   }
3633: 
3634:   /**
3635:    * Get the value of the {@link #rowSelectionAllowed} property.
3636:    *
3637:    * @return The current value of the property
3638:    * 
3639:    * @see #setRowSelectionAllowed(boolean)
3640:    */
3641:   public boolean getRowSelectionAllowed()
3642:   {
3643:     return rowSelectionAllowed;
3644:   }
3645: 
3646:   /**
3647:    * Get the value of the {@link #cellSelectionEnabled} property.
3648:    *
3649:    * @return The current value of the property
3650:    */
3651:   public boolean getCellSelectionEnabled()
3652:   {
3653:     return getColumnSelectionAllowed() && getRowSelectionAllowed();
3654:   }
3655: 
3656:   /**
3657:    * Get the value of the {@link #dataModel} property.
3658:    *
3659:    * @return The current value of the property
3660:    */
3661:   public TableModel getModel()
3662:   {
3663:     return dataModel;
3664:   }
3665: 
3666:   /**
3667:    * Get the value of the <code>columnCount</code> property by
3668:    * delegation to the {@link #columnModel} field.
3669:    *
3670:    * @return The current value of the columnCount property
3671:    */
3672:   public int getColumnCount()
3673:   {
3674:     return columnModel.getColumnCount();    
3675:   }
3676: 
3677:   /**
3678:    * Get the value of the <code>rowCount</code> property by
3679:    * delegation to the {@link #dataModel} field.
3680:    *
3681:    * @return The current value of the rowCount property
3682:    */
3683:   public int getRowCount()
3684:   {
3685:     return dataModel.getRowCount();
3686:   }
3687: 
3688:   /**
3689:    * Get the value of the {@link #columnModel} property.
3690:    *
3691:    * @return The current value of the property
3692:    */
3693:   public TableColumnModel getColumnModel()
3694:   {
3695:     return columnModel;
3696:   }
3697: 
3698:   /**
3699:    * Get the value of the <code>selectedColumn</code> property by
3700:    * delegation to the {@link #columnModel} field.
3701:    *
3702:    * @return The current value of the selectedColumn property
3703:    */
3704:   public int getSelectedColumn()
3705:   {
3706:     return columnModel.getSelectionModel().getMinSelectionIndex();
3707:   }
3708: 
3709:   private static int countSelections(ListSelectionModel lsm)
3710:   {
3711:     int lo = lsm.getMinSelectionIndex();
3712:     int hi = lsm.getMaxSelectionIndex();
3713:     int sum = 0;
3714:     if (lo != -1 && hi != -1)
3715:       {
3716:         switch (lsm.getSelectionMode())
3717:           {
3718:           case ListSelectionModel.SINGLE_SELECTION:
3719:             sum = 1;
3720:             break;
3721:             
3722:           case ListSelectionModel.SINGLE_INTERVAL_SELECTION:
3723:             sum = hi - lo + 1;
3724:             break;
3725:             
3726:           case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:        
3727:             for (int i = lo; i <= hi; ++i)
3728:               if (lsm.isSelectedIndex(i))        
3729:                 ++sum;
3730:             break;
3731:           }
3732:       }
3733:     return sum;
3734:   }
3735: 
3736:   private static int[] getSelections(ListSelectionModel lsm)
3737:   {
3738:     int sz = countSelections(lsm);
3739:     int [] ret = new int[sz];
3740: 
3741:     int lo = lsm.getMinSelectionIndex();
3742:     int hi = lsm.getMaxSelectionIndex();
3743:     int j = 0;
3744:     if (lo != -1 && hi != -1)
3745:       {
3746:         switch (lsm.getSelectionMode())
3747:           {
3748:           case ListSelectionModel.SINGLE_SELECTION:
3749:             ret[0] = lo;
3750:             break;      
3751:       
3752:           case ListSelectionModel.SINGLE_INTERVAL_SELECTION:            
3753:             for (int i = lo; i <= hi; ++i)
3754:               ret[j++] = i;
3755:             break;
3756:             
3757:           case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:        
3758:             for (int i = lo; i <= hi; ++i)
3759:               if (lsm.isSelectedIndex(i))        
3760:                 ret[j++] = i;
3761:             break;
3762:           }
3763:       }
3764:     return ret;
3765:   }
3766: 
3767:   /**
3768:    * Get the value of the <code>selectedColumnCount</code> property by
3769:    * delegation to the {@link #columnModel} field.
3770:    *
3771:    * @return The current value of the selectedColumnCount property
3772:    */  
3773:   public int getSelectedColumnCount()
3774:   {
3775:     return countSelections(columnModel.getSelectionModel());
3776:   }
3777: 
3778:   /**
3779:    * Get the value of the <code>selectedColumns</code> property by
3780:    * delegation to the {@link #columnModel} field.
3781:    *
3782:    * @return The current value of the selectedColumns property
3783:    */
3784:   public int[] getSelectedColumns()
3785:   {
3786:     return getSelections(columnModel.getSelectionModel());
3787:   }
3788: 
3789:   /**
3790:    * Get the value of the <code>columnSelectionAllowed</code> property.
3791:    *
3792:    * @return The current value of the columnSelectionAllowed property
3793:    * 
3794:    * @see #setColumnSelectionAllowed(boolean)
3795:    */
3796:   public boolean getColumnSelectionAllowed()
3797:   {
3798:     return getColumnModel().getColumnSelectionAllowed();
3799:   }
3800: 
3801:   /**
3802:    * Get the value of the <code>selectedRowCount</code> property by
3803:    * delegation to the {@link #selectionModel} field.
3804:    *
3805:    * @return The current value of the selectedRowCount property
3806:    */
3807:   public int getSelectedRowCount()
3808:   {
3809:     return countSelections(selectionModel);
3810:   }
3811: 
3812:   /**
3813:    * Get the value of the <code>selectedRows</code> property by
3814:    * delegation to the {@link #selectionModel} field.
3815:    *
3816:    * @return The current value of the selectedRows property
3817:    */
3818:   public int[] getSelectedRows()
3819:   {
3820:     return getSelections(selectionModel);
3821:   }
3822: 
3823:   /**
3824:    * Get the value of the {@link #accessibleContext} property.
3825:    *
3826:    * @return The current value of the property
3827:    */
3828:   public AccessibleContext getAccessibleContext()
3829:   {
3830:     if (accessibleContext == null)
3831:       {
3832:         AccessibleJTable ctx = new AccessibleJTable();
3833:         addPropertyChangeListener(ctx);
3834:         TableColumnModel tcm = getColumnModel();
3835:         tcm.addColumnModelListener(ctx);
3836:         tcm.getSelectionModel().addListSelectionListener(ctx);
3837:         getSelectionModel().addListSelectionListener(ctx);
3838:         
3839:         accessibleContext = ctx;
3840:       }
3841:     return accessibleContext;
3842:   }
3843: 
3844:   /**
3845:    * Get the value of the {@link #cellEditor} property.
3846:    *
3847:    * @return The current value of the property
3848:    */
3849:   public TableCellEditor getCellEditor()
3850:   {
3851:     return cellEditor;
3852:   }
3853: 
3854:   /**
3855:    * Get the value of the {@link #dragEnabled} property.
3856:    *
3857:    * @return The current value of the property
3858:    */
3859:   public boolean getDragEnabled()
3860:   {
3861:     return dragEnabled;
3862:   }
3863: 
3864:   /**
3865:    * Get the value of the {@link #gridColor} property.
3866:    *
3867:    * @return The current value of the property
3868:    */
3869:   public Color getGridColor()
3870:   {
3871:     return gridColor;
3872:   }
3873: 
3874:   /**
3875:    * Get the value of the <code>intercellSpacing</code> property.
3876:    *
3877:    * @return The current value of the property
3878:    */
3879:   public Dimension getIntercellSpacing()
3880:   {
3881:     return new Dimension(columnModel.getColumnMargin(), rowMargin);
3882:   }
3883: 
3884:   /**
3885:    * Get the value of the {@link #preferredViewportSize} property.
3886:    *
3887:    * @return The current value of the property
3888:    */
3889:   public Dimension getPreferredScrollableViewportSize()
3890:   {
3891:     return preferredViewportSize;
3892:   }
3893: 
3894:   /**
3895:    * Get the value of the {@link #selectionBackground} property.
3896:    *
3897:    * @return The current value of the property
3898:    */
3899:   public Color getSelectionBackground()
3900:   {
3901:     return selectionBackground;
3902:   }
3903: 
3904:   /**
3905:    * Get the value of the {@link #selectionForeground} property.
3906:    *
3907:    * @return The current value of the property
3908:    */
3909:   public Color getSelectionForeground()
3910:   {
3911:     return selectionForeground;
3912:   }
3913: 
3914:   /**
3915:    * Get the value of the {@link #showHorizontalLines} property.
3916:    *
3917:    * @return The current value of the property
3918:    */
3919:   public boolean getShowHorizontalLines()
3920:   {
3921:     return showHorizontalLines;
3922:   }
3923: 
3924:   /**
3925:    * Get the value of the {@link #showVerticalLines} property.
3926:    *
3927:    * @return The current value of the property
3928:    */
3929:   public boolean getShowVerticalLines()
3930:   {
3931:     return showVerticalLines;
3932:   }
3933: 
3934:   /**
3935:    * Get the value of the {@link #tableHeader} property.
3936:    *
3937:    * @return The current value of the property
3938:    */
3939:   public JTableHeader getTableHeader()
3940:   {
3941:     return tableHeader;
3942:   }
3943: 
3944:   /**
3945:    * Removes specified column from displayable columns of this table.
3946:    *
3947:    * @param column column to removed
3948:    */
3949:   public void removeColumn(TableColumn column)
3950:   {    
3951:     columnModel.removeColumn(column);
3952:   }
3953: 
3954:   /**
3955:    * Moves column at the specified index to new given location.
3956:    *
3957:    * @param column index of the column to move
3958:    * @param targetColumn index specifying new location of the column
3959:    */ 
3960:   public void moveColumn(int column,int targetColumn) 
3961:   {
3962:     columnModel.moveColumn(column, targetColumn);
3963:   }
3964: 
3965:   /**
3966:    * Set the value of the {@link #autoCreateColumnsFromModel} flag.  If the
3967:    * flag changes from <code>false</code> to <code>true</code>, the
3968:    * {@link #createDefaultColumnsFromModel()} method is called.
3969:    *
3970:    * @param autoCreate  the new value of the flag.
3971:    */ 
3972:   public void setAutoCreateColumnsFromModel(boolean autoCreate)
3973:   {
3974:     if (autoCreateColumnsFromModel != autoCreate)
3975:     {
3976:       autoCreateColumnsFromModel = autoCreate;
3977:       if (autoCreate)
3978:         createDefaultColumnsFromModel();
3979:     }
3980:   }
3981: 
3982:   /**
3983:    * Set the value of the {@link #autoResizeMode} property.
3984:    *
3985:    * @param a The new value of the autoResizeMode property
3986:    */ 
3987:   public void setAutoResizeMode(int a)
3988:   {
3989:     autoResizeMode = a;
3990:     revalidate();
3991:     repaint();
3992:   }
3993: 
3994:   /**
3995:    * Sets the height for all rows in the table. If you want to change the
3996:    * height of a single row instead, use {@link #setRowHeight(int, int)}.
3997:    *
3998:    * @param r the height to set for all rows
3999:    *
4000:    * @see #getRowHeight()
4001:    * @see #setRowHeight(int, int)
4002:    * @see #getRowHeight(int)
4003:    */ 
4004:   public void setRowHeight(int r)
4005:   {
4006:     if (r < 1)
4007:       throw new IllegalArgumentException();
4008: 
4009:     clientRowHeightSet = true;
4010: 
4011:     rowHeight = r;
4012:     rowHeights = null;
4013:     revalidate();
4014:     repaint();
4015:   }
4016:   
4017:   /**
4018:    * Sets the height of a single row in the table.
4019:    * 
4020:    * @param rh the new row height
4021:    * @param row the row to change the height of
4022:    */
4023:   public void setRowHeight(int row, int rh)
4024:   {
4025:     if (rowHeights == null)
4026:       {
4027:         rowHeights = new SizeSequence(getRowCount(), rowHeight);
4028:       }
4029:     rowHeights.setSize(row, rh);
4030:   }
4031:   
4032:   /**
4033:    * Set the value of the {@link #rowMargin} property.
4034:    *
4035:    * @param r The new value of the rowMargin property
4036:    */ 
4037:   public void setRowMargin(int r)
4038:   {
4039:     rowMargin = r;
4040:     revalidate();
4041:     repaint();
4042:   }
4043: 
4044:   /**
4045:    * Set the value of the {@link #rowSelectionAllowed} property.
4046:    *
4047:    * @param r The new value of the rowSelectionAllowed property
4048:    * 
4049:    * @see #getRowSelectionAllowed()
4050:    */ 
4051:   public void setRowSelectionAllowed(boolean r)
4052:   {
4053:     if (rowSelectionAllowed != r) 
4054:       {
4055:         rowSelectionAllowed = r;
4056:         firePropertyChange("rowSelectionAllowed", !r, r);
4057:         repaint();
4058:       }
4059:   }
4060: 
4061:   /**
4062:    * Set the value of the {@link #cellSelectionEnabled} property.
4063:    *
4064:    * @param c The new value of the cellSelectionEnabled property
4065:    */ 
4066:   public void setCellSelectionEnabled(boolean c)
4067:   {
4068:     setColumnSelectionAllowed(c);
4069:     setRowSelectionAllowed(c);
4070:     // for backward-compatibility sake:
4071:     cellSelectionEnabled = true;
4072:   }
4073: 
4074:   /**
4075:    * <p>Set the value of the {@link #dataModel} property.</p>
4076:    *
4077:    * <p>Unregister <code>this</code> as a {@link TableModelListener} from
4078:    * previous {@link #dataModel} and register it with new parameter
4079:    * <code>m</code>.</p>
4080:    *
4081:    * @param m The new value of the model property
4082:    */ 
4083:   public void setModel(TableModel m)
4084:   {
4085:     // Throw exception is m is null.
4086:     if (m == null)
4087:       throw new IllegalArgumentException();
4088:    
4089:     // Don't do anything if setting the current model again.
4090:     if (dataModel == m)
4091:       return;
4092: 
4093:     TableModel oldModel = dataModel;
4094: 
4095:     // Remove table as TableModelListener from old model.
4096:     if (dataModel != null)
4097:       dataModel.removeTableModelListener(this);
4098:     
4099:     if (m != null)
4100:       {
4101:         // Set property.
4102:         dataModel = m;
4103: 
4104:         // Add table as TableModelListener to new model.
4105:         dataModel.addTableModelListener(this);
4106: 
4107:         // Notify the tableChanged method.
4108:         tableChanged(new TableModelEvent(dataModel,
4109:                                          TableModelEvent.HEADER_ROW));
4110: 
4111:         // Automatically create columns.
4112:         if (autoCreateColumnsFromModel)
4113:           createDefaultColumnsFromModel();
4114:       }
4115: 
4116:     // This property is bound, so we fire a property change event.
4117:     firePropertyChange("model", oldModel, dataModel);
4118: 
4119:     // Repaint table.
4120:     revalidate();
4121:     repaint();
4122:   }
4123: 
4124:   /**
4125:    * <p>Set the value of the {@link #columnModel} property.</p>
4126:    *
4127:    * <p>Unregister <code>this</code> as a {@link TableColumnModelListener}
4128:    * from previous {@link #columnModel} and register it with new parameter
4129:    * <code>c</code>.</p>
4130:    *
4131:    * @param c The new value of the columnModel property
4132:    */ 
4133:   public void setColumnModel(TableColumnModel c)
4134:   {
4135:     if (c == null)
4136:       throw new IllegalArgumentException();
4137:     TableColumnModel tmp = columnModel;
4138:     if (tmp != null)
4139:       tmp.removeColumnModelListener(this);
4140:     if (c != null)
4141:       c.addColumnModelListener(this);
4142:     columnModel = c;
4143:     if (dataModel != null && columnModel != null)
4144:       {
4145:         int ncols = getColumnCount();
4146:         TableColumn column;
4147:         for (int i = 0; i < ncols; ++i)
4148:           {
4149:             column = columnModel.getColumn(i); 
4150:             if (column.getHeaderValue()==null)
4151:               column.setHeaderValue(dataModel.getColumnName(i));
4152:           }
4153:       }
4154: 
4155:     // according to Sun's spec we also have to set the tableHeader's
4156:     // column model here
4157:     if (tableHeader != null)
4158:       tableHeader.setColumnModel(c);
4159: 
4160:     revalidate();
4161:     repaint();
4162:   }
4163: 
4164:   /**
4165:    * Set the value of the <code>columnSelectionAllowed</code> property.
4166:    *
4167:    * @param c The new value of the property
4168:    * 
4169:    * @see #getColumnSelectionAllowed()
4170:    */ 
4171:   public void setColumnSelectionAllowed(boolean c)
4172:   {
4173:     if (columnModel.getColumnSelectionAllowed() != c)
4174:       {
4175:         columnModel.setColumnSelectionAllowed(c);
4176:         firePropertyChange("columnSelectionAllowed", !c, c);
4177:         repaint();
4178:       }
4179:   }
4180: 
4181:   /**
4182:    * <p>Set the value of the {@link #selectionModel} property.</p>
4183:    *
4184:    * <p>Unregister <code>this</code> as a {@link ListSelectionListener}
4185:    * from previous {@link #selectionModel} and register it with new
4186:    * parameter <code>s</code>.</p>
4187:    *
4188:    * @param s The new value of the selectionModel property
4189:    */ 
4190:   public void setSelectionModel(ListSelectionModel s)
4191:   {
4192:     if (s == null)
4193:       throw new IllegalArgumentException();
4194:     ListSelectionModel tmp = selectionModel;
4195:     if (tmp != null)
4196:       tmp.removeListSelectionListener(this);
4197:     if (s != null)
4198:       s.addListSelectionListener(this);
4199:     selectionModel = s;
4200:     checkSelection();
4201:   }
4202: 
4203:   /**
4204:    * Set the value of the <code>selectionMode</code> property by
4205:    * delegation to the {@link #selectionModel} field. The same selection
4206:    * mode is set for row and column selection models.
4207:    *
4208:    * @param s The new value of the property
4209:    */ 
4210:   public void setSelectionMode(int s)
4211:   { 
4212:     selectionModel.setSelectionMode(s);    
4213:     columnModel.getSelectionModel().setSelectionMode(s);
4214:     
4215:     repaint();
4216:   }
4217: 
4218:   /**
4219:    * <p>Set the value of the {@link #cellEditor} property.</p>
4220:    *
4221:    * <p>Unregister <code>this</code> as a {@link CellEditorListener} from
4222:    * previous {@link #cellEditor} and register it with new parameter
4223:    * <code>c</code>.</p>
4224:    *
4225:    * @param c The new value of the cellEditor property
4226:    */ 
4227:   public void setCellEditor(TableCellEditor c)
4228:   {
4229:     TableCellEditor tmp = cellEditor;
4230:     if (tmp != null)
4231:       tmp.removeCellEditorListener(this);
4232:     if (c != null)
4233:       c.addCellEditorListener(this);
4234:     cellEditor = c;
4235:   }
4236: 
4237:   /**
4238:    * Set the value of the {@link #dragEnabled} property.
4239:    *
4240:    * @param d The new value of the dragEnabled property
4241:    */ 
4242:   public void setDragEnabled(boolean d)
4243:   {
4244:     dragEnabled = d;
4245:   }
4246: 
4247:   /**
4248:    * Set the value of the {@link #gridColor} property.
4249:    *
4250:    * @param g The new value of the gridColor property
4251:    */ 
4252:   public void setGridColor(Color g)
4253:   {
4254:     gridColor = g;
4255:     repaint();
4256:   }
4257: 
4258:   /**
4259:    * Set the value of the <code>intercellSpacing</code> property.
4260:    *
4261:    * @param i The new value of the intercellSpacing property
4262:    */ 
4263:   public void setIntercellSpacing(Dimension i)
4264:   {
4265:     rowMargin = i.height;
4266:     columnModel.setColumnMargin(i.width);
4267:     repaint();
4268:   }
4269: 
4270:   /**
4271:    * Set the value of the {@link #preferredViewportSize} property.
4272:    *
4273:    * @param p The new value of the preferredViewportSize property
4274:    */ 
4275:   public void setPreferredScrollableViewportSize(Dimension p)
4276:   {
4277:     preferredViewportSize = p;
4278:     revalidate();
4279:     repaint();
4280:   }
4281: 
4282:   /**
4283:    * <p>Set the value of the {@link #selectionBackground} property.</p>
4284:    *
4285:    * <p>Fire a PropertyChangeEvent with name {@link
4286:    * #SELECTION_BACKGROUND_CHANGED_PROPERTY} to registered listeners, if
4287:    * selectionBackground changed.</p>
4288:    *
4289:    * @param s The new value of the selectionBackground property
4290:    */ 
4291:   public void setSelectionBackground(Color s)
4292:   {
4293:     Color tmp = selectionBackground;
4294:     selectionBackground = s;
4295:     if (((tmp == null && s != null)
4296:          || (s == null && tmp != null)
4297:          || (tmp != null && s != null && !tmp.equals(s))))
4298:       firePropertyChange(SELECTION_BACKGROUND_CHANGED_PROPERTY, tmp, s);
4299:     repaint();
4300:   }
4301: 
4302:   /**
4303:    * <p>Set the value of the {@link #selectionForeground} property.</p>
4304:    *
4305:    * <p>Fire a PropertyChangeEvent with name {@link
4306:    * #SELECTION_FOREGROUND_CHANGED_PROPERTY} to registered listeners, if
4307:    * selectionForeground changed.</p>
4308:    *
4309:    * @param s The new value of the selectionForeground property
4310:    */ 
4311:   public void setSelectionForeground(Color s)
4312:   {
4313:     Color tmp = selectionForeground;
4314:     selectionForeground = s;
4315:     if (((tmp == null && s != null)
4316:          || (s == null && tmp != null)
4317:          || (tmp != null && s != null && !tmp.equals(s))))
4318:       firePropertyChange(SELECTION_FOREGROUND_CHANGED_PROPERTY, tmp, s);
4319:     repaint();
4320:   }
4321: 
4322:   /**
4323:    * Set the value of the <code>showGrid</code> property.
4324:    *
4325:    * @param s The new value of the showGrid property
4326:    */ 
4327:   public void setShowGrid(boolean s)
4328:   {
4329:     setShowVerticalLines(s);
4330:     setShowHorizontalLines(s);
4331:   }
4332: 
4333:   /**
4334:    * Set the value of the {@link #showHorizontalLines} property.
4335:    *
4336:    * @param s The new value of the showHorizontalLines property
4337:    */ 
4338:   public void setShowHorizontalLines(boolean s)
4339:   {
4340:     showHorizontalLines = s;
4341:     repaint();
4342:   }
4343: 
4344:   /**
4345:    * Set the value of the {@link #showVerticalLines} property.
4346:    *
4347:    * @param s The new value of the showVerticalLines property
4348:    */ 
4349:   public void setShowVerticalLines(boolean s)
4350:   {
4351:     showVerticalLines = s;
4352:     repaint();
4353:   }
4354: 
4355:   /**
4356:    * Set the value of the {@link #tableHeader} property.
4357:    *
4358:    * @param t The new value of the tableHeader property
4359:    */ 
4360:   public void setTableHeader(JTableHeader t)
4361:   {
4362:     if (tableHeader != null)
4363:       tableHeader.setTable(null);
4364:     tableHeader = t;
4365:     if (tableHeader != null)
4366:       tableHeader.setTable(this);
4367:     revalidate();
4368:     repaint();
4369:   }
4370: 
4371:   protected void configureEnclosingScrollPane()
4372:   {
4373:     JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
4374:     if (jsp != null && tableHeader != null)
4375:       {
4376:         jsp.setColumnHeaderView(tableHeader);
4377:       }
4378:   }
4379: 
4380:   protected void unconfigureEnclosingScrollPane()
4381:   {
4382:     JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
4383:     if (jsp != null)
4384:       {
4385:         jsp.setColumnHeaderView(null);
4386:       }    
4387:   }
4388: 
4389: 
4390:   public void addNotify()
4391:   {
4392:     super.addNotify();
4393:     configureEnclosingScrollPane();
4394:   }
4395: 
4396:   public void removeNotify()
4397:   {
4398:     super.addNotify();
4399:     unconfigureEnclosingScrollPane();
4400:   }
4401: 
4402: 
4403:   /**
4404:    * This distributes the superfluous width in a table evenly on its columns.
4405:    *
4406:    * The implementation used here is different to that one described in
4407:    * the JavaDocs. It is much simpler, and seems to work very well.
4408:    *
4409:    * TODO: correctly implement the algorithm described in the JavaDoc
4410:    */
4411:   private void distributeSpill(TableColumn[] cols, int spill)
4412:   {
4413:     int average = spill / cols.length;
4414:     for (int i = 0; i < cols.length; i++)
4415:       {
4416:         if (cols[i] != null)
4417:           cols[i].setWidth(cols[i].getPreferredWidth() + average);
4418:       }
4419:   }
4420:   
4421:   /**
4422:    * This distributes the superfluous width in a table, setting the width of the
4423:    * column being resized strictly to its preferred width.
4424:    */
4425:   private void distributeSpillResizing(TableColumn[] cols, int spill,
4426:                                        TableColumn resizeIt)
4427:   {
4428:     int average = 0;
4429:     if (cols.length != 1)
4430:       average = spill / (cols.length-1);
4431:     for (int i = 0; i < cols.length; i++)
4432:       {
4433:         if (cols[i] != null && !cols[i].equals(resizeIt))
4434:           cols[i].setWidth(cols[i].getPreferredWidth() + average);
4435:       }
4436:     resizeIt.setWidth(resizeIt.getPreferredWidth());
4437:   }  
4438:   
4439:   /**
4440:    * Set the widths of all columns, taking they preferred widths into
4441:    * consideration. The excess space, if any, will be distrubuted between
4442:    * all columns. This method also handles special cases when one of the
4443:    * collumns is currently being resized.
4444:    * 
4445:    * @see TableColumn#setPreferredWidth(int)
4446:    */
4447:   public void doLayout()
4448:   {
4449:     TableColumn resizingColumn = null;
4450:     
4451:     int ncols = columnModel.getColumnCount();
4452:     if (ncols < 1)
4453:       return;
4454: 
4455:     int prefSum = 0;
4456:     int rCol = -1;
4457: 
4458:     if (tableHeader != null)
4459:       resizingColumn = tableHeader.getResizingColumn();
4460:      
4461:     for (int i = 0; i < ncols; ++i)
4462:       {
4463:         TableColumn col = columnModel.getColumn(i);
4464:         int p = col.getPreferredWidth();
4465:         prefSum += p;
4466:         if (resizingColumn == col)
4467:           rCol = i;
4468:       }
4469:  
4470:     int spill = getWidth() - prefSum;
4471: 
4472:     if (resizingColumn != null)
4473:       {
4474:         TableColumn col;
4475:         TableColumn [] cols;
4476:         
4477:         switch (getAutoResizeMode())
4478:           {
4479:           case AUTO_RESIZE_LAST_COLUMN:
4480:             col = columnModel.getColumn(ncols-1);
4481:             col.setWidth(col.getPreferredWidth() + spill);
4482:             break;
4483:             
4484:           case AUTO_RESIZE_NEXT_COLUMN:
4485:             col = columnModel.getColumn(ncols-1);
4486:             col.setWidth(col.getPreferredWidth() + spill);
4487:             break;
4488: 
4489:           case AUTO_RESIZE_ALL_COLUMNS:
4490:             cols = new TableColumn[ncols];
4491:             for (int i = 0; i < ncols; ++i)
4492:               cols[i] = columnModel.getColumn(i);
4493:             distributeSpillResizing(cols, spill, resizingColumn);
4494:             break;
4495: 
4496:           case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
4497:             
4498:             // Subtract the width of the non-resized columns from the spill.
4499:             int w = 0;
4500:             int wp = 0;
4501:             TableColumn column;
4502:             for (int i = 0; i < rCol; i++)
4503:               {
4504:                 column = columnModel.getColumn(i);
4505:                 w += column.getWidth();
4506:                 wp+= column.getPreferredWidth();
4507:               }
4508: 
4509:             // The number of columns right from the column being resized.
4510:             int n = ncols-rCol-1;
4511:             if (n>0)
4512:               {
4513:                 // If there are any columns on the right sied to resize.
4514:                 spill = (getWidth()-w) - (prefSum-wp);
4515:                 int average = spill / n;
4516:             
4517:                  // For all columns right from the column being resized:
4518:                 for (int i = rCol+1; i < ncols; i++)
4519:                   {
4520:                     column = columnModel.getColumn(i);
4521:                     column.setWidth(column.getPreferredWidth() + average);
4522:                   }
4523:               }
4524:             resizingColumn.setWidth(resizingColumn.getPreferredWidth());
4525:             break;
4526: 
4527:           case AUTO_RESIZE_OFF:
4528:           default:
4529:             int prefWidth = resizingColumn.getPreferredWidth();
4530:             resizingColumn.setWidth(prefWidth);
4531:           }
4532:       }
4533:     else
4534:       {
4535:         TableColumn[] cols = new TableColumn[ncols];
4536: 
4537:         for (int i = 0; i < ncols; ++i)
4538:           cols[i] = columnModel.getColumn(i);
4539: 
4540:         distributeSpill(cols, spill);
4541:       }
4542:     
4543:     if (editorComp!=null)
4544:       moveToCellBeingEdited(editorComp);
4545:     
4546:     int leftBoundary = getLeftResizingBoundary();
4547:     int width = getWidth() - leftBoundary;
4548:     repaint(leftBoundary, 0, width, getHeight());
4549:     if (tableHeader != null)
4550:       tableHeader.repaint(leftBoundary, 0, width, tableHeader.getHeight());
4551:   }
4552:   
4553:   /**
4554:    * Get the left boundary of the rectangle which changes during the column
4555:    * resizing.
4556:    */
4557:   int getLeftResizingBoundary()
4558:   {
4559:     if (tableHeader == null || getAutoResizeMode() == AUTO_RESIZE_ALL_COLUMNS)
4560:       return 0;
4561:     else
4562:       {
4563:         TableColumn resizingColumn = tableHeader.getResizingColumn();
4564:         if (resizingColumn == null)
4565:           return 0;
4566: 
4567:         int rc = convertColumnIndexToView(resizingColumn.getModelIndex());
4568:         int p = 0;
4569: 
4570:         for (int i = 0; i < rc; i++)
4571:           p += columnModel.getColumn(i).getWidth();
4572:         
4573:         return p;
4574:       }
4575:   }
4576:   
4577:   
4578:   /**
4579:    * @deprecated Replaced by <code>doLayout()</code>
4580:    */
4581:   public void sizeColumnsToFit(boolean lastColumnOnly)
4582:   {
4583:     doLayout();
4584:   }
4585:   
4586:   /**
4587:    * Obsolete since JDK 1.4. Please use <code>doLayout()</code>.
4588:    */
4589:   public void sizeColumnsToFit(int resizingColumn)
4590:   {
4591:     doLayout();
4592:   }
4593: 
4594:   public String getUIClassID()
4595:   {
4596:     return "TableUI";
4597:   }
4598: 
4599:   /**
4600:    * This method returns the table's UI delegate.
4601:    *
4602:    * @return The table's UI delegate.
4603:    */
4604:   public TableUI getUI()
4605:   {
4606:     return (TableUI) ui;
4607:   }
4608: 
4609:   /**
4610:    * This method sets the table's UI delegate.
4611:    *
4612:    * @param ui The table's UI delegate.
4613:    */
4614:   public void setUI(TableUI ui)
4615:   {
4616:     super.setUI(ui);
4617:     // The editors and renderers must be recreated because they constructors
4618:     // may use the look and feel properties.
4619:     createDefaultEditors();
4620:     createDefaultRenderers();
4621:   }
4622: 
4623:   public void updateUI()
4624:   {
4625:     setUI((TableUI) UIManager.getUI(this));
4626:   }
4627: 
4628:   /**
4629:    * Get the class (datatype) of the column. The cells are rendered and edited
4630:    * differently, depending from they data type.
4631:    * 
4632:    * @param column the column (not the model index).
4633:    * 
4634:    * @return the class, defining data type of that column (String.class for
4635:    * String, Boolean.class for boolean and so on).
4636:    */
4637:   public Class<?> getColumnClass(int column)
4638:   {
4639:     return getModel().getColumnClass(convertColumnIndexToModel(column));
4640:   }
4641:   
4642:   /**
4643:    * Get the name of the column. If the column has the column identifier set,
4644:    * the return value is the result of the .toString() method call on that
4645:    * identifier. If the identifier is not explicitly set, the returned value
4646:    * is calculated by 
4647:    * {@link javax.swing.table.AbstractTableModel#getColumnName(int)}.
4648:    * 
4649:    * @param column the column
4650:    * 
4651:    * @return the name of that column.
4652:    */
4653:   public String getColumnName(int column)
4654:   {
4655:     int modelColumn = columnModel.getColumn(column).getModelIndex();
4656:     return dataModel.getColumnName(modelColumn);
4657:   }
4658: 
4659:   /**
4660:    * Get the column, currently being edited
4661:    * 
4662:    * @return the column, currently being edited.
4663:    */
4664:   public int getEditingColumn()
4665:   {
4666:     return editingColumn;
4667:   }
4668: 
4669:   /**
4670:    * Set the column, currently being edited
4671:    * 
4672:    * @param column the column, currently being edited.
4673:    */
4674:   public void setEditingColumn(int column)
4675:   {
4676:     editingColumn = column;
4677:   }
4678:   
4679:   /**
4680:    * Get the row currently being edited.
4681:    * 
4682:    * @return the row, currently being edited.
4683:    */
4684:   public int getEditingRow()
4685:   {
4686:     return editingRow;
4687:   }
4688: 
4689:   /**
4690:    * Set the row currently being edited.
4691:    * 
4692:    * @param row the row, that will be edited
4693:    */
4694:   public void setEditingRow(int row)
4695:   {
4696:     editingRow = row;
4697:   }
4698:   
4699:   /**
4700:    * Get the editor component that is currently editing one of the cells
4701:    * 
4702:    * @return the editor component or null, if none of the cells is being
4703:    * edited.
4704:    */
4705:   public Component getEditorComponent()
4706:   {
4707:     return editorComp;
4708:   }
4709:   
4710:   /**
4711:    * Check if one of the table cells is currently being edited.
4712:    * 
4713:    * @return true if there is a cell being edited.
4714:    */
4715:   public boolean isEditing()
4716:   {
4717:     return editorComp != null;
4718:   }
4719: 
4720:   /**
4721:    * Set the default editor for the given column class (column data type).
4722:    * By default, String is handled by text field and Boolean is handled by
4723:    * the check box.
4724:    *  
4725:    * @param columnClass the column data type
4726:    * @param editor the editor that will edit this data type
4727:    * 
4728:    * @see TableModel#getColumnClass(int)
4729:    */
4730:   public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor)
4731:   {
4732:     if (editor != null)
4733:       defaultEditorsByColumnClass.put(columnClass, editor);
4734:     else
4735:       defaultEditorsByColumnClass.remove(columnClass);
4736:   }
4737:   
4738:   public void addColumnSelectionInterval(int index0, int index1)
4739:   {
4740:     if ((index0 < 0 || index0 > (getColumnCount()-1)
4741:          || index1 < 0 || index1 > (getColumnCount()-1)))
4742:       throw new IllegalArgumentException("Column index out of range.");
4743:     
4744:     getColumnModel().getSelectionModel().addSelectionInterval(index0, index1);
4745:   }
4746:   
4747:   public void addRowSelectionInterval(int index0, int index1)
4748:   {            
4749:     if ((index0 < 0 || index0 > (getRowCount()-1)
4750:          || index1 < 0 || index1 > (getRowCount()-1)))
4751:       throw new IllegalArgumentException("Row index out of range.");
4752:         
4753:     getSelectionModel().addSelectionInterval(index0, index1);
4754:   }
4755:   
4756:   public void setColumnSelectionInterval(int index0, int index1)
4757:   {
4758:     if ((index0 < 0 || index0 > (getColumnCount()-1)
4759:          || index1 < 0 || index1 > (getColumnCount()-1)))
4760:       throw new IllegalArgumentException("Column index out of range.");
4761: 
4762:     getColumnModel().getSelectionModel().setSelectionInterval(index0, index1);
4763:   }
4764:   
4765:   public void setRowSelectionInterval(int index0, int index1)
4766:   {    
4767:     if ((index0 < 0 || index0 > (getRowCount()-1)
4768:          || index1 < 0 || index1 > (getRowCount()-1)))
4769:       throw new IllegalArgumentException("Row index out of range.");
4770: 
4771:     getSelectionModel().setSelectionInterval(index0, index1);
4772:   }
4773:   
4774:   public void removeColumnSelectionInterval(int index0, int index1)  
4775:   {
4776:     if ((index0 < 0 || index0 > (getColumnCount()-1)
4777:          || index1 < 0 || index1 > (getColumnCount()-1)))
4778:       throw new IllegalArgumentException("Column index out of range.");
4779: 
4780:     getColumnModel().getSelectionModel().removeSelectionInterval(index0, index1);
4781:   }
4782:   
4783:   public void removeRowSelectionInterval(int index0, int index1)
4784:   {
4785:     if ((index0 < 0 || index0 > (getRowCount()-1)
4786:          || index1 < 0 || index1 > (getRowCount()-1)))
4787:       throw new IllegalArgumentException("Row index out of range.");
4788: 
4789:     getSelectionModel().removeSelectionInterval(index0, index1);
4790:   }
4791:   
4792:   /**
4793:    * Checks if the given column is selected.
4794:    * 
4795:    * @param column the column
4796:    * 
4797:    * @return true if the column is selected (as reported by the selection
4798:    * model, associated with the column model), false otherwise.
4799:    */
4800:   public boolean isColumnSelected(int column)
4801:   {
4802:     return getColumnModel().getSelectionModel().isSelectedIndex(column);
4803:   }
4804:   
4805:   /**
4806:    * Checks if the given row is selected.
4807:    * 
4808:    * @param row the row
4809:    * 
4810:    * @return true if the row is selected (as reported by the selection model),
4811:    * false otherwise.
4812:    */
4813:   public boolean isRowSelected(int row)
4814:   {
4815:     return getSelectionModel().isSelectedIndex(row);
4816:   }
4817:   
4818:   /**
4819:    * Checks if the given cell is selected. The cell is selected if both
4820:    * the cell row and the cell column are selected.
4821:    * 
4822:    * @param row the cell row
4823:    * @param column the cell column
4824:    * 
4825:    * @return true if the cell is selected, false otherwise
4826:    */
4827:   public boolean isCellSelected(int row, int column)
4828:   {
4829:     return isRowSelected(row) && isColumnSelected(column);
4830:   }
4831:   
4832:   /**
4833:    * Select all table.
4834:    */
4835:   public void selectAll()
4836:   {
4837:     // The table is empty - nothing to do!
4838:     if (getRowCount() == 0 || getColumnCount() == 0)
4839:       return;
4840:     
4841:     // rowLead and colLead store the current lead selection indices
4842:     int rowLead = selectionModel.getLeadSelectionIndex();
4843:     int colLead = getColumnModel().getSelectionModel().getLeadSelectionIndex();
4844:     // the following calls to setSelectionInterval change the lead selection
4845:     // indices
4846:     setColumnSelectionInterval(0, getColumnCount() - 1);
4847:     setRowSelectionInterval(0, getRowCount() - 1);
4848:     // the following addSelectionInterval calls restore the lead selection
4849:     // indices to their previous values
4850:     addColumnSelectionInterval(colLead,colLead);
4851:     addRowSelectionInterval(rowLead, rowLead);
4852:   }
4853:   
4854:   /**
4855:    * Get the cell value at the given position.
4856:    * 
4857:    * @param row the row to get the value
4858:    * @param column the actual column number (not the model index) 
4859:    * to get the value.
4860:    * 
4861:    * @return the cell value, as returned by model.
4862:    */
4863:   public Object getValueAt(int row, int column)
4864:   {
4865:     return dataModel.getValueAt(row, convertColumnIndexToModel(column));
4866:   }
4867:   
4868:   /**
4869:    * Set value for the cell at the given position. The modified cell is
4870:    * repainted.
4871:    * 
4872:    * @param value the value to set
4873:    * @param row the row of the cell being modified
4874:    * @param column the column of the cell being modified
4875:    */
4876:   public void setValueAt(Object value, int row, int column)
4877:   {
4878:     dataModel.setValueAt(value, row, convertColumnIndexToModel(column));
4879:     
4880:     repaint(getCellRect(row, column, true));
4881:   }
4882:   
4883:   /**
4884:    * Get table column with the given identified.
4885:    * 
4886:    * @param identifier the column identifier
4887:    * 
4888:    * @return the table column with this identifier
4889:    * 
4890:    * @throws IllegalArgumentException if <code>identifier</code> is 
4891:    *         <code>null</code> or there is no column with that identifier.
4892:    * 
4893:    * @see TableColumn#setIdentifier(Object)
4894:    */
4895:   public TableColumn getColumn(Object identifier)
4896:   {
4897:     return columnModel.getColumn(columnModel.getColumnIndex(identifier));
4898:   }
4899: 
4900:   /**
4901:    * Returns <code>true</code> if the specified cell is editable, and
4902:    * <code>false</code> otherwise.
4903:    *
4904:    * @param row  the row index.
4905:    * @param column  the column index.
4906:    *
4907:    * @return true if the cell is editable, false otherwise.
4908:    */
4909:   public boolean isCellEditable(int row, int column)
4910:   {
4911:     return dataModel.isCellEditable(row, convertColumnIndexToModel(column));
4912:   }
4913: 
4914:   /**
4915:    * Clears any existing columns from the <code>JTable</code>'s
4916:    * {@link TableColumnModel} and creates new columns to match the values in
4917:    * the data ({@link TableModel}) used by the table.
4918:    *
4919:    * @see #setAutoCreateColumnsFromModel(boolean)
4920:    */
4921:   public void createDefaultColumnsFromModel()
4922:   {
4923:     assert columnModel != null : "The columnModel must not be null.";
4924: 
4925:     // remove existing columns
4926:     int columnIndex = columnModel.getColumnCount() - 1;
4927:     while (columnIndex >= 0)
4928:     {
4929:       columnModel.removeColumn(columnModel.getColumn(columnIndex));
4930:       columnIndex--;
4931:     }
4932:   
4933:     // add new columns to match the TableModel
4934:     int columnCount = dataModel.getColumnCount();
4935:     for (int c = 0; c < columnCount; c++)
4936:     {
4937:       TableColumn column = new TableColumn(c);
4938:       column.setIdentifier(dataModel.getColumnName(c));
4939:       column.setHeaderValue(dataModel.getColumnName(c));
4940:       columnModel.addColumn(column);
4941:       column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
4942:     }
4943:   }
4944: 
4945:   public void changeSelection (int rowIndex, int columnIndex, boolean toggle, boolean extend)
4946:   {
4947:     if (toggle && extend)
4948:       {
4949:         // Leave the selection state as is, but move the anchor
4950:         //   index to the specified location
4951:         selectionModel.setAnchorSelectionIndex(rowIndex);
4952:         getColumnModel().getSelectionModel().setAnchorSelectionIndex(columnIndex);
4953:       }
4954:     else if (toggle)
4955:       {
4956:         // Toggle the state of the specified cell
4957:         if (isCellSelected(rowIndex,columnIndex))
4958:           {
4959:             selectionModel.removeSelectionInterval(rowIndex,rowIndex);
4960:             getColumnModel().getSelectionModel().removeSelectionInterval(columnIndex,columnIndex);
4961:           }
4962:         else
4963:           {
4964:             selectionModel.addSelectionInterval(rowIndex,rowIndex);
4965:             getColumnModel().getSelectionModel().addSelectionInterval(columnIndex,columnIndex);
4966:           }
4967:       }
4968:     else if (extend)
4969:       {
4970:         // Extend the previous selection from the anchor to the 
4971:         // specified cell, clearing all other selections
4972:         selectionModel.setLeadSelectionIndex(rowIndex);
4973:         getColumnModel().getSelectionModel().setLeadSelectionIndex(columnIndex);
4974:       }
4975:     else
4976:       {
4977:         // Clear the previous selection and ensure the new cell
4978:         // is selected
4979:          selectionModel.clearSelection();
4980:         selectionModel.setSelectionInterval(rowIndex,rowIndex);
4981:         getColumnModel().getSelectionModel().clearSelection();
4982:         getColumnModel().getSelectionModel().setSelectionInterval(columnIndex, columnIndex);
4983:         
4984:         
4985:       }
4986:   }
4987: 
4988:   /**
4989:    * Programmatically starts editing the specified cell.
4990:    * 
4991:    * @param row the row of the cell to edit.
4992:    * @param column the column of the cell to edit.
4993:    */
4994:   public boolean editCellAt(int row, int column)
4995:   {
4996:     // Complete the previous editing session, if still active.
4997:     if (isEditing())
4998:       editingStopped(new ChangeEvent("editingStopped"));
4999: 
5000:     TableCellEditor editor = getCellEditor(row, column);
5001:     
5002:     // The boolean values are inverted by the single click without the
5003:     // real editing session.
5004:     if (editor == booleanInvertingEditor && isCellEditable(row, column))
5005:       {
5006:         if (Boolean.TRUE.equals(getValueAt(row, column)))
5007:           setValueAt(Boolean.FALSE, row, column);
5008:         else
5009:           setValueAt(Boolean.TRUE, row, column);
5010:         return false;
5011:       }
5012:     else
5013:       {
5014:         editingRow = row;
5015:         editingColumn = column;
5016: 
5017:         setCellEditor(editor);
5018:         editorComp = prepareEditor(cellEditor, row, column);
5019: 
5020:         // Remove the previous editor components, if present. Only one
5021:         // editor component at time is allowed in the table.
5022:         removeAll();
5023:         add(editorComp);
5024:         moveToCellBeingEdited(editorComp);
5025:         scrollRectToVisible(editorComp.getBounds());
5026:         editorComp.requestFocusInWindow();
5027:         
5028:         // Deliver the should select event.
5029:         return editor.shouldSelectCell(null);        
5030:       }
5031:   }
5032: 
5033:   /**
5034:    * Move the given component under the cell being edited. 
5035:    * The table must be in the editing mode.
5036:    * 
5037:    * @param component the component to move.
5038:    */
5039:   private void moveToCellBeingEdited(Component component)
5040:   {
5041:      Rectangle r = getCellRect(editingRow, editingColumn, true);
5042:      // Adjust bounding box of the editing component, so that it lies
5043:      // 'above' the grid on all edges, not only right and bottom.
5044:      // The table grid is painted only at the right and bottom edge of a cell.
5045:      r.x -= 1;
5046:      r.y -= 1;
5047:      r.width += 1;
5048:      r.height += 1;
5049:      component.setBounds(r);
5050:   }
5051: 
5052:   /**
5053:    * Programmatically starts editing the specified cell.
5054:    *
5055:    * @param row the row of the cell to edit.
5056:    * @param column the column of the cell to edit.
5057:    */
5058:   public boolean editCellAt (int row, int column, EventObject e)
5059:   {
5060:     return editCellAt(row, column);
5061:   }
5062: 
5063:   /**
5064:    * Discards the editor object.
5065:    */
5066:   public void removeEditor()
5067:   {
5068:     editingStopped(new ChangeEvent(this));
5069:   }
5070: 
5071:   /**
5072:    * Prepares the editor by querying for the value and selection state of the
5073:    * cell at (row, column).
5074:    *
5075:    * @param editor the TableCellEditor to set up
5076:    * @param row the row of the cell to edit
5077:    * @param column the column of the cell to edit
5078:    * @return the Component being edited
5079:    */
5080:   public Component prepareEditor (TableCellEditor editor, int row, int column)
5081:   {
5082:     return editor.getTableCellEditorComponent
5083:       (this, getValueAt(row, column), isCellSelected(row, column), row, column);
5084:   }
5085: 
5086:   /**
5087:    * This revalidates the <code>JTable</code> and queues a repaint.
5088:    */
5089:   protected void resizeAndRepaint()
5090:   {
5091:     revalidate();
5092:     repaint();
5093:   }
5094: 
5095:   /**
5096:    * Sets whether cell editors of this table should receive keyboard focus
5097:    * when the editor is activated by a keystroke. The default setting is
5098:    * <code>false</code> which means that the table should keep the keyboard
5099:    * focus until the cell is selected by a mouse click.
5100:    *
5101:    * @param value the value to set
5102:    *
5103:    * @since 1.4
5104:    */
5105:   public void setSurrendersFocusOnKeystroke(boolean value)
5106:   {
5107:     // TODO: Implement functionality of this property (in UI impl).
5108:     surrendersFocusOnKeystroke = value;
5109:   }
5110:   
5111:   /**
5112:    * Returns whether cell editors of this table should receive keyboard focus
5113:    * when the editor is activated by a keystroke. The default setting is
5114:    * <code>false</code> which means that the table should keep the keyboard
5115:    * focus until the cell is selected by a mouse click.
5116:    *
5117:    * @return whether cell editors of this table should receive keyboard focus
5118:    *         when the editor is activated by a keystroke
5119:    *
5120:    * @since 1.4
5121:    */
5122:   public boolean getSurrendersFocusOnKeystroke()
5123:   {
5124:     // TODO: Implement functionality of this property (in UI impl).
5125:     return surrendersFocusOnKeystroke;
5126:   }
5127: 
5128:   /**
5129:    * Helper method for
5130:    * {@link LookAndFeel#installProperty(JComponent, String, Object)}.
5131:    * 
5132:    * @param propertyName the name of the property
5133:    * @param value the value of the property
5134:    *
5135:    * @throws IllegalArgumentException if the specified property cannot be set
5136:    *         by this method
5137:    * @throws ClassCastException if the property value does not match the
5138:    *         property type
5139:    * @throws NullPointerException if <code>c</code> or
5140:    *         <code>propertyValue</code> is <code>null</code>
5141:    */
5142:   void setUIProperty(String propertyName, Object value)
5143:   {
5144:     if (propertyName.equals("rowHeight"))
5145:       {
5146:         if (! clientRowHeightSet)
5147:           {
5148:             setRowHeight(((Integer) value).intValue());
5149:             clientRowHeightSet = false;
5150:           }
5151:       }
5152:     else
5153:       {
5154:         super.setUIProperty(propertyName, value);
5155:       }
5156:   }
5157: }