GNU Classpath (0.91) | |
Frames | No Frames |
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: }
GNU Classpath (0.91) |