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