Source for javax.swing.JTable

   1: /* JTable.java -- 
   2:    Copyright (C) 2002, 2004, 2005  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.Dimension;
  44: import java.awt.Point;
  45: import java.awt.Rectangle;
  46: import java.text.DateFormat;
  47: import java.text.NumberFormat;
  48: import java.util.Date;
  49: import java.util.Hashtable;
  50: import java.util.Vector;
  51: 
  52: import javax.accessibility.Accessible;
  53: import javax.accessibility.AccessibleContext;
  54: import javax.swing.event.CellEditorListener;
  55: import javax.swing.event.ChangeEvent;
  56: import javax.swing.event.ListSelectionEvent;
  57: import javax.swing.event.ListSelectionListener;
  58: import javax.swing.event.TableColumnModelEvent;
  59: import javax.swing.event.TableColumnModelListener;
  60: import javax.swing.event.TableModelEvent;
  61: import javax.swing.event.TableModelListener;
  62: import javax.swing.plaf.TableUI;
  63: import javax.swing.table.DefaultTableCellRenderer;
  64: import javax.swing.table.DefaultTableColumnModel;
  65: import javax.swing.table.DefaultTableModel;
  66: import javax.swing.table.JTableHeader;
  67: import javax.swing.table.TableCellEditor;
  68: import javax.swing.table.TableCellRenderer;
  69: import javax.swing.table.TableColumn;
  70: import javax.swing.table.TableColumnModel;
  71: import javax.swing.table.TableModel;
  72: 
  73: public class JTable extends JComponent
  74:   implements TableModelListener, Scrollable, TableColumnModelListener,
  75:              ListSelectionListener, CellEditorListener, Accessible
  76: {
  77: 
  78:   /**
  79:    * A cell renderer for boolean values.
  80:    */
  81:   private class BooleanCellRenderer
  82:     extends DefaultTableCellRenderer
  83:   {
  84: 
  85:     /**
  86:      * The CheckBox that is used for rendering.
  87:      */
  88:     private JCheckBox checkBox = new JCheckBox();
  89: 
  90:     /**
  91:      * Returns the component that is used for rendering the value.
  92:      *
  93:      * @param table the JTable
  94:      * @param value the value of the object
  95:      * @param isSelected is the cell selected?
  96:      * @param hasFocus has the cell the focus?
  97:      * @param row the row to render
  98:      * @param column the cell to render
  99:      * 
 100:      * @return this component (the default table cell renderer)
 101:      */
 102:     public Component getTableCellRendererComponent(JTable table, Object value,
 103:                                                    boolean isSelected,
 104:                                                    boolean hasFocus, int row,
 105:                                                    int column)
 106:     {
 107:       Boolean boolValue = (Boolean) value;
 108:       checkBox.setSelected(boolValue.booleanValue());
 109:       return checkBox;
 110:     }
 111:   }
 112: 
 113:   /**
 114:    * A cell renderer for Date values.
 115:    */
 116:   private class DateCellRenderer
 117:     extends DefaultTableCellRenderer
 118:   {
 119:     /**
 120:      * Returns the component that is used for rendering the value.
 121:      *
 122:      * @param table the JTable
 123:      * @param value the value of the object
 124:      * @param isSelected is the cell selected?
 125:      * @param hasFocus has the cell the focus?
 126:      * @param row the row to render
 127:      * @param column the cell to render
 128:      * 
 129:      * @return this component (the default table cell renderer)
 130:      */
 131:     public Component getTableCellRendererComponent(JTable table, Object value,
 132:                                                    boolean isSelected,
 133:                                                    boolean hasFocus, int row,
 134:                                                    int column)
 135:     {
 136:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
 137:                                           row, column);
 138:       if (value instanceof Date)
 139:         {
 140:           Date dateValue = (Date) value;
 141:           DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
 142:           setText(df.format(dateValue));
 143:         }
 144:       return this;
 145:     }
 146:   }
 147: 
 148:   /**
 149:    * A cell renderer for Double values.
 150:    */
 151:   private class DoubleCellRenderer
 152:     extends DefaultTableCellRenderer
 153:   {
 154:     /**
 155:      * Creates a new instance of NumberCellRenderer.
 156:      */
 157:     public DoubleCellRenderer()
 158:     {
 159:       setHorizontalAlignment(JLabel.RIGHT);
 160:     }
 161: 
 162:     /**
 163:      * Returns the component that is used for rendering the value.
 164:      *
 165:      * @param table the JTable
 166:      * @param value the value of the object
 167:      * @param isSelected is the cell selected?
 168:      * @param hasFocus has the cell the focus?
 169:      * @param row the row to render
 170:      * @param column the cell to render
 171:      * 
 172:      * @return this component (the default table cell renderer)
 173:      */
 174:     public Component getTableCellRendererComponent(JTable table, Object value,
 175:                                                    boolean isSelected,
 176:                                                    boolean hasFocus, int row,
 177:                                                    int column)
 178:     {
 179:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
 180:                                           row, column);
 181:       if (value instanceof Double)
 182:         {
 183:           Double doubleValue = (Double) value;
 184:           NumberFormat nf = NumberFormat.getInstance();
 185:           setText(nf.format(doubleValue.doubleValue()));
 186:         }
 187:       return this;
 188:     }
 189:   }
 190: 
 191:   /**
 192:    * A cell renderer for Float values.
 193:    */
 194:   private class FloatCellRenderer
 195:     extends DefaultTableCellRenderer
 196:   {
 197:     /**
 198:      * Creates a new instance of NumberCellRenderer.
 199:      */
 200:     public FloatCellRenderer()
 201:     {
 202:       setHorizontalAlignment(JLabel.RIGHT);
 203:     }
 204: 
 205:     /**
 206:      * Returns the component that is used for rendering the value.
 207:      *
 208:      * @param table the JTable
 209:      * @param value the value of the object
 210:      * @param isSelected is the cell selected?
 211:      * @param hasFocus has the cell the focus?
 212:      * @param row the row to render
 213:      * @param column the cell to render
 214:      * 
 215:      * @return this component (the default table cell renderer)
 216:      */
 217:     public Component getTableCellRendererComponent(JTable table, Object value,
 218:                                                    boolean isSelected,
 219:                                                    boolean hasFocus, int row,
 220:                                                    int column)
 221:     {
 222:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
 223:                                           row, column);
 224:       if (value instanceof Float)
 225:         {
 226:           Float floatValue = (Float) value;
 227:           NumberFormat nf = NumberFormat.getInstance();
 228:           setText(nf.format(floatValue.floatValue()));
 229:         }
 230:       return this;
 231:     }
 232:   }
 233: 
 234:   /**
 235:    * A cell renderer for Number values.
 236:    */
 237:   private class NumberCellRenderer
 238:     extends DefaultTableCellRenderer
 239:   {
 240:     /**
 241:      * Creates a new instance of NumberCellRenderer.
 242:      */
 243:     public NumberCellRenderer()
 244:     {
 245:       setHorizontalAlignment(JLabel.RIGHT);
 246:     }
 247:   }
 248: 
 249:   /**
 250:    * A cell renderer for Icon values.
 251:    */
 252:   private class IconCellRenderer
 253:     extends DefaultTableCellRenderer
 254:   {
 255:     /**
 256:      * Returns the component that is used for rendering the value.
 257:      *
 258:      * @param table the JTable
 259:      * @param value the value of the object
 260:      * @param isSelected is the cell selected?
 261:      * @param hasFocus has the cell the focus?
 262:      * @param row the row to render
 263:      * @param column the cell to render
 264:      * 
 265:      * @return this component (the default table cell renderer)
 266:      */
 267:     public Component getTableCellRendererComponent(JTable table, Object value,
 268:                                                    boolean isSelected,
 269:                                                    boolean hasFocus, int row,
 270:                                                    int column)
 271:     {
 272:       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
 273:                                           row, column);
 274:       if (value instanceof Icon)
 275:         {
 276:           Icon iconValue = (Icon) value;
 277:           setIcon(iconValue);
 278:         }
 279:       return this;
 280:     }
 281:   }
 282: 
 283:   private static final long serialVersionUID = 3876025080382781659L;
 284: 
 285: 
 286:   /**
 287:    * When resizing columns, do not automatically change any columns. In this
 288:    * case the table should be enclosed in a {@link JScrollPane} in order to
 289:    * accomodate cases in which the table size exceeds its visible area.
 290:    */
 291:   public static final int AUTO_RESIZE_OFF = 0;
 292: 
 293:   /**
 294:    * When resizing column <code>i</code>, automatically change only the
 295:    * single column <code>i+1</code> to provide or absorb excess space
 296:    * requirements.
 297:    */
 298:   public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
 299: 
 300:   /**
 301:    * When resizing column <code>i</code> in a table of <code>n</code>
 302:    * columns, automatically change all columns in the range <code>[i+1,
 303:    * n)</code>, uniformly, to provide or absorb excess space requirements.
 304:    */
 305:   public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
 306:   
 307:   /**
 308:    * When resizing column <code>i</code> in a table of <code>n</code>
 309:    * columns, automatically change all columns in the range <code>[0,
 310:    * n)</code> (with the exception of column i) uniformly, to provide or
 311:    * absorb excess space requirements.
 312:    */
 313:   public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
 314: 
 315:   /**
 316:    * When resizing column <code>i</code> in a table of <code>n</code>
 317:    * columns, automatically change column <code>n-1</code> (the last column
 318:    * in the table) to provide or absorb excess space requirements.
 319:    */
 320:   public static final int AUTO_RESIZE_LAST_COLUMN = 3;
 321: 
 322: 
 323:   /**
 324:    * A table mapping {@link java.lang.Class} objects to 
 325:    * {@link TableCellEditor} objects. This table is consulted by the 
 326:    * FIXME
 327:    */
 328:   protected Hashtable defaultEditorsByColumnClass;
 329: 
 330:   /**
 331:    * A table mapping {@link java.lang.Class} objects to 
 332:    * {@link TableCellEditor} objects. This table is consulted by the 
 333:    * FIXME
 334:    */
 335:   protected Hashtable defaultRenderersByColumnClass;
 336: 
 337:   /**
 338:    * The column that is edited, -1 if the table is not edited currently.
 339:    */
 340:   protected int editingColumn;
 341: 
 342:   /**
 343:    * The row that is edited, -1 if the table is not edited currently.
 344:    */
 345:   protected int editingRow;
 346: 
 347:   /**
 348:    * The component that is used for editing.
 349:    * <code>null</code> if the table is not editing currently.
 350:    *
 351:    */
 352:   protected transient Component editorComp;
 353: 
 354:   /**
 355:    * Whether or not the table should automatically compute a matching
 356:    * {@link TableColumnModel} and assign it to the {@link #columnModel}
 357:    * property when the {@link #dataModel} property is changed. 
 358:    *
 359:    * @see #setModel(TableModel)
 360:    * @see #createColumnsFromModel()
 361:    * @see #setColumnModel(TableColumnModel)
 362:    * @see #setAutoCreateColumnsFromModel(boolean)
 363:    * @see #getAutoCreateColumnsFromModel()
 364:    */
 365:   protected boolean autoCreateColumnsFromModel;
 366: 
 367:   /**
 368:    * A numeric code specifying the resizing behavior of the table. Must be
 369:    * one of {@link #AUTO_RESIZE_ALL_COLUMNS} (the default), {@link
 370:    * #AUTO_RESIZE_LAST_COLUMN}, {@link #AUTO_RESIZE_NEXT_COLUMN}, {@link
 371:    * #AUTO_RESIZE_SUBSEQUENT_COLUMNS}, or {@link #AUTO_RESIZE_OFF}.
 372:    * 
 373:    * @see #doLayout()
 374:    * @see #setAutoResizeMode(int)
 375:    * @see #getAutoResizeMode()
 376:    */
 377:   protected int autoResizeMode;
 378: 
 379:   /**
 380:    * The height in pixels of any row of the table. All rows in a table are
 381:    * of uniform height. This differs from column width, which varies on a
 382:    * per-column basis, and is stored in the individual columns of the
 383:    * {@link #columnModel}.
 384:    * 
 385:    * @see #getRowHeight()
 386:    * @see #setRowHeight(int)
 387:    * @see TableColumn#getWidth()
 388:    * @see TableColumn#setWidth(int)
 389:    */
 390:   protected int rowHeight;
 391: 
 392:   /**
 393:    * The height in pixels of the gap left between any two rows of the table. 
 394:    * 
 395:    * @see #setRowMargin(int)
 396:    * @see #getRowHeight()
 397:    * @see #getIntercellSpacing()
 398:    * @see #setIntercellSpacing(Dimension)
 399:    * @see TableColumnModel#getColumnMargin()
 400:    * @see TableColumnModel#setColumnMargin(int)
 401:    */
 402:   protected int rowMargin;
 403: 
 404:   /**
 405:    * Whether or not the table should allow row selection. If the table
 406:    * allows both row <em>and</em> column selection, it is said to allow
 407:    * "cell selection". Previous versions of the JDK supported cell
 408:    * selection as an independent concept, but it is now represented solely
 409:    * in terms of simultaneous row and column selection.
 410:    *
 411:    * @see TableColumnModel#getColumnSelectionAllowed()
 412:    * @see #setRowSelectionAllowed(boolean)
 413:    * @see #getRowSelectionAllowed()
 414:    * @see #getCellSelectionEnabled()
 415:    * @see #setCellSelectionEnabled(boolean)
 416:    */
 417:   protected boolean rowSelectionAllowed;
 418: 
 419:   /**
 420:    * @deprecated Use {@link #rowSelectionAllowed}, {@link 
 421:    * #getColumnSelectionAllowed}, or the combined methods {@link
 422:    * #getCellSelectionEnabled} and {@link #setCellSelectionEnabled(boolean)}.
 423:    */
 424:   protected boolean cellSelectionEnabled;
 425:   
 426:   /**
 427:    * The model for data stored in the table. Confusingly, the published API
 428:    * requires that this field be called <code>dataModel</code>, despite its
 429:    * property name. The table listens to its model as a {@link
 430:    * TableModelListener}.
 431:    *
 432:    * @see #tableChanged(TableModelEvent)
 433:    * @see TableModel#addTableModelListener(TableModelListener)
 434:    */
 435:   protected TableModel dataModel;
 436: 
 437:   /**
 438:    * <p>A model of various aspects of the columns of the table, <em>not
 439:    * including</em> the data stored in them. The {@link TableColumnModel}
 440:    * is principally concerned with holding a set of {@link TableColumn}
 441:    * objects, each of which describes the display parameters of a column
 442:    * and the numeric index of the column from the data model which the
 443:    * column is presenting.</p>
 444:    *
 445:    * <p>The TableColumnModel also contains a {@link ListSelectionModel} which
 446:    * indicates which columns are currently selected. This selection model
 447:    * works in combination with the {@link #selectionModel} of the table
 448:    * itself to specify a <em>table selection</em>: a combination of row and
 449:    * column selections.</p>
 450:    *
 451:    * <p>Most application programmers do not need to work with this property
 452:    * at all: setting {@link #autoCreateColumnsFromModel} will construct the
 453:    * columnModel automatically, and the table acts as a facade for most of
 454:    * the interesting properties of the columnModel anyways.</p>
 455:    * 
 456:    * @see #setColumnModel(TableColumnModel)
 457:    * @see #getColumnModel()
 458:    */
 459:   protected TableColumnModel columnModel;
 460: 
 461:   /**
 462:    * A model of the rows of this table which are currently selected. This
 463:    * model is used in combination with the column selection model held as a
 464:    * member of the {@link #columnModel} property, to represent the rows and
 465:    * columns (or both: cells) of the table which are currently selected.
 466:    *
 467:    * @see #rowSelectionAllowed
 468:    * @see #setSelectionModel(ListSelectionModel)
 469:    * @see #getSelectionModel()
 470:    * @see TableColumnModel#getSelectionModel()
 471:    * @see ListSelectionModel#addListSelectionListener(ListSelectionListener)   
 472:    */
 473:   protected ListSelectionModel selectionModel;
 474: 
 475:   /**
 476:    * The accessibleContext property.
 477:    */
 478:   protected AccessibleContext accessibleContext;
 479: 
 480:   /**
 481:    * The current cell editor. 
 482:    */
 483:   protected TableCellEditor cellEditor;
 484: 
 485:   /**
 486:    * Whether or not drag-and-drop is enabled on this table.
 487:    *
 488:    * @see #setDragEnabled()
 489:    * @see #getDragEnabled()
 490:    */
 491:   private boolean dragEnabled;
 492: 
 493:   /**
 494:    * The color to paint the grid lines of the table, when either {@link
 495:    * #showHorizontalLines} or {@link #showVerticalLines} is set.
 496:    *
 497:    * @see #setGridColor(Color)
 498:    * @see #getGridColor()
 499:    */
 500:   protected Color gridColor;
 501: 
 502:   /**
 503:    * The size this table would prefer its viewport assume, if it is
 504:    * contained in a {@link JScrollPane}.
 505:    *
 506:    * @see #setPreferredScrollableViewportSize(Dimension)
 507:    * @see #getPreferredScrollableViewportSize()
 508:    */
 509:   protected Dimension preferredViewportSize;
 510: 
 511:   /**
 512:    * The color to paint the background of selected cells. Fires a property
 513:    * change event with name {@link #SELECTION_BACKGROUND_CHANGED_PROPERTY}
 514:    * when its value changes.
 515:    *
 516:    * @see #setSelectionBackground(Color)
 517:    * @see #getSelectionBackground()
 518:    */
 519:   protected Color selectionBackground;
 520: 
 521:   /**
 522:    * The name carried in property change events when the {@link
 523:    * #selectionBackground} property changes.
 524:    */
 525:   private static final String SELECTION_BACKGROUND_CHANGED_PROPERTY = "selectionBackground";
 526: 
 527:   /**
 528:    * The color to paint the foreground of selected cells. Fires a property
 529:    * change event with name {@link #SELECTION_FOREGROUND_CHANGED_PROPERTY}
 530:    * when its value changes.
 531:    *
 532:    * @see #setSelectionForeground(Color)
 533:    * @see #getSelectionForeground()
 534:    */
 535:   protected Color selectionForeground;
 536: 
 537:   /**
 538:    * The name carried in property change events when the
 539:    * {@link #selectionForeground} property changes.
 540:    */
 541:   private static final String SELECTION_FOREGROUND_CHANGED_PROPERTY = "selectionForeground";
 542: 
 543:   /**
 544:    * The showHorizontalLines property.
 545:    */
 546:   protected boolean showHorizontalLines;
 547: 
 548:   /**
 549:    * The showVerticalLines property.
 550:    */
 551:   protected boolean showVerticalLines;
 552: 
 553:   /**
 554:    * The tableHeader property.
 555:    */
 556:   protected JTableHeader tableHeader;
 557: 
 558:   
 559:   /**
 560:    * Creates a new <code>JTable</code> instance.
 561:    */
 562:   public JTable ()
 563:   {
 564:     this(null, null, null);
 565:   }
 566: 
 567:   /**
 568:    * Creates a new <code>JTable</code> instance.
 569:    *
 570:    * @param numRows an <code>int</code> value
 571:    * @param numColumns an <code>int</code> value
 572:    */
 573:   public JTable (int numRows, int numColumns)
 574:   {
 575:     this(new DefaultTableModel(numRows, numColumns));
 576:   }
 577: 
 578:   /**
 579:    * Creates a new <code>JTable</code> instance.
 580:    *
 581:    * @param data an <code>Object[][]</code> value
 582:    * @param columnNames an <code>Object[]</code> value
 583:    */
 584:   public JTable(Object[][] data, Object[] columnNames)
 585:   {
 586:     this(new DefaultTableModel(data, columnNames));
 587:   }
 588: 
 589:   /**
 590:    * Creates a new <code>JTable</code> instance.
 591:    *
 592:    * @param dm a <code>TableModel</code> value
 593:    */
 594:   public JTable (TableModel dm)
 595:   {
 596:     this(dm, null, null);
 597:   }
 598: 
 599:   /**
 600:    * Creates a new <code>JTable</code> instance.
 601:    *
 602:    * @param dm a <code>TableModel</code> value
 603:    * @param cm a <code>TableColumnModel</code> value
 604:    */
 605:   public JTable (TableModel dm, TableColumnModel cm)
 606:   {
 607:     this(dm, cm, null);
 608:   }
 609: 
 610:   /**
 611:    * Creates a new <code>JTable</code> instance.
 612:    *
 613:    * @param dm a <code>TableModel</code> value
 614:    * @param cm a <code>TableColumnModel</code> value
 615:    * @param sm a <code>ListSelectionModel</code> value
 616:    */
 617:   public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm)
 618:   {
 619:     setModel(dm == null ? createDefaultDataModel() : dm);
 620:     setSelectionModel(sm == null ? createDefaultSelectionModel() : sm);
 621: 
 622:     this.columnModel = cm;
 623:     initializeLocalVars();
 624:     updateUI();
 625:   }    
 626: 
 627:   protected void initializeLocalVars()
 628:   {
 629:     setTableHeader(createDefaultTableHeader());
 630:     this.autoCreateColumnsFromModel = false;
 631:     if (columnModel == null)
 632:       {
 633:         this.autoCreateColumnsFromModel = true;
 634:         createColumnsFromModel();
 635:       }
 636:     this.columnModel.addColumnModelListener(this);
 637:     
 638:     this.defaultRenderersByColumnClass = new Hashtable();
 639:     createDefaultRenderers();
 640: 
 641:     this.defaultEditorsByColumnClass = new Hashtable();
 642:     createDefaultEditors();
 643: 
 644:     this.autoResizeMode = AUTO_RESIZE_ALL_COLUMNS;
 645:     this.rowHeight = 16;
 646:     this.rowMargin = 1;
 647:     this.rowSelectionAllowed = true;
 648:     // this.accessibleContext = new AccessibleJTable();
 649:     this.cellEditor = null;
 650:     // COMPAT: Both Sun and IBM have drag enabled
 651:     this.dragEnabled = true;
 652:     this.preferredViewportSize = new Dimension(450,400);
 653:     this.showHorizontalLines = true;
 654:     this.showVerticalLines = true;
 655:     this.editingColumn = -1;
 656:     this.editingRow = -1;
 657:     setIntercellSpacing(new Dimension(1,1));
 658:   }
 659: 
 660:   /**
 661:    * Creates a new <code>JTable</code> instance.
 662:    *
 663:    * @param data a <code>Vector</code> value
 664:    * @param columnNames a <code>Vector</code> value
 665:    */
 666:   public JTable(Vector data, Vector columnNames)
 667:   {
 668:     this(new DefaultTableModel(data, columnNames));
 669:   }
 670: 
 671:   public void addColumn(TableColumn column)
 672:   {
 673:     if (column.getHeaderValue() == null)
 674:       {
 675:         String name = dataModel.getColumnName(column.getModelIndex());
 676:         column.setHeaderValue(name);
 677:       }
 678:     
 679:     columnModel.addColumn(column);
 680:   }
 681: 
 682:   protected void createDefaultEditors()
 683:   {
 684:     //FIXME: Create the editor object.
 685:   }
 686: 
 687:   protected void createDefaultRenderers()
 688:   {
 689:     setDefaultRenderer(Boolean.class, new BooleanCellRenderer());
 690:     setDefaultRenderer(Number.class, new NumberCellRenderer());
 691:     setDefaultRenderer(Double.class, new DoubleCellRenderer());
 692:     setDefaultRenderer(Double.class, new FloatCellRenderer());
 693:     setDefaultRenderer(Date.class, new DateCellRenderer());
 694:     setDefaultRenderer(Icon.class, new IconCellRenderer());
 695:   }
 696:   
 697:   /**
 698:    * @deprecated 1.0.2, replaced by <code>new JScrollPane(JTable)</code>
 699:    */
 700:   public static JScrollPane createScrollPaneForTable(JTable table)
 701:   {
 702:     return new JScrollPane(table);
 703:   }
 704: 
 705:   protected TableColumnModel createDefaultColumnModel()
 706:   {
 707:     return new DefaultTableColumnModel();
 708:   }
 709: 
 710:   protected TableModel createDefaultDataModel()
 711:   {
 712:     return new DefaultTableModel();
 713:   }
 714: 
 715:   protected ListSelectionModel createDefaultSelectionModel()
 716:   {
 717:     return new DefaultListSelectionModel();
 718:   }
 719: 
 720:   protected JTableHeader createDefaultTableHeader()
 721:   {
 722:     return new JTableHeader(columnModel);
 723:   }
 724:  
 725:   private void createColumnsFromModel()
 726:   {
 727:     if (dataModel == null)
 728:       return;
 729: 
 730:     TableColumnModel cm = createDefaultColumnModel();
 731: 
 732:     for (int i = 0; i < dataModel.getColumnCount(); ++i)
 733:       {
 734:         cm.addColumn(new TableColumn(i));
 735:       }
 736:     this.setColumnModel(cm);
 737:   }
 738: 
 739:   // listener support 
 740: 
 741:   public void columnAdded (TableColumnModelEvent event)
 742:   {
 743:     revalidate();
 744:     repaint();
 745:   }
 746: 
 747:   public void columnMarginChanged (ChangeEvent event)
 748:   {
 749:     revalidate();
 750:     repaint();
 751:   }
 752: 
 753:   public void columnMoved (TableColumnModelEvent event)
 754:   {
 755:     revalidate();
 756:     repaint();
 757:   }
 758: 
 759:   public void columnRemoved (TableColumnModelEvent event)
 760:   {
 761:     revalidate();
 762:     repaint();
 763:   }
 764:   
 765:   public void columnSelectionChanged (ListSelectionEvent event)
 766:   {
 767:     repaint();
 768:   }
 769: 
 770:   public void editingCanceled (ChangeEvent event)
 771:   {
 772:     repaint();
 773:   }
 774: 
 775:   public void editingStopped (ChangeEvent event)
 776:   {
 777:     repaint();
 778:   }
 779: 
 780:   public void tableChanged (TableModelEvent event)
 781:   {
 782:     // update the column model from the table model if the structure has
 783:     // changed and the flag autoCreateColumnsFromModel is set
 784:     if ((event.getFirstRow() ==TableModelEvent.HEADER_ROW)
 785:         && autoCreateColumnsFromModel)
 786: 
 787:         createColumnsFromModel();
 788: 
 789:     repaint();
 790:   }
 791: 
 792:   public void valueChanged (ListSelectionEvent event)
 793:   {
 794:     repaint();
 795:   }
 796: 
 797:  /**
 798:    * Returns index of the column that contains specified point 
 799:    * or -1 if this table doesn't contain this point.
 800:    *
 801:    * @param point point to identify the column
 802:    * @return index of the column that contains specified point or 
 803:    * -1 if this table doesn't contain this point.
 804:    */
 805:   public int columnAtPoint(Point point)
 806:   {
 807:     int x0 = getLocation().x;
 808:     int ncols = getColumnCount();
 809:     Dimension gap = getIntercellSpacing();
 810:     TableColumnModel cols = getColumnModel();
 811:     int x = point.x;
 812:     
 813:     for (int i = 0; i < ncols; ++i)
 814:       {
 815:         int width = cols.getColumn(i).getWidth() + (gap == null ? 0 : gap.width);
 816:         if (0 <= x && x < width)
 817:           return i;
 818:         x -= width;  
 819:       }
 820:     
 821:     return -1;
 822:   }
 823: 
 824:   /**
 825:    * Returns index of the row that contains specified point or 
 826:    * -1 if this table doesn't contain this point.
 827:    *
 828:    * @param point point to identify the row
 829:    * @return index of the row that contains specified point or 
 830:    * -1 if this table doesn't contain this point.
 831:    */
 832:   public int rowAtPoint(Point point)
 833:   {
 834:     int y0 = getLocation().y;
 835:     int nrows = getRowCount();
 836:     Dimension gap = getIntercellSpacing();
 837:     int height = getRowHeight() + (gap == null ? 0 : gap.height);
 838:     int y = point.y;
 839:     
 840:     for (int i = 0; i < nrows; ++i)
 841:       {
 842:         if (0 <= y && y < height)
 843:           return i;
 844:         y -= height;
 845:       }
 846:       
 847:     return -1;
 848:   }
 849: 
 850:   /** 
 851:    * Calculate the visible rectangle for a particular row and column. The
 852:    * row and column are specified in visual terms; the column may not match
 853:    * the {@link #dataModel} column.
 854:    *
 855:    * @param row the visible row to get the cell rectangle of
 856:    *
 857:    * @param column the visible column to get the cell rectangle of, which may
 858:    * differ from the {@link #dataModel} column
 859:    *
 860:    * @param includeSpacing whether or not to include the cell margins in the
 861:    * resulting cell. If <code>false</code>, the result will only contain the
 862:    * inner area of the target cell, not including its margins.
 863:    *
 864:    * @return a rectangle enclosing the specified cell
 865:    */
 866:   public Rectangle getCellRect(int row,
 867:                                int column,
 868:                                boolean includeSpacing)
 869:   {
 870:     int height = getHeight();
 871:     int width = columnModel.getColumn(column).getWidth();
 872:     int x_gap = columnModel.getColumnMargin();
 873:     int y_gap = rowMargin;
 874: 
 875:     column = Math.max(0, Math.min(column, getColumnCount() - 1));
 876:     row = Math.max(0, Math.min(row, getRowCount() - 1));
 877: 
 878:     int x = 0;
 879:     int y = (height + y_gap) * row;
 880: 
 881:     for (int i = 0; i < column; ++i)
 882:       {        
 883:         x += columnModel.getColumn(i).getWidth();
 884:         x += x_gap;
 885:       }
 886: 
 887:     if (includeSpacing)
 888:       return new Rectangle(x, y, width, height);
 889:     else
 890:       return new Rectangle(x, y, width - x_gap, height - y_gap);
 891:   }
 892: 
 893:   public void clearSelection()
 894:   {
 895:     selectionModel.clearSelection();
 896:     getColumnModel().getSelectionModel().clearSelection();
 897:   }
 898: 
 899:   /**
 900:    * Get the value of the selectedRow property by delegation to
 901:    * the {@link ListSelectionModel#getMinSelectionIndex} method of the
 902:    * {@link #selectionModel} field.
 903:    *
 904:    * @return The current value of the selectedRow property
 905:    */
 906:   public int getSelectedRow ()
 907:   {
 908:     return selectionModel.getMinSelectionIndex();
 909:   }
 910:   
 911:   /**
 912:    * Get the value of the {@link #selectionModel} property.
 913:    *
 914:    * @return The current value of the property
 915:    */
 916:   public ListSelectionModel getSelectionModel()
 917:   {
 918:     //Neither Sun nor IBM returns null if rowSelection not allowed
 919:     return selectionModel;
 920:   }
 921:   
 922:   public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
 923:   {
 924:     if (orientation == SwingConstants.VERTICAL)
 925:       return visibleRect.height * direction;
 926:     else
 927:       return visibleRect.width * direction;
 928:   }
 929: 
 930:   /**
 931:    * Get the value of the <code>scrollableTracksViewportHeight</code> property.
 932:    *
 933:    * @return The constant value <code>false</code>
 934:    */
 935:   public boolean getScrollableTracksViewportHeight()
 936:   {
 937:     return false;
 938:   }
 939:   
 940:   /**
 941:    * Get the value of the <code>scrollableTracksViewportWidth</code> property.
 942:    *
 943:    * @return <code>true</code> unless the {@link #autoResizeMode} property is
 944:    * <code>AUTO_RESIZE_OFF</code>
 945:    */
 946:   public boolean getScrollableTracksViewportWidth()
 947:   {
 948:     if (autoResizeMode == AUTO_RESIZE_OFF)
 949:       return false;
 950:     else
 951:       return true;
 952:   }
 953: 
 954:   public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
 955:   {
 956:     // FIXME: I don't exactly know what sun does here. in both cases they
 957:     // pick values which do *not* simply expose the next cell in a given
 958:     // scroll direction.
 959: 
 960:     if (orientation == SwingConstants.VERTICAL)
 961:       return rowHeight;
 962:     else
 963:       {
 964:         int sum = 0;
 965:         for (int i = 0; i < getColumnCount(); ++i)
 966:           sum += columnModel.getColumn(0).getWidth();
 967:         return getColumnCount() == 0 ? 10 : sum / getColumnCount();
 968:       }
 969:   }
 970: 
 971: 
 972:   public TableCellEditor getCellEditor(int row, int column)
 973:   {
 974:     TableCellEditor editor = columnModel.getColumn(column).getCellEditor();
 975: 
 976:     if (editor == null)
 977:       editor = getDefaultEditor(dataModel.getColumnClass(column));
 978: 
 979:     return editor;
 980:   }
 981: 
 982:   public TableCellEditor getDefaultEditor(Class columnClass)
 983:   {
 984:     if (defaultEditorsByColumnClass.containsKey(columnClass))
 985:       return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass);
 986:     else
 987:       {
 988:     // FIXME: We have at least an editor for Object.class in our defaults.
 989:         TableCellEditor r = new DefaultCellEditor(new JTextField());
 990:         defaultEditorsByColumnClass.put(columnClass, r);
 991:         return r;
 992:       }
 993:   }
 994: 
 995: 
 996: 
 997:   public TableCellRenderer getCellRenderer(int row, int column)
 998:   {
 999:     TableCellRenderer renderer =
1000:       columnModel.getColumn(column).getCellRenderer();
1001:     
1002:     if (renderer == null)
1003:       renderer = getDefaultRenderer(dataModel.getColumnClass(column));
1004:     
1005:     return renderer;
1006:   }
1007: 
1008:   public void setDefaultRenderer(Class columnClass, TableCellRenderer rend)
1009:   {
1010:     defaultRenderersByColumnClass.put(columnClass, rend);
1011:   }
1012: 
1013:   public TableCellRenderer getDefaultRenderer(Class columnClass)
1014:   {
1015:     if (defaultRenderersByColumnClass.containsKey(columnClass))
1016:       return (TableCellRenderer) defaultRenderersByColumnClass.get(columnClass);
1017:     else
1018:       {
1019:         TableCellRenderer r = new DefaultTableCellRenderer();
1020:         defaultRenderersByColumnClass.put(columnClass, r);
1021:         return r;
1022:       }
1023:   }
1024: 
1025:   public int convertColumnIndexToModel(int vc)
1026:   {
1027:     if (vc < 0)
1028:       return vc;
1029:     else
1030:       return columnModel.getColumn(vc).getModelIndex();
1031:   }
1032: 
1033:   public int convertColumnIndexToView(int mc)
1034:   {
1035:     if (mc < 0)
1036:       return mc;
1037:     int ncols = getColumnCount();
1038:     for (int vc = 0; vc < ncols; ++vc)
1039:       {
1040:         if (columnModel.getColumn(vc).getModelIndex() == mc)
1041:           return vc;
1042:       }
1043:     return -1;
1044:   }
1045: 
1046:   public Component prepareRenderer(TableCellRenderer renderer,
1047:                                    int row,
1048:                                    int column)
1049:   {
1050:     boolean rsa = getRowSelectionAllowed();
1051:     boolean csa = getColumnSelectionAllowed();
1052:     boolean rs = rsa ? getSelectionModel().isSelectedIndex(row) : false;
1053:     boolean cs = csa ? columnModel.getSelectionModel().isSelectedIndex(column) : false;
1054:     boolean isSelected = ((rsa && csa && rs && cs) 
1055:                           || (rsa && !csa && rs) 
1056:                           || (!rsa && csa && cs));
1057:     
1058:     return renderer.getTableCellRendererComponent(this,
1059:                                                   dataModel.getValueAt(row, 
1060:                                                convertColumnIndexToModel(column)),
1061:                                                   isSelected,
1062:                                                   false, // hasFocus
1063:                                                   row, column);
1064:   }
1065: 
1066: 
1067:   /**
1068:    * Get the value of the {@link #autoCreateColumnsFromModel} property.
1069:    *
1070:    * @return The current value of the property
1071:    */
1072:   public boolean getAutoCreateColumnsFromModel()
1073:   {
1074:     return autoCreateColumnsFromModel;
1075:   }
1076: 
1077:   /**
1078:    * Get the value of the {@link #autoResizeMode} property.
1079:    *
1080:    * @return The current value of the property
1081:    */
1082:   public int getAutoResizeMode()
1083:   {
1084:     return autoResizeMode;
1085:   }
1086: 
1087:   /**
1088:    * Get the value of the {@link #rowHeight} property.
1089:    *
1090:    * @return The current value of the property
1091:    */
1092:   public int getRowHeight()
1093:   {
1094:     return rowHeight;
1095:   }
1096: 
1097:   /**
1098:    * Get the value of the {@link #rowMargin} property.
1099:    *
1100:    * @return The current value of the property
1101:    */
1102:   public int getRowMargin()
1103:   {
1104:     return rowMargin;
1105:   }
1106: 
1107:   /**
1108:    * Get the value of the {@link #rowSelectionAllowed} property.
1109:    *
1110:    * @return The current value of the property
1111:    */
1112:   public boolean getRowSelectionAllowed()
1113:   {
1114:     return rowSelectionAllowed;
1115:   }
1116: 
1117:   /**
1118:    * Get the value of the {@link #cellSelectionEnabled} property.
1119:    *
1120:    * @return The current value of the property
1121:    */
1122:   public boolean getCellSelectionEnabled()
1123:   {
1124:     return getColumnSelectionAllowed() && getRowSelectionAllowed();
1125:   }
1126: 
1127:   /**
1128:    * Get the value of the {@link #dataModel} property.
1129:    *
1130:    * @return The current value of the property
1131:    */
1132:   public TableModel getModel()
1133:   {
1134:     return dataModel;
1135:   }
1136: 
1137:   /**
1138:    * Get the value of the <code>columnCount</code> property by
1139:    * delegation to the @{link #columnModel} field.
1140:    *
1141:    * @return The current value of the columnCount property
1142:    */
1143:   public int getColumnCount()
1144:   {
1145:     return columnModel.getColumnCount();    
1146:   }
1147: 
1148:   /**
1149:    * Get the value of the <code>rowCount</code> property by
1150:    * delegation to the @{link #dataModel} field.
1151:    *
1152:    * @return The current value of the rowCount property
1153:    */
1154:   public int getRowCount()
1155:   {
1156:     return dataModel.getRowCount();
1157:   }
1158: 
1159:   /**
1160:    * Get the value of the {@link #columnModel} property.
1161:    *
1162:    * @return The current value of the property
1163:    */
1164:   public TableColumnModel getColumnModel()
1165:   {
1166:     return columnModel;
1167:   }
1168: 
1169:   /**
1170:    * Get the value of the <code>selectedColumn</code> property by
1171:    * delegation to the @{link #columnModel} field.
1172:    *
1173:    * @return The current value of the selectedColumn property
1174:    */
1175:   public int getSelectedColumn()
1176:   {
1177:     return columnModel.getSelectionModel().getMinSelectionIndex();
1178:   }
1179: 
1180:   private static int countSelections(ListSelectionModel lsm)
1181:   {
1182:     int lo = lsm.getMinSelectionIndex();
1183:     int hi = lsm.getMaxSelectionIndex();
1184:     int sum = 0;
1185:     if (lo != -1 && hi != -1)
1186:       {
1187:         switch (lsm.getSelectionMode())
1188:           {
1189:           case ListSelectionModel.SINGLE_SELECTION:
1190:             sum = 1;
1191:             break;
1192:             
1193:           case ListSelectionModel.SINGLE_INTERVAL_SELECTION:
1194:             sum = hi - lo + 1;
1195:             break;
1196:             
1197:           case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:        
1198:             for (int i = lo; i <= hi; ++i)
1199:               if (lsm.isSelectedIndex(i))        
1200:                 ++sum;
1201:             break;
1202:           }
1203:       }
1204:     return sum;
1205:   }
1206: 
1207:   private static int[] getSelections(ListSelectionModel lsm)
1208:   {
1209:     int sz = countSelections(lsm);
1210:     int [] ret = new int[sz];
1211: 
1212:     int lo = lsm.getMinSelectionIndex();
1213:     int hi = lsm.getMaxSelectionIndex();
1214:     int j = 0;
1215:     java.util.ArrayList ls = new java.util.ArrayList();
1216:     if (lo != -1 && hi != -1)
1217:       {
1218:         switch (lsm.getSelectionMode())
1219:           {
1220:           case ListSelectionModel.SINGLE_SELECTION:
1221:             ret[0] = lo;
1222:             break;      
1223:       
1224:           case ListSelectionModel.SINGLE_INTERVAL_SELECTION:            
1225:             for (int i = lo; i <= hi; ++i)
1226:               ret[j++] = i;
1227:             break;
1228:             
1229:           case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:        
1230:             for (int i = lo; i <= hi; ++i)
1231:               if (lsm.isSelectedIndex(i))        
1232:                 ret[j++] = i;
1233:             break;
1234:           }
1235:       }
1236:     return ret;
1237:   }
1238: 
1239:   /**
1240:    * Get the value of the <code>selectedColumnCount</code> property by
1241:    * delegation to the @{link #columnModel} field.
1242:    *
1243:    * @return The current value of the selectedColumnCount property
1244:    */  
1245:   public int getSelectedColumnCount()
1246:   {
1247:     return countSelections(columnModel.getSelectionModel());
1248:   }
1249: 
1250:   /**
1251:    * Get the value of the <code>selectedColumns</code> property by
1252:    * delegation to the @{link #columnModel} field.
1253:    *
1254:    * @return The current value of the selectedColumns property
1255:    */
1256:   public int[] getSelectedColumns()
1257:   {
1258:     return getSelections(columnModel.getSelectionModel());
1259:   }
1260: 
1261:   /**
1262:    * Get the value of the <code>columnSelectionAllowed</code> property.
1263:    *
1264:    * @return The current value of the columnSelectionAllowed property
1265:    */
1266:   public boolean getColumnSelectionAllowed()
1267:   {
1268:     return getColumnModel().getColumnSelectionAllowed();
1269:   }
1270: 
1271:   /**
1272:    * Get the value of the <code>selectedRowCount</code> property by
1273:    * delegation to the @{link #selectionModel} field.
1274:    *
1275:    * @return The current value of the selectedRowCount property
1276:    */
1277:   public int getSelectedRowCount()
1278:   {
1279:     return countSelections(selectionModel);
1280:   }
1281: 
1282:   /**
1283:    * Get the value of the <code>selectedRows</code> property by
1284:    * delegation to the @{link #selectionModel} field.
1285:    *
1286:    * @return The current value of the selectedRows property
1287:    */
1288:   public int[] getSelectedRows()
1289:   {
1290:     return getSelections(selectionModel);
1291:   }
1292: 
1293:   /**
1294:    * Get the value of the {@link #accessibleContext} property.
1295:    *
1296:    * @return The current value of the property
1297:    */
1298:   public AccessibleContext getAccessibleContext()
1299:   {
1300:     return accessibleContext;
1301:   }
1302: 
1303:   /**
1304:    * Get the value of the {@link #cellEditor} property.
1305:    *
1306:    * @return The current value of the property
1307:    */
1308:   public TableCellEditor getCellEditor()
1309:   {
1310:     return cellEditor;
1311:   }
1312: 
1313:   /**
1314:    * Get the value of the {@link #dragEnabled} property.
1315:    *
1316:    * @return The current value of the property
1317:    */
1318:   public boolean getDragEnabled()
1319:   {
1320:     return dragEnabled;
1321:   }
1322: 
1323:   /**
1324:    * Get the value of the {@link #gridColor} property.
1325:    *
1326:    * @return The current value of the property
1327:    */
1328:   public Color getGridColor()
1329:   {
1330:     return gridColor;
1331:   }
1332: 
1333:   /**
1334:    * Get the value of the <code>intercellSpacing</code> property.
1335:    *
1336:    * @return The current value of the property
1337:    */
1338:   public Dimension getIntercellSpacing()
1339:   {
1340:     return new Dimension(columnModel.getColumnMargin(), rowMargin);
1341:   }
1342: 
1343:   /**
1344:    * Get the value of the {@link #preferredViewportSize} property.
1345:    *
1346:    * @return The current value of the property
1347:    */
1348:   public Dimension getPreferredScrollableViewportSize()
1349:   {
1350:     return preferredViewportSize;
1351:   }
1352: 
1353:   /**
1354:    * Get the value of the {@link #selectionBackground} property.
1355:    *
1356:    * @return The current value of the property
1357:    */
1358:   public Color getSelectionBackground()
1359:   {
1360:     return selectionBackground;
1361:   }
1362: 
1363:   /**
1364:    * Get the value of the {@link #selectionForeground} property.
1365:    *
1366:    * @return The current value of the property
1367:    */
1368:   public Color getSelectionForeground()
1369:   {
1370:     return selectionForeground;
1371:   }
1372: 
1373:   /**
1374:    * Get the value of the {@link #showHorizontalLines} property.
1375:    *
1376:    * @return The current value of the property
1377:    */
1378:   public boolean getShowHorizontalLines()
1379:   {
1380:     return showHorizontalLines;
1381:   }
1382: 
1383:   /**
1384:    * Get the value of the {@link #showVerticalLines} property.
1385:    *
1386:    * @return The current value of the property
1387:    */
1388:   public boolean getShowVerticalLines()
1389:   {
1390:     return showVerticalLines;
1391:   }
1392: 
1393:   /**
1394:    * Get the value of the {@link #tableHeader} property.
1395:    *
1396:    * @return The current value of the property
1397:    */
1398:   public JTableHeader getTableHeader()
1399:   {
1400:     return tableHeader;
1401:   }
1402: 
1403:   /**
1404:    * Removes specified column from displayable columns of this table.
1405:    *
1406:    * @param column column to removed
1407:    */
1408:   public void removeColumn(TableColumn column)
1409:   {    
1410:     columnModel.removeColumn(column);
1411:   }
1412: 
1413:   /**
1414:    * Moves column at the specified index to new given location.
1415:    *
1416:    * @param column index of the column to move
1417:    * @param targetColumn index specifying new location of the column
1418:    */ 
1419:   public void moveColumn(int column,int targetColumn) 
1420:   {
1421:     columnModel.moveColumn(column, targetColumn);
1422:   }
1423: 
1424:   /**
1425:    * Set the value of the {@link #autoCreateColumnsFromModel} flag.  If the
1426:    * flag changes from <code>false</code> to <code>true</code>, the
1427:    * {@link #createDefaultColumnsFromModel()} method is called.
1428:    *
1429:    * @param autoCreate  the new value of the flag.
1430:    */ 
1431:   public void setAutoCreateColumnsFromModel(boolean autoCreate)
1432:   {
1433:     if (autoCreateColumnsFromModel != autoCreate)
1434:     {
1435:       autoCreateColumnsFromModel = autoCreate;
1436:       if (autoCreate)
1437:         createDefaultColumnsFromModel();
1438:     }
1439:   }
1440: 
1441:   /**
1442:    * Set the value of the {@link #autoResizeMode} property.
1443:    *
1444:    * @param a The new value of the autoResizeMode property
1445:    */ 
1446:   public void setAutoResizeMode(int a)
1447:   {
1448:     autoResizeMode = a;
1449:     revalidate();
1450:     repaint();
1451:   }
1452: 
1453:   /**
1454:    * Set the value of the {@link #rowHeight} property.
1455:    *
1456:    * @param r The new value of the rowHeight property
1457:    */ 
1458:   public void setRowHeight(int r)
1459:   {
1460:     if (rowHeight < 1)
1461:       throw new IllegalArgumentException();
1462:     
1463:     rowHeight = r;
1464:     revalidate();
1465:     repaint();
1466:   }
1467: 
1468:   /**
1469:    * Set the value of the {@link #rowMargin} property.
1470:    *
1471:    * @param r The new value of the rowMargin property
1472:    */ 
1473:   public void setRowMargin(int r)
1474:   {
1475:     rowMargin = r;
1476:     revalidate();
1477:     repaint();
1478:   }
1479: 
1480:   /**
1481:    * Set the value of the {@link #rowSelectionAllowed} property.
1482:    *
1483:    * @param r The new value of the rowSelectionAllowed property
1484:    */ 
1485:   public void setRowSelectionAllowed(boolean r)
1486:   {
1487:     rowSelectionAllowed = r;
1488:     repaint();
1489:   }
1490: 
1491:   /**
1492:    * Set the value of the {@link #cellSelectionEnabled} property.
1493:    *
1494:    * @param c The new value of the cellSelectionEnabled property
1495:    */ 
1496:   public void setCellSelectionEnabled(boolean c)
1497:   {
1498:     setColumnSelectionAllowed(c);
1499:     setRowSelectionAllowed(c);
1500:     // for backward-compatibility sake:
1501:     cellSelectionEnabled = true;
1502:   }
1503: 
1504:   /**
1505:    * <p>Set the value of the {@link #dataModel} property.</p>
1506:    *
1507:    * <p>Unregister <code>this</code> as a {@link TableModelListener} from
1508:    * previous {@link #dataModel} and register it with new parameter
1509:    * <code>m</code>.</p>
1510:    *
1511:    * @param m The new value of the model property
1512:    */ 
1513:   public void setModel(TableModel m)
1514:   {
1515:     // Throw exception is m is null.
1516:     if (m == null)
1517:       throw new IllegalArgumentException();
1518:    
1519:     // Don't do anything if setting the current model again.
1520:     if (dataModel == m)
1521:       return;
1522:     
1523:     // Remove table as TableModelListener from old model.
1524:     if (dataModel != null)
1525:       dataModel.removeTableModelListener(this);
1526:     
1527:     if (m != null)
1528:       {
1529:     // Set property.
1530:         dataModel = m;
1531: 
1532:     // Add table as TableModelListener to new model.
1533:     dataModel.addTableModelListener(this);
1534: 
1535:     // Automatically create columns.
1536:     if (autoCreateColumnsFromModel)
1537:       createColumnsFromModel();
1538:       }
1539:     
1540:     // Repaint table.
1541:     revalidate();
1542:     repaint();
1543:   }
1544: 
1545:   /**
1546:    * <p>Set the value of the {@link #columnModel} property.</p>
1547:    *
1548:    * <p>Unregister <code>this</code> as a {@link TableColumnModelListener}
1549:    * from previous {@link #columnModel} and register it with new parameter
1550:    * <code>c</code>.</p>
1551:    *
1552:    * @param c The new value of the columnModel property
1553:    */ 
1554:   public void setColumnModel(TableColumnModel c)
1555:   {
1556:     if (c == null)
1557:       throw new IllegalArgumentException();
1558:     TableColumnModel tmp = columnModel;
1559:     if (tmp != null)
1560:       tmp.removeColumnModelListener(this);
1561:     if (c != null)
1562:       c.addColumnModelListener(this);
1563:     columnModel = c;
1564:     if (dataModel != null && columnModel != null)
1565:       {
1566:         int ncols = getColumnCount();
1567:         for (int i = 0; i < ncols; ++i)
1568:           columnModel.getColumn(i).setHeaderValue(dataModel.getColumnName(i));
1569:       }
1570: 
1571:     // according to Sun's spec we also have to set the tableHeader's
1572:     // column model here
1573:     if (tableHeader != null)
1574:       tableHeader.setColumnModel(c);
1575: 
1576:     revalidate();
1577:     repaint();
1578:   }
1579: 
1580:   /**
1581:    * Set the value of the <code>columnSelectionAllowed</code> property.
1582:    *
1583:    * @param c The new value of the property
1584:    */ 
1585:   public void setColumnSelectionAllowed(boolean c)
1586:   {
1587:     getColumnModel().setColumnSelectionAllowed(c);
1588:     repaint();
1589:   }
1590: 
1591:   /**
1592:    * <p>Set the value of the {@link #selectionModel} property.</p>
1593:    *
1594:    * <p>Unregister <code>this</code> as a {@link ListSelectionListener}
1595:    * from previous {@link #selectionModel} and register it with new
1596:    * parameter <code>s</code>.</p>
1597:    *
1598:    * @param s The new value of the selectionModel property
1599:    */ 
1600:   public void setSelectionModel(ListSelectionModel s)
1601:   {
1602:     if (s == null)
1603:       throw new IllegalArgumentException();
1604:     ListSelectionModel tmp = selectionModel;
1605:     if (tmp != null)
1606:       tmp.removeListSelectionListener(this);
1607:     if (s != null)
1608:       s.addListSelectionListener(this);
1609:     selectionModel = s;
1610:   }
1611: 
1612:   /**
1613:    * Set the value of the <code>selectionMode</code> property by
1614:    * delegation to the {@link #selectionModel} field. The same selection
1615:    * mode is set for row and column selection models.
1616:    *
1617:    * @param s The new value of the property
1618:    */ 
1619:   public void setSelectionMode(int s)
1620:   { 
1621:     selectionModel.setSelectionMode(s);    
1622:     columnModel.getSelectionModel().setSelectionMode(s);
1623:     
1624:     repaint();
1625:   }
1626: 
1627:   /**
1628:    * <p>Set the value of the {@link #cellEditor} property.</p>
1629:    *
1630:    * <p>Unregister <code>this</code> as a {@link CellEditorListener} from
1631:    * previous {@link #cellEditor} and register it with new parameter
1632:    * <code>c</code>.</p>
1633:    *
1634:    * @param c The new value of the cellEditor property
1635:    */ 
1636:   public void setCellEditor(TableCellEditor c)
1637:   {
1638:     TableCellEditor tmp = cellEditor;
1639:     if (tmp != null)
1640:       tmp.removeCellEditorListener(this);
1641:     if (c != null)
1642:       c.addCellEditorListener(this);
1643:     cellEditor = c;
1644:   }
1645: 
1646:   /**
1647:    * Set the value of the {@link #dragEnabled} property.
1648:    *
1649:    * @param d The new value of the dragEnabled property
1650:    */ 
1651:   public void setDragEnabled(boolean d)
1652:   {
1653:     dragEnabled = d;
1654:   }
1655: 
1656:   /**
1657:    * Set the value of the {@link #gridColor} property.
1658:    *
1659:    * @param g The new value of the gridColor property
1660:    */ 
1661:   public void setGridColor(Color g)
1662:   {
1663:     gridColor = g;
1664:     repaint();
1665:   }
1666: 
1667:   /**
1668:    * Set the value of the <code>intercellSpacing</code> property.
1669:    *
1670:    * @param i The new value of the intercellSpacing property
1671:    */ 
1672:   public void setIntercellSpacing(Dimension i)
1673:   {
1674:     rowMargin = i.height;
1675:     columnModel.setColumnMargin(i.width);
1676:     repaint();
1677:   }
1678: 
1679:   /**
1680:    * Set the value of the {@link #preferredViewportSize} property.
1681:    *
1682:    * @param p The new value of the preferredViewportSize property
1683:    */ 
1684:   public void setPreferredScrollableViewportSize(Dimension p)
1685:   {
1686:     preferredViewportSize = p;
1687:     revalidate();
1688:     repaint();
1689:   }
1690: 
1691:   /**
1692:    * <p>Set the value of the {@link #selectionBackground} property.</p>
1693:    *
1694:    * <p>Fire a PropertyChangeEvent with name {@link
1695:    * #SELECTION_BACKGROUND_CHANGED_PROPERTY} to registered listeners, if
1696:    * selectionBackground changed.</p>
1697:    *
1698:    * @param s The new value of the selectionBackground property
1699:    */ 
1700:   public void setSelectionBackground(Color s)
1701:   {
1702:     Color tmp = selectionBackground;
1703:     selectionBackground = s;
1704:     if (((tmp == null && s != null)
1705:          || (s == null && tmp != null)
1706:          || (tmp != null && s != null && !tmp.equals(s))))
1707:       firePropertyChange(SELECTION_BACKGROUND_CHANGED_PROPERTY, tmp, s);
1708:     repaint();
1709:   }
1710: 
1711:   /**
1712:    * <p>Set the value of the {@link #selectionForeground} property.</p>
1713:    *
1714:    * <p>Fire a PropertyChangeEvent with name {@link
1715:    * #SELECTION_FOREGROUND_CHANGED_PROPERTY} to registered listeners, if
1716:    * selectionForeground changed.</p>
1717:    *
1718:    * @param s The new value of the selectionForeground property
1719:    */ 
1720:   public void setSelectionForeground(Color s)
1721:   {
1722:     Color tmp = selectionForeground;
1723:     selectionForeground = s;
1724:     if (((tmp == null && s != null)
1725:          || (s == null && tmp != null)
1726:          || (tmp != null && s != null && !tmp.equals(s))))
1727:       firePropertyChange(SELECTION_FOREGROUND_CHANGED_PROPERTY, tmp, s);
1728:     repaint();
1729:   }
1730: 
1731:   /**
1732:    * Set the value of the <code>showGrid</code> property.
1733:    *
1734:    * @param s The new value of the showGrid property
1735:    */ 
1736:   public void setShowGrid(boolean s)
1737:   {
1738:     setShowVerticalLines(s);
1739:     setShowHorizontalLines(s);
1740:   }
1741: 
1742:   /**
1743:    * Set the value of the {@link #showHorizontalLines} property.
1744:    *
1745:    * @param s The new value of the showHorizontalLines property
1746:    */ 
1747:   public void setShowHorizontalLines(boolean s)
1748:   {
1749:     showHorizontalLines = s;
1750:     repaint();
1751:   }
1752: 
1753:   /**
1754:    * Set the value of the {@link #showVerticalLines} property.
1755:    *
1756:    * @param s The new value of the showVerticalLines property
1757:    */ 
1758:   public void setShowVerticalLines(boolean s)
1759:   {
1760:     showVerticalLines = s;
1761:     repaint();
1762:   }
1763: 
1764:   /**
1765:    * Set the value of the {@link #tableHeader} property.
1766:    *
1767:    * @param t The new value of the tableHeader property
1768:    */ 
1769:   public void setTableHeader(JTableHeader t)
1770:   {
1771:     if (tableHeader != null)
1772:       tableHeader.setTable(null);
1773:     tableHeader = t;
1774:     if (tableHeader != null)
1775:       tableHeader.setTable(this);
1776:     revalidate();
1777:     repaint();
1778:   }
1779: 
1780:   protected void configureEnclosingScrollPane()
1781:   {
1782:     JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
1783:     if (jsp != null && tableHeader != null)
1784:       {
1785:         jsp.setColumnHeaderView(tableHeader);
1786:       }
1787:   }
1788: 
1789:   protected void unconfigureEnclosingScrollPane()
1790:   {
1791:     JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
1792:     if (jsp != null)
1793:       {
1794:         jsp.setColumnHeaderView(null);
1795:       }    
1796:   }
1797: 
1798: 
1799:   public void addNotify()
1800:   {
1801:     super.addNotify();
1802:     configureEnclosingScrollPane();
1803:   }
1804: 
1805:   public void removeNotify()
1806:   {
1807:     super.addNotify();
1808:     unconfigureEnclosingScrollPane();
1809:   }
1810: 
1811: 
1812:   /**
1813:    * This distributes the superfluous width in a table evenly on its columns.
1814:    *
1815:    * The implementation used here is different to that one described in
1816:    * the JavaDocs. It is much simpler, and seems to work very well.
1817:    *
1818:    * TODO: correctly implement the algorithm described in the JavaDoc
1819:    */
1820:   private void distributeSpill(TableColumn[] cols, int spill)
1821:   {
1822:     int average = spill / cols.length;
1823:     for (int i = 0; i < cols.length; i++)
1824:       {
1825:         cols[i].setWidth(cols[i].getWidth() + average);
1826:       }
1827:   }
1828: 
1829:   public void doLayout()
1830:   {
1831:     TableColumn resizingColumn = null;
1832: 
1833:     int ncols = getColumnCount();
1834:     if (ncols < 1)
1835:       return;
1836: 
1837:     int[] pref = new int[ncols];
1838:     int prefSum = 0;
1839:     int rCol = -1;
1840: 
1841:     if (tableHeader != null)
1842:       resizingColumn = tableHeader.getResizingColumn();
1843: 
1844:     for (int i = 0; i < ncols; ++i)
1845:       {
1846:         TableColumn col = columnModel.getColumn(i);
1847:         int p = col.getWidth();
1848:         pref[i] = p;
1849:         prefSum += p;
1850:         if (resizingColumn == col)
1851:           rCol = i;
1852:       }
1853: 
1854:     int spill = getWidth() - prefSum;
1855: 
1856:     if (resizingColumn != null)
1857:       {
1858:         TableColumn col;
1859:         TableColumn [] cols;
1860: 
1861:         switch (getAutoResizeMode())
1862:           {
1863:           case AUTO_RESIZE_LAST_COLUMN:
1864:             col = columnModel.getColumn(ncols-1);
1865:             col.setWidth(col.getPreferredWidth() + spill);
1866:             break;
1867:             
1868:           case AUTO_RESIZE_NEXT_COLUMN:
1869:             col = columnModel.getColumn(ncols-1);
1870:             col.setWidth(col.getPreferredWidth() + spill);
1871:             break;
1872: 
1873:           case AUTO_RESIZE_ALL_COLUMNS:
1874:             cols = new TableColumn[ncols];
1875:             for (int i = 0; i < ncols; ++i)
1876:               cols[i] = columnModel.getColumn(i);
1877:             distributeSpill(cols, spill);
1878:             break;
1879: 
1880:           case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
1881:             cols = new TableColumn[ncols];
1882:             for (int i = rCol; i < ncols; ++i)
1883:               cols[i] = columnModel.getColumn(i);
1884:             distributeSpill(cols, spill);
1885:             break;
1886: 
1887:           case AUTO_RESIZE_OFF:
1888:           default:
1889:           }
1890:       }
1891:     else
1892:       {
1893:         TableColumn [] cols = new TableColumn[ncols];
1894:         for (int i = 0; i < ncols; ++i)
1895:           cols[i] = columnModel.getColumn(i);
1896:         distributeSpill(cols, spill);        
1897:       }
1898:   }
1899:   
1900:   /**
1901:    * @deprecated Replaced by <code>doLayout()</code>
1902:    */
1903:   public void sizeColumnsToFit(boolean lastColumnOnly)
1904:   {
1905:     doLayout();
1906:   }
1907: 
1908:   /**
1909:    * Obsolete since JDK 1.4. Please use <code>doLayout()</code>.
1910:    */
1911:   public void sizeColumnsToFit(int resizingColumn)
1912:   {
1913:     doLayout();
1914:   }
1915: 
1916:   public String getUIClassID()
1917:   {
1918:     return "TableUI";
1919:   }
1920: 
1921:   /**
1922:    * This method returns the table's UI delegate.
1923:    *
1924:    * @return The table's UI delegate.
1925:    */
1926:   public TableUI getUI()
1927:   {
1928:     return (TableUI) ui;
1929:   }
1930: 
1931:   /**
1932:    * This method sets the table's UI delegate.
1933:    *
1934:    * @param ui The table's UI delegate.
1935:    */
1936:   public void setUI(TableUI ui)
1937:   {
1938:     super.setUI(ui);
1939:   }
1940: 
1941:   public void updateUI()
1942:   {
1943:     setUI((TableUI) UIManager.getUI(this));
1944:     revalidate();
1945:     repaint();
1946:   }
1947: 
1948:   public Class getColumnClass(int column)
1949:   {
1950:     return dataModel.getColumnClass(column);
1951:   }
1952:   
1953:   public String getColumnName(int column)
1954:   {
1955:     int modelColumn = columnModel.getColumn(column).getModelIndex();
1956:     return dataModel.getColumnName(modelColumn);
1957:   }
1958: 
1959:   public int getEditingColumn()
1960:   {
1961:     return editingColumn;
1962:   }
1963: 
1964:   public void setEditingColumn(int column)
1965:   {
1966:     editingColumn = column;
1967:   }
1968:   
1969:   public int getEditingRow()
1970:   {
1971:     return editingRow;
1972:   }
1973: 
1974:   public void setEditingRow(int column)
1975:   {
1976:     editingRow = column;
1977:   }
1978:   
1979:   public Component getEditorComponent()
1980:   {
1981:     return editorComp;
1982:   }
1983:   
1984:   public boolean isEditing()
1985:   {
1986:     return editorComp != null;
1987:   }
1988: 
1989:   public void setDefaultEditor(Class columnClass, TableCellEditor editor)
1990:   {
1991:     if (editor != null)
1992:       defaultEditorsByColumnClass.put(columnClass, editor);
1993:     else
1994:       defaultEditorsByColumnClass.remove(columnClass);
1995:   }
1996: 
1997:   public void addColumnSelectionInterval(int index0, int index1)
1998:   {
1999:     if ((index0 < 0 || index0 > (getColumnCount()-1)
2000:          || index1 < 0 || index1 > (getColumnCount()-1)))
2001:       throw new IllegalArgumentException("Column index out of range.");
2002:     
2003:     getColumnModel().getSelectionModel().addSelectionInterval(index0, index1);
2004:   }
2005:   
2006:   public void addRowSelectionInterval(int index0, int index1)
2007:   {            
2008:     if ((index0 < 0 || index0 > (getRowCount()-1)
2009:          || index1 < 0 || index1 > (getRowCount()-1)))
2010:       throw new IllegalArgumentException("Row index out of range.");
2011:           
2012:     getSelectionModel().addSelectionInterval(index0, index1);
2013:   }
2014:   
2015:   public void setColumnSelectionInterval(int index0, int index1)
2016:   {
2017:     if ((index0 < 0 || index0 > (getColumnCount()-1)
2018:          || index1 < 0 || index1 > (getColumnCount()-1)))
2019:       throw new IllegalArgumentException("Column index out of range.");
2020: 
2021:     getColumnModel().getSelectionModel().setSelectionInterval(index0, index1);
2022:   }
2023:   
2024:   public void setRowSelectionInterval(int index0, int index1)
2025:   {    
2026:     if ((index0 < 0 || index0 > (getRowCount()-1)
2027:          || index1 < 0 || index1 > (getRowCount()-1)))
2028:       throw new IllegalArgumentException("Row index out of range.");
2029: 
2030:     getSelectionModel().setSelectionInterval(index0, index1);
2031:   }
2032:   
2033:   public void removeColumnSelectionInterval(int index0, int index1)  
2034:   {
2035:     if ((index0 < 0 || index0 > (getColumnCount()-1)
2036:          || index1 < 0 || index1 > (getColumnCount()-1)))
2037:       throw new IllegalArgumentException("Column index out of range.");
2038: 
2039:     getColumnModel().getSelectionModel().removeSelectionInterval(index0, index1);
2040:   }
2041:   
2042:   public void removeRowSelectionInterval(int index0, int index1)
2043:   {
2044:     if ((index0 < 0 || index0 > (getRowCount()-1)
2045:          || index1 < 0 || index1 > (getRowCount()-1)))
2046:       throw new IllegalArgumentException("Row index out of range.");
2047: 
2048:     getSelectionModel().removeSelectionInterval(index0, index1);
2049:   }
2050:   
2051:   public boolean isColumnSelected(int column)
2052:   {
2053:     return getColumnModel().getSelectionModel().isSelectedIndex(column);
2054:   }
2055: 
2056:   public boolean isRowSelected(int row)
2057:   {
2058:     return getSelectionModel().isSelectedIndex(row);
2059:   }
2060: 
2061:   public boolean isCellSelected(int row, int column)
2062:   {
2063:     return isRowSelected(row) && isColumnSelected(column);
2064:   }
2065:   
2066:   public void selectAll()
2067:   {
2068:     setColumnSelectionInterval(0, getColumnCount() - 1);
2069:     setRowSelectionInterval(0, getRowCount() - 1);
2070:   }
2071: 
2072:   public Object getValueAt(int row, int column)
2073:   {
2074:     return dataModel.getValueAt(row, convertColumnIndexToModel(column));
2075:   }
2076: 
2077:   public void setValueAt(Object value, int row, int column)
2078:   {
2079:     dataModel.setValueAt(value, row, convertColumnIndexToModel(column));
2080:   }
2081: 
2082:   public TableColumn getColumn(Object identifier)
2083:   {
2084:     return columnModel.getColumn(columnModel.getColumnIndex(identifier));
2085:   }
2086: 
2087:   /**
2088:    * Returns <code>true</code> if the specified cell is editable, and
2089:    * <code>false</code> otherwise.
2090:    *
2091:    * @param row  the row index.
2092:    * @param column  the column index.
2093:    *
2094:    * @return A boolean.
2095:    */
2096:   public boolean isCellEditable(int row, int column)
2097:   {
2098:     return dataModel.isCellEditable(row, convertColumnIndexToModel(column));
2099:   }
2100: 
2101:   /**
2102:    * Clears any existing columns from the <code>JTable</code>'s
2103:    * {@link TableColumnModel} and creates new columns to match the values in
2104:    * the data ({@link TableModel}) used by the table.
2105:    *
2106:    * @see #setAutoCreateColumnsFromModel(boolean)
2107:    */
2108:   public void createDefaultColumnsFromModel()
2109:   {
2110:     // remove existing columns
2111:     int columnIndex = columnModel.getColumnCount() - 1;
2112:     while (columnIndex >= 0)
2113:     {
2114:       columnModel.removeColumn(columnModel.getColumn(columnIndex));
2115:       columnIndex--;
2116:     }
2117:   
2118:     // add new columns to match the TableModel
2119:     int columnCount = dataModel.getColumnCount();
2120:     for (int c = 0; c < columnCount; c++)
2121:     {
2122:       TableColumn column = new TableColumn(c);
2123:       column.setIdentifier(dataModel.getColumnName(c));
2124:       columnModel.addColumn(column);
2125:     }
2126:   }
2127: 
2128:   public void changeSelection (int rowIndex, int columnIndex, boolean toggle, boolean extend)
2129:   {
2130:     if (toggle && extend)
2131:       {
2132:         // Leave the selection state as is, but move the anchor
2133:         //   index to the specified location
2134:         selectionModel.setAnchorSelectionIndex(rowIndex);
2135:         getColumnModel().getSelectionModel().setAnchorSelectionIndex(columnIndex);
2136:       }
2137:     else if (toggle)
2138:       {
2139:         // Toggle the state of the specified cell
2140:         if (isCellSelected(rowIndex,columnIndex))
2141:           {
2142:             selectionModel.removeSelectionInterval(rowIndex,rowIndex);
2143:             getColumnModel().getSelectionModel().removeSelectionInterval(columnIndex,columnIndex);
2144:           }
2145:         else
2146:           {
2147:             selectionModel.addSelectionInterval(rowIndex,rowIndex);
2148:             getColumnModel().getSelectionModel().addSelectionInterval(columnIndex,columnIndex);
2149:           }
2150:       }
2151:     else if (extend)
2152:       {
2153:         // Extend the previous selection from the anchor to the 
2154:         // specified cell, clearing all other selections
2155:         selectionModel.setLeadSelectionIndex(rowIndex);
2156:         getColumnModel().getSelectionModel().setLeadSelectionIndex(columnIndex);
2157:       }
2158:     else
2159:       {
2160:         // Clear the previous selection and ensure the new cell
2161:         // is selected
2162:          selectionModel.clearSelection();
2163:         selectionModel.setSelectionInterval(rowIndex,rowIndex);
2164:         getColumnModel().getSelectionModel().clearSelection();
2165:         getColumnModel().getSelectionModel().setSelectionInterval(columnIndex, columnIndex);
2166:         
2167:         
2168:       }
2169:   }
2170: }