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.AccessibleStateSet;
  67: import javax.accessibility.AccessibleTable;
  68: import javax.accessibility.AccessibleTableModelChange;
  69: import javax.swing.event.CellEditorListener;
  70: import javax.swing.event.ChangeEvent;
  71: import javax.swing.event.ListSelectionEvent;
  72: import javax.swing.event.ListSelectionListener;
  73: import javax.swing.event.TableColumnModelEvent;
  74: import javax.swing.event.TableColumnModelListener;
  75: import javax.swing.event.TableModelEvent;
  76: import javax.swing.event.TableModelListener;
  77: import javax.swing.plaf.TableUI;
  78: import javax.swing.table.DefaultTableCellRenderer;
  79: import javax.swing.table.DefaultTableColumnModel;
  80: import javax.swing.table.DefaultTableModel;
  81: import javax.swing.table.JTableHeader;
  82: import javax.swing.table.TableCellEditor;
  83: import javax.swing.table.TableCellRenderer;
  84: import javax.swing.table.TableColumn;
  85: import javax.swing.table.TableColumnModel;
  86: import javax.swing.table.TableModel;
  87: 
  88: /**
  89:  * The table component, displaying information, organized in rows and columns.
  90:  * The table can be placed in the scroll bar and have the optional header
  91:  * that is always visible. Cell values may be editable after double clicking
  92:  * on the cell. Cell columns may have various data types, that are 
  93:  * displayed and edited by the different renderers and editors. It is possible
  94:  * to set different column width. The columns are also resizeable by 
  95:  * dragging the column boundary in the header.
  96:  */
  97: public class JTable
  98:   extends JComponent
  99:   implements TableModelListener, Scrollable, TableColumnModelListener,
 100:              ListSelectionListener, CellEditorListener, Accessible
 101: {
 102:   /**
 103:    * Provides accessibility support for <code>JTable</code>.
 104:    *
 105:    * @author Roman Kennke (kennke@aicas.com)
 106:    */
 107:   protected class AccessibleJTable
 108:     extends AccessibleJComponent
 109:     implements AccessibleSelection, ListSelectionListener, TableModelListener,
 110:     TableColumnModelListener, CellEditorListener, PropertyChangeListener,
 111:     AccessibleExtendedTable
 112:   {
 113: 
 114:     /**
 115:      * Provides accessibility support for table cells.
 116:      *
 117:      * @author Roman Kennke (kennke@aicas.com)
 118:      */
 119:     protected class AccessibleJTableCell
 120:       extends AccessibleContext
 121:       implements Accessible, AccessibleComponent
 122:     {
 123: 
 124:       /**
 125:        * The table of this cell.
 126:        */
 127:       private JTable table;
 128: 
 129:       /**
 130:        * The row index of this cell.
 131:        */
 132:       private int row;
 133: 
 134:       /**
 135:        * The column index of this cell.
 136:        */
 137:       private int column;
 138: 
 139:       /**
 140:        * The index of this cell inside the AccessibleJTable parent.
 141:        */
 142:       private int index;
 143: 
 144:       /**
 145:        * Creates a new <code>AccessibleJTableCell</code>.
 146:        *
 147:        * @param t the table
 148:        * @param r the row
 149:        * @param c the column
 150:        * @param i the index of this cell inside the accessible table parent
 151:        */
 152:       public AccessibleJTableCell(JTable t, int r, int c, int i)
 153:       {
 154:         table = t;
 155:         row = r;
 156:         column = c;
 157:         index = i;
 158:       }
 159: 
 160:       /**
 161:        * Returns the accessible row for the table cell.
 162:        *
 163:        * @return the accessible row for the table cell
 164:        */
 165:       public AccessibleRole getAccessibleRole()
 166:       {
 167:         // TODO: What is the role of the table cell?
 168:         return AccessibleRole.UNKNOWN;
 169:       }
 170: 
 171:       /**
 172:        * Returns the accessible state set of this accessible table cell.
 173:        *
 174:        * @return the accessible state set of this accessible table cell
 175:        */
 176:       public AccessibleStateSet getAccessibleStateSet()
 177:       {
 178:         // TODO: What state shoiuld be returned here?
 179:         return new AccessibleStateSet();
 180:       }
 181: 
 182:       /**
 183:        * Returns the index of this cell in the parent object.
 184:        *
 185:        * @return the index of this cell in the parent object
 186:        */
 187:       public int getAccessibleIndexInParent()
 188:       {
 189:         return index;
 190:       }
 191: 
 192:       /**
 193:        * Returns the number of children of this object. Table cells cannot have
 194:        * children, so we return <code>0</code> here.
 195:        *
 196:        * @return <code>0</code>
 197:        */
 198:       public int getAccessibleChildrenCount()
 199:       {
 200:         return 0;
 201:       }
 202: 
 203:       /**
 204:        * Returns the accessible child at index <code>i</code>. Table cells
 205:        * don't have children, so we return <code>null</code> here.
 206:        *
 207:        * @return <code>null</code>
 208:        */
 209:       public Accessible getAccessibleChild(int i)
 210:       {
 211:         return null;
 212:       }
 213: 
 214:       /**
 215:        * Returns the locale setting for this accessible table cell.
 216:        *
 217:        * @return the locale setting for this accessible table cell
 218:        */
 219:       public Locale getLocale()
 220:       {
 221:         // TODO: For now, we return english here. This must be fixed as soon
 222:         // as we have a localized Swing.
 223:         return Locale.ENGLISH;
 224:       }
 225: 
 226:       /**
 227:        * Returns the accessible context of this table cell. Since accessible
 228:        * table cells are their own accessible context, we return
 229:        * <code>this</code>.
 230:        *
 231:        * @return the accessible context of this table cell
 232:        */
 233:       public AccessibleContext getAccessibleContext()
 234:       {
 235:         return this;
 236:       }
 237: 
 238:       /**
 239:        * Returns the background color of this cell.
 240:        *
 241:        * @return the background color of this cell
 242:        */
 243:       public Color getBackground()
 244:       {
 245:         return table.getBackground();
 246:       }
 247: 
 248:       /**
 249:        * Sets the background of the cell. Since table cells cannot have
 250:        * individual background colors, this method does nothing. Set the
 251:        * background directly on the table instead.
 252:        * 
 253:        * @param color not used
 254:        */
 255:       public void setBackground(Color color)
 256:       {
 257:         // This method does nothing. See API comments.
 258:       }
 259: 
 260:       /**
 261:        * Returns the foreground color of the table cell.
 262:        *
 263:        * @return the foreground color of the table cell
 264:        */
 265:       public Color getForeground()
 266:       {
 267:         return table.getForeground();
 268:       }
 269: 
 270:       /**
 271:        * Sets the foreground of the cell. Since table cells cannot have
 272:        * individual foreground colors, this method does nothing. Set the
 273:        * foreground directly on the table instead.
 274:        * 
 275:        * @param color not used
 276:        */
 277:       public void setForeground(Color color)
 278:       {
 279:         // This method does nothing. See API comments.
 280:       }
 281: 
 282:       /**
 283:        * Returns the cursor for this table cell.
 284:        *
 285:        * @return the cursor for this table cell
 286:        */
 287:       public Cursor getCursor()
 288:       {
 289:         return table.getCursor();
 290:       }
 291: 
 292:       /**
 293:        * Sets the cursor of the cell. Since table cells cannot have
 294:        * individual cursors, this method does nothing. Set the
 295:        * cursor directly on the table instead.
 296:        * 
 297:        * @param cursor not used
 298:        */
 299:       public void setCursor(Cursor cursor)
 300:       {
 301:         // This method does nothing. See API comments.
 302:       }
 303: 
 304:       /**
 305:        * Returns the font of the table cell.
 306:        *
 307:        * @return the font of the table cell
 308:        */
 309:       public Font getFont()
 310:       {
 311:         return table.getFont();
 312:       }
 313: 
 314:       /**
 315:        * Sets the font of the cell. Since table cells cannot have
 316:        * individual fonts, this method does nothing. Set the
 317:        * font directly on the table instead.
 318:        * 
 319:        * @param font not used
 320:        */
 321:       public void setFont(Font font)
 322:       {
 323:         // This method does nothing. See API comments.
 324:       }
 325: 
 326:       /**
 327:        * Returns the font metrics for a specified font.
 328:        *
 329:        * @param font the font for which we return the metrics
 330:        *
 331:        * @return the font metrics for a specified font
 332:        */
 333:       public FontMetrics getFontMetrics(Font font)
 334:       {
 335:         return table.getFontMetrics(font);
 336:       }
 337: 
 338:       /**
 339:        * Returns <code>true</code> if this table cell is enabled,
 340:        * <code>false</code> otherwise.
 341:        *
 342:        * @return <code>true</code> if this table cell is enabled,
 343:        *         <code>false</code> otherwise
 344:        */
 345:       public boolean isEnabled()
 346:       {
 347:         return table.isEnabled();
 348:       }
 349: 
 350:       /**
 351:        * Table cells cannot be disabled or enabled individually, so this method
 352:        * does nothing. Set the enabled flag on the table itself.
 353:        *
 354:        * @param b not used here
 355:        */
 356:       public void setEnabled(boolean b)
 357:       {
 358:         // This method does nothing. See API comments.
 359:       }
 360: 
 361:       /**
 362:        * Returns <code>true</code> if this cell is visible, <code>false</code>
 363:        * otherwise.
 364:        *
 365:        * @return <code>true</code> if this cell is visible, <code>false</code>
 366:        *         otherwise
 367:        */
 368:       public boolean isVisible()
 369:       {
 370:         return table.isVisible();
 371:       }
 372: 
 373:       /**
 374:        * The visibility cannot be set on individual table cells, so this method
 375:        * does nothing. Set the visibility on the table itself.
 376:        *
 377:        * @param b not used
 378:        */
 379:       public void setVisible(boolean b)
 380:       {
 381:         // This method does nothing. See API comments.
 382:       }
 383: 
 384:       /**
 385:        * Returns <code>true</code> if this table cell is currently showing on
 386:        * screen.
 387:        *
 388:        * @return <code>true</code> if this table cell is currently showing on
 389:        *         screen
 390:        */
 391:       public boolean isShowing()
 392:       {
 393:         return table.isShowing();
 394:       }
 395: 
 396:       /**
 397:        * Returns <code>true</code> if this table cell contains the location
 398:        * at <code>point</code>, <code>false</code> otherwise.
 399:        * <code>point</code> is interpreted as relative to the coordinate system
 400:        * of the table cell.
 401:        *
 402:        * @return <code>true</code> if this table cell contains the location
 403:        *         at <code>point</code>, <code>false</code> otherwise
 404:        */
 405:       public boolean contains(Point point)
 406:       {
 407:         Rectangle cellRect = table.getCellRect(row, column, true);
 408:         cellRect.x = 0;
 409:         cellRect.y = 0;
 410:         return cellRect.contains(point);
 411:       }
 412: 
 413:       /**
 414:        * Returns the screen location of the table cell.
 415:        *
 416:        * @return the screen location of the table cell
 417:        */
 418:       public Point getLocationOnScreen()
 419:       {
 420:         Point tableLoc = table.getLocationOnScreen();
 421:         Rectangle cellRect = table.getCellRect(row, column, true);
 422:         tableLoc.x += cellRect.x;
 423:         tableLoc.y += cellRect.y;
 424:         return tableLoc;
 425:       }
 426: 
 427:       /**
 428:        * Returns the location of this cell relative to the table's bounds.
 429:        *
 430:        * @return the location of this cell relative to the table's bounds
 431:        */
 432:       public Point getLocation()
 433:       {
 434:         Rectangle cellRect = table.getCellRect(row, column, true);
 435:         return new Point(cellRect.x, cellRect.y);
 436:       }
 437: 
 438:       /**
 439:        * The location of the table cells cannot be manipulated directly, so
 440:        * this method does nothing.
 441:        *
 442:        * @param point not used
 443:        */
 444:       public void setLocation(Point point)
 445:       {
 446:         // This method does nothing. See API comments.
 447:       }
 448: 
 449:       /**
 450:        * Returns the bounds of the cell relative to its table.
 451:        *
 452:        * @return the bounds of the cell relative to its table
 453:        */
 454:       public Rectangle getBounds()
 455:       {
 456:         return table.getCellRect(row, column, true);
 457:       }
 458: 
 459:       /**
 460:        * The bounds of the table cells cannot be manipulated directly, so
 461:        * this method does nothing.
 462:        *
 463:        * @param rectangle not used
 464:        */
 465:       public void setBounds(Rectangle rectangle)
 466:       {
 467:         // This method does nothing. See API comments.
 468:       }
 469: 
 470:       /**
 471:        * Returns the size of the table cell.
 472:        *
 473:        * @return the size of the table cell
 474:        */
 475:       public Dimension getSize()
 476:       {
 477:         Rectangle cellRect = table.getCellRect(row, column, true);
 478:         return new Dimension(cellRect.width, cellRect.height);
 479:       }
 480: 
 481:       /**
 482:        * The size cannot be set on table cells directly, so this method does
 483:        * nothing.
 484:        *
 485:        * @param dimension not used
 486:        */
 487:       public void setSize(Dimension dimension)
 488:       {
 489:         // This method does nothing. See API comments.
 490:       }
 491: 
 492:       /**
 493:        * Table cells have no children, so we return <code>null</code> here.
 494:        *
 495:        * @return <code>null</code>
 496:        */
 497:       public Accessible getAccessibleAt(Point point)
 498:       {
 499:         return null;
 500:       }
 501: 
 502:       /**
 503:        * Returns <code>true</code> if this table cell is focus traversable,
 504:        * <code>false</code> otherwise.
 505:        *
 506:        * @return <code>true</code> if this table cell is focus traversable,
 507:        *         <code>false</code> otherwise
 508:        */
 509:       public boolean isFocusTraversable()
 510:       {
 511:         return table.isFocusable();
 512:       }
 513: 
 514:       /**
 515:        * Requests that this table cell gets the keyboard focus.
 516:        */
 517:       public void requestFocus()
 518:       {
 519:         // We first set the selection models' lead selection to this cell.
 520:         table.getColumnModel().getSelectionModel()
 521:         .setLeadSelectionIndex(column);
 522:         table.getSelectionModel().setLeadSelectionIndex(row);
 523:         // Now we request that the table receives focus.
 524:         table.requestFocus();
 525:       }
 526: 
 527:       /**
 528:        * Adds a focus listener to this cell. The focus listener is really
 529:        * added to the table, so there is no way to find out when an individual
 530:        * cell changes the focus.
 531:        *
 532:        * @param listener the focus listener to add
 533:        */
 534:       public void addFocusListener(FocusListener listener)
 535:       {
 536:         table.addFocusListener(listener);
 537:       }
 538: 
 539:       /**
 540:        * Removes a focus listener from the cell. The focus listener is really
 541:        * removed from the table.
 542:        *
 543:        * @param listener the listener to remove
 544:        */
 545:       public void removeFocusListener(FocusListener listener)
 546:       {
 547:         table.removeFocusListener(listener);
 548:       }
 549:         
 550:     }
 551: 
 552:     protected class AccessibleJTableModelChange
 553:       implements AccessibleTableModelChange
 554:     {
 555:       protected int type;
 556:       protected int firstRow;
 557:       protected int lastRow;
 558:       protected int firstColumn;
 559:       protected int lastColumn;
 560: 
 561:       protected AccessibleJTableModelChange(int type, int firstRow,
 562:                                             int lastRow, int firstColumn,
 563:                                             int lastColumn)
 564:       {
 565:         this.type = type;
 566:         this.firstRow = firstRow;
 567:         this.lastRow = lastRow;
 568:         this.firstColumn = firstColumn;
 569:         this.lastColumn = lastColumn;
 570:       }
 571: 
 572:       public int getType()
 573:       {
 574:         return type;
 575:       }
 576: 
 577:       public int getFirstRow()
 578:       {
 579:         return firstRow;
 580:       }
 581: 
 582:       public int getLastRow()
 583:       {
 584:         return lastRow;
 585:       }
 586: 
 587:       public int getFirstColumn()
 588:       {
 589:         return firstColumn;
 590:       }
 591: 
 592:       public int getLastColumn()
 593:       {
 594:         return lastColumn;
 595:       }
 596:     }
 597:    
 598:     /**
 599:      * Creates a new <code>AccessibleJTable</code>.
 600:      *
 601:      * @since JDK1.5
 602:      */
 603:     protected AccessibleJTable()
 604:     {
 605:       getModel().addTableModelListener(this);
 606:       getSelectionModel().addListSelectionListener(this);
 607:       getColumnModel().addColumnModelListener(this);
 608:       getCellEditor().addCellEditorListener(this);
 609:     }
 610: 
 611:     /**
 612:      * Returns the number of selected items in this table.
 613:      */
 614:     public int getAccessibleSelectionCount()
 615:     {
 616:       return getSelectedColumnCount();
 617:     }
 618: 
 619:     public Accessible getAccessibleSelection(int i)
 620:     {
 621:       // TODO Auto-generated method stub
 622:       return null;
 623:     }
 624: 
 625:     public boolean isAccessibleChildSelected(int i)
 626:     {
 627:       // TODO Auto-generated method stub
 628:       return false;
 629:     }
 630: 
 631:     public void addAccessibleSelection(int i)
 632:     {
 633:       // TODO Auto-generated method stub
 634:       
 635:     }
 636: 
 637:     public void removeAccessibleSelection(int i)
 638:     {
 639:       // TODO Auto-generated method stub
 640:       
 641:     }
 642: 
 643:     public void clearAccessibleSelection()
 644:     {
 645:       // TODO Auto-generated method stub
 646:       
 647:     }
 648: 
 649:     public void selectAllAccessibleSelection()
 650:     {
 651:       // TODO Auto-generated method stub
 652:       
 653:     }
 654: 
 655:     public void valueChanged(ListSelectionEvent event)
 656:     {
 657:       // TODO Auto-generated method stub
 658:       
 659:     }
 660: 
 661:     /**
 662:      * Receives notification when the table model changes. Depending on the
 663:      * type of change, this method calls {@link #tableRowsInserted} or
 664:      * {@link #tableRowsDeleted}.
 665:      *
 666:      * @param event the table model event
 667:      */
 668:     public void tableChanged(TableModelEvent event)
 669:     {
 670:       switch (event.getType())
 671:         {
 672:         case TableModelEvent.INSERT:
 673:           tableRowsInserted(event);
 674:           break;
 675:         case TableModelEvent.DELETE:
 676:           tableRowsDeleted(event);
 677:           break;
 678:         }
 679:     }
 680: 
 681:     /**
 682:      * Receives notification when one or more rows have been inserted into the
 683:      * table.
 684:      *
 685:      * @param event the table model event
 686:      */
 687:     public void tableRowsInserted(TableModelEvent event)
 688:     {
 689:       // TODO: What to do here, if anything? This might be a hook method for
 690:       // subclasses...
 691:     }
 692: 
 693:     /**
 694:      * Receives notification when one or more rows have been deleted from the
 695:      * table.
 696:      *
 697:      * @param event the table model event
 698:      */
 699:     public void tableRowsDeleted(TableModelEvent event)
 700:     {
 701:       // TODO: What to do here, if anything? This might be a hook method for
 702:       // subclasses...
 703:     }
 704: 
 705:     public void columnAdded(TableColumnModelEvent event)
 706:     {
 707:       // TODO Auto-generated method stub
 708:       
 709:     }
 710: 
 711:     public void columnMarginChanged(ChangeEvent event)
 712:     {
 713:       // TODO Auto-generated method stub
 714:       
 715:     }
 716: 
 717:     public void columnMoved(TableColumnModelEvent event)
 718:     {
 719:       // TODO Auto-generated method stub
 720:       
 721:     }
 722: 
 723:     public void columnRemoved(TableColumnModelEvent event)
 724:     {
 725:       // TODO Auto-generated method stub
 726:       
 727:     }
 728: 
 729:     public void columnSelectionChanged(ListSelectionEvent event)
 730:     {
 731:       // TODO Auto-generated method stub
 732:       
 733:     }
 734: 
 735:     public void editingCanceled(ChangeEvent event)
 736:     {
 737:       // TODO Auto-generated method stub
 738:       
 739:     }
 740: 
 741:     public void editingStopped(ChangeEvent event)
 742:     {
 743:       // TODO Auto-generated method stub
 744:       
 745:     }
 746: 
 747:     /**
 748:      * Receives notification when any of the JTable's properties changes. This
 749:      * is used to replace the listeners on the table's model, selection model,
 750:      * column model and cell editor.
 751:      *
 752:      * @param e the property change event
 753:      */
 754:     public void propertyChange(PropertyChangeEvent e)
 755:     {
 756:       String propName = e.getPropertyName(); 
 757:       if (propName.equals("tableModel"))
 758:         {
 759:           TableModel oldModel = (TableModel) e.getOldValue();
 760:           oldModel.removeTableModelListener(this);
 761:           TableModel newModel = (TableModel) e.getNewValue();
 762:           newModel.addTableModelListener(this);
 763:         }
 764:       else if (propName.equals("columnModel"))
 765:         {
 766:           TableColumnModel oldModel = (TableColumnModel) e.getOldValue();
 767:           oldModel.removeColumnModelListener(this);
 768:           TableColumnModel newModel = (TableColumnModel) e.getNewValue();
 769:           newModel.addColumnModelListener(this);
 770:         }
 771:       else if (propName.equals("selectionModel"))
 772:         {
 773:           ListSelectionModel oldModel = (ListSelectionModel) e.getOldValue();
 774:           oldModel.removeListSelectionListener(this);
 775:           ListSelectionModel newModel = (ListSelectionModel) e.getNewValue();
 776:           newModel.addListSelectionListener(this);
 777:         }
 778:       else if (propName.equals("cellEditor"))
 779:         {
 780:           CellEditor oldEd = (CellEditor) e.getOldValue();
 781:           oldEd.removeCellEditorListener(this);
 782:           CellEditor newEd = (CellEditor) e.getNewValue();
 783:           newEd.addCellEditorListener(this);
 784:         }
 785:     }
 786: 
 787:     public int getAccessibleRow(int index)
 788:     {
 789:       // TODO Auto-generated method stub
 790:       return 0;
 791:     }
 792: 
 793:     public int getAccessibleColumn(int index)
 794:     {
 795:       // TODO Auto-generated method stub
 796:       return 0;
 797:     }
 798: 
 799:     public int getAccessibleIndex(int r, int c)
 800:     {
 801:       // TODO Auto-generated method stub
 802:       return 0;
 803:     }
 804: 
 805:     public Accessible getAccessibleCaption()
 806:     {
 807:       // TODO Auto-generated method stub
 808:       return null;
 809:     }
 810: 
 811:     public void setAccessibleCaption(Accessible caption)
 812:     {
 813:       // TODO Auto-generated method stub
 814:       
 815:     }
 816: 
 817:     public Accessible getAccessibleSummary()
 818:     {
 819:       // TODO Auto-generated method stub
 820:       return null;
 821:     }
 822: 
 823:     public void setAccessibleSummary(Accessible summary)
 824:     {
 825:       // TODO Auto-generated method stub
 826:       
 827:     }
 828: 
 829:     public int getAccessibleRowCount()
 830:     {
 831:       // TODO Auto-generated method stub
 832:       return 0;
 833:     }
 834: 
 835:     public int getAccessibleColumnCount()
 836:     {
 837:       // TODO Auto-generated method stub
 838:       return 0;
 839:     }
 840: 
 841:     public Accessible getAccessibleAt(int r, int c)
 842:     {
 843:       // TODO Auto-generated method stub
 844:       return null;
 845:     }
 846: 
 847:     public int getAccessibleRowExtentAt(int r, int c)
 848:     {
 849:       // TODO Auto-generated method stub
 850:       return 0;
 851:     }
 852: 
 853:     public int getAccessibleColumnExtentAt(int r, int c)
 854:     {
 855:       // TODO Auto-generated method stub
 856:       return 0;
 857:     }
 858: 
 859:     public AccessibleTable getAccessibleRowHeader()
 860:     {
 861:       // TODO Auto-generated method stub
 862:       return null;
 863:     }
 864: 
 865:     public void setAccessibleRowHeader(AccessibleTable header)
 866:     {
 867:       // TODO Auto-generated method stub
 868:       
 869:     }
 870: 
 871:     public AccessibleTable getAccessibleColumnHeader()
 872:     {
 873:       // TODO Auto-generated method stub
 874:       return null;
 875:     }
 876: 
 877:     public void setAccessibleColumnHeader(AccessibleTable header)
 878:     {
 879:       // TODO Auto-generated method stub
 880:       
 881:     }
 882: 
 883:     public Accessible getAccessibleRowDescription(int r)
 884:     {
 885:       // TODO Auto-generated method stub
 886:       return null;
 887:     }
 888: 
 889:     public void setAccessibleRowDescription(int r, Accessible description)
 890:     {
 891:       // TODO Auto-generated method stub
 892:       
 893:     }
 894: 
 895:     public Accessible getAccessibleColumnDescription(int c)
 896:     {
 897:       // TODO Auto-generated method stub
 898:       return null;
 899:     }
 900: 
 901:     public void setAccessibleColumnDescription(int c, Accessible description)
 902:     {
 903:       // TODO Auto-generated method stub
 904:       
 905:     }
 906: 
 907:     public boolean isAccessibleSelected(int r, int c)
 908:     {
 909:       // TODO Auto-generated method stub
 910:       return false;
 911:     }
 912: 
 913:     public boolean isAccessibleRowSelected(int r)
 914:     {
 915:       // TODO Auto-generated method stub
 916:       return false;
 917:     }
 918: 
 919:     public boolean isAccessibleColumnSelected(int c)
 920:     {
 921:       // TODO Auto-generated method stub
 922:       return false;
 923:     }
 924: 
 925:     public int[] getSelectedAccessibleRows()
 926:     {
 927:       // TODO Auto-generated method stub
 928:       return null;
 929:     }
 930: 
 931:     public int[] getSelectedAccessibleColumns()
 932:     {
 933:       // TODO Auto-generated method stub
 934:       return null;
 935:     }
 936: 
 937:     /**
 938:      * Returns the accessible row at the specified index.
 939:      *
 940:      * @param index the index for which to query the row
 941:      *
 942:      * @return the row number at the specified table index
 943:      */
 944:     public int getAccessibleRowAtIndex(int index)
 945:     {
 946:       // TODO: Back this up by a Mauve test and update API docs accordingly.
 947:       return index / getColumnCount();
 948:     }
 949: 
 950:     /**
 951:      * Returns the accessible column at the specified index.
 952:      *
 953:      * @param index the index for which to query the column
 954:      *
 955:      * @return the column number at the specified table index
 956:      */
 957:     public int getAccessibleColumnAtIndex(int index)
 958:     {
 959:       // TODO: Back this up by a Mauve test and update API docs accordingly.
 960:       return index % getColumnCount();
 961:     }
 962: 
 963:     /**
 964:      * Returns the accessible child index at the specified column and row.
 965:      *
 966:      * @param row the row
 967:      * @param column the column
 968:      *
 969:      * @return the index of the accessible child at the specified row and
 970:      *         column
 971:      */
 972:     public int getAccessibleIndexAt(int row, int column)
 973:     {
 974:       // TODO: Back this up by a Mauve test and update API docs accordingly.
 975:       return row * getColumnCount() + column;
 976:     }
 977:   }
 978:   /**
 979:    * Handles property changes from the <code>TableColumn</code>s of this
 980:    * <code>JTable</code>.
 981:    *
 982:    * More specifically, this triggers a {@link #revalidate()} call if the
 983:    * preferredWidth of one of the observed columns changes.
 984:    */
 985:   class TableColumnPropertyChangeHandler implements PropertyChangeListener
 986:   {
 987:     /**
 988:      * Receives notification that a property of the observed TableColumns has
 989:      * changed.
 990:      * 
 991:      * @param ev the property change event
 992:      */
 993:     public void propertyChange(PropertyChangeEvent ev)
 994:     {
 995:       if (ev.getPropertyName().equals("preferredWidth"))
 996:         {
 997:           JTableHeader header = getTableHeader();
 998:           if (header != null)
 999:             // Do nothing if the table is in the resizing mode.
1000:             if (header.getResizingColumn() == null)
1001:               {
1002:                 TableColumn col = (TableColumn) ev.getSource();
1003:                 header.setResizingColumn(col);
1004:                 doLayout();
1005:                 header.setResizingColumn(null);
1006:               }
1007:         }
1008:     }
1009:   }
1010: 
1011:   /**
1012:    * A cell renderer for boolean values.
1013:    */
1014:   private class BooleanCellRenderer
1015:     extends DefaultTableCellRenderer
1016:   {
1017:     /**
1018:      * The CheckBox that is used for rendering.
1019:      */
1020:     private final JCheckBox checkBox = new JCheckBox();
1021:    
1022:     /**
1023:      * Get the check box.
1024:      */
1025:     JCheckBox getCheckBox()
1026:     {
1027:       return checkBox;
1028:     }
1029: 
1030:     /**
1031:      * Returns the component that is used for rendering the value.
1032:      * 
1033:      * @param table the JTable
1034:      * @param value the value of the object
1035:      * @param isSelected is the cell selected?
1036:      * @param hasFocus has the cell the focus?
1037:      * @param row the row to render
1038:      * @param column the cell to render
1039:      * @return this component (the default table cell renderer)
1040:      */
1041:     public Component getTableCellRendererComponent(JTable table, Object value,
1042:                                                    boolean isSelected,
1043:                                                    boolean hasFocus, int row,
1044:                                                    int column)
1045:     {
1046:       if (isSelected)
1047:         {
1048:           checkBox.setBackground(table.getSelectionBackground());
1049:           checkBox.setForeground(table.getSelectionForeground());
1050:         }
1051:       else
1052:         {
1053:           checkBox.setBackground(table.getBackground());
1054:           checkBox.setForeground(table.getForeground());
1055:         }
1056: 
1057:       if (hasFocus)
1058:         {
1059:           checkBox.setBorder(
1060:             UIManager.getBorder("Table.focusCellHighlightBorder"));
1061:           if (table.isCellEditable(row, column))
1062:             {
1063:               checkBox.setBackground(
1064:                 UIManager.getColor("Table.focusCellBackground"));
1065:               checkBox.setForeground(
1066:                 UIManager.getColor("Table.focusCellForeground"));
1067:             }
1068:         }
1069:       else
1070:         checkBox.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
1071: 
1072:       // Null is rendered as false.
1073:       if (value == null)
1074:         checkBox.setSelected(false);
1075:       else
1076:         {
1077:           Boolean boolValue = (Boolean) value;
1078:           checkBox.setSelected(boolValue.booleanValue());
1079:         }
1080:       return checkBox;
1081:     }
1082:   }
1083: 
1084:   /**
1085:    * A cell renderer for Date values.
1086:    */
1087:   private class DateCellRenderer
1088:     extends DefaultTableCellRenderer
1089:   {
1090:     /**
1091:      * Returns the component that is used for rendering the value.
1092:      *
1093:      * @param table the JTable
1094:      * @param value the value of the object
1095:      * @param isSelected is the cell selected?
1096:      * @param hasFocus has the cell the focus?
1097:      * @param row the row to render
1098:      * @param column the cell to render
1099:      * 
1100:      * @return this component (the default table cell renderer)
1101:      */
1102:     public Component getTableCellRendererComponent(JTable table, Object value,
1103:                                                    boolean isSelected,
1104:                                                    boolean hasFocus, int row,
1105:                                                    int column)
1106:     {
1107:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
1108:                                           row, column);
1109:       if (value instanceof Date)
1110:         {
1111:           Date dateValue = (Date) value;
1112:           DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
1113:           setText(df.format(dateValue));
1114:         }
1115:       return this;
1116:     }
1117:   }
1118: 
1119:   /**
1120:    * A cell renderer for Double values.
1121:    */
1122:   private class DoubleCellRenderer
1123:     extends DefaultTableCellRenderer
1124:   {
1125:     /**
1126:      * Creates a new instance of NumberCellRenderer.
1127:      */
1128:     public DoubleCellRenderer()
1129:     {
1130:       setHorizontalAlignment(JLabel.RIGHT);
1131:     }
1132: 
1133:     /**
1134:      * Returns the component that is used for rendering the value.
1135:      *
1136:      * @param table the JTable
1137:      * @param value the value of the object
1138:      * @param isSelected is the cell selected?
1139:      * @param hasFocus has the cell the focus?
1140:      * @param row the row to render
1141:      * @param column the cell to render
1142:      * 
1143:      * @return this component (the default table cell renderer)
1144:      */
1145:     public Component getTableCellRendererComponent(JTable table, Object value,
1146:                                                    boolean isSelected,
1147:                                                    boolean hasFocus, int row,
1148:                                                    int column)
1149:     {
1150:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
1151:                                           row, column);
1152:       if (value instanceof Double)
1153:         {
1154:           Double doubleValue = (Double) value;
1155:           NumberFormat nf = NumberFormat.getInstance();
1156:           setText(nf.format(doubleValue.doubleValue()));
1157:         }
1158:       return this;
1159:     }
1160:   }
1161: 
1162:   /**
1163:    * A cell renderer for Float values.
1164:    */
1165:   private class FloatCellRenderer
1166:     extends DefaultTableCellRenderer
1167:   {
1168:     /**
1169:      * Creates a new instance of NumberCellRenderer.
1170:      */
1171:     public FloatCellRenderer()
1172:     {
1173:       setHorizontalAlignment(JLabel.RIGHT);
1174:     }
1175: 
1176:     /**
1177:      * Returns the component that is used for rendering the value.
1178:      *
1179:      * @param table the JTable
1180:      * @param value the value of the object
1181:      * @param isSelected is the cell selected?
1182:      * @param hasFocus has the cell the focus?
1183:      * @param row the row to render
1184:      * @param column the cell to render
1185:      * 
1186:      * @return this component (the default table cell renderer)
1187:      */
1188:     public Component getTableCellRendererComponent(JTable table, Object value,
1189:                                                    boolean isSelected,
1190:                                                    boolean hasFocus, int row,
1191:                                                    int column)
1192:     {
1193:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
1194:                                           row, column);
1195:       if (value instanceof Float)
1196:         {
1197:           Float floatValue = (Float) value;
1198:           NumberFormat nf = NumberFormat.getInstance();
1199:           setText(nf.format(floatValue.floatValue()));
1200:         }
1201:       return this;
1202:     }
1203:   }
1204: 
1205:   /**
1206:    * A cell renderer for Number values.
1207:    */
1208:   private class NumberCellRenderer
1209:     extends DefaultTableCellRenderer
1210:   {
1211:     /**
1212:      * Creates a new instance of NumberCellRenderer.
1213:      */
1214:     public NumberCellRenderer()
1215:     {
1216:       setHorizontalAlignment(JLabel.RIGHT);
1217:     }
1218:   }
1219: 
1220:   /**
1221:    * A cell renderer for Icon values.
1222:    */
1223:   private class IconCellRenderer
1224:     extends DefaultTableCellRenderer
1225:   {
1226:     /**
1227:      * Returns the component that is used for rendering the value.
1228:      *
1229:      * @param table the JTable
1230:      * @param value the value of the object
1231:      * @param isSelected is the cell selected?
1232:      * @param hasFocus has the cell the focus?
1233:      * @param row the row to render
1234:      * @param column the cell to render
1235:      * 
1236:      * @return this component (the default table cell renderer)
1237:      */
1238:     public Component getTableCellRendererComponent(JTable table, Object value,
1239:                                                    boolean isSelected,
1240:                                                    boolean hasFocus, int row,
1241:                                                    int column)
1242:     {
1243:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
1244:                                           row, column);
1245:       if (value instanceof Icon)
1246:         {
1247:           Icon iconValue = (Icon) value;
1248:           setIcon(iconValue);
1249:         }
1250:       else
1251:         {
1252:           setIcon(null);
1253:         }
1254:       setText("");
1255:       return this;
1256:     }
1257:   }
1258:   
1259:     /**
1260:      * The JTable text component (used in editing) always has the table
1261:      * as its parent. The scrollRectToVisible must be adjusted taking the
1262:      * relative component position.
1263:      *
1264:      * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
1265:      */
1266:     private class TableTextField extends JTextField
1267:     {
1268:       /**
1269:        * Create the text field without the border.
1270:        */
1271:       TableTextField()
1272:       {
1273:         setBorder(BorderFactory.createLineBorder(getGridColor(), 2));
1274:       }
1275:     
1276:       /**
1277:        * With not this method overridden, the scroll pane scrolls to the
1278:        * top left cornec (untranslated position of the caret) after the first
1279:        * keystroke. 
1280:        */
1281:       public void scrollRectToVisible(Rectangle r)
1282:       {
1283:         // Do nothing here. If the editing session starts outside the visible
1284:         // bounds, the editCellAt will scroll.
1285:       }
1286:     }    
1287:   
1288: 
1289:   private static final long serialVersionUID = 3876025080382781659L;
1290:   
1291:   /**
1292:    * This table, for referring identically name methods from inner classes.
1293:    */
1294:   final JTable this_table = this;
1295: 
1296: 
1297:   /**
1298:    * When resizing columns, do not automatically change any columns. In this
1299:    * case the table should be enclosed in a {@link JScrollPane} in order to
1300:    * accomodate cases in which the table size exceeds its visible area.
1301:    */
1302:   public static final int AUTO_RESIZE_OFF = 0;
1303: 
1304:   /**
1305:    * When resizing column <code>i</code>, automatically change only the
1306:    * single column <code>i+1</code> to provide or absorb excess space
1307:    * requirements.
1308:    */
1309:   public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
1310: 
1311:   /**
1312:    * When resizing column <code>i</code> in a table of <code>n</code>
1313:    * columns, automatically change all columns in the range <code>[i+1,
1314:    * n)</code>, uniformly, to provide or absorb excess space requirements.
1315:    */
1316:   public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
1317:   
1318:   /**
1319:    * When resizing column <code>i</code> in a table of <code>n</code>
1320:    * columns, automatically change all columns in the range <code>[0,
1321:    * n)</code> (with the exception of column i) uniformly, to provide or
1322:    * absorb excess space requirements.
1323:    */
1324:   public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
1325: 
1326:   /**
1327:    * When resizing column <code>i</code> in a table of <code>n</code>
1328:    * columns, automatically change column <code>n-1</code> (the last column
1329:    * in the table) to provide or absorb excess space requirements.
1330:    */
1331:   public static final int AUTO_RESIZE_LAST_COLUMN = 3;
1332: 
1333:   /**
1334:    * A table mapping {@link java.lang.Class} objects to 
1335:    * {@link TableCellEditor} objects. This table is consulted by the 
1336:    * FIXME
1337:    */
1338:   protected Hashtable defaultEditorsByColumnClass;
1339: 
1340:   /**
1341:    * A table mapping {@link java.lang.Class} objects to 
1342:    * {@link TableCellEditor} objects. This table is consulted by the 
1343:    * FIXME
1344:    */
1345:   protected Hashtable defaultRenderersByColumnClass;
1346: 
1347:   /**
1348:    * The column that is edited, -1 if the table is not edited currently.
1349:    */
1350:   protected int editingColumn;
1351: 
1352:   /**
1353:    * The row that is edited, -1 if the table is not edited currently.
1354:    */
1355:   protected int editingRow;
1356: 
1357:   /**
1358:    * The component that is used for editing.
1359:    * <code>null</code> if the table is not editing currently.
1360:    *
1361:    */
1362:   protected transient Component editorComp;
1363: 
1364: 
1365:   /**
1366:    * Whether or not the table should automatically compute a matching
1367:    * {@link TableColumnModel} and assign it to the {@link #columnModel}
1368:    * property when the {@link #dataModel} property is changed. 
1369:    *
1370:    * @see #setModel(TableModel)
1371:    * @see #createDefaultColumnsFromModel()
1372:    * @see #setColumnModel(TableColumnModel)
1373:    * @see #setAutoCreateColumnsFromModel(boolean)
1374:    * @see #getAutoCreateColumnsFromModel()
1375:    */
1376:   protected boolean autoCreateColumnsFromModel;
1377: 
1378:   /**
1379:    * A numeric code specifying the resizing behavior of the table. Must be
1380:    * one of {@link #AUTO_RESIZE_ALL_COLUMNS} (the default), {@link
1381:    * #AUTO_RESIZE_LAST_COLUMN}, {@link #AUTO_RESIZE_NEXT_COLUMN}, {@link
1382:    * #AUTO_RESIZE_SUBSEQUENT_COLUMNS}, or {@link #AUTO_RESIZE_OFF}.
1383:    * 
1384:    * @see #doLayout()
1385:    * @see #setAutoResizeMode(int)
1386:    * @see #getAutoResizeMode()
1387:    */
1388:   protected int autoResizeMode;
1389: 
1390:   /**
1391:    * The height in pixels of any row of the table. All rows in a table are
1392:    * of uniform height. This differs from column width, which varies on a
1393:    * per-column basis, and is stored in the individual columns of the
1394:    * {@link #columnModel}.
1395:    * 
1396:    * @see #getRowHeight()
1397:    * @see #setRowHeight(int)
1398:    * @see TableColumn#getWidth()
1399:    * @see TableColumn#setWidth(int)
1400:    */
1401:   protected int rowHeight;
1402: 
1403:   /**
1404:    * The height in pixels of the gap left between any two rows of the table. 
1405:    * 
1406:    * @see #setRowMargin(int)
1407:    * @see #getRowHeight()
1408:    * @see #getIntercellSpacing()
1409:    * @see #setIntercellSpacing(Dimension)
1410:    * @see TableColumnModel#getColumnMargin()
1411:    * @see TableColumnModel#setColumnMargin(int)
1412:    */
1413:   protected int rowMargin;
1414: 
1415:   /**
1416:    * Whether or not the table should allow row selection. If the table
1417:    * allows both row <em>and</em> column selection, it is said to allow
1418:    * "cell selection". Previous versions of the JDK supported cell
1419:    * selection as an independent concept, but it is now represented solely
1420:    * in terms of simultaneous row and column selection.
1421:    *
1422:    * @see TableColumnModel#getColumnSelectionAllowed()
1423:    * @see #setRowSelectionAllowed(boolean)
1424:    * @see #getRowSelectionAllowed()
1425:    * @see #getCellSelectionEnabled()
1426:    * @see #setCellSelectionEnabled(boolean)
1427:    */
1428:   protected boolean rowSelectionAllowed;
1429: 
1430:   /**
1431:    * Obsolete. Use {@link #rowSelectionAllowed}, {@link 
1432:    * #getColumnSelectionAllowed}, or the combined methods {@link
1433:    * #getCellSelectionEnabled} and {@link #setCellSelectionEnabled(boolean)}.
1434:    */
1435:   protected boolean cellSelectionEnabled;
1436:   
1437:   /**
1438:    * The model for data stored in the table. Confusingly, the published API
1439:    * requires that this field be called <code>dataModel</code>, despite its
1440:    * property name. The table listens to its model as a {@link
1441:    * TableModelListener}.
1442:    *
1443:    * @see #tableChanged(TableModelEvent)
1444:    * @see TableModel#addTableModelListener(TableModelListener)
1445:    */
1446:   protected TableModel dataModel;
1447: 
1448:   /**
1449:    * <p>A model of various aspects of the columns of the table, <em>not
1450:    * including</em> the data stored in them. The {@link TableColumnModel}
1451:    * is principally concerned with holding a set of {@link TableColumn}
1452:    * objects, each of which describes the display parameters of a column
1453:    * and the numeric index of the column from the data model which the
1454:    * column is presenting.</p>
1455:    *
1456:    * <p>The TableColumnModel also contains a {@link ListSelectionModel} which
1457:    * indicates which columns are currently selected. This selection model
1458:    * works in combination with the {@link #selectionModel} of the table
1459:    * itself to specify a <em>table selection</em>: a combination of row and
1460:    * column selections.</p>
1461:    *
1462:    * <p>Most application programmers do not need to work with this property
1463:    * at all: setting {@link #autoCreateColumnsFromModel} will construct the
1464:    * columnModel automatically, and the table acts as a facade for most of
1465:    * the interesting properties of the columnModel anyways.</p>
1466:    * 
1467:    * @see #setColumnModel(TableColumnModel)
1468:    * @see #getColumnModel()
1469:    */
1470:   protected TableColumnModel columnModel;
1471: 
1472:   /**
1473:    * A model of the rows of this table which are currently selected. This
1474:    * model is used in combination with the column selection model held as a
1475:    * member of the {@link #columnModel} property, to represent the rows and
1476:    * columns (or both: cells) of the table which are currently selected.
1477:    *
1478:    * @see #rowSelectionAllowed
1479:    * @see #setSelectionModel(ListSelectionModel)
1480:    * @see #getSelectionModel()
1481:    * @see TableColumnModel#getSelectionModel()
1482:    * @see ListSelectionModel#addListSelectionListener(ListSelectionListener)   
1483:    */
1484:   protected ListSelectionModel selectionModel;
1485: 
1486:   /**
1487:    * The current cell editor. 
1488:    */
1489:   protected TableCellEditor cellEditor;
1490: 
1491:   /**
1492:    * Whether or not drag-and-drop is enabled on this table.
1493:    *
1494:    * @see #setDragEnabled(boolean)
1495:    * @see #getDragEnabled()
1496:    */
1497:   private boolean dragEnabled;
1498: 
1499:   /**
1500:    * The color to paint the grid lines of the table, when either {@link
1501:    * #showHorizontalLines} or {@link #showVerticalLines} is set.
1502:    *
1503:    * @see #setGridColor(Color)
1504:    * @see #getGridColor()
1505:    */
1506:   protected Color gridColor;
1507: 
1508:   /**
1509:    * The size this table would prefer its viewport assume, if it is
1510:    * contained in a {@link JScrollPane}.
1511:    *
1512:    * @see #setPreferredScrollableViewportSize(Dimension)
1513:    * @see #getPreferredScrollableViewportSize()
1514:    */
1515:   protected Dimension preferredViewportSize;
1516: 
1517:   /**
1518:    * The color to paint the background of selected cells. Fires a property
1519:    * change event with name {@link #SELECTION_BACKGROUND_CHANGED_PROPERTY}
1520:    * when its value changes.
1521:    *
1522:    * @see #setSelectionBackground(Color)
1523:    * @see #getSelectionBackground()
1524:    */
1525:   protected Color selectionBackground;
1526: 
1527:   /**
1528:    * The name carried in property change events when the {@link
1529:    * #selectionBackground} property changes.
1530:    */
1531:   private static final String SELECTION_BACKGROUND_CHANGED_PROPERTY = "selectionBackground";
1532: 
1533:   /**
1534:    * The color to paint the foreground of selected cells. Fires a property
1535:    * change event with name {@link #SELECTION_FOREGROUND_CHANGED_PROPERTY}
1536:    * when its value changes.
1537:    *
1538:    * @see #setSelectionForeground(Color)
1539:    * @see #getSelectionForeground()
1540:    */
1541:   protected Color selectionForeground;
1542: 
1543:   /**
1544:    * The name carried in property change events when the
1545:    * {@link #selectionForeground} property changes.
1546:    */
1547:   private static final String SELECTION_FOREGROUND_CHANGED_PROPERTY = "selectionForeground";
1548: 
1549:   /**
1550:    * The showHorizontalLines property.
1551:    */
1552:   protected boolean showHorizontalLines;
1553: 
1554:   /**
1555:    * The showVerticalLines property.
1556:    */
1557:   protected boolean showVerticalLines;
1558: 
1559:   /**
1560:    * The tableHeader property.
1561:    */
1562:   protected JTableHeader tableHeader;
1563: 
1564:   /**
1565:    * The property handler for this table's columns.
1566:    */
1567:   TableColumnPropertyChangeHandler tableColumnPropertyChangeHandler =
1568:     new TableColumnPropertyChangeHandler();
1569: 
1570:   /**
1571:    * Whether cell editors should receive keyboard focus when the table is
1572:    * activated.
1573:    */
1574:   private boolean surrendersFocusOnKeystroke = false;
1575: 
1576:   /**
1577:    * A Rectangle object to be reused in {@link #getCellRect}. 
1578:    */
1579:   private Rectangle rectCache = new Rectangle();
1580: 
1581:   /**
1582:    * Indicates if the rowHeight property has been set by a client program or by
1583:    * the UI.
1584:    *
1585:    * @see #setUIProperty(String, Object)
1586:    * @see LookAndFeel#installProperty(JComponent, String, Object)
1587:    */
1588:   private boolean clientRowHeightSet = false;
1589: 
1590:   /**
1591:    * Creates a new <code>JTable</code> instance.
1592:    */
1593:   public JTable ()
1594:   {
1595:     this(null, null, null);
1596:   }
1597: 
1598:   /**
1599:    * Creates a new <code>JTable</code> instance with the given number
1600:    * of rows and columns.
1601:    *
1602:    * @param numRows an <code>int</code> value
1603:    * @param numColumns an <code>int</code> value
1604:    */
1605:   public JTable (int numRows, int numColumns)
1606:   {
1607:     this(new DefaultTableModel(numRows, numColumns));
1608:   }
1609: 
1610:   /**
1611:    * Creates a new <code>JTable</code> instance, storing the given data 
1612:    * array and heaving the given column names. To see the column names,
1613:    * you must place the JTable into the {@link JScrollPane}.
1614:    *
1615:    * @param data an <code>Object[][]</code> the table data
1616:    * @param columnNames an <code>Object[]</code> the column headers
1617:    */
1618:   public JTable(Object[][] data, Object[] columnNames)
1619:   {
1620:     this(new DefaultTableModel(data, columnNames));
1621:   }
1622: 
1623:   /**
1624:    * Creates a new <code>JTable</code> instance, using the given data model
1625:    * object that provides information about the table content. The table model
1626:    * object is asked for the table size, other features and also receives
1627:    * notifications in the case when the table has been edited by the user.
1628:    * 
1629:    * @param model
1630:    *          the table model.
1631:    */
1632:   public JTable (TableModel model)
1633:   {
1634:     this(model, null, null);
1635:   }
1636: 
1637:   /**
1638:    * Creates a new <code>JTable</code> instance, using the given model object
1639:    * that provides information about the table content. The table data model
1640:    * object is asked for the table size, other features and also receives
1641:    * notifications in the case when the table has been edited by the user. The
1642:    * table column model provides more detailed control on the table column
1643:    * related features.
1644:    * 
1645:    * @param dm
1646:    *          the table data mode
1647:    * @param cm
1648:    *          the table column model
1649:    */
1650:   public JTable (TableModel dm, TableColumnModel cm)
1651:   {
1652:     this(dm, cm, null);
1653:   }
1654: 
1655:   /**
1656:    * Creates a new <code>JTable</code> instance, providing data model,
1657:    * column model and list selection model. The list selection model
1658:    * manages the selections.
1659:    *
1660:    * @param dm data model (manages table data)
1661:    * @param cm column model (manages table columns)
1662:    * @param sm list selection model (manages table selections)
1663:    */
1664:   public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm)
1665:   {
1666:     boolean autoCreate = false;
1667:     TableColumnModel columnModel;
1668:     if (cm != null)
1669:         columnModel = cm;
1670:     else 
1671:       {
1672:         columnModel = createDefaultColumnModel();
1673:         autoCreate = true;
1674:       }
1675:     
1676:     // Initialise the intercelar spacing before setting the column model to
1677:     // avoid firing unnecessary events.
1678:     // The initial incellar spacing is new Dimenstion(1,1). 
1679:     rowMargin = 1;
1680:     columnModel.setColumnMargin(1);
1681:     setColumnModel(columnModel);
1682:     
1683:     setSelectionModel(sm == null ? createDefaultSelectionModel() : sm);
1684:     setModel(dm == null ? createDefaultDataModel() : dm);
1685:     setAutoCreateColumnsFromModel(autoCreate);
1686:     initializeLocalVars();
1687:     // The following four lines properly set the lead selection indices.
1688:     // After this, the UI will handle the lead selection indices.
1689:     // FIXME: this should probably not be necessary, if the UI is installed
1690:     // before the TableModel is set then the UI will handle things on its
1691:     // own, but certain variables need to be set before the UI can be installed
1692:     // so we must get the correct order for all the method calls in this
1693:     // constructor.
1694:     selectionModel.setAnchorSelectionIndex(0);    
1695:     selectionModel.setLeadSelectionIndex(0);
1696:     columnModel.getSelectionModel().setAnchorSelectionIndex(0);
1697:     columnModel.getSelectionModel().setLeadSelectionIndex(0);
1698:     updateUI();
1699:   }
1700:   
1701:   /**
1702:    * Creates a new <code>JTable</code> instance that uses data and column
1703:    * names, stored in {@link Vector}s.
1704:    *
1705:    * @param data the table data
1706:    * @param columnNames the table column names.
1707:    */
1708:   public JTable(Vector data, Vector columnNames)
1709:   {
1710:     this(new DefaultTableModel(data, columnNames));
1711:   }  
1712:   
1713:   /**
1714:    * Initialize local variables to default values.
1715:    */
1716:   protected void initializeLocalVars()
1717:   {
1718:     setTableHeader(createDefaultTableHeader());
1719:     if (autoCreateColumnsFromModel)
1720:       createDefaultColumnsFromModel();
1721:     this.columnModel.addColumnModelListener(this);
1722:     
1723:     this.defaultRenderersByColumnClass = new Hashtable();
1724:     createDefaultRenderers();
1725: 
1726:     this.defaultEditorsByColumnClass = new Hashtable();
1727:     createDefaultEditors();
1728: 
1729:     this.autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
1730:     this.rowHeight = 16;
1731:     this.rowMargin = 1;
1732:     this.rowSelectionAllowed = true;
1733:     // this.accessibleContext = new AccessibleJTable();
1734:     this.cellEditor = null;
1735:     // COMPAT: Both Sun and IBM have drag enabled
1736:     this.dragEnabled = true;
1737:     this.preferredViewportSize = new Dimension(450,400);
1738:     this.showHorizontalLines = true;
1739:     this.showVerticalLines = true;
1740:     this.editingColumn = -1;
1741:     this.editingRow = -1;
1742:   }
1743:   
1744:   /**
1745:    * Add the new table column. The table column class allows to specify column
1746:    * features more precisely, setting the preferred width, column data type
1747:    * (column class) and table headers.
1748:    * 
1749:    * There is no need the add columns to the table if the default column 
1750:    * handling is sufficient.
1751:    * 
1752:    * @param column
1753:    *          the new column to add.
1754:    */
1755:   public void addColumn(TableColumn column)
1756:   {
1757:     if (column.getHeaderValue() == null)
1758:       {
1759:         String name = dataModel.getColumnName(column.getModelIndex());
1760:         column.setHeaderValue(name);
1761:       }
1762:     
1763:     columnModel.addColumn(column);
1764:     column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
1765:   }
1766:   
1767:   /**
1768:    * Create the default editors for this table. The default method creates
1769:    * the editor for Booleans.
1770:    * 
1771:    * Other fields are edited as strings at the moment.
1772:    */
1773:   protected void createDefaultEditors()
1774:   {
1775:     JCheckBox box = new BooleanCellRenderer().getCheckBox();
1776:     setDefaultEditor(Boolean.class, new DefaultCellEditor(box));
1777:   }
1778:   
1779:   /**
1780:    * Create the default renderers for this table. The default method creates
1781:    * renderers for Boolean, Number, Double, Date, Icon and ImageIcon.
1782:    *
1783:    */
1784:   protected void createDefaultRenderers()
1785:   {
1786:     setDefaultRenderer(Boolean.class, new BooleanCellRenderer());
1787:     setDefaultRenderer(Number.class, new NumberCellRenderer());
1788:     setDefaultRenderer(Double.class, new DoubleCellRenderer());
1789:     setDefaultRenderer(Double.class, new FloatCellRenderer());
1790:     setDefaultRenderer(Date.class, new DateCellRenderer());
1791:     setDefaultRenderer(Icon.class, new IconCellRenderer());
1792:     setDefaultRenderer(ImageIcon.class, new IconCellRenderer());    
1793:   }
1794:   
1795:   /**
1796:    * @deprecated 1.0.2, replaced by <code>new JScrollPane(JTable)</code>
1797:    */
1798:   public static JScrollPane createScrollPaneForTable(JTable table)
1799:   {
1800:     return new JScrollPane(table);
1801:   }
1802:   
1803:   /**
1804:    * Create the default table column model that is used if the user-defined
1805:    * column model is not provided. The default method creates
1806:    * {@link DefaultTableColumnModel}.
1807:    * 
1808:    * @return the created table column model.
1809:    */
1810:   protected TableColumnModel createDefaultColumnModel()
1811:   {
1812:     return new DefaultTableColumnModel();
1813:   }
1814: 
1815:   /**
1816:    * Create the default table data model that is used if the user-defined
1817:    * data model is not provided. The default method creates
1818:    * {@link DefaultTableModel}.
1819:    * 
1820:    * @return the created table data model.
1821:    */
1822:   protected TableModel createDefaultDataModel()
1823:   {
1824:     return new DefaultTableModel();
1825:   }
1826: 
1827:   /**
1828:    * Create the default table selection model that is used if the user-defined
1829:    * selection model is not provided. The default method creates
1830:    * {@link DefaultListSelectionModel}.
1831:    * 
1832:    * @return the created table data model.
1833:    */
1834:   protected ListSelectionModel createDefaultSelectionModel()
1835:   {
1836:     return new DefaultListSelectionModel();
1837:   }
1838:   
1839:   /**
1840:    * Create the default table header, if the user - defined table header is not
1841:    * provided.
1842:    * 
1843:    * @return the default table header.
1844:    */
1845:   protected JTableHeader createDefaultTableHeader()
1846:   {
1847:     return new JTableHeader(columnModel);
1848:   }
1849:   
1850:   /**
1851:    * Invoked when the column is added. Revalidates and repains the table.
1852:    */
1853:   public void columnAdded (TableColumnModelEvent event)
1854:   {
1855:     revalidate();
1856:     repaint();
1857:   }
1858: 
1859:   /**
1860:    * Invoked when the column margin is changed. 
1861:    * Revalidates and repains the table.
1862:    */
1863:   public void columnMarginChanged (ChangeEvent event)
1864:   {
1865:     revalidate();
1866:     repaint();
1867:   }
1868: 
1869:   /**
1870:    * Invoked when the column is moved. Revalidates and repains the table.
1871:    */
1872:   public void columnMoved (TableColumnModelEvent event)
1873:   {
1874:     revalidate();
1875:     repaint();
1876:   }
1877: 
1878:   /**
1879:    * Invoked when the column is removed. Revalidates and repains the table.
1880:    */
1881:   public void columnRemoved (TableColumnModelEvent event)
1882:   {
1883:     revalidate();
1884:     repaint();
1885:   }
1886:   
1887:   /**
1888:    * Invoked when the the column selection changes, repaints the changed
1889:    * columns. It is not recommended to override this method, register the
1890:    * listener instead.
1891:    */
1892:   public void columnSelectionChanged (ListSelectionEvent event)
1893:   {
1894:     // Does not make sense for the table with the single column.
1895:     if (getColumnCount() < 2)
1896:       return;
1897:     
1898:     int x0 = 0;
1899:     
1900:     // We must limit the indices to the bounds of the JTable's model, because
1901:     // we might get values of -1 or greater then columnCount in the case
1902:     // when columns get removed.
1903:     int idx0 = Math.max(0, Math.min(getColumnCount() - 1,
1904:                                     event.getFirstIndex()));
1905:     int idxn = Math.max(0, Math.min(getColumnCount() - 1,
1906:                                     event.getLastIndex()));
1907:     int i;
1908: 
1909:     for (i = 0; i < idx0; i++)
1910:       x0 += columnModel.getColumn(i).getWidth();
1911:     
1912:     int xn = x0;
1913:     
1914:     for (i = idx0; i <= idxn; i++)
1915:       xn += columnModel.getColumn(i).getWidth();
1916:     
1917:     repaint(x0, 0, xn-x0, getHeight());
1918:   }
1919:  
1920:   /**
1921:    * Invoked when the editing is cancelled.
1922:    */
1923:   public void editingCanceled (ChangeEvent event)
1924:   {
1925:     if (editorComp!=null)
1926:       {
1927:         remove(editorComp);
1928:         repaint(editorComp.getBounds());        
1929:         editorComp = null;
1930:       }
1931:   }
1932:   
1933:   /**
1934:    * Finish the current editing session and update the table with the
1935:    * new value by calling {@link #setValueAt}.
1936:    * 
1937:    * @param event the change event
1938:    */
1939:   public void editingStopped (ChangeEvent event)
1940:   {
1941:     if (editorComp!=null)
1942:       {
1943:         remove(editorComp);        
1944:         setValueAt(cellEditor.getCellEditorValue(), editingRow, editingColumn);            
1945:         repaint(editorComp.getBounds());
1946:         editorComp = null;
1947:       }
1948:     requestFocusInWindow();
1949:   }
1950: 
1951:   /**
1952:    * Invoked when the table changes.
1953:    * <code>null</code> means everything changed.
1954:    */
1955:   public void tableChanged (TableModelEvent event)
1956:   {
1957:     // update the column model from the table model if the structure has
1958:     // changed and the flag autoCreateColumnsFromModel is set
1959:     if ((event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW))
1960:     && autoCreateColumnsFromModel)
1961:       createDefaultColumnsFromModel();
1962: 
1963:     // If the structure changes, we need to revalidate, since that might
1964:     // affect the size parameters of the JTable. Otherwise we only need
1965:     // to perform a repaint to update the view.
1966:     if (event == null || event.getType() == TableModelEvent.INSERT)
1967:       {
1968:         // Sync selection model with data model.
1969:         if (event != null)
1970:           {
1971:             int first = event.getFirstRow();
1972:             if (first < 0)
1973:               first = 0;
1974:             int last = event.getLastRow();
1975:             if (last < 0)
1976:               last = getRowCount() - 1;
1977:             selectionModel.insertIndexInterval(first, last - first + 1, true);
1978:           }
1979:         revalidate();
1980:       }
1981:     if (event == null || event.getType() == TableModelEvent.DELETE)
1982:       {
1983:         // Sync selection model with data model.
1984:         if (event != null)
1985:           {
1986:             int first = event.getFirstRow();
1987:             if (first < 0)
1988:               first = 0;
1989:             int last = event.getLastRow();
1990:             if (last < 0)
1991:               last = getRowCount() - 1;
1992:             selectionModel.removeIndexInterval(first, last);
1993:           }
1994:         if (dataModel.getRowCount() == 0)
1995:           clearSelection();
1996:         revalidate();
1997:       }
1998:     repaint();
1999:   }
2000: 
2001:   /**
2002:    * Invoked when another table row is selected. It is not recommended
2003:    * to override thid method, register the listener instead.
2004:    */
2005:   public void valueChanged (ListSelectionEvent event)
2006:   {
2007:     // Does not make sense for the table with the single row.
2008:     if (getRowCount() < 2)
2009:       return;
2010:     
2011:     int y_gap = rowMargin;
2012:     int y0 = (getRowHeight() + y_gap) * (event.getFirstIndex());
2013:     int yn = (getRowHeight() + y_gap) * (event.getLastIndex()+1);
2014:     repaint(0, y0, getWidth(), yn-y0);
2015:   }
2016: 
2017:  /**
2018:    * Returns index of the column that contains specified point 
2019:    * or -1 if this table doesn't contain this point.
2020:    *
2021:    * @param point point to identify the column
2022:    * @return index of the column that contains specified point or 
2023:    * -1 if this table doesn't contain this point.
2024:    */
2025:   public int columnAtPoint(Point point)
2026:   {
2027:     int ncols = getColumnCount();
2028:     Dimension gap = getIntercellSpacing();
2029:     TableColumnModel cols = getColumnModel();
2030:     int x = point.x;
2031: 
2032:     for (int i = 0; i < ncols; ++i)
2033:       {
2034:         int width = cols.getColumn(i).getWidth()
2035:                     + (gap == null ? 0 : gap.width);
2036:         if (0 <= x && x < width)
2037:           return i;
2038:         x -= width;
2039:       }
2040:     return -1;
2041:   }
2042: 
2043:   /**
2044:    * Returns index of the row that contains specified point or -1 if this table
2045:    * doesn't contain this point.
2046:    * 
2047:    * @param point point to identify the row
2048:    * @return index of the row that contains specified point or -1 if this table
2049:    *         doesn't contain this point.
2050:    */
2051:   public int rowAtPoint(Point point)
2052:   {
2053:     if (point != null)
2054:       {
2055:         int nrows = getRowCount();
2056:         int height = getRowHeight() + getRowMargin();
2057:         int y = point.y;
2058: 
2059:         int r = y / height;
2060:         if (r < 0 || r >= nrows)
2061:           return -1;
2062:         else
2063:           return r;
2064:       }
2065:     else
2066:       return -1;
2067:   }
2068: 
2069:   /** 
2070:    * Calculate the visible rectangle for a particular row and column. The
2071:    * row and column are specified in visual terms; the column may not match
2072:    * the {@link #dataModel} column.
2073:    *
2074:    * @param row the visible row to get the cell rectangle of
2075:    *
2076:    * @param column the visible column to get the cell rectangle of, which may
2077:    * differ from the {@link #dataModel} column
2078:    *
2079:    * @param includeSpacing whether or not to include the cell margins in the
2080:    * resulting cell. If <code>false</code>, the result will only contain the
2081:    * inner area of the target cell, not including its margins.
2082:    *
2083:    * @return a rectangle enclosing the specified cell
2084:    */
2085:   public Rectangle getCellRect(int row,
2086:                                int column,
2087:                                boolean includeSpacing)
2088:   {
2089:     int height = getRowHeight(row);
2090:     int width = columnModel.getColumn(column).getWidth();
2091:     int x_gap = columnModel.getColumnMargin();
2092:     int y_gap = rowMargin;
2093: 
2094:     column = Math.max(0, Math.min(column, getColumnCount() - 1));
2095:     row = Math.max(0, Math.min(row, getRowCount() - 1));
2096: 
2097:     int x = 0;
2098:     int y = (height + y_gap) * row;
2099: 
2100:     for (int i = 0; i < column; ++i)
2101:       x += columnModel.getColumn(i).getWidth();
2102:     
2103:     Rectangle rect = new Rectangle();
2104: 
2105:     if (includeSpacing)
2106:       rect.setBounds(x, y, width, height +y_gap);
2107:     else
2108:       rect.setBounds(x, y, width - x_gap, height);
2109:     return rect;
2110:   }
2111: 
2112:   public void clearSelection()
2113:   {
2114:     selectionModel.clearSelection();
2115:     getColumnModel().getSelectionModel().clearSelection();
2116:   }
2117: 
2118:   /**
2119:    * Get the value of the selectedRow property by delegation to
2120:    * the {@link ListSelectionModel#getMinSelectionIndex} method of the
2121:    * {@link #selectionModel} field.
2122:    *
2123:    * @return The current value of the selectedRow property
2124:    */
2125:   public int getSelectedRow ()
2126:   {    
2127:     return selectionModel.getMinSelectionIndex();
2128:   }
2129:   
2130:   /**
2131:    * Get the value of the {@link #selectionModel} property.
2132:    *
2133:    * @return The current value of the property
2134:    */
2135:   public ListSelectionModel getSelectionModel()
2136:   {
2137:     //Neither Sun nor IBM returns null if rowSelection not allowed
2138:     return selectionModel;
2139:   }
2140:   
2141:   public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
2142:   {
2143:     if (orientation == SwingConstants.VERTICAL)
2144:       return visibleRect.height * direction;
2145:     else
2146:       return visibleRect.width * direction;
2147:   }
2148: 
2149:   /**
2150:    * Get the value of the <code>scrollableTracksViewportHeight</code> property.
2151:    *
2152:    * @return The constant value <code>false</code>
2153:    */
2154:   public boolean getScrollableTracksViewportHeight()
2155:   {
2156:     return false;
2157:   }
2158:   
2159:   /**
2160:    * Get the value of the <code>scrollableTracksViewportWidth</code> property.
2161:    *
2162:    * @return <code>true</code> unless the {@link #autoResizeMode} property is
2163:    * <code>AUTO_RESIZE_OFF</code>
2164:    */
2165:   public boolean getScrollableTracksViewportWidth()
2166:   {
2167:     if (autoResizeMode == AUTO_RESIZE_OFF)
2168:       return false;
2169:     else
2170:       return true;
2171:   }
2172:   
2173:   /**
2174:    * Return the preferred scrolling amount (in pixels) for the given scrolling
2175:    * direction and orientation. This method handles a partially exposed row by
2176:    * returning the distance required to completely expose the item. When
2177:    * scrolling the top item is completely exposed.
2178:    * 
2179:    * @param visibleRect the currently visible part of the component.
2180:    * @param orientation the scrolling orientation
2181:    * @param direction the scrolling direction (negative - up, positive -down).
2182:    *          The values greater than one means that more mouse wheel or similar
2183:    *          events were generated, and hence it is better to scroll the longer
2184:    *          distance.
2185:    * @author Audrius Meskauskas (audriusa@bioinformatics.org)
2186:    */
2187:   public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
2188:                                         int direction)
2189:   {
2190:     int h = (rowHeight + rowMargin);
2191:     int delta = h * direction;
2192: 
2193:     // Round so that the top would start from the row boundary
2194:     if (orientation == SwingConstants.VERTICAL)
2195:       {
2196:         // Completely expose the top row
2197:         int near = ((visibleRect.y + delta + h / 2) / h) * h;
2198:         int diff = visibleRect.y + delta - near;
2199:         delta -= diff;
2200:       }
2201:     return delta;
2202:     // TODO when scrollng horizontally, scroll into the column boundary.
2203:   }
2204: 
2205:   /**
2206:    * Get the cell editor, suitable for editing the given cell. The default
2207:    * method requests the editor from the column model. If the column model does
2208:    * not provide the editor, the call is forwarded to the
2209:    * {@link #getDefaultEditor(Class)} with the parameter, obtained from
2210:    * {@link TableModel#getColumnClass(int)}.
2211:    * 
2212:    * @param row the cell row
2213:    * @param column the cell column
2214:    * @return the editor to edit that cell
2215:    */
2216:   public TableCellEditor getCellEditor(int row, int column)
2217:   {
2218:     TableCellEditor editor = columnModel.getColumn(column).getCellEditor();
2219: 
2220:     if (editor == null)
2221:       {
2222:         int mcolumn = convertColumnIndexToModel(column);
2223:         editor = getDefaultEditor(dataModel.getColumnClass(mcolumn));
2224:       }
2225: 
2226:     return editor;
2227:   }
2228:   
2229:   /**
2230:    * Get the default editor for editing values of the given type
2231:    * (String, Boolean and so on).
2232:    * 
2233:    * @param columnClass the class of the value that will be edited.
2234:    * 
2235:    * @return the editor, suitable for editing this data type
2236:    */
2237:   public TableCellEditor getDefaultEditor(Class columnClass)
2238:   {
2239:     if (defaultEditorsByColumnClass.containsKey(columnClass))
2240:       return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass);
2241:     else
2242:       {
2243:         JTextField t = new TableTextField();        
2244:         TableCellEditor r = new DefaultCellEditor(t);
2245:         defaultEditorsByColumnClass.put(columnClass, r);
2246:         return r;
2247:       }
2248:   }
2249:   
2250:   /**
2251:    * Get the cell renderer for rendering the given cell.
2252:    * 
2253:    * @param row the cell row
2254:    * @param column the cell column
2255:    * @return the cell renderer to render that cell.
2256:    */
2257:   public TableCellRenderer getCellRenderer(int row, int column)
2258:   {
2259:     TableCellRenderer renderer = columnModel.getColumn(column).getCellRenderer();
2260:     if (renderer == null)
2261:       {
2262:         int mcolumn = convertColumnIndexToModel(column);
2263:         renderer = getDefaultRenderer(dataModel.getColumnClass(mcolumn));
2264:       }
2265:     return renderer;
2266:   }
2267:   
2268:   /**
2269:    * Set default renderer for rendering the given data type.
2270:    * 
2271:    * @param columnClass the data type (String, Boolean and so on) that must be
2272:    *          rendered.
2273:    * @param rend the renderer that will rend this data type
2274:    */
2275:   public void setDefaultRenderer(Class columnClass, TableCellRenderer rend)
2276:   {
2277:     defaultRenderersByColumnClass.put(columnClass, rend);
2278:   }
2279:   
2280:   /**
2281:    * Get the default renderer for rendering the given data type.
2282:    * 
2283:    * @param columnClass the data that must be rendered
2284:    * 
2285:    * @return the appropriate defauld renderer for rendering that data type.
2286:    */
2287:   public TableCellRenderer getDefaultRenderer(Class columnClass)
2288:   {
2289:     if (defaultRenderersByColumnClass.containsKey(columnClass))
2290:       return (TableCellRenderer) defaultRenderersByColumnClass.get(columnClass);
2291:     else
2292:       {
2293:         TableCellRenderer r = new DefaultTableCellRenderer();
2294:         defaultRenderersByColumnClass.put(columnClass, r);
2295:         return r;
2296:       }
2297:   }
2298:   
2299:   /**
2300:    * Convert the table model index into the table column number.
2301:    * The model number need not match the real column position. The columns
2302:    * may be rearranged by the user with mouse at any time by dragging the
2303:    * column headers.
2304:    *
2305:    * @param vc the column number (0=first).
2306:    * 
2307:    * @return the table column model index of this column.
2308:    * 
2309:    * @see TableColumn#getModelIndex()
2310:    */
2311:   public int convertColumnIndexToModel(int vc)
2312:   {
2313:     if (vc < 0)
2314:       return vc;
2315:     else
2316:       return columnModel.getColumn(vc).getModelIndex();
2317:   }
2318:   
2319:   /**
2320:    * Convert the table column number to the table column model index.
2321:    * The model number need not match the real column position. The columns
2322:    * may be rearranged by the user with mouse at any time by dragging the
2323:    * column headers.
2324:    *  
2325:    * @param mc the table column index (0=first).
2326:    * 
2327:    * @return the table column number in the model
2328:    * 
2329:    * @see TableColumn#getModelIndex() 
2330:    */
2331:   public int convertColumnIndexToView(int mc)
2332:   {
2333:     if (mc < 0)
2334:       return mc;
2335:     int ncols = getColumnCount();
2336:     for (int vc = 0; vc < ncols; ++vc)
2337:       {
2338:         if (columnModel.getColumn(vc).getModelIndex() == mc)
2339:           return vc;
2340:       }
2341:     return -1;
2342:   }
2343:   
2344:   /**
2345:    * Prepare the renderer for rendering the given cell.
2346:    * 
2347:    * @param renderer the renderer being prepared
2348:    * @param row the row of the cell being rendered
2349:    * @param column the column of the cell being rendered
2350:    * 
2351:    * @return the component which .paint() method will paint the cell.
2352:    */
2353:   public Component prepareRenderer(TableCellRenderer renderer,
2354:                                    int row,
2355:                                    int column)
2356:   {
2357: 
2358:     boolean rowSelAllowed = getRowSelectionAllowed();
2359:     boolean colSelAllowed = getColumnSelectionAllowed();
2360:     boolean isSel = false;
2361:     if (rowSelAllowed && colSelAllowed || !rowSelAllowed && !colSelAllowed)
2362:       isSel = isCellSelected(row, column);
2363:     else
2364:       isSel = isRowSelected(row) && getRowSelectionAllowed()
2365:            || isColumnSelected(column) && getColumnSelectionAllowed();
2366: 
2367:     // Determine the focused cell. The focused cell is the cell at the
2368:     // leadSelectionIndices of the row and column selection model.
2369:     ListSelectionModel rowSel = getSelectionModel();
2370:     ListSelectionModel colSel = getColumnModel().getSelectionModel();
2371:     boolean hasFocus = hasFocus() && isEnabled()
2372:                        && rowSel.getLeadSelectionIndex() == row
2373:                        && colSel.getLeadSelectionIndex() == column;
2374: 
2375:     return renderer.getTableCellRendererComponent(this,
2376:                                                   dataModel.getValueAt(row, 
2377:                                                convertColumnIndexToModel(column)),
2378:                                                   isSel,
2379:                                                   hasFocus,
2380:                                                   row, column);
2381:   }
2382: 
2383: 
2384:   /**
2385:    * Get the value of the {@link #autoCreateColumnsFromModel} property.
2386:    *
2387:    * @return The current value of the property
2388:    */
2389:   public boolean getAutoCreateColumnsFromModel()
2390:   {
2391:     return autoCreateColumnsFromModel;
2392:   }
2393: 
2394:   /**
2395:    * Get the value of the {@link #autoResizeMode} property.
2396:    *
2397:    * @return The current value of the property
2398:    */
2399:   public int getAutoResizeMode()
2400:   {
2401:     return autoResizeMode;
2402:   }
2403: 
2404:   /**
2405:    * Get the value of the {@link #rowHeight} property.
2406:    *
2407:    * @return The current value of the property
2408:    */
2409:   public int getRowHeight()
2410:   {
2411:     return rowHeight;
2412:   }
2413: 
2414:   /**
2415:    * Get the height of the specified row.
2416:    *
2417:    * @param row the row whose height to return
2418:    */
2419:   public int getRowHeight(int row)
2420:   {
2421:     // FIXME: return the height of the specified row
2422:     // which may be different from the general rowHeight
2423:     return rowHeight;
2424:   }
2425: 
2426: 
2427:   /**
2428:    * Get the value of the {@link #rowMargin} property.
2429:    *
2430:    * @return The current value of the property
2431:    */
2432:   public int getRowMargin()
2433:   {
2434:     return rowMargin;
2435:   }
2436: 
2437:   /**
2438:    * Get the value of the {@link #rowSelectionAllowed} property.
2439:    *
2440:    * @return The current value of the property
2441:    */
2442:   public boolean getRowSelectionAllowed()
2443:   {
2444:     return rowSelectionAllowed;
2445:   }
2446: 
2447:   /**
2448:    * Get the value of the {@link #cellSelectionEnabled} property.
2449:    *
2450:    * @return The current value of the property
2451:    */
2452:   public boolean getCellSelectionEnabled()
2453:   {
2454:     return getColumnSelectionAllowed() && getRowSelectionAllowed();
2455:   }
2456: 
2457:   /**
2458:    * Get the value of the {@link #dataModel} property.
2459:    *
2460:    * @return The current value of the property
2461:    */
2462:   public TableModel getModel()
2463:   {
2464:     return dataModel;
2465:   }
2466: 
2467:   /**
2468:    * Get the value of the <code>columnCount</code> property by
2469:    * delegation to the {@link #columnModel} field.
2470:    *
2471:    * @return The current value of the columnCount property
2472:    */
2473:   public int getColumnCount()
2474:   {
2475:     return columnModel.getColumnCount();    
2476:   }
2477: 
2478:   /**
2479:    * Get the value of the <code>rowCount</code> property by
2480:    * delegation to the {@link #dataModel} field.
2481:    *
2482:    * @return The current value of the rowCount property
2483:    */
2484:   public int getRowCount()
2485:   {
2486:     return dataModel.getRowCount();
2487:   }
2488: 
2489:   /**
2490:    * Get the value of the {@link #columnModel} property.
2491:    *
2492:    * @return The current value of the property
2493:    */
2494:   public TableColumnModel getColumnModel()
2495:   {
2496:     return columnModel;
2497:   }
2498: 
2499:   /**
2500:    * Get the value of the <code>selectedColumn</code> property by
2501:    * delegation to the {@link #columnModel} field.
2502:    *
2503:    * @return The current value of the selectedColumn property
2504:    */
2505:   public int getSelectedColumn()
2506:   {
2507:     return columnModel.getSelectionModel().getMinSelectionIndex();
2508:   }
2509: 
2510:   private static int countSelections(ListSelectionModel lsm)
2511:   {
2512:     int lo = lsm.getMinSelectionIndex();
2513:     int hi = lsm.getMaxSelectionIndex();
2514:     int sum = 0;
2515:     if (lo != -1 && hi != -1)
2516:       {
2517:         switch (lsm.getSelectionMode())
2518:           {
2519:           case ListSelectionModel.SINGLE_SELECTION:
2520:             sum = 1;
2521:             break;
2522:             
2523:           case ListSelectionModel.SINGLE_INTERVAL_SELECTION:
2524:             sum = hi - lo + 1;
2525:             break;
2526:             
2527:           case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:        
2528:             for (int i = lo; i <= hi; ++i)
2529:               if (lsm.isSelectedIndex(i))        
2530:                 ++sum;
2531:             break;
2532:           }
2533:       }
2534:     return sum;
2535:   }
2536: 
2537:   private static int[] getSelections(ListSelectionModel lsm)
2538:   {
2539:     int sz = countSelections(lsm);
2540:     int [] ret = new int[sz];
2541: 
2542:     int lo = lsm.getMinSelectionIndex();
2543:     int hi = lsm.getMaxSelectionIndex();
2544:     int j = 0;
2545:     if (lo != -1 && hi != -1)
2546:       {
2547:         switch (lsm.getSelectionMode())
2548:           {
2549:           case ListSelectionModel.SINGLE_SELECTION:
2550:             ret[0] = lo;
2551:             break;      
2552:       
2553:           case ListSelectionModel.SINGLE_INTERVAL_SELECTION:            
2554:             for (int i = lo; i <= hi; ++i)
2555:               ret[j++] = i;
2556:             break;
2557:             
2558:           case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:        
2559:             for (int i = lo; i <= hi; ++i)
2560:               if (lsm.isSelectedIndex(i))        
2561:                 ret[j++] = i;
2562:             break;
2563:           }
2564:       }
2565:     return ret;
2566:   }
2567: 
2568:   /**
2569:    * Get the value of the <code>selectedColumnCount</code> property by
2570:    * delegation to the {@link #columnModel} field.
2571:    *
2572:    * @return The current value of the selectedColumnCount property
2573:    */  
2574:   public int getSelectedColumnCount()
2575:   {
2576:     return countSelections(columnModel.getSelectionModel());
2577:   }
2578: 
2579:   /**
2580:    * Get the value of the <code>selectedColumns</code> property by
2581:    * delegation to the {@link #columnModel} field.
2582:    *
2583:    * @return The current value of the selectedColumns property
2584:    */
2585:   public int[] getSelectedColumns()
2586:   {
2587:     return getSelections(columnModel.getSelectionModel());
2588:   }
2589: 
2590:   /**
2591:    * Get the value of the <code>columnSelectionAllowed</code> property.
2592:    *
2593:    * @return The current value of the columnSelectionAllowed property
2594:    */
2595:   public boolean getColumnSelectionAllowed()
2596:   {
2597:     return getColumnModel().getColumnSelectionAllowed();
2598:   }
2599: 
2600:   /**
2601:    * Get the value of the <code>selectedRowCount</code> property by
2602:    * delegation to the {@link #selectionModel} field.
2603:    *
2604:    * @return The current value of the selectedRowCount property
2605:    */
2606:   public int getSelectedRowCount()
2607:   {
2608:     return countSelections(selectionModel);
2609:   }
2610: 
2611:   /**
2612:    * Get the value of the <code>selectedRows</code> property by
2613:    * delegation to the {@link #selectionModel} field.
2614:    *
2615:    * @return The current value of the selectedRows property
2616:    */
2617:   public int[] getSelectedRows()
2618:   {
2619:     return getSelections(selectionModel);
2620:   }
2621: 
2622:   /**
2623:    * Get the value of the {@link #accessibleContext} property.
2624:    *
2625:    * @return The current value of the property
2626:    */
2627:   public AccessibleContext getAccessibleContext()
2628:   {
2629:     return accessibleContext;
2630:   }
2631: 
2632:   /**
2633:    * Get the value of the {@link #cellEditor} property.
2634:    *
2635:    * @return The current value of the property
2636:    */
2637:   public TableCellEditor getCellEditor()
2638:   {
2639:     return cellEditor;
2640:   }
2641: 
2642:   /**
2643:    * Get the value of the {@link #dragEnabled} property.
2644:    *
2645:    * @return The current value of the property
2646:    */
2647:   public boolean getDragEnabled()
2648:   {
2649:     return dragEnabled;
2650:   }
2651: 
2652:   /**
2653:    * Get the value of the {@link #gridColor} property.
2654:    *
2655:    * @return The current value of the property
2656:    */
2657:   public Color getGridColor()
2658:   {
2659:     return gridColor;
2660:   }
2661: 
2662:   /**
2663:    * Get the value of the <code>intercellSpacing</code> property.
2664:    *
2665:    * @return The current value of the property
2666:    */
2667:   public Dimension getIntercellSpacing()
2668:   {
2669:     return new Dimension(columnModel.getColumnMargin(), rowMargin);
2670:   }
2671: 
2672:   /**
2673:    * Get the value of the {@link #preferredViewportSize} property.
2674:    *
2675:    * @return The current value of the property
2676:    */
2677:   public Dimension getPreferredScrollableViewportSize()
2678:   {
2679:     return preferredViewportSize;
2680:   }
2681: 
2682:   /**
2683:    * Get the value of the {@link #selectionBackground} property.
2684:    *
2685:    * @return The current value of the property
2686:    */
2687:   public Color getSelectionBackground()
2688:   {
2689:     return selectionBackground;
2690:   }
2691: 
2692:   /**
2693:    * Get the value of the {@link #selectionForeground} property.
2694:    *
2695:    * @return The current value of the property
2696:    */
2697:   public Color getSelectionForeground()
2698:   {
2699:     return selectionForeground;
2700:   }
2701: 
2702:   /**
2703:    * Get the value of the {@link #showHorizontalLines} property.
2704:    *
2705:    * @return The current value of the property
2706:    */
2707:   public boolean getShowHorizontalLines()
2708:   {
2709:     return showHorizontalLines;
2710:   }
2711: 
2712:   /**
2713:    * Get the value of the {@link #showVerticalLines} property.
2714:    *
2715:    * @return The current value of the property
2716:    */
2717:   public boolean getShowVerticalLines()
2718:   {
2719:     return showVerticalLines;
2720:   }
2721: 
2722:   /**
2723:    * Get the value of the {@link #tableHeader} property.
2724:    *
2725:    * @return The current value of the property
2726:    */
2727:   public JTableHeader getTableHeader()
2728:   {
2729:     return tableHeader;
2730:   }
2731: 
2732:   /**
2733:    * Removes specified column from displayable columns of this table.
2734:    *
2735:    * @param column column to removed
2736:    */
2737:   public void removeColumn(TableColumn column)
2738:   {    
2739:     columnModel.removeColumn(column);
2740:   }
2741: 
2742:   /**
2743:    * Moves column at the specified index to new given location.
2744:    *
2745:    * @param column index of the column to move
2746:    * @param targetColumn index specifying new location of the column
2747:    */ 
2748:   public void moveColumn(int column,int targetColumn) 
2749:   {
2750:     columnModel.moveColumn(column, targetColumn);
2751:   }
2752: 
2753:   /**
2754:    * Set the value of the {@link #autoCreateColumnsFromModel} flag.  If the
2755:    * flag changes from <code>false</code> to <code>true</code>, the
2756:    * {@link #createDefaultColumnsFromModel()} method is called.
2757:    *
2758:    * @param autoCreate  the new value of the flag.
2759:    */ 
2760:   public void setAutoCreateColumnsFromModel(boolean autoCreate)
2761:   {
2762:     if (autoCreateColumnsFromModel != autoCreate)
2763:     {
2764:       autoCreateColumnsFromModel = autoCreate;
2765:       if (autoCreate)
2766:         createDefaultColumnsFromModel();
2767:     }
2768:   }
2769: 
2770:   /**
2771:    * Set the value of the {@link #autoResizeMode} property.
2772:    *
2773:    * @param a The new value of the autoResizeMode property
2774:    */ 
2775:   public void setAutoResizeMode(int a)
2776:   {
2777:     autoResizeMode = a;
2778:     revalidate();
2779:     repaint();
2780:   }
2781: 
2782:   /**
2783:    * Set the value of the {@link #rowHeight} property.
2784:    *
2785:    * @param r The new value of the rowHeight property
2786:    */ 
2787:   public void setRowHeight(int r)
2788:   {
2789:     if (r < 1)
2790:       throw new IllegalArgumentException();
2791: 
2792:     clientRowHeightSet = true;
2793: 
2794:     rowHeight = r;
2795:     revalidate();
2796:     repaint();
2797:   }
2798:   
2799:   /**
2800:    * Sets the value of the rowHeight property for the specified
2801:    * row.
2802:    * 
2803:    * @param rh is the new rowHeight
2804:    * @param row is the row to change the rowHeight of
2805:    */
2806:   public void setRowHeight(int row, int rh)
2807:   {
2808:      setRowHeight(rh);
2809:      // FIXME: not implemented
2810:   }
2811:   
2812:   /**
2813:    * Set the value of the {@link #rowMargin} property.
2814:    *
2815:    * @param r The new value of the rowMargin property
2816:    */ 
2817:   public void setRowMargin(int r)
2818:   {
2819:     rowMargin = r;
2820:     revalidate();
2821:     repaint();
2822:   }
2823: 
2824:   /**
2825:    * Set the value of the {@link #rowSelectionAllowed} property.
2826:    *
2827:    * @param r The new value of the rowSelectionAllowed property
2828:    */ 
2829:   public void setRowSelectionAllowed(boolean r)
2830:   {
2831:     rowSelectionAllowed = r;
2832:     repaint();
2833:   }
2834: 
2835:   /**
2836:    * Set the value of the {@link #cellSelectionEnabled} property.
2837:    *
2838:    * @param c The new value of the cellSelectionEnabled property
2839:    */ 
2840:   public void setCellSelectionEnabled(boolean c)
2841:   {
2842:     setColumnSelectionAllowed(c);
2843:     setRowSelectionAllowed(c);
2844:     // for backward-compatibility sake:
2845:     cellSelectionEnabled = true;
2846:   }
2847: 
2848:   /**
2849:    * <p>Set the value of the {@link #dataModel} property.</p>
2850:    *
2851:    * <p>Unregister <code>this</code> as a {@link TableModelListener} from
2852:    * previous {@link #dataModel} and register it with new parameter
2853:    * <code>m</code>.</p>
2854:    *
2855:    * @param m The new value of the model property
2856:    */ 
2857:   public void setModel(TableModel m)
2858:   {
2859:     // Throw exception is m is null.
2860:     if (m == null)
2861:       throw new IllegalArgumentException();
2862:    
2863:     // Don't do anything if setting the current model again.
2864:     if (dataModel == m)
2865:       return;
2866: 
2867:     TableModel oldModel = dataModel;
2868: 
2869:     // Remove table as TableModelListener from old model.
2870:     if (dataModel != null)
2871:       dataModel.removeTableModelListener(this);
2872:     
2873:     if (m != null)
2874:       {
2875:         // Set property.
2876:         dataModel = m;
2877: 
2878:         // Add table as TableModelListener to new model.
2879:         dataModel.addTableModelListener(this);
2880: 
2881:         // Automatically create columns.
2882:         if (autoCreateColumnsFromModel)
2883:           createDefaultColumnsFromModel();
2884:       }
2885: 
2886:     // This property is bound, so we fire a property change event.
2887:     firePropertyChange("model", oldModel, dataModel);
2888: 
2889:     // Repaint table.
2890:     revalidate();
2891:     repaint();
2892:   }
2893: 
2894:   /**
2895:    * <p>Set the value of the {@link #columnModel} property.</p>
2896:    *
2897:    * <p>Unregister <code>this</code> as a {@link TableColumnModelListener}
2898:    * from previous {@link #columnModel} and register it with new parameter
2899:    * <code>c</code>.</p>
2900:    *
2901:    * @param c The new value of the columnModel property
2902:    */ 
2903:   public void setColumnModel(TableColumnModel c)
2904:   {
2905:     if (c == null)
2906:       throw new IllegalArgumentException();
2907:     TableColumnModel tmp = columnModel;
2908:     if (tmp != null)
2909:       tmp.removeColumnModelListener(this);
2910:     if (c != null)
2911:       c.addColumnModelListener(this);
2912:     columnModel = c;
2913:     if (dataModel != null && columnModel != null)
2914:       {
2915:         int ncols = getColumnCount();
2916:         TableColumn column;
2917:         for (int i = 0; i < ncols; ++i)
2918:           {
2919:             column = columnModel.getColumn(i); 
2920:             if (column.getHeaderValue()==null)
2921:               column.setHeaderValue(dataModel.getColumnName(i));
2922:           }
2923:       }
2924: 
2925:     // according to Sun's spec we also have to set the tableHeader's
2926:     // column model here
2927:     if (tableHeader != null)
2928:       tableHeader.setColumnModel(c);
2929: 
2930:     revalidate();
2931:     repaint();
2932:   }
2933: 
2934:   /**
2935:    * Set the value of the <code>columnSelectionAllowed</code> property.
2936:    *
2937:    * @param c The new value of the property
2938:    */ 
2939:   public void setColumnSelectionAllowed(boolean c)
2940:   {
2941:     getColumnModel().setColumnSelectionAllowed(c);
2942:     repaint();
2943:   }
2944: 
2945:   /**
2946:    * <p>Set the value of the {@link #selectionModel} property.</p>
2947:    *
2948:    * <p>Unregister <code>this</code> as a {@link ListSelectionListener}
2949:    * from previous {@link #selectionModel} and register it with new
2950:    * parameter <code>s</code>.</p>
2951:    *
2952:    * @param s The new value of the selectionModel property
2953:    */ 
2954:   public void setSelectionModel(ListSelectionModel s)
2955:   {
2956:     if (s == null)
2957:       throw new IllegalArgumentException();
2958:     ListSelectionModel tmp = selectionModel;
2959:     if (tmp != null)
2960:       tmp.removeListSelectionListener(this);
2961:     if (s != null)
2962:       s.addListSelectionListener(this);
2963:     selectionModel = s;
2964:   }
2965: 
2966:   /**
2967:    * Set the value of the <code>selectionMode</code> property by
2968:    * delegation to the {@link #selectionModel} field. The same selection
2969:    * mode is set for row and column selection models.
2970:    *
2971:    * @param s The new value of the property
2972:    */ 
2973:   public void setSelectionMode(int s)
2974:   { 
2975:     selectionModel.setSelectionMode(s);    
2976:     columnModel.getSelectionModel().setSelectionMode(s);
2977:     
2978:     repaint();
2979:   }
2980: 
2981:   /**
2982:    * <p>Set the value of the {@link #cellEditor} property.</p>
2983:    *
2984:    * <p>Unregister <code>this</code> as a {@link CellEditorListener} from
2985:    * previous {@link #cellEditor} and register it with new parameter
2986:    * <code>c</code>.</p>
2987:    *
2988:    * @param c The new value of the cellEditor property
2989:    */ 
2990:   public void setCellEditor(TableCellEditor c)
2991:   {
2992:     TableCellEditor tmp = cellEditor;
2993:     if (tmp != null)
2994:       tmp.removeCellEditorListener(this);
2995:     if (c != null)
2996:       c.addCellEditorListener(this);
2997:     cellEditor = c;
2998:   }
2999: 
3000:   /**
3001:    * Set the value of the {@link #dragEnabled} property.
3002:    *
3003:    * @param d The new value of the dragEnabled property
3004:    */ 
3005:   public void setDragEnabled(boolean d)
3006:   {
3007:     dragEnabled = d;
3008:   }
3009: 
3010:   /**
3011:    * Set the value of the {@link #gridColor} property.
3012:    *
3013:    * @param g The new value of the gridColor property
3014:    */ 
3015:   public void setGridColor(Color g)
3016:   {
3017:     gridColor = g;
3018:     repaint();
3019:   }
3020: 
3021:   /**
3022:    * Set the value of the <code>intercellSpacing</code> property.
3023:    *
3024:    * @param i The new value of the intercellSpacing property
3025:    */ 
3026:   public void setIntercellSpacing(Dimension i)
3027:   {
3028:     rowMargin = i.height;
3029:     columnModel.setColumnMargin(i.width);
3030:     repaint();
3031:   }
3032: 
3033:   /**
3034:    * Set the value of the {@link #preferredViewportSize} property.
3035:    *
3036:    * @param p The new value of the preferredViewportSize property
3037:    */ 
3038:   public void setPreferredScrollableViewportSize(Dimension p)
3039:   {
3040:     preferredViewportSize = p;
3041:     revalidate();
3042:     repaint();
3043:   }
3044: 
3045:   /**
3046:    * <p>Set the value of the {@link #selectionBackground} property.</p>
3047:    *
3048:    * <p>Fire a PropertyChangeEvent with name {@link
3049:    * #SELECTION_BACKGROUND_CHANGED_PROPERTY} to registered listeners, if
3050:    * selectionBackground changed.</p>
3051:    *
3052:    * @param s The new value of the selectionBackground property
3053:    */ 
3054:   public void setSelectionBackground(Color s)
3055:   {
3056:     Color tmp = selectionBackground;
3057:     selectionBackground = s;
3058:     if (((tmp == null && s != null)
3059:          || (s == null && tmp != null)
3060:          || (tmp != null && s != null && !tmp.equals(s))))
3061:       firePropertyChange(SELECTION_BACKGROUND_CHANGED_PROPERTY, tmp, s);
3062:     repaint();
3063:   }
3064: 
3065:   /**
3066:    * <p>Set the value of the {@link #selectionForeground} property.</p>
3067:    *
3068:    * <p>Fire a PropertyChangeEvent with name {@link
3069:    * #SELECTION_FOREGROUND_CHANGED_PROPERTY} to registered listeners, if
3070:    * selectionForeground changed.</p>
3071:    *
3072:    * @param s The new value of the selectionForeground property
3073:    */ 
3074:   public void setSelectionForeground(Color s)
3075:   {
3076:     Color tmp = selectionForeground;
3077:     selectionForeground = s;
3078:     if (((tmp == null && s != null)
3079:          || (s == null && tmp != null)
3080:          || (tmp != null && s != null && !tmp.equals(s))))
3081:       firePropertyChange(SELECTION_FOREGROUND_CHANGED_PROPERTY, tmp, s);
3082:     repaint();
3083:   }
3084: 
3085:   /**
3086:    * Set the value of the <code>showGrid</code> property.
3087:    *
3088:    * @param s The new value of the showGrid property
3089:    */ 
3090:   public void setShowGrid(boolean s)
3091:   {
3092:     setShowVerticalLines(s);
3093:     setShowHorizontalLines(s);
3094:   }
3095: 
3096:   /**
3097:    * Set the value of the {@link #showHorizontalLines} property.
3098:    *
3099:    * @param s The new value of the showHorizontalLines property
3100:    */ 
3101:   public void setShowHorizontalLines(boolean s)
3102:   {
3103:     showHorizontalLines = s;
3104:     repaint();
3105:   }
3106: 
3107:   /**
3108:    * Set the value of the {@link #showVerticalLines} property.
3109:    *
3110:    * @param s The new value of the showVerticalLines property
3111:    */ 
3112:   public void setShowVerticalLines(boolean s)
3113:   {
3114:     showVerticalLines = s;
3115:     repaint();
3116:   }
3117: 
3118:   /**
3119:    * Set the value of the {@link #tableHeader} property.
3120:    *
3121:    * @param t The new value of the tableHeader property
3122:    */ 
3123:   public void setTableHeader(JTableHeader t)
3124:   {
3125:     if (tableHeader != null)
3126:       tableHeader.setTable(null);
3127:     tableHeader = t;
3128:     if (tableHeader != null)
3129:       tableHeader.setTable(this);
3130:     revalidate();
3131:     repaint();
3132:   }
3133: 
3134:   protected void configureEnclosingScrollPane()
3135:   {
3136:     JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
3137:     if (jsp != null && tableHeader != null)
3138:       {
3139:         jsp.setColumnHeaderView(tableHeader);
3140:       }
3141:   }
3142: 
3143:   protected void unconfigureEnclosingScrollPane()
3144:   {
3145:     JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
3146:     if (jsp != null)
3147:       {
3148:         jsp.setColumnHeaderView(null);
3149:       }    
3150:   }
3151: 
3152: 
3153:   public void addNotify()
3154:   {
3155:     super.addNotify();
3156:     configureEnclosingScrollPane();
3157:   }
3158: 
3159:   public void removeNotify()
3160:   {
3161:     super.addNotify();
3162:     unconfigureEnclosingScrollPane();
3163:   }
3164: 
3165: 
3166:   /**
3167:    * This distributes the superfluous width in a table evenly on its columns.
3168:    *
3169:    * The implementation used here is different to that one described in
3170:    * the JavaDocs. It is much simpler, and seems to work very well.
3171:    *
3172:    * TODO: correctly implement the algorithm described in the JavaDoc
3173:    */
3174:   private void distributeSpill(TableColumn[] cols, int spill)
3175:   {
3176:     int average = spill / cols.length;
3177:     for (int i = 0; i < cols.length; i++)
3178:       {
3179:         if (cols[i] != null)
3180:           cols[i].setWidth(cols[i].getPreferredWidth() + average);
3181:       }
3182:   }
3183:   
3184:   /**
3185:    * This distributes the superfluous width in a table, setting the width of the
3186:    * column being resized strictly to its preferred width.
3187:    */
3188:   private void distributeSpillResizing(TableColumn[] cols, int spill,
3189:                                        TableColumn resizeIt)
3190:   {
3191:     int average = 0;
3192:     if (cols.length != 1)
3193:       average = spill / (cols.length-1);
3194:     for (int i = 0; i < cols.length; i++)
3195:       {
3196:         if (cols[i] != null && !cols[i].equals(resizeIt))
3197:           cols[i].setWidth(cols[i].getPreferredWidth() + average);
3198:       }
3199:     resizeIt.setWidth(resizeIt.getPreferredWidth());
3200:   }  
3201:   
3202:   /**
3203:    * Set the widths of all columns, taking they preferred widths into
3204:    * consideration. The excess space, if any, will be distrubuted between
3205:    * all columns. This method also handles special cases when one of the
3206:    * collumns is currently being resized.
3207:    * 
3208:    * @see TableColumn#setPreferredWidth(int)
3209:    */
3210:   public void doLayout()
3211:   {
3212:     TableColumn resizingColumn = null;
3213: 
3214:     int ncols = getColumnCount();
3215:     if (ncols < 1)
3216:       return;
3217: 
3218:     int prefSum = 0;
3219:     int rCol = -1;
3220: 
3221:     if (tableHeader != null)
3222:       resizingColumn = tableHeader.getResizingColumn();
3223: 
3224:     for (int i = 0; i < ncols; ++i)
3225:       {
3226:         TableColumn col = columnModel.getColumn(i);
3227:         int p = col.getPreferredWidth();
3228:         prefSum += p;
3229:         if (resizingColumn == col)
3230:           rCol = i;
3231:       }
3232: 
3233:     int spill = getWidth() - prefSum;
3234: 
3235:     if (resizingColumn != null)
3236:       {
3237:         TableColumn col;
3238:         TableColumn [] cols;
3239: 
3240:         switch (getAutoResizeMode())
3241:           {
3242:           case AUTO_RESIZE_LAST_COLUMN:
3243:             col = columnModel.getColumn(ncols-1);
3244:             col.setWidth(col.getPreferredWidth() + spill);
3245:             break;
3246:             
3247:           case AUTO_RESIZE_NEXT_COLUMN:
3248:             col = columnModel.getColumn(ncols-1);
3249:             col.setWidth(col.getPreferredWidth() + spill);
3250:             break;
3251: 
3252:           case AUTO_RESIZE_ALL_COLUMNS:
3253:             cols = new TableColumn[ncols];
3254:             for (int i = 0; i < ncols; ++i)
3255:               cols[i] = columnModel.getColumn(i);
3256:             distributeSpillResizing(cols, spill, resizingColumn);
3257:             break;
3258: 
3259:           case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
3260:             
3261:             // Subtract the width of the non-resized columns from the spill.
3262:             int w = 0;
3263:             int wp = 0;
3264:             TableColumn column;
3265:             for (int i = 0; i < rCol; i++)
3266:               {
3267:                 column = columnModel.getColumn(i);
3268:                 w += column.getWidth();
3269:                 wp+= column.getPreferredWidth();
3270:               }
3271: 
3272:             // The number of columns right from the column being resized.
3273:             int n = ncols-rCol-1;
3274:             if (n>0)
3275:               {
3276:                 // If there are any columns on the right sied to resize.
3277:                 spill = (getWidth()-w) - (prefSum-wp);
3278:                 int average = spill / n;
3279:             
3280:                  // For all columns right from the column being resized:
3281:                 for (int i = rCol+1; i < ncols; i++)
3282:                   {
3283:                     column = columnModel.getColumn(i);
3284:                     column.setWidth(column.getPreferredWidth() + average);
3285:                   }
3286:               }
3287:             resizingColumn.setWidth(resizingColumn.getPreferredWidth());
3288:             break;
3289: 
3290:           case AUTO_RESIZE_OFF:
3291:           default:
3292:             int prefWidth = resizingColumn.getPreferredWidth();
3293:             resizingColumn.setWidth(prefWidth);
3294:           }
3295:       }
3296:     else
3297:       {
3298:         TableColumn [] cols = new TableColumn[ncols];
3299:         for (int i = 0; i < ncols; ++i)
3300:           cols[i] = columnModel.getColumn(i);
3301:         distributeSpill(cols, spill);        
3302:       }
3303:     
3304:     if (editorComp!=null)
3305:       moveToCellBeingEdited(editorComp);
3306:     
3307:     // Repaint fixes the invalid view after the first keystroke if the cell
3308:     // editing is started immediately after the program start or cell
3309:     // resizing. 
3310:     repaint();
3311:     if (tableHeader!=null)
3312:       tableHeader.repaint();
3313:   }
3314:   
3315:   /**
3316:    * @deprecated Replaced by <code>doLayout()</code>
3317:    */
3318:   public void sizeColumnsToFit(boolean lastColumnOnly)
3319:   {
3320:     doLayout();
3321:   }
3322:   
3323:   /**
3324:    * Obsolete since JDK 1.4. Please use <code>doLayout()</code>.
3325:    */
3326:   public void sizeColumnsToFit(int resizingColumn)
3327:   {
3328:     doLayout();
3329:   }
3330: 
3331:   public String getUIClassID()
3332:   {
3333:     return "TableUI";
3334:   }
3335: 
3336:   /**
3337:    * This method returns the table's UI delegate.
3338:    *
3339:    * @return The table's UI delegate.
3340:    */
3341:   public TableUI getUI()
3342:   {
3343:     return (TableUI) ui;
3344:   }
3345: 
3346:   /**
3347:    * This method sets the table's UI delegate.
3348:    *
3349:    * @param ui The table's UI delegate.
3350:    */
3351:   public void setUI(TableUI ui)
3352:   {
3353:     super.setUI(ui);
3354:   }
3355: 
3356:   public void updateUI()
3357:   {
3358:     setUI((TableUI) UIManager.getUI(this));
3359:   }
3360:   
3361:   /**
3362:    * Get the class (datatype) of the column. The cells are rendered and edited
3363:    * differently, depending from they data type.
3364:    * 
3365:    * @param column the column (not the model index).
3366:    * 
3367:    * @return the class, defining data type of that column (String.class for
3368:    * String, Boolean.class for boolean and so on).
3369:    */
3370:   public Class getColumnClass(int column)
3371:   {
3372:     return getModel().getColumnClass(convertColumnIndexToModel(column));
3373:   }
3374:   
3375:   /**
3376:    * Get the name of the column. If the column has the column identifier set,
3377:    * the return value is the result of the .toString() method call on that
3378:    * identifier. If the identifier is not explicitly set, the returned value
3379:    * is calculated by 
3380:    * {@link javax.swing.table.AbstractTableModel#getColumnName(int)}.
3381:    * 
3382:    * @param column the column
3383:    * 
3384:    * @return the name of that column.
3385:    */
3386:   public String getColumnName(int column)
3387:   {
3388:     int modelColumn = columnModel.getColumn(column).getModelIndex();
3389:     return dataModel.getColumnName(modelColumn);
3390:   }
3391:   
3392:   /**
3393:    * Get the column, currently being edited
3394:    * 
3395:    * @return the column, currently being edited.
3396:    */
3397:   public int getEditingColumn()
3398:   {
3399:     return editingColumn;
3400:   }
3401:   
3402:   /**
3403:    * Set the column, currently being edited
3404:    * 
3405:    * @param column the column, currently being edited.
3406:    */
3407:   public void setEditingColumn(int column)
3408:   {
3409:     editingColumn = column;
3410:   }
3411:   
3412:   /**
3413:    * Get the row currently being edited.
3414:    * 
3415:    * @return the row, currently being edited.
3416:    */
3417:   public int getEditingRow()
3418:   {
3419:     return editingRow;
3420:   }
3421:   
3422:   /**
3423:    * Set the row currently being edited.
3424:    * 
3425:    * @param row the row, that will be edited
3426:    */
3427:   public void setEditingRow(int row)
3428:   {
3429:     editingRow = row;
3430:   }
3431:   
3432:   /**
3433:    * Get the editor component that is currently editing one of the cells
3434:    * 
3435:    * @return the editor component or null, if none of the cells is being
3436:    * edited.
3437:    */
3438:   public Component getEditorComponent()
3439:   {
3440:     return editorComp;
3441:   }
3442:   
3443:   /**
3444:    * Check if one of the table cells is currently being edited.
3445:    * 
3446:    * @return true if there is a cell being edited.
3447:    */
3448:   public boolean isEditing()
3449:   {
3450:     return editorComp != null;
3451:   }
3452:   
3453:   /**
3454:    * Set the default editor for the given column class (column data type).
3455:    * By default, String is handled by text field and Boolean is handled by
3456:    * the check box.
3457:    *  
3458:    * @param columnClass the column data type
3459:    * @param editor the editor that will edit this data type
3460:    * 
3461:    * @see TableModel#getColumnClass(int)
3462:    */
3463:   public void setDefaultEditor(Class columnClass, TableCellEditor editor)
3464:   {
3465:     if (editor != null)
3466:       defaultEditorsByColumnClass.put(columnClass, editor);
3467:     else
3468:       defaultEditorsByColumnClass.remove(columnClass);
3469:   }
3470:   
3471:   public void addColumnSelectionInterval(int index0, int index1)
3472:   {
3473:     if ((index0 < 0 || index0 > (getColumnCount()-1)
3474:          || index1 < 0 || index1 > (getColumnCount()-1)))
3475:       throw new IllegalArgumentException("Column index out of range.");
3476:     
3477:     getColumnModel().getSelectionModel().addSelectionInterval(index0, index1);
3478:   }
3479:   
3480:   public void addRowSelectionInterval(int index0, int index1)
3481:   {            
3482:     if ((index0 < 0 || index0 > (getRowCount()-1)
3483:          || index1 < 0 || index1 > (getRowCount()-1)))
3484:       throw new IllegalArgumentException("Row index out of range.");
3485:           
3486:     getSelectionModel().addSelectionInterval(index0, index1);
3487:   }
3488:   
3489:   public void setColumnSelectionInterval(int index0, int index1)
3490:   {
3491:     if ((index0 < 0 || index0 > (getColumnCount()-1)
3492:          || index1 < 0 || index1 > (getColumnCount()-1)))
3493:       throw new IllegalArgumentException("Column index out of range.");
3494: 
3495:     getColumnModel().getSelectionModel().setSelectionInterval(index0, index1);
3496:   }
3497:   
3498:   public void setRowSelectionInterval(int index0, int index1)
3499:   {    
3500:     if ((index0 < 0 || index0 > (getRowCount()-1)
3501:          || index1 < 0 || index1 > (getRowCount()-1)))
3502:       throw new IllegalArgumentException("Row index out of range.");
3503: 
3504:     getSelectionModel().setSelectionInterval(index0, index1);
3505:   }
3506:   
3507:   public void removeColumnSelectionInterval(int index0, int index1)  
3508:   {
3509:     if ((index0 < 0 || index0 > (getColumnCount()-1)
3510:          || index1 < 0 || index1 > (getColumnCount()-1)))
3511:       throw new IllegalArgumentException("Column index out of range.");
3512: 
3513:     getColumnModel().getSelectionModel().removeSelectionInterval(index0, index1);
3514:   }
3515:   
3516:   public void removeRowSelectionInterval(int index0, int index1)
3517:   {
3518:     if ((index0 < 0 || index0 > (getRowCount()-1)
3519:          || index1 < 0 || index1 > (getRowCount()-1)))
3520:       throw new IllegalArgumentException("Row index out of range.");
3521: 
3522:     getSelectionModel().removeSelectionInterval(index0, index1);
3523:   }
3524:   
3525:   /**
3526:    * Checks if the given column is selected.
3527:    * 
3528:    * @param column the column
3529:    * 
3530:    * @return true if the column is selected (as reported by the selection
3531:    * model, associated with the column model), false otherwise.
3532:    */
3533:   public boolean isColumnSelected(int column)
3534:   {
3535:     return getColumnModel().getSelectionModel().isSelectedIndex(column);
3536:   }
3537:   
3538:   /**
3539:    * Checks if the given row is selected.
3540:    * 
3541:    * @param row the row
3542:    * 
3543:    * @return true if the row is selected (as reported by the selection model),
3544:    * false otherwise.
3545:    */
3546:   public boolean isRowSelected(int row)
3547:   {
3548:     return getSelectionModel().isSelectedIndex(row);
3549:   }
3550:   
3551:   /**
3552:    * Checks if the given cell is selected. The cell is selected if both
3553:    * the cell row and the cell column are selected.
3554:    * 
3555:    * @param row the cell row
3556:    * @param column the cell column
3557:    * 
3558:    * @return true if the cell is selected, false otherwise
3559:    */
3560:   public boolean isCellSelected(int row, int column)
3561:   {
3562:     return isRowSelected(row) && isColumnSelected(column);
3563:   }
3564:   
3565:   /**
3566:    * Select all table.
3567:    */
3568:   public void selectAll()
3569:   {
3570:     // rowLead and colLead store the current lead selection indices
3571:     int rowLead = selectionModel.getLeadSelectionIndex();
3572:     int colLead = getColumnModel().getSelectionModel().getLeadSelectionIndex();
3573:     // the following calls to setSelectionInterval change the lead selection
3574:     // indices
3575:     setColumnSelectionInterval(0, getColumnCount() - 1);
3576:     setRowSelectionInterval(0, getRowCount() - 1);
3577:     // the following addSelectionInterval calls restore the lead selection
3578:     // indices to their previous values
3579:     addColumnSelectionInterval(colLead,colLead);
3580:     addRowSelectionInterval(rowLead, rowLead);
3581:   }
3582:   
3583:   /**
3584:    * Get the cell value at the given position.
3585:    * 
3586:    * @param row the row to get the value
3587:    * @param column the actual column number (not the model index) 
3588:    * to get the value.
3589:    * 
3590:    * @return the cell value, as returned by model.
3591:    */
3592:   public Object getValueAt(int row, int column)
3593:   {
3594:     return dataModel.getValueAt(row, convertColumnIndexToModel(column));
3595:   }
3596:   
3597:   /**
3598:    * Set value for the cell at the given position. The modified cell is
3599:    * repainted.
3600:    * 
3601:    * @param value the value to set
3602:    * @param row the row of the cell being modified
3603:    * @param column the column of the cell being modified
3604:    */
3605:   public void setValueAt(Object value, int row, int column)
3606:   {
3607:     dataModel.setValueAt(value, row, convertColumnIndexToModel(column));
3608:     
3609:     repaint(getCellRect(row, column, true));
3610:   }
3611:   
3612:   /**
3613:    * Get table column with the given identified.
3614:    * 
3615:    * @param identifier the column identifier
3616:    * 
3617:    * @return the table column with this identifier
3618:    * 
3619:    * @throws IllegalArgumentException if <code>identifier</code> is 
3620:    *         <code>null</code> or there is no column with that identifier.
3621:    * 
3622:    * @see TableColumn#setIdentifier(Object)
3623:    */
3624:   public TableColumn getColumn(Object identifier)
3625:   {
3626:     return columnModel.getColumn(columnModel.getColumnIndex(identifier));
3627:   }
3628: 
3629:   /**
3630:    * Returns <code>true</code> if the specified cell is editable, and
3631:    * <code>false</code> otherwise.
3632:    *
3633:    * @param row  the row index.
3634:    * @param column  the column index.
3635:    *
3636:    * @return true if the cell is editable, false otherwise.
3637:    */
3638:   public boolean isCellEditable(int row, int column)
3639:   {
3640:     return dataModel.isCellEditable(row, convertColumnIndexToModel(column));
3641:   }
3642: 
3643:   /**
3644:    * Clears any existing columns from the <code>JTable</code>'s
3645:    * {@link TableColumnModel} and creates new columns to match the values in
3646:    * the data ({@link TableModel}) used by the table.
3647:    *
3648:    * @see #setAutoCreateColumnsFromModel(boolean)
3649:    */
3650:   public void createDefaultColumnsFromModel()
3651:   {
3652:     assert columnModel != null : "The columnModel must not be null.";
3653: 
3654:     // remove existing columns
3655:     int columnIndex = columnModel.getColumnCount() - 1;
3656:     while (columnIndex >= 0)
3657:     {
3658:       columnModel.removeColumn(columnModel.getColumn(columnIndex));
3659:       columnIndex--;
3660:     }
3661:   
3662:     // add new columns to match the TableModel
3663:     int columnCount = dataModel.getColumnCount();
3664:     for (int c = 0; c < columnCount; c++)
3665:     {
3666:       TableColumn column = new TableColumn(c);
3667:       column.setIdentifier(dataModel.getColumnName(c));
3668:       column.setHeaderValue(dataModel.getColumnName(c));
3669:       columnModel.addColumn(column);
3670:       column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
3671:     }
3672:   }
3673: 
3674:   public void changeSelection (int rowIndex, int columnIndex, boolean toggle, boolean extend)
3675:   {
3676:     if (toggle && extend)
3677:       {
3678:         // Leave the selection state as is, but move the anchor
3679:         //   index to the specified location
3680:         selectionModel.setAnchorSelectionIndex(rowIndex);
3681:         getColumnModel().getSelectionModel().setAnchorSelectionIndex(columnIndex);
3682:       }
3683:     else if (toggle)
3684:       {
3685:         // Toggle the state of the specified cell
3686:         if (isCellSelected(rowIndex,columnIndex))
3687:           {
3688:             selectionModel.removeSelectionInterval(rowIndex,rowIndex);
3689:             getColumnModel().getSelectionModel().removeSelectionInterval(columnIndex,columnIndex);
3690:           }
3691:         else
3692:           {
3693:             selectionModel.addSelectionInterval(rowIndex,rowIndex);
3694:             getColumnModel().getSelectionModel().addSelectionInterval(columnIndex,columnIndex);
3695:           }
3696:       }
3697:     else if (extend)
3698:       {
3699:         // Extend the previous selection from the anchor to the 
3700:         // specified cell, clearing all other selections
3701:         selectionModel.setLeadSelectionIndex(rowIndex);
3702:         getColumnModel().getSelectionModel().setLeadSelectionIndex(columnIndex);
3703:       }
3704:     else
3705:       {
3706:         // Clear the previous selection and ensure the new cell
3707:         // is selected
3708:          selectionModel.clearSelection();
3709:         selectionModel.setSelectionInterval(rowIndex,rowIndex);
3710:         getColumnModel().getSelectionModel().clearSelection();
3711:         getColumnModel().getSelectionModel().setSelectionInterval(columnIndex, columnIndex);
3712:         
3713:         
3714:       }
3715:   }
3716: 
3717:   /**
3718:    * Programmatically starts editing the specified cell.
3719:    *
3720:    * @param row the row of the cell to edit.
3721:    * @param column the column of the cell to edit.
3722:    */
3723:   public boolean editCellAt (int row, int column)
3724:   {
3725:     // Complete the previous editing session, if still active.
3726:     if (isEditing())
3727:       editingStopped(new ChangeEvent("editingStopped"));
3728:     
3729:     editingRow = row;
3730:     editingColumn = column;
3731: 
3732:     setCellEditor(getCellEditor(row, column));
3733:     editorComp = prepareEditor(cellEditor, row, column);
3734:     
3735:     // Remove the previous editor components, if present. Only one
3736:     // editor component at time is allowed in the table.
3737:     removeAll();
3738:     add(editorComp);    
3739:     moveToCellBeingEdited(editorComp);
3740:     scrollRectToVisible(editorComp.getBounds());
3741:     editorComp.requestFocusInWindow();
3742:     return true;
3743:   }
3744: 
3745:   /**
3746:    * Move the given component under the cell being edited. 
3747:    * The table must be in the editing mode.
3748:    * 
3749:    * @param component the component to move.
3750:    */
3751:   private void moveToCellBeingEdited(Component component)
3752:   {
3753:      Rectangle r = getCellRect(editingRow, editingColumn, true);
3754:      // Adjust bounding box of the editing component, so that it lies
3755:      // 'above' the grid on all edges, not only right and bottom.
3756:      // The table grid is painted only at the right and bottom edge of a cell.
3757:      r.x -= 1;
3758:      r.y -= 1;
3759:      r.width += 1;
3760:      r.height += 1;
3761:      component.setBounds(r);
3762:   }
3763: 
3764:   /**
3765:    * Programmatically starts editing the specified cell.
3766:    *
3767:    * @param row the row of the cell to edit.
3768:    * @param column the column of the cell to edit.
3769:    */
3770:   public boolean editCellAt (int row, int column, EventObject e)
3771:   {
3772:     return editCellAt(row, column);
3773:   }
3774: 
3775:   /**
3776:    * Discards the editor object.
3777:    */
3778:   public void removeEditor()
3779:   {
3780:     editingStopped(new ChangeEvent(this));
3781:   }
3782: 
3783:   /**
3784:    * Prepares the editor by querying for the value and selection state of the
3785:    * cell at (row, column).
3786:    *
3787:    * @param editor the TableCellEditor to set up
3788:    * @param row the row of the cell to edit
3789:    * @param column the column of the cell to edit
3790:    * @return the Component being edited
3791:    */
3792:   public Component prepareEditor (TableCellEditor editor, int row, int column)
3793:   {
3794:     return editor.getTableCellEditorComponent
3795:       (this, getValueAt(row, column), isCellSelected(row, column), row, column);
3796:   }
3797: 
3798:   /**
3799:    * This revalidates the <code>JTable</code> and queues a repaint.
3800:    */
3801:   protected void resizeAndRepaint()
3802:   {
3803:     revalidate();
3804:     repaint();
3805:   }
3806: 
3807:   /**
3808:    * Sets whether cell editors of this table should receive keyboard focus
3809:    * when the editor is activated by a keystroke. The default setting is
3810:    * <code>false</code> which means that the table should keep the keyboard
3811:    * focus until the cell is selected by a mouse click.
3812:    *
3813:    * @param value the value to set
3814:    *
3815:    * @since 1.4
3816:    */
3817:   public void setSurrendersFocusOnKeystroke(boolean value)
3818:   {
3819:     // TODO: Implement functionality of this property (in UI impl).
3820:     surrendersFocusOnKeystroke = value;
3821:   }
3822:   
3823:   /**
3824:    * Returns whether cell editors of this table should receive keyboard focus
3825:    * when the editor is activated by a keystroke. The default setting is
3826:    * <code>false</code> which means that the table should keep the keyboard
3827:    * focus until the cell is selected by a mouse click.
3828:    *
3829:    * @return whether cell editors of this table should receive keyboard focus
3830:    *         when the editor is activated by a keystroke
3831:    *
3832:    * @since 1.4
3833:    */
3834:   public boolean getSurrendersFocusOnKeystroke()
3835:   {
3836:     // TODO: Implement functionality of this property (in UI impl).
3837:     return surrendersFocusOnKeystroke;
3838:   }
3839: 
3840:   /**
3841:    * Helper method for
3842:    * {@link LookAndFeel#installProperty(JComponent, String, Object)}.
3843:    * 
3844:    * @param propertyName the name of the property
3845:    * @param value the value of the property
3846:    *
3847:    * @throws IllegalArgumentException if the specified property cannot be set
3848:    *         by this method
3849:    * @throws ClassCastException if the property value does not match the
3850:    *         property type
3851:    * @throws NullPointerException if <code>c</code> or
3852:    *         <code>propertyValue</code> is <code>null</code>
3853:    */
3854:   void setUIProperty(String propertyName, Object value)
3855:   {
3856:     if (propertyName.equals("rowHeight"))
3857:       {
3858:         if (! clientRowHeightSet)
3859:           {
3860:             setRowHeight(((Integer) value).intValue());
3861:             clientRowHeightSet = false;
3862:           }
3863:       }
3864:     else
3865:       {
3866:         super.setUIProperty(propertyName, value);
3867:       }
3868:   }
3869: }