1 /* 2 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing.table; 27 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 { 368 for(int i = 0; i < column; i++) { 369 r.x += cm.getColumn(i).getWidth(); 370 } 371 if( !getComponentOrientation().isLeftToRight() ) { 372 r.x = getWidthInRightToLeft() - r.x - cm.getColumn(column).getWidth(); 373 } 374 375 r.width = cm.getColumn(column).getWidth(); 376 } 377 return r; 378 } 379 380 381 /** 382 * Allows the renderer's tips to be used if there is text set. 383 * @param event the location of the event identifies the proper 384 * renderer and, therefore, the proper tip 385 * @return the tool tip for this component 386 */ 387 public String getToolTipText(MouseEvent event) { 388 String tip = null; 389 Point p = event.getPoint(); 390 int column; 391 392 // Locate the renderer under the event location 393 if ((column = columnAtPoint(p)) != -1) { 394 TableColumn aColumn = columnModel.getColumn(column); 395 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 396 if (renderer == null) { 397 renderer = defaultRenderer; 398 } 399 Component component = renderer.getTableCellRendererComponent( 400 getTable(), aColumn.getHeaderValue(), false, false, 401 -1, column); 402 403 // Now have to see if the component is a JComponent before 404 // getting the tip 405 if (component instanceof JComponent) { 406 // Convert the event to the renderer's coordinate system 407 MouseEvent newEvent; 408 Rectangle cellRect = getHeaderRect(column); 409 410 p.translate(-cellRect.x, -cellRect.y); 411 newEvent = new MouseEvent(component, event.getID(), 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 761 /** 762 * Gets the AccessibleContext associated with this JTableHeader. 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 * 814 * @param p The point defining the top-left corner of the Accessible, 815 * given in the coordinate space of the object's parent. 816 * @return the Accessible, if it exists, at the specified location; 817 * else null 818 */ 819 public Accessible getAccessibleAt(Point p) { 820 int column; 821 822 // Locate the renderer under the Point 823 if ((column = JTableHeader.this.columnAtPoint(p)) != -1) { 824 TableColumn aColumn = JTableHeader.this.columnModel.getColumn(column); 825 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 826 if (renderer == null) { 827 if (defaultRenderer != null) { 828 renderer = defaultRenderer; 829 } else { 830 return null; 831 } 832 } 833 Component component = renderer.getTableCellRendererComponent( 834 JTableHeader.this.getTable(), 835 aColumn.getHeaderValue(), false, false, 836 -1, column); 837 838 return new AccessibleJTableHeaderEntry(column, JTableHeader.this, JTableHeader.this.table); 839 } else { 840 return null; 841 } 842 } 843 844 /** 845 * Returns the number of accessible children in the object. If all 846 * of the children of this object implement Accessible, than this 847 * method should return the number of children of this object. 848 * 849 * @return the number of accessible children in the object. 850 */ 851 public int getAccessibleChildrenCount() { 852 return JTableHeader.this.columnModel.getColumnCount(); 853 } 854 855 /** 856 * Return the nth Accessible child of the object. 857 * 858 * @param i zero-based index of child 859 * @return the nth Accessible child of the object 860 */ 861 public Accessible getAccessibleChild(int i) { 862 if (i < 0 || i >= getAccessibleChildrenCount()) { 863 return null; 864 } else { 865 TableColumn aColumn = JTableHeader.this.columnModel.getColumn(i) 866 ; 867 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 868 if (renderer == null) { 869 if (defaultRenderer != null) { 870 renderer = defaultRenderer; 871 } else { 872 return null; 873 } 874 } 875 Component component = renderer.getTableCellRendererComponent( 876 JTableHeader.this.getTable(), 877 aColumn.getHeaderValue(), false, false, 878 -1, i); 879 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 922 private AccessibleContext getCurrentAccessibleContext() { 923 TableColumnModel tcm = table.getColumnModel(); 924 if (tcm != null) { 925 // Fixes 4772355 - ArrayOutOfBoundsException in 926 // JTableHeader 927 if (column < 0 || column >= tcm.getColumnCount()) { 928 return null; 929 } 930 TableColumn aColumn = tcm.getColumn(column); 931 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 932 if (renderer == null) { 933 if (defaultRenderer != null) { 934 renderer = defaultRenderer; 935 } else { 936 return null; 937 } 938 } 939 Component c = renderer.getTableCellRendererComponent( 940 JTableHeader.this.getTable(), 941 aColumn.getHeaderValue(), false, false, 942 -1, column); 943 if (c instanceof Accessible) { 944 return ((Accessible) c).getAccessibleContext(); 945 } 946 } 947 return null; 948 } 949 950 private Component getCurrentComponent() { 951 TableColumnModel tcm = table.getColumnModel(); 952 if (tcm != null) { 953 // Fixes 4772355 - ArrayOutOfBoundsException in 954 // JTableHeader 955 if (column < 0 || column >= tcm.getColumnCount()) { 956 return null; 957 } 958 TableColumn aColumn = tcm.getColumn(column); 959 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 960 if (renderer == null) { 961 if (defaultRenderer != null) { 962 renderer = defaultRenderer; 963 } else { 964 return null; 965 } 966 } 967 return renderer.getTableCellRendererComponent( 968 JTableHeader.this.getTable(), 969 aColumn.getHeaderValue(), false, false, 970 -1, column); 971 } else { 972 return null; 973 } 974 } 975 976 // AccessibleContext methods 977 978 public String getAccessibleName() { 979 AccessibleContext ac = getCurrentAccessibleContext(); 980 if (ac != null) { 981 String name = ac.getAccessibleName(); 982 if ((name != null) && (name != "")) { 983 // return the cell renderer's AccessibleName 984 return name; 985 } 986 } 987 if ((accessibleName != null) && (accessibleName != "")) { 988 return accessibleName; 989 } else { 990 // fall back to the client property 991 String name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY); 992 if (name != null) { 993 return name; 994 } else { 995 return table.getColumnName(column); 996 } 997 } 998 } 999 1000 public void setAccessibleName(String s) { 1001 AccessibleContext ac = getCurrentAccessibleContext(); 1002 if (ac != null) { 1003 ac.setAccessibleName(s); 1004 } else { 1005 super.setAccessibleName(s); 1006 } 1007 } 1008 1009 // 1010 // *** should check toolTip text for desc. (needs MouseEvent) 1011 // 1012 public String getAccessibleDescription() { 1013 AccessibleContext ac = getCurrentAccessibleContext(); 1014 if (ac != null) { 1015 return ac.getAccessibleDescription(); 1016 } else { 1017 return super.getAccessibleDescription(); 1018 } 1019 } 1020 1021 public void setAccessibleDescription(String s) { 1022 AccessibleContext ac = getCurrentAccessibleContext(); 1023 if (ac != null) { 1024 ac.setAccessibleDescription(s); 1025 } else { 1026 super.setAccessibleDescription(s); 1027 } 1028 } 1029 1030 public AccessibleRole getAccessibleRole() { 1031 AccessibleContext ac = getCurrentAccessibleContext(); 1032 if (ac != null) { 1033 return ac.getAccessibleRole(); 1034 } else { 1035 return AccessibleRole.COLUMN_HEADER; 1036 } 1037 } 1038 1039 public AccessibleStateSet getAccessibleStateSet() { 1040 AccessibleContext ac = getCurrentAccessibleContext(); 1041 if (ac != null) { 1042 AccessibleStateSet states = ac.getAccessibleStateSet(); 1043 if (isShowing()) { 1044 states.add(AccessibleState.SHOWING); 1045 } 1046 return states; 1047 } else { 1048 return new AccessibleStateSet(); // must be non null? 1049 } 1050 } 1051 1052 public int getAccessibleIndexInParent() { 1053 return column; 1054 } 1055 1056 public int getAccessibleChildrenCount() { 1057 AccessibleContext ac = getCurrentAccessibleContext(); 1058 if (ac != null) { 1059 return ac.getAccessibleChildrenCount(); 1060 } else { 1061 return 0; 1062 } 1063 } 1064 1065 public Accessible getAccessibleChild(int i) { 1066 AccessibleContext ac = getCurrentAccessibleContext(); 1067 if (ac != null) { 1068 Accessible accessibleChild = ac.getAccessibleChild(i); 1069 ac.setAccessibleParent(this); 1070 return accessibleChild; 1071 } else { 1072 return null; 1073 } 1074 } 1075 1076 public Locale getLocale() { 1077 AccessibleContext ac = getCurrentAccessibleContext(); 1078 if (ac != null) { 1079 return ac.getLocale(); 1080 } else { 1081 return null; 1082 } 1083 } 1084 1085 public void addPropertyChangeListener(PropertyChangeListener l) { 1086 AccessibleContext ac = getCurrentAccessibleContext(); 1087 if (ac != null) { 1088 ac.addPropertyChangeListener(l); 1089 } else { 1090 super.addPropertyChangeListener(l); 1091 } 1092 } 1093 1094 public void removePropertyChangeListener(PropertyChangeListener l) { 1095 AccessibleContext ac = getCurrentAccessibleContext(); 1096 if (ac != null) { 1097 ac.removePropertyChangeListener(l); 1098 } else { 1099 super.removePropertyChangeListener(l); 1100 } 1101 } 1102 1103 public AccessibleAction getAccessibleAction() { 1104 return getCurrentAccessibleContext().getAccessibleAction(); 1105 } 1106 1107 /** 1108 * Get the AccessibleComponent associated with this object. In the 1109 * implementation of the Java Accessibility API for this class, 1110 * return this object, which is responsible for implementing the 1111 * AccessibleComponent interface on behalf of itself. 1112 * 1113 * @return this object 1114 */ 1115 public AccessibleComponent getAccessibleComponent() { 1116 return this; // to override getBounds() 1117 } 1118 1119 public AccessibleSelection getAccessibleSelection() { 1120 return getCurrentAccessibleContext().getAccessibleSelection(); 1121 } 1122 1123 public AccessibleText getAccessibleText() { 1124 return getCurrentAccessibleContext().getAccessibleText(); 1125 } 1126 1127 public AccessibleValue getAccessibleValue() { 1128 return getCurrentAccessibleContext().getAccessibleValue(); 1129 } 1130 1131 1132 // AccessibleComponent methods 1133 1134 public Color getBackground() { 1135 AccessibleContext ac = getCurrentAccessibleContext(); 1136 if (ac instanceof AccessibleComponent) { 1137 return ((AccessibleComponent) ac).getBackground(); 1138 } else { 1139 Component c = getCurrentComponent(); 1140 if (c != null) { 1141 return c.getBackground(); 1142 } else { 1143 return null; 1144 } 1145 } 1146 } 1147 1148 public void setBackground(Color c) { 1149 AccessibleContext ac = getCurrentAccessibleContext(); 1150 if (ac instanceof AccessibleComponent) { 1151 ((AccessibleComponent) ac).setBackground(c); 1152 } else { 1153 Component cp = getCurrentComponent(); 1154 if (cp != null) { 1155 cp.setBackground(c); 1156 } 1157 } 1158 } 1159 1160 public Color getForeground() { 1161 AccessibleContext ac = getCurrentAccessibleContext(); 1162 if (ac instanceof AccessibleComponent) { 1163 return ((AccessibleComponent) ac).getForeground(); 1164 } else { 1165 Component c = getCurrentComponent(); 1166 if (c != null) { 1167 return c.getForeground(); 1168 } else { 1169 return null; 1170 } 1171 } 1172 } 1173 1174 public void setForeground(Color c) { 1175 AccessibleContext ac = getCurrentAccessibleContext(); 1176 if (ac instanceof AccessibleComponent) { 1177 ((AccessibleComponent) ac).setForeground(c); 1178 } else { 1179 Component cp = getCurrentComponent(); 1180 if (cp != null) { 1181 cp.setForeground(c); 1182 } 1183 } 1184 } 1185 1186 public Cursor getCursor() { 1187 AccessibleContext ac = getCurrentAccessibleContext(); 1188 if (ac instanceof AccessibleComponent) { 1189 return ((AccessibleComponent) ac).getCursor(); 1190 } else { 1191 Component c = getCurrentComponent(); 1192 if (c != null) { 1193 return c.getCursor(); 1194 } else { 1195 Accessible ap = getAccessibleParent(); 1196 if (ap instanceof AccessibleComponent) { 1197 return ((AccessibleComponent) ap).getCursor(); 1198 } else { 1199 return null; 1200 } 1201 } 1202 } 1203 } 1204 1205 public void setCursor(Cursor c) { 1206 AccessibleContext ac = getCurrentAccessibleContext(); 1207 if (ac instanceof AccessibleComponent) { 1208 ((AccessibleComponent) ac).setCursor(c); 1209 } else { 1210 Component cp = getCurrentComponent(); 1211 if (cp != null) { 1212 cp.setCursor(c); 1213 } 1214 } 1215 } 1216 1217 public Font getFont() { 1218 AccessibleContext ac = getCurrentAccessibleContext(); 1219 if (ac instanceof AccessibleComponent) { 1220 return ((AccessibleComponent) ac).getFont(); 1221 } else { 1222 Component c = getCurrentComponent(); 1223 if (c != null) { 1224 return c.getFont(); 1225 } else { 1226 return null; 1227 } 1228 } 1229 } 1230 1231 public void setFont(Font f) { 1232 AccessibleContext ac = getCurrentAccessibleContext(); 1233 if (ac instanceof AccessibleComponent) { 1234 ((AccessibleComponent) ac).setFont(f); 1235 } else { 1236 Component c = getCurrentComponent(); 1237 if (c != null) { 1238 c.setFont(f); 1239 } 1240 } 1241 } 1242 1243 public FontMetrics getFontMetrics(Font f) { 1244 AccessibleContext ac = getCurrentAccessibleContext(); 1245 if (ac instanceof AccessibleComponent) { 1246 return ((AccessibleComponent) ac).getFontMetrics(f); 1247 } else { 1248 Component c = getCurrentComponent(); 1249 if (c != null) { 1250 return c.getFontMetrics(f); 1251 } else { 1252 return null; 1253 } 1254 } 1255 } 1256 1257 public boolean isEnabled() { 1258 AccessibleContext ac = getCurrentAccessibleContext(); 1259 if (ac instanceof AccessibleComponent) { 1260 return ((AccessibleComponent) ac).isEnabled(); 1261 } else { 1262 Component c = getCurrentComponent(); 1263 if (c != null) { 1264 return c.isEnabled(); 1265 } else { 1266 return false; 1267 } 1268 } 1269 } 1270 1271 public void setEnabled(boolean b) { 1272 AccessibleContext ac = getCurrentAccessibleContext(); 1273 if (ac instanceof AccessibleComponent) { 1274 ((AccessibleComponent) ac).setEnabled(b); 1275 } else { 1276 Component c = getCurrentComponent(); 1277 if (c != null) { 1278 c.setEnabled(b); 1279 } 1280 } 1281 } 1282 1283 public boolean isVisible() { 1284 AccessibleContext ac = getCurrentAccessibleContext(); 1285 if (ac instanceof AccessibleComponent) { 1286 return ((AccessibleComponent) ac).isVisible(); 1287 } else { 1288 Component c = getCurrentComponent(); 1289 if (c != null) { 1290 return c.isVisible(); 1291 } else { 1292 return false; 1293 } 1294 } 1295 } 1296 1297 public void setVisible(boolean b) { 1298 AccessibleContext ac = getCurrentAccessibleContext(); 1299 if (ac instanceof AccessibleComponent) { 1300 ((AccessibleComponent) ac).setVisible(b); 1301 } else { 1302 Component c = getCurrentComponent(); 1303 if (c != null) { 1304 c.setVisible(b); 1305 } 1306 } 1307 } 1308 1309 public boolean isShowing() { 1310 if (isVisible() && JTableHeader.this.isShowing()) { 1311 return true; 1312 } else { 1313 return false; 1314 } 1315 } 1316 1317 public boolean contains(Point p) { 1318 AccessibleContext ac = getCurrentAccessibleContext(); 1319 if (ac instanceof AccessibleComponent) { 1320 Rectangle r = ((AccessibleComponent) ac).getBounds(); 1321 return r.contains(p); 1322 } else { 1323 Component c = getCurrentComponent(); 1324 if (c != null) { 1325 Rectangle r = c.getBounds(); 1326 return r.contains(p); 1327 } else { 1328 return getBounds().contains(p); 1329 } 1330 } 1331 } 1332 1333 public Point getLocationOnScreen() { 1334 if (parent != null) { 1335 Point parentLocation = parent.getLocationOnScreen(); 1336 Point componentLocation = getLocation(); 1337 componentLocation.translate(parentLocation.x, parentLocation.y); 1338 return componentLocation; 1339 } else { 1340 return null; 1341 } 1342 } 1343 1344 public Point getLocation() { 1345 AccessibleContext ac = getCurrentAccessibleContext(); 1346 if (ac instanceof AccessibleComponent) { 1347 Rectangle r = ((AccessibleComponent) ac).getBounds(); 1348 return r.getLocation(); 1349 } else { 1350 Component c = getCurrentComponent(); 1351 if (c != null) { 1352 Rectangle r = c.getBounds(); 1353 return r.getLocation(); 1354 } else { 1355 return getBounds().getLocation(); 1356 } 1357 } 1358 } 1359 1360 public void setLocation(Point p) { 1361 // if ((parent != null) && (parent.contains(p))) { 1362 // ensureIndexIsVisible(indexInParent); 1363 // } 1364 } 1365 1366 public Rectangle getBounds() { 1367 Rectangle r = table.getCellRect(-1, column, false); 1368 r.y = 0; 1369 return r; 1370 1371 // AccessibleContext ac = getCurrentAccessibleContext(); 1372 // if (ac instanceof AccessibleComponent) { 1373 // return ((AccessibleComponent) ac).getBounds(); 1374 // } else { 1375 // Component c = getCurrentComponent(); 1376 // if (c != null) { 1377 // return c.getBounds(); 1378 // } else { 1379 // Rectangle r = table.getCellRect(-1, column, false); 1380 // r.y = 0; 1381 // return r; 1382 // } 1383 // } 1384 } 1385 1386 public void setBounds(Rectangle r) { 1387 AccessibleContext ac = getCurrentAccessibleContext(); 1388 if (ac instanceof AccessibleComponent) { 1389 ((AccessibleComponent) ac).setBounds(r); 1390 } else { 1391 Component c = getCurrentComponent(); 1392 if (c != null) { 1393 c.setBounds(r); 1394 } 1395 } 1396 } 1397 1398 public Dimension getSize() { 1399 return getBounds().getSize(); 1400 // AccessibleContext ac = getCurrentAccessibleContext(); 1401 // if (ac instanceof AccessibleComponent) { 1402 // Rectangle r = ((AccessibleComponent) ac).getBounds(); 1403 // return r.getSize(); 1404 // } else { 1405 // Component c = getCurrentComponent(); 1406 // if (c != null) { 1407 // Rectangle r = c.getBounds(); 1408 // return r.getSize(); 1409 // } else { 1410 // return getBounds().getSize(); 1411 // } 1412 // } 1413 } 1414 1415 public void setSize (Dimension d) { 1416 AccessibleContext ac = getCurrentAccessibleContext(); 1417 if (ac instanceof AccessibleComponent) { 1418 ((AccessibleComponent) ac).setSize(d); 1419 } else { 1420 Component c = getCurrentComponent(); 1421 if (c != null) { 1422 c.setSize(d); 1423 } 1424 } 1425 } 1426 1427 public Accessible getAccessibleAt(Point p) { 1428 AccessibleContext ac = getCurrentAccessibleContext(); 1429 if (ac instanceof AccessibleComponent) { 1430 return ((AccessibleComponent) ac).getAccessibleAt(p); 1431 } else { 1432 return null; 1433 } 1434 } 1435 1436 @SuppressWarnings("deprecation") 1437 public boolean isFocusTraversable() { 1438 AccessibleContext ac = getCurrentAccessibleContext(); 1439 if (ac instanceof AccessibleComponent) { 1440 return ((AccessibleComponent) ac).isFocusTraversable(); 1441 } else { 1442 Component c = getCurrentComponent(); 1443 if (c != null) { 1444 return c.isFocusTraversable(); 1445 } else { 1446 return false; 1447 } 1448 } 1449 } 1450 1451 public void requestFocus() { 1452 AccessibleContext ac = getCurrentAccessibleContext(); 1453 if (ac instanceof AccessibleComponent) { 1454 ((AccessibleComponent) ac).requestFocus(); 1455 } else { 1456 Component c = getCurrentComponent(); 1457 if (c != null) { 1458 c.requestFocus(); 1459 } 1460 } 1461 } 1462 1463 public void addFocusListener(FocusListener l) { 1464 AccessibleContext ac = getCurrentAccessibleContext(); 1465 if (ac instanceof AccessibleComponent) { 1466 ((AccessibleComponent) ac).addFocusListener(l); 1467 } else { 1468 Component c = getCurrentComponent(); 1469 if (c != null) { 1470 c.addFocusListener(l); 1471 } 1472 } 1473 } 1474 1475 public void removeFocusListener(FocusListener l) { 1476 AccessibleContext ac = getCurrentAccessibleContext(); 1477 if (ac instanceof AccessibleComponent) { 1478 ((AccessibleComponent) ac).removeFocusListener(l); 1479 } else { 1480 Component c = getCurrentComponent(); 1481 if (c != null) { 1482 c.removeFocusListener(l); 1483 } 1484 } 1485 } 1486 1487 } // inner class AccessibleJTableHeaderElement 1488 1489 } // inner class AccessibleJTableHeader 1490 1491 } // End of Class JTableHeader --- EOF ---