28 import sun.swing.table.DefaultTableCellHeaderRenderer; 29 30 import java.util.*; 31 import java.awt.*; 32 import java.awt.event.*; 33 34 import javax.swing.*; 35 import javax.swing.event.*; 36 import javax.swing.plaf.*; 37 import javax.accessibility.*; 38 39 import java.beans.PropertyChangeListener; 40 import java.beans.Transient; 41 42 import java.io.ObjectOutputStream; 43 import java.io.ObjectInputStream; 44 import java.io.IOException; 45 46 47 /** 48 * This is the object which manages the header of the <code>JTable</code>. 49 * <p> 50 * <strong>Warning:</strong> 51 * Serialized objects of this class will not be compatible with 52 * future Swing releases. The current serialization support is 53 * appropriate for short term storage or RMI between applications running 54 * the same version of Swing. As of 1.4, support for long term storage 55 * of all JavaBeans™ 56 * has been added to the <code>java.beans</code> package. 57 * Please see {@link java.beans.XMLEncoder}. 58 * 59 * @author Alan Chung 60 * @author Philip Milne 61 * @see javax.swing.JTable 62 */ 63 @SuppressWarnings("serial") // Same-version serialization only 64 public class JTableHeader extends JComponent implements TableColumnModelListener, Accessible 65 { 66 /** 67 * @see #getUIClassID 68 * @see #readObject 69 */ 70 private static final String uiClassID = "TableHeaderUI"; 71 72 // 73 // Instance Variables 74 // 75 /** 76 * The table for which this object is the header; 77 * the default is <code>null</code>. 78 */ 79 protected JTable table; 80 81 /** 82 * The <code>TableColumnModel</code> of the table header. 83 */ 84 protected TableColumnModel columnModel; 85 86 /** 87 * If true, reordering of columns are allowed by the user; 88 * the default is true. 89 */ 90 protected boolean reorderingAllowed; 91 92 /** 93 * If true, resizing of columns are allowed by the user; 94 * the default is true. 95 */ 96 protected boolean resizingAllowed; 97 98 /** 99 * Obsolete as of Java 2 platform v1.3. Real time repaints, in response 100 * to column dragging or resizing, are now unconditional. 101 */ 102 /* 103 * If this flag is true, then the header will repaint the table as 104 * a column is dragged or resized; the default is true. 105 */ 106 protected boolean updateTableInRealTime; 107 108 /** The index of the column being resized. <code>null</code> if not resizing. */ 109 protected transient TableColumn resizingColumn; 110 111 /** The index of the column being dragged. <code>null</code> if not dragging. */ 112 protected transient TableColumn draggedColumn; 113 114 /** The distance from its original position the column has been dragged. */ 115 protected transient int draggedDistance; 116 117 /** 118 * The default renderer to be used when a <code>TableColumn</code> 119 * does not define a <code>headerRenderer</code>. 120 */ 121 private TableCellRenderer defaultRenderer; 122 123 // 124 // Constructors 125 // 126 127 /** 128 * Constructs a <code>JTableHeader</code> with a default 129 * <code>TableColumnModel</code>. 130 * 131 * @see #createDefaultColumnModel 132 */ 133 public JTableHeader() { 134 this(null); 135 } 136 137 /** 138 * Constructs a <code>JTableHeader</code> which is initialized with 139 * <code>cm</code> as the column model. If <code>cm</code> is 140 * <code>null</code> this method will initialize the table header 141 * with a default <code>TableColumnModel</code>. 142 * 143 * @param cm the column model for the table 144 * @see #createDefaultColumnModel 145 */ 146 public JTableHeader(TableColumnModel cm) { 147 super(); 148 149 //setFocusable(false); // for strict win/mac compatibility mode, 150 // this method should be invoked 151 152 if (cm == null) 153 cm = createDefaultColumnModel(); 154 setColumnModel(cm); 155 156 // Initialize local ivars 157 initializeLocalVars(); 158 159 // Get UI going 160 updateUI(); 161 } 162 163 // 164 // Local behavior attributes 165 // 166 167 /** 168 * Sets the table associated with this header. 169 * @param table the new table 170 * @beaninfo 171 * bound: true 172 * description: The table associated with this header. 173 */ 174 public void setTable(JTable table) { 175 JTable old = this.table; 176 this.table = table; 177 firePropertyChange("table", old, table); 178 } 179 180 /** 181 * Returns the table associated with this header. 182 * @return the <code>table</code> property 183 */ 184 public JTable getTable() { 185 return table; 186 } 187 188 /** 189 * Sets whether the user can drag column headers to reorder columns. 190 * 191 * @param reorderingAllowed true if the table view should allow 192 * reordering; otherwise false 193 * @see #getReorderingAllowed 194 * @beaninfo 195 * bound: true 196 * description: Whether the user can drag column headers to reorder columns. 197 */ 198 public void setReorderingAllowed(boolean reorderingAllowed) { 199 boolean old = this.reorderingAllowed; 200 this.reorderingAllowed = reorderingAllowed; 201 firePropertyChange("reorderingAllowed", old, reorderingAllowed); 202 } 203 204 /** 205 * Returns true if the user is allowed to rearrange columns by 206 * dragging their headers, false otherwise. The default is true. You can 207 * rearrange columns programmatically regardless of this setting. 208 * 209 * @return the <code>reorderingAllowed</code> property 210 * @see #setReorderingAllowed 211 */ 212 public boolean getReorderingAllowed() { 213 return reorderingAllowed; 214 } 215 216 /** 217 * Sets whether the user can resize columns by dragging between headers. 218 * 219 * @param resizingAllowed true if table view should allow 220 * resizing 221 * @see #getResizingAllowed 222 * @beaninfo 223 * bound: true 224 * description: Whether the user can resize columns by dragging between headers. 225 */ 226 public void setResizingAllowed(boolean resizingAllowed) { 227 boolean old = this.resizingAllowed; 228 this.resizingAllowed = resizingAllowed; 229 firePropertyChange("resizingAllowed", old, resizingAllowed); 230 } 231 232 /** 233 * Returns true if the user is allowed to resize columns by dragging 234 * between their headers, false otherwise. The default is true. You can 235 * resize columns programmatically regardless of this setting. 236 * 237 * @return the <code>resizingAllowed</code> property 238 * @see #setResizingAllowed 239 */ 240 public boolean getResizingAllowed() { 241 return resizingAllowed; 242 } 243 244 /** 245 * Returns the dragged column, if and only if, a drag is in 246 * process, otherwise returns <code>null</code>. 247 * 248 * @return the dragged column, if a drag is in 249 * process, otherwise returns <code>null</code> 250 * @see #getDraggedDistance 251 */ 252 public TableColumn getDraggedColumn() { 253 return draggedColumn; 254 } 255 256 /** 257 * Returns the column's horizontal distance from its original 258 * position, if and only if, a drag is in process. Otherwise, the 259 * the return value is meaningless. 260 * 261 * @return the column's horizontal distance from its original 262 * position, if a drag is in process, otherwise the return 263 * value is meaningless 264 * @see #getDraggedColumn 265 */ 266 public int getDraggedDistance() { 267 return draggedDistance; 268 } 269 270 /** 271 * Returns the resizing column. If no column is being 272 * resized this method returns <code>null</code>. 273 * 274 * @return the resizing column, if a resize is in process, otherwise 275 * returns <code>null</code> 276 */ 277 public TableColumn getResizingColumn() { 278 return resizingColumn; 279 } 280 281 /** 282 * Obsolete as of Java 2 platform v1.3. Real time repaints, in response to 283 * column dragging or resizing, are now unconditional. 284 * @param flag true if tableView should update the body of the 285 * table in real time 286 */ 287 public void setUpdateTableInRealTime(boolean flag) { 288 updateTableInRealTime = flag; 289 } 290 291 /** 292 * Obsolete as of Java 2 platform v1.3. Real time repaints, in response to 293 * column dragging or resizing, are now unconditional. 294 * @return true if the table updates in real time 295 */ 296 public boolean getUpdateTableInRealTime() { 297 return updateTableInRealTime; 298 } 299 300 /** 301 * Sets the default renderer to be used when no <code>headerRenderer</code> 302 * is defined by a <code>TableColumn</code>. 303 * @param defaultRenderer the default renderer 304 * @since 1.3 305 */ 306 public void setDefaultRenderer(TableCellRenderer defaultRenderer) { 307 this.defaultRenderer = defaultRenderer; 308 } 309 310 /** 311 * Returns the default renderer used when no <code>headerRenderer</code> 312 * is defined by a <code>TableColumn</code>. 313 * @return the default renderer 314 * @since 1.3 315 */ 316 @Transient 317 public TableCellRenderer getDefaultRenderer() { 318 return defaultRenderer; 319 } 320 321 /** 322 * Returns the index of the column that <code>point</code> lies in, or -1 if it 323 * lies out of bounds. 324 * 325 * @param point if this <code>point</code> lies within a column, the index of 326 * that column will be returned; otherwise it is out of bounds 327 * and -1 is returned 328 * 329 * @return the index of the column that <code>point</code> lies in, or -1 if it 330 * lies out of bounds 331 */ 332 public int columnAtPoint(Point point) { 333 int x = point.x; 334 if (!getComponentOrientation().isLeftToRight()) { 335 x = getWidthInRightToLeft() - x - 1; 336 } 337 return getColumnModel().getColumnIndexAtX(x); 338 } 339 340 /** 341 * Returns the rectangle containing the header tile at <code>column</code>. 342 * When the <code>column</code> parameter is out of bounds this method uses the 343 * same conventions as the <code>JTable</code> method <code>getCellRect</code>. 344 * 345 * @param column index of the column 346 * 347 * @return the rectangle containing the header tile at <code>column</code> 348 * @see JTable#getCellRect 349 */ 350 public Rectangle getHeaderRect(int column) { 351 Rectangle r = new Rectangle(); 352 TableColumnModel cm = getColumnModel(); 353 354 r.height = getHeight(); 355 356 if (column < 0) { 357 // x = width = 0; 358 if( !getComponentOrientation().isLeftToRight() ) { 359 r.x = getWidthInRightToLeft(); 360 } 361 } 362 else if (column >= cm.getColumnCount()) { 363 if( getComponentOrientation().isLeftToRight() ) { 364 r.x = getWidth(); 365 } 366 } 367 else { 412 event.getWhen(), event.getModifiers(), 413 p.x, p.y, event.getXOnScreen(), event.getYOnScreen(), 414 event.getClickCount(), 415 event.isPopupTrigger(), MouseEvent.NOBUTTON); 416 417 tip = ((JComponent)component).getToolTipText(newEvent); 418 } 419 } 420 421 // No tip from the renderer get our own tip 422 if (tip == null) 423 tip = getToolTipText(); 424 425 return tip; 426 } 427 428 /** 429 * Returns the preferred size of the table header. 430 * This is the size required to display the header and requested for 431 * the viewport. 432 * The returned {@code Dimension} {@code width} will always be calculated by 433 * the underlying TableHeaderUI, regardless of any width specified by 434 * {@link JComponent#setPreferredSize(java.awt.Dimension)} 435 * 436 * @return the size 437 */ 438 @Override 439 public Dimension getPreferredSize() { 440 Dimension preferredSize = super.getPreferredSize(); 441 if (isPreferredSizeSet() && ui != null) { 442 Dimension size = ui.getPreferredSize(this); 443 if (size != null) preferredSize.width = size.width; 444 } 445 return preferredSize; 446 } 447 448 // 449 // Managing TableHeaderUI 450 // 451 452 /** 453 * Returns the look and feel (L&F) object that renders this component. 454 * 455 * @return the <code>TableHeaderUI</code> object that renders this component 456 */ 457 public TableHeaderUI getUI() { 458 return (TableHeaderUI)ui; 459 } 460 461 /** 462 * Sets the look and feel (L&F) object that renders this component. 463 * 464 * @param ui the <code>TableHeaderUI</code> L&F object 465 * @see UIDefaults#getUI 466 */ 467 public void setUI(TableHeaderUI ui){ 468 if (this.ui != ui) { 469 super.setUI(ui); 470 repaint(); 471 } 472 } 473 474 /** 475 * Notification from the <code>UIManager</code> that the look and feel 476 * (L&F) has changed. 477 * Replaces the current UI object with the latest version from the 478 * <code>UIManager</code>. 479 * 480 * @see JComponent#updateUI 481 */ 482 public void updateUI(){ 483 setUI((TableHeaderUI)UIManager.getUI(this)); 484 485 TableCellRenderer renderer = getDefaultRenderer(); 486 if (renderer instanceof Component) { 487 SwingUtilities.updateComponentTreeUI((Component)renderer); 488 } 489 } 490 491 492 /** 493 * Returns the suffix used to construct the name of the look and feel 494 * (L&F) class used to render this component. 495 * @return the string "TableHeaderUI" 496 * 497 * @return "TableHeaderUI" 498 * @see JComponent#getUIClassID 499 * @see UIDefaults#getUI 500 */ 501 public String getUIClassID() { 502 return uiClassID; 503 } 504 505 506 // 507 // Managing models 508 // 509 510 511 /** 512 * Sets the column model for this table to <code>newModel</code> and registers 513 * for listener notifications from the new column model. 514 * 515 * @param columnModel the new data source for this table 516 * @exception IllegalArgumentException 517 * if <code>newModel</code> is <code>null</code> 518 * @see #getColumnModel 519 * @beaninfo 520 * bound: true 521 * description: The object governing the way columns appear in the view. 522 */ 523 public void setColumnModel(TableColumnModel columnModel) { 524 if (columnModel == null) { 525 throw new IllegalArgumentException("Cannot set a null ColumnModel"); 526 } 527 TableColumnModel old = this.columnModel; 528 if (columnModel != old) { 529 if (old != null) { 530 old.removeColumnModelListener(this); 531 } 532 this.columnModel = columnModel; 533 columnModel.addColumnModelListener(this); 534 535 firePropertyChange("columnModel", old, columnModel); 536 resizeAndRepaint(); 537 } 538 } 539 540 /** 541 * Returns the <code>TableColumnModel</code> that contains all column information 542 * of this table header. 543 * 544 * @return the <code>columnModel</code> property 545 * @see #setColumnModel 546 */ 547 public TableColumnModel getColumnModel() { 548 return columnModel; 549 } 550 551 // 552 // Implementing TableColumnModelListener interface 553 // 554 555 /** 556 * Invoked when a column is added to the table column model. 557 * <p> 558 * Application code will not use these methods explicitly, they 559 * are used internally by <code>JTable</code>. 560 * 561 * @param e the event received 562 * @see TableColumnModelListener 563 */ 564 public void columnAdded(TableColumnModelEvent e) { resizeAndRepaint(); } 565 566 567 /** 568 * Invoked when a column is removed from the table column model. 569 * <p> 570 * Application code will not use these methods explicitly, they 571 * are used internally by <code>JTable</code>. 572 * 573 * @param e the event received 574 * @see TableColumnModelListener 575 */ 576 public void columnRemoved(TableColumnModelEvent e) { resizeAndRepaint(); } 577 578 579 /** 580 * Invoked when a column is repositioned. 581 * <p> 582 * Application code will not use these methods explicitly, they 583 * are used internally by <code>JTable</code>. 584 * 585 * @param e the event received 586 * @see TableColumnModelListener 587 */ 588 public void columnMoved(TableColumnModelEvent e) { repaint(); } 589 590 591 /** 592 * Invoked when a column is moved due to a margin change. 593 * <p> 594 * Application code will not use these methods explicitly, they 595 * are used internally by <code>JTable</code>. 596 * 597 * @param e the event received 598 * @see TableColumnModelListener 599 */ 600 public void columnMarginChanged(ChangeEvent e) { resizeAndRepaint(); } 601 602 603 // --Redrawing the header is slow in cell selection mode. 604 // --Since header selection is ugly and it is always clear from the 605 // --view which columns are selected, don't redraw the header. 606 /** 607 * Invoked when the selection model of the <code>TableColumnModel</code> 608 * is changed. This method currently has no effect (the header is not 609 * redrawn). 610 * <p> 611 * Application code will not use these methods explicitly, they 612 * are used internally by <code>JTable</code>. 613 * 614 * @param e the event received 615 * @see TableColumnModelListener 616 */ 617 public void columnSelectionChanged(ListSelectionEvent e) { } // repaint(); } 618 619 // 620 // Package Methods 621 // 622 623 /** 624 * Returns the default column model object which is 625 * a <code>DefaultTableColumnModel</code>. A subclass can override this 626 * method to return a different column model object 627 * 628 * @return the default column model object 629 */ 630 protected TableColumnModel createDefaultColumnModel() { 631 return new DefaultTableColumnModel(); 632 } 633 634 /** 635 * Returns a default renderer to be used when no header renderer 636 * is defined by a <code>TableColumn</code>. 637 * 638 * @return the default table column renderer 639 * @since 1.3 640 */ 641 protected TableCellRenderer createDefaultRenderer() { 642 return new DefaultTableCellHeaderRenderer(); 643 } 644 645 646 /** 647 * Initializes the local variables and properties with default values. 648 * Used by the constructor methods. 649 */ 650 protected void initializeLocalVars() { 651 setOpaque(true); 652 table = null; 653 reorderingAllowed = true; 654 resizingAllowed = true; 655 draggedColumn = null; 656 draggedDistance = 0; 657 resizingColumn = null; 658 updateTableInRealTime = true; 659 660 // I'm registered to do tool tips so we can draw tips for the 661 // renderers 662 ToolTipManager toolTipManager = ToolTipManager.sharedInstance(); 663 toolTipManager.registerComponent(this); 664 setDefaultRenderer(createDefaultRenderer()); 665 } 666 667 /** 668 * Sizes the header and marks it as needing display. Equivalent 669 * to <code>revalidate</code> followed by <code>repaint</code>. 670 */ 671 public void resizeAndRepaint() { 672 revalidate(); 673 repaint(); 674 } 675 676 /** 677 * Sets the header's <code>draggedColumn</code> to <code>aColumn</code>. 678 * <p> 679 * Application code will not use this method explicitly, it is used 680 * internally by the column dragging mechanism. 681 * 682 * @param aColumn the column being dragged, or <code>null</code> if 683 * no column is being dragged 684 */ 685 public void setDraggedColumn(TableColumn aColumn) { 686 draggedColumn = aColumn; 687 } 688 689 /** 690 * Sets the header's <code>draggedDistance</code> to <code>distance</code>. 691 * @param distance the distance dragged 692 */ 693 public void setDraggedDistance(int distance) { 694 draggedDistance = distance; 695 } 696 697 /** 698 * Sets the header's <code>resizingColumn</code> to <code>aColumn</code>. 699 * <p> 700 * Application code will not use this method explicitly, it 701 * is used internally by the column sizing mechanism. 702 * 703 * @param aColumn the column being resized, or <code>null</code> if 704 * no column is being resized 705 */ 706 public void setResizingColumn(TableColumn aColumn) { 707 resizingColumn = aColumn; 708 } 709 710 /** 711 * See <code>readObject</code> and <code>writeObject</code> in 712 * <code>JComponent</code> for more 713 * information about serialization in Swing. 714 */ 715 private void writeObject(ObjectOutputStream s) throws IOException { 716 s.defaultWriteObject(); 717 if ((ui != null) && (getUIClassID().equals(uiClassID))) { 718 ui.installUI(this); 719 } 720 } 721 722 private int getWidthInRightToLeft() { 723 if ((table != null) && 724 (table.getAutoResizeMode() != JTable.AUTO_RESIZE_OFF)) { 725 return table.getWidth(); 726 } 727 return super.getWidth(); 728 } 729 730 /** 731 * Returns a string representation of this <code>JTableHeader</code>. This method 732 * is intended to be used only for debugging purposes, and the 733 * content and format of the returned string may vary between 734 * implementations. The returned string may be empty but may not 735 * be <code>null</code>. 736 * <P> 737 * Overriding <code>paramString</code> to provide information about the 738 * specific new aspects of the JFC components. 739 * 740 * @return a string representation of this <code>JTableHeader</code> 741 */ 742 protected String paramString() { 743 String reorderingAllowedString = (reorderingAllowed ? 744 "true" : "false"); 745 String resizingAllowedString = (resizingAllowed ? 746 "true" : "false"); 747 String updateTableInRealTimeString = (updateTableInRealTime ? 748 "true" : "false"); 749 750 return super.paramString() + 751 ",draggedDistance=" + draggedDistance + 752 ",reorderingAllowed=" + reorderingAllowedString + 753 ",resizingAllowed=" + resizingAllowedString + 754 ",updateTableInRealTime=" + updateTableInRealTimeString; 755 } 756 757 ///////////////// 758 // Accessibility support 759 //////////////// 760 763 * For JTableHeaders, the AccessibleContext takes the form of an 764 * AccessibleJTableHeader. 765 * A new AccessibleJTableHeader instance is created if necessary. 766 * 767 * @return an AccessibleJTableHeader that serves as the 768 * AccessibleContext of this JTableHeader 769 */ 770 public AccessibleContext getAccessibleContext() { 771 if (accessibleContext == null) { 772 accessibleContext = new AccessibleJTableHeader(); 773 } 774 return accessibleContext; 775 } 776 777 // 778 // *** should also implement AccessibleSelection? 779 // *** and what's up with keyboard navigation/manipulation? 780 // 781 /** 782 * This class implements accessibility support for the 783 * <code>JTableHeader</code> class. It provides an implementation of the 784 * Java Accessibility API appropriate to table header user-interface 785 * elements. 786 * <p> 787 * <strong>Warning:</strong> 788 * Serialized objects of this class will not be compatible with 789 * future Swing releases. The current serialization support is 790 * appropriate for short term storage or RMI between applications running 791 * the same version of Swing. As of 1.4, support for long term storage 792 * of all JavaBeans™ 793 * has been added to the <code>java.beans</code> package. 794 * Please see {@link java.beans.XMLEncoder}. 795 */ 796 @SuppressWarnings("serial") // Same-version serialization only 797 protected class AccessibleJTableHeader extends AccessibleJComponent { 798 799 /** 800 * Get the role of this object. 801 * 802 * @return an instance of AccessibleRole describing the role of the 803 * object 804 * @see AccessibleRole 805 */ 806 public AccessibleRole getAccessibleRole() { 807 return AccessibleRole.PANEL; 808 } 809 810 /** 811 * Returns the Accessible child, if one exists, contained at the local 812 * coordinate Point. 813 * 880 return new AccessibleJTableHeaderEntry(i, JTableHeader.this, JTableHeader.this.table); 881 } 882 } 883 884 /** 885 * This class provides an implementation of the Java Accessibility 886 * API appropriate for JTableHeader entries. 887 */ 888 protected class AccessibleJTableHeaderEntry extends AccessibleContext 889 implements Accessible, AccessibleComponent { 890 891 private JTableHeader parent; 892 private int column; 893 private JTable table; 894 895 /** 896 * Constructs an AccessiblJTableHeaaderEntry 897 * @since 1.4 898 * 899 * @param c the column index 900 * @param p the parent <code>JTableHeader</code> 901 * @param t the table <code>JTable</code> 902 */ 903 public AccessibleJTableHeaderEntry(int c, JTableHeader p, JTable t) { 904 parent = p; 905 column = c; 906 table = t; 907 this.setAccessibleParent(parent); 908 } 909 910 /** 911 * Get the AccessibleContext associated with this object. 912 * In the implementation of the Java Accessibility API 913 * for this class, returns this object, which serves as 914 * its own AccessibleContext. 915 * 916 * @return this object 917 */ 918 public AccessibleContext getAccessibleContext() { 919 return this; 920 } 921 | 28 import sun.swing.table.DefaultTableCellHeaderRenderer; 29 30 import java.util.*; 31 import java.awt.*; 32 import java.awt.event.*; 33 34 import javax.swing.*; 35 import javax.swing.event.*; 36 import javax.swing.plaf.*; 37 import javax.accessibility.*; 38 39 import java.beans.PropertyChangeListener; 40 import java.beans.Transient; 41 42 import java.io.ObjectOutputStream; 43 import java.io.ObjectInputStream; 44 import java.io.IOException; 45 46 47 /** 48 * This is the object which manages the header of the {@code JTable}. 49 * <p> 50 * <strong>Warning:</strong> 51 * Serialized objects of this class will not be compatible with 52 * future Swing releases. The current serialization support is 53 * appropriate for short term storage or RMI between applications running 54 * the same version of Swing. As of 1.4, support for long term storage 55 * of all JavaBeans™ 56 * has been added to the {@code java.beans} package. 57 * Please see {@link java.beans.XMLEncoder}. 58 * 59 * @author Alan Chung 60 * @author Philip Milne 61 * @see javax.swing.JTable 62 */ 63 @SuppressWarnings("serial") // Same-version serialization only 64 public class JTableHeader extends JComponent implements TableColumnModelListener, Accessible 65 { 66 /** 67 * @see #getUIClassID 68 * @see #readObject 69 */ 70 private static final String uiClassID = "TableHeaderUI"; 71 72 // 73 // Instance Variables 74 // 75 /** 76 * The table for which this object is the header; 77 * the default is {@code null}. 78 */ 79 protected JTable table; 80 81 /** 82 * The {@code TableColumnModel} of the table header. 83 */ 84 protected TableColumnModel columnModel; 85 86 /** 87 * If true, reordering of columns are allowed by the user; 88 * the default is true. 89 */ 90 protected boolean reorderingAllowed; 91 92 /** 93 * If true, resizing of columns are allowed by the user; 94 * the default is true. 95 */ 96 protected boolean resizingAllowed; 97 98 /** 99 * Obsolete as of Java 2 platform v1.3. Real time repaints, in response 100 * to column dragging or resizing, are now unconditional. 101 */ 102 /* 103 * If this flag is true, then the header will repaint the table as 104 * a column is dragged or resized; the default is true. 105 */ 106 protected boolean updateTableInRealTime; 107 108 /** The index of the column being resized. {@code null} if not resizing. */ 109 protected transient TableColumn resizingColumn; 110 111 /** The index of the column being dragged. {@code null} if not dragging. */ 112 protected transient TableColumn draggedColumn; 113 114 /** The distance from its original position the column has been dragged. */ 115 protected transient int draggedDistance; 116 117 /** 118 * The default renderer to be used when a {@code TableColumn} 119 * does not define a {@code headerRenderer}. 120 */ 121 private TableCellRenderer defaultRenderer; 122 123 // 124 // Constructors 125 // 126 127 /** 128 * Constructs a {@code JTableHeader} with a default 129 * {@code TableColumnModel}. 130 * 131 * @see #createDefaultColumnModel 132 */ 133 public JTableHeader() { 134 this(null); 135 } 136 137 /** 138 * Constructs a {@code JTableHeader} which is initialized with 139 * {@code cm} as the column model. If {@code cm} is 140 * {@code null} this method will initialize the table header 141 * with a default {@code TableColumnModel}. 142 * 143 * @param cm the column model for the table 144 * @see #createDefaultColumnModel 145 */ 146 public JTableHeader(TableColumnModel cm) { 147 super(); 148 149 //setFocusable(false); // for strict win/mac compatibility mode, 150 // this method should be invoked 151 152 if (cm == null) 153 cm = createDefaultColumnModel(); 154 setColumnModel(cm); 155 156 // Initialize local ivars 157 initializeLocalVars(); 158 159 // Get UI going 160 updateUI(); 161 } 162 163 // 164 // Local behavior attributes 165 // 166 167 /** 168 * Sets the table associated with this header. 169 * @param table the new table 170 * @beaninfo 171 * bound: true 172 * description: The table associated with this header. 173 */ 174 public void setTable(JTable table) { 175 JTable old = this.table; 176 this.table = table; 177 firePropertyChange("table", old, table); 178 } 179 180 /** 181 * Returns the table associated with this header. 182 * @return the {@code table} property 183 */ 184 public JTable getTable() { 185 return table; 186 } 187 188 /** 189 * Sets whether the user can drag column headers to reorder columns. 190 * 191 * @param reorderingAllowed true if the table view should allow 192 * reordering; otherwise false 193 * @see #getReorderingAllowed 194 * @beaninfo 195 * bound: true 196 * description: Whether the user can drag column headers to reorder columns. 197 */ 198 public void setReorderingAllowed(boolean reorderingAllowed) { 199 boolean old = this.reorderingAllowed; 200 this.reorderingAllowed = reorderingAllowed; 201 firePropertyChange("reorderingAllowed", old, reorderingAllowed); 202 } 203 204 /** 205 * Returns true if the user is allowed to rearrange columns by 206 * dragging their headers, false otherwise. The default is true. You can 207 * rearrange columns programmatically regardless of this setting. 208 * 209 * @return the {@code reorderingAllowed} property 210 * @see #setReorderingAllowed 211 */ 212 public boolean getReorderingAllowed() { 213 return reorderingAllowed; 214 } 215 216 /** 217 * Sets whether the user can resize columns by dragging between headers. 218 * 219 * @param resizingAllowed true if table view should allow 220 * resizing 221 * @see #getResizingAllowed 222 * @beaninfo 223 * bound: true 224 * description: Whether the user can resize columns by dragging between headers. 225 */ 226 public void setResizingAllowed(boolean resizingAllowed) { 227 boolean old = this.resizingAllowed; 228 this.resizingAllowed = resizingAllowed; 229 firePropertyChange("resizingAllowed", old, resizingAllowed); 230 } 231 232 /** 233 * Returns true if the user is allowed to resize columns by dragging 234 * between their headers, false otherwise. The default is true. You can 235 * resize columns programmatically regardless of this setting. 236 * 237 * @return the {@code resizingAllowed} property 238 * @see #setResizingAllowed 239 */ 240 public boolean getResizingAllowed() { 241 return resizingAllowed; 242 } 243 244 /** 245 * Returns the dragged column, if and only if, a drag is in 246 * process, otherwise returns {@code null}. 247 * 248 * @return the dragged column, if a drag is in 249 * process, otherwise returns {@code null} 250 * @see #getDraggedDistance 251 */ 252 public TableColumn getDraggedColumn() { 253 return draggedColumn; 254 } 255 256 /** 257 * Returns the column's horizontal distance from its original 258 * position, if and only if, a drag is in process. Otherwise, the 259 * the return value is meaningless. 260 * 261 * @return the column's horizontal distance from its original 262 * position, if a drag is in process, otherwise the return 263 * value is meaningless 264 * @see #getDraggedColumn 265 */ 266 public int getDraggedDistance() { 267 return draggedDistance; 268 } 269 270 /** 271 * Returns the resizing column. If no column is being 272 * resized this method returns {@code null}. 273 * 274 * @return the resizing column, if a resize is in process, otherwise 275 * returns {@code null} 276 */ 277 public TableColumn getResizingColumn() { 278 return resizingColumn; 279 } 280 281 /** 282 * Obsolete as of Java 2 platform v1.3. Real time repaints, in response to 283 * column dragging or resizing, are now unconditional. 284 * @param flag true if tableView should update the body of the 285 * table in real time 286 */ 287 public void setUpdateTableInRealTime(boolean flag) { 288 updateTableInRealTime = flag; 289 } 290 291 /** 292 * Obsolete as of Java 2 platform v1.3. Real time repaints, in response to 293 * column dragging or resizing, are now unconditional. 294 * @return true if the table updates in real time 295 */ 296 public boolean getUpdateTableInRealTime() { 297 return updateTableInRealTime; 298 } 299 300 /** 301 * Sets the default renderer to be used when no {@code headerRenderer} 302 * is defined by a {@code TableColumn}. 303 * @param defaultRenderer the default renderer 304 * @since 1.3 305 */ 306 public void setDefaultRenderer(TableCellRenderer defaultRenderer) { 307 this.defaultRenderer = defaultRenderer; 308 } 309 310 /** 311 * Returns the default renderer used when no {@code headerRenderer} 312 * is defined by a {@code TableColumn}. 313 * @return the default renderer 314 * @since 1.3 315 */ 316 @Transient 317 public TableCellRenderer getDefaultRenderer() { 318 return defaultRenderer; 319 } 320 321 /** 322 * Returns the index of the column that {@code point} lies in, or -1 if it 323 * lies out of bounds. 324 * 325 * @param point if this {@code point} lies within a column, the index of 326 * that column will be returned; otherwise it is out of bounds 327 * and -1 is returned 328 * 329 * @return the index of the column that {@code point} lies in, or -1 if it 330 * lies out of bounds 331 */ 332 public int columnAtPoint(Point point) { 333 int x = point.x; 334 if (!getComponentOrientation().isLeftToRight()) { 335 x = getWidthInRightToLeft() - x - 1; 336 } 337 return getColumnModel().getColumnIndexAtX(x); 338 } 339 340 /** 341 * Returns the rectangle containing the header tile at {@code column}. 342 * When the {@code column} parameter is out of bounds this method uses the 343 * same conventions as the {@code JTable} method {@code getCellRect}. 344 * 345 * @param column index of the column 346 * 347 * @return the rectangle containing the header tile at {@code column} 348 * @see JTable#getCellRect 349 */ 350 public Rectangle getHeaderRect(int column) { 351 Rectangle r = new Rectangle(); 352 TableColumnModel cm = getColumnModel(); 353 354 r.height = getHeight(); 355 356 if (column < 0) { 357 // x = width = 0; 358 if( !getComponentOrientation().isLeftToRight() ) { 359 r.x = getWidthInRightToLeft(); 360 } 361 } 362 else if (column >= cm.getColumnCount()) { 363 if( getComponentOrientation().isLeftToRight() ) { 364 r.x = getWidth(); 365 } 366 } 367 else { 412 event.getWhen(), event.getModifiers(), 413 p.x, p.y, event.getXOnScreen(), event.getYOnScreen(), 414 event.getClickCount(), 415 event.isPopupTrigger(), MouseEvent.NOBUTTON); 416 417 tip = ((JComponent)component).getToolTipText(newEvent); 418 } 419 } 420 421 // No tip from the renderer get our own tip 422 if (tip == null) 423 tip = getToolTipText(); 424 425 return tip; 426 } 427 428 /** 429 * Returns the preferred size of the table header. 430 * This is the size required to display the header and requested for 431 * the viewport. 432 * The returned {@code Dimension width} will always be calculated by 433 * the underlying TableHeaderUI, regardless of any width specified by 434 * {@link JComponent#setPreferredSize(java.awt.Dimension)} 435 * 436 * @return the size 437 */ 438 @Override 439 public Dimension getPreferredSize() { 440 Dimension preferredSize = super.getPreferredSize(); 441 if (isPreferredSizeSet() && ui != null) { 442 Dimension size = ui.getPreferredSize(this); 443 if (size != null) preferredSize.width = size.width; 444 } 445 return preferredSize; 446 } 447 448 // 449 // Managing TableHeaderUI 450 // 451 452 /** 453 * Returns the look and feel (L&F) object that renders this component. 454 * 455 * @return the {@code TableHeaderUI} object that renders this component 456 */ 457 public TableHeaderUI getUI() { 458 return (TableHeaderUI)ui; 459 } 460 461 /** 462 * Sets the look and feel (L&F) object that renders this component. 463 * 464 * @param ui the {@code TableHeaderUI} L&F object 465 * @see UIDefaults#getUI 466 */ 467 public void setUI(TableHeaderUI ui){ 468 if (this.ui != ui) { 469 super.setUI(ui); 470 repaint(); 471 } 472 } 473 474 /** 475 * Notification from the {@code UIManager} that the look and feel 476 * (L&F) has changed. 477 * Replaces the current UI object with the latest version from the 478 * {@code UIManager}. 479 * 480 * @see JComponent#updateUI 481 */ 482 public void updateUI(){ 483 setUI((TableHeaderUI)UIManager.getUI(this)); 484 485 TableCellRenderer renderer = getDefaultRenderer(); 486 if (renderer instanceof Component) { 487 SwingUtilities.updateComponentTreeUI((Component)renderer); 488 } 489 } 490 491 492 /** 493 * Returns the suffix used to construct the name of the look and feel 494 * (L&F) class used to render this component. 495 * @return the string "TableHeaderUI" 496 * 497 * @return "TableHeaderUI" 498 * @see JComponent#getUIClassID 499 * @see UIDefaults#getUI 500 */ 501 public String getUIClassID() { 502 return uiClassID; 503 } 504 505 506 // 507 // Managing models 508 // 509 510 511 /** 512 * Sets the column model for this table to {@code newModel} and registers 513 * for listener notifications from the new column model. 514 * 515 * @param columnModel the new data source for this table 516 * @exception IllegalArgumentException 517 * if {@code newModel} is {@code null} 518 * @see #getColumnModel 519 * @beaninfo 520 * bound: true 521 * description: The object governing the way columns appear in the view. 522 */ 523 public void setColumnModel(TableColumnModel columnModel) { 524 if (columnModel == null) { 525 throw new IllegalArgumentException("Cannot set a null ColumnModel"); 526 } 527 TableColumnModel old = this.columnModel; 528 if (columnModel != old) { 529 if (old != null) { 530 old.removeColumnModelListener(this); 531 } 532 this.columnModel = columnModel; 533 columnModel.addColumnModelListener(this); 534 535 firePropertyChange("columnModel", old, columnModel); 536 resizeAndRepaint(); 537 } 538 } 539 540 /** 541 * Returns the {@code TableColumnModel} that contains all column information 542 * of this table header. 543 * 544 * @return the {@code columnModel} property 545 * @see #setColumnModel 546 */ 547 public TableColumnModel getColumnModel() { 548 return columnModel; 549 } 550 551 // 552 // Implementing TableColumnModelListener interface 553 // 554 555 /** 556 * Invoked when a column is added to the table column model. 557 * <p> 558 * Application code will not use these methods explicitly, they 559 * are used internally by {@code JTable}. 560 * 561 * @param e the event received 562 * @see TableColumnModelListener 563 */ 564 public void columnAdded(TableColumnModelEvent e) { resizeAndRepaint(); } 565 566 567 /** 568 * Invoked when a column is removed from the table column model. 569 * <p> 570 * Application code will not use these methods explicitly, they 571 * are used internally by {@code JTable}. 572 * 573 * @param e the event received 574 * @see TableColumnModelListener 575 */ 576 public void columnRemoved(TableColumnModelEvent e) { resizeAndRepaint(); } 577 578 579 /** 580 * Invoked when a column is repositioned. 581 * <p> 582 * Application code will not use these methods explicitly, they 583 * are used internally by {@code JTable}. 584 * 585 * @param e the event received 586 * @see TableColumnModelListener 587 */ 588 public void columnMoved(TableColumnModelEvent e) { repaint(); } 589 590 591 /** 592 * Invoked when a column is moved due to a margin change. 593 * <p> 594 * Application code will not use these methods explicitly, they 595 * are used internally by {@code JTable}. 596 * 597 * @param e the event received 598 * @see TableColumnModelListener 599 */ 600 public void columnMarginChanged(ChangeEvent e) { resizeAndRepaint(); } 601 602 603 // --Redrawing the header is slow in cell selection mode. 604 // --Since header selection is ugly and it is always clear from the 605 // --view which columns are selected, don't redraw the header. 606 /** 607 * Invoked when the selection model of the {@code TableColumnModel} 608 * is changed. This method currently has no effect (the header is not 609 * redrawn). 610 * <p> 611 * Application code will not use these methods explicitly, they 612 * are used internally by {@code JTable}. 613 * 614 * @param e the event received 615 * @see TableColumnModelListener 616 */ 617 public void columnSelectionChanged(ListSelectionEvent e) { } // repaint(); } 618 619 // 620 // Package Methods 621 // 622 623 /** 624 * Returns the default column model object which is 625 * a {@code DefaultTableColumnModel}. A subclass can override this 626 * method to return a different column model object 627 * 628 * @return the default column model object 629 */ 630 protected TableColumnModel createDefaultColumnModel() { 631 return new DefaultTableColumnModel(); 632 } 633 634 /** 635 * Returns a default renderer to be used when no header renderer 636 * is defined by a {@code TableColumn}. 637 * 638 * @return the default table column renderer 639 * @since 1.3 640 */ 641 protected TableCellRenderer createDefaultRenderer() { 642 return new DefaultTableCellHeaderRenderer(); 643 } 644 645 646 /** 647 * Initializes the local variables and properties with default values. 648 * Used by the constructor methods. 649 */ 650 protected void initializeLocalVars() { 651 setOpaque(true); 652 table = null; 653 reorderingAllowed = true; 654 resizingAllowed = true; 655 draggedColumn = null; 656 draggedDistance = 0; 657 resizingColumn = null; 658 updateTableInRealTime = true; 659 660 // I'm registered to do tool tips so we can draw tips for the 661 // renderers 662 ToolTipManager toolTipManager = ToolTipManager.sharedInstance(); 663 toolTipManager.registerComponent(this); 664 setDefaultRenderer(createDefaultRenderer()); 665 } 666 667 /** 668 * Sizes the header and marks it as needing display. Equivalent 669 * to {@code revalidate} followed by {@code repaint}. 670 */ 671 public void resizeAndRepaint() { 672 revalidate(); 673 repaint(); 674 } 675 676 /** 677 * Sets the header's {@code draggedColumn} to {@code aColumn}. 678 * <p> 679 * Application code will not use this method explicitly, it is used 680 * internally by the column dragging mechanism. 681 * 682 * @param aColumn the column being dragged, or {@code null} if 683 * no column is being dragged 684 */ 685 public void setDraggedColumn(TableColumn aColumn) { 686 draggedColumn = aColumn; 687 } 688 689 /** 690 * Sets the header's {@code draggedDistance} to {@code distance}. 691 * @param distance the distance dragged 692 */ 693 public void setDraggedDistance(int distance) { 694 draggedDistance = distance; 695 } 696 697 /** 698 * Sets the header's {@code resizingColumn} to {@code aColumn}. 699 * <p> 700 * Application code will not use this method explicitly, it 701 * is used internally by the column sizing mechanism. 702 * 703 * @param aColumn the column being resized, or {@code null} if 704 * no column is being resized 705 */ 706 public void setResizingColumn(TableColumn aColumn) { 707 resizingColumn = aColumn; 708 } 709 710 /** 711 * See {@code readObject} and {@code writeObject} in 712 * {@code JComponent} for more 713 * information about serialization in Swing. 714 */ 715 private void writeObject(ObjectOutputStream s) throws IOException { 716 s.defaultWriteObject(); 717 if ((ui != null) && (getUIClassID().equals(uiClassID))) { 718 ui.installUI(this); 719 } 720 } 721 722 private int getWidthInRightToLeft() { 723 if ((table != null) && 724 (table.getAutoResizeMode() != JTable.AUTO_RESIZE_OFF)) { 725 return table.getWidth(); 726 } 727 return super.getWidth(); 728 } 729 730 /** 731 * Returns a string representation of this {@code JTableHeader}. This method 732 * is intended to be used only for debugging purposes, and the 733 * content and format of the returned string may vary between 734 * implementations. The returned string may be empty but may not 735 * be {@code null}. 736 * <P> 737 * Overriding {@code paramString} to provide information about the 738 * specific new aspects of the JFC components. 739 * 740 * @return a string representation of this {@code JTableHeader} 741 */ 742 protected String paramString() { 743 String reorderingAllowedString = (reorderingAllowed ? 744 "true" : "false"); 745 String resizingAllowedString = (resizingAllowed ? 746 "true" : "false"); 747 String updateTableInRealTimeString = (updateTableInRealTime ? 748 "true" : "false"); 749 750 return super.paramString() + 751 ",draggedDistance=" + draggedDistance + 752 ",reorderingAllowed=" + reorderingAllowedString + 753 ",resizingAllowed=" + resizingAllowedString + 754 ",updateTableInRealTime=" + updateTableInRealTimeString; 755 } 756 757 ///////////////// 758 // Accessibility support 759 //////////////// 760 763 * For JTableHeaders, the AccessibleContext takes the form of an 764 * AccessibleJTableHeader. 765 * A new AccessibleJTableHeader instance is created if necessary. 766 * 767 * @return an AccessibleJTableHeader that serves as the 768 * AccessibleContext of this JTableHeader 769 */ 770 public AccessibleContext getAccessibleContext() { 771 if (accessibleContext == null) { 772 accessibleContext = new AccessibleJTableHeader(); 773 } 774 return accessibleContext; 775 } 776 777 // 778 // *** should also implement AccessibleSelection? 779 // *** and what's up with keyboard navigation/manipulation? 780 // 781 /** 782 * This class implements accessibility support for the 783 * {@code JTableHeader} class. It provides an implementation of the 784 * Java Accessibility API appropriate to table header user-interface 785 * elements. 786 * <p> 787 * <strong>Warning:</strong> 788 * Serialized objects of this class will not be compatible with 789 * future Swing releases. The current serialization support is 790 * appropriate for short term storage or RMI between applications running 791 * the same version of Swing. As of 1.4, support for long term storage 792 * of all JavaBeans™ 793 * has been added to the {@code java.beans} package. 794 * Please see {@link java.beans.XMLEncoder}. 795 */ 796 @SuppressWarnings("serial") // Same-version serialization only 797 protected class AccessibleJTableHeader extends AccessibleJComponent { 798 799 /** 800 * Get the role of this object. 801 * 802 * @return an instance of AccessibleRole describing the role of the 803 * object 804 * @see AccessibleRole 805 */ 806 public AccessibleRole getAccessibleRole() { 807 return AccessibleRole.PANEL; 808 } 809 810 /** 811 * Returns the Accessible child, if one exists, contained at the local 812 * coordinate Point. 813 * 880 return new AccessibleJTableHeaderEntry(i, JTableHeader.this, JTableHeader.this.table); 881 } 882 } 883 884 /** 885 * This class provides an implementation of the Java Accessibility 886 * API appropriate for JTableHeader entries. 887 */ 888 protected class AccessibleJTableHeaderEntry extends AccessibleContext 889 implements Accessible, AccessibleComponent { 890 891 private JTableHeader parent; 892 private int column; 893 private JTable table; 894 895 /** 896 * Constructs an AccessiblJTableHeaaderEntry 897 * @since 1.4 898 * 899 * @param c the column index 900 * @param p the parent {@code JTableHeader} 901 * @param t the table {@code JTable} 902 */ 903 public AccessibleJTableHeaderEntry(int c, JTableHeader p, JTable t) { 904 parent = p; 905 column = c; 906 table = t; 907 this.setAccessibleParent(parent); 908 } 909 910 /** 911 * Get the AccessibleContext associated with this object. 912 * In the implementation of the Java Accessibility API 913 * for this class, returns this object, which serves as 914 * its own AccessibleContext. 915 * 916 * @return this object 917 */ 918 public AccessibleContext getAccessibleContext() { 919 return this; 920 } 921 |