1 /* 2 * Copyright (c) 1997, 2014, 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 transient protected TableColumn resizingColumn; 110 111 /** The index of the column being dragged. <code>null</code> if not dragging. */ 112 transient protected TableColumn draggedColumn; 113 114 /** The distance from its original position the column has been dragged. */ 115 transient protected 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 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 */ 285 /* 286 * Sets whether the body of the table updates in real time when 287 * a column is resized or dragged. 288 * 289 * @param flag true if tableView should update 290 * the body of the table in real time 291 * @see #getUpdateTableInRealTime 292 */ 293 public void setUpdateTableInRealTime(boolean flag) { 294 updateTableInRealTime = flag; 295 } 296 297 /** 298 * Obsolete as of Java 2 platform v1.3. Real time repaints, in response to 299 * column dragging or resizing, are now unconditional. 300 */ 301 /* 302 * Returns true if the body of the table view updates in real 303 * time when a column is resized or dragged. User can set this flag to 304 * false to speed up the table's response to user resize or drag actions. 305 * The default is true. 306 * 307 * @return true if the table updates in real time 308 * @see #setUpdateTableInRealTime 309 */ 310 public boolean getUpdateTableInRealTime() { 311 return updateTableInRealTime; 312 } 313 314 /** 315 * Sets the default renderer to be used when no <code>headerRenderer</code> 316 * is defined by a <code>TableColumn</code>. 317 * @param defaultRenderer the default renderer 318 * @since 1.3 319 */ 320 public void setDefaultRenderer(TableCellRenderer defaultRenderer) { 321 this.defaultRenderer = defaultRenderer; 322 } 323 324 /** 325 * Returns the default renderer used when no <code>headerRenderer</code> 326 * is defined by a <code>TableColumn</code>. 327 * @return the default renderer 328 * @since 1.3 329 */ 330 @Transient 331 public TableCellRenderer getDefaultRenderer() { 332 return defaultRenderer; 333 } 334 335 /** 336 * Returns the index of the column that <code>point</code> lies in, or -1 if it 337 * lies out of bounds. 338 * 339 * @param point if this <code>point</code> lies within a column, the index of 340 * that column will be returned; otherwise it is out of bounds 341 * and -1 is returned 342 * 343 * @return the index of the column that <code>point</code> lies in, or -1 if it 344 * lies out of bounds 345 */ 346 public int columnAtPoint(Point point) { 347 int x = point.x; 348 if (!getComponentOrientation().isLeftToRight()) { 349 x = getWidthInRightToLeft() - x - 1; 350 } 351 return getColumnModel().getColumnIndexAtX(x); 352 } 353 354 /** 355 * Returns the rectangle containing the header tile at <code>column</code>. 356 * When the <code>column</code> parameter is out of bounds this method uses the 357 * same conventions as the <code>JTable</code> method <code>getCellRect</code>. 358 * 359 * @param column index of the column 360 * 361 * @return the rectangle containing the header tile at <code>column</code> 362 * @see JTable#getCellRect 363 */ 364 public Rectangle getHeaderRect(int column) { 365 Rectangle r = new Rectangle(); 366 TableColumnModel cm = getColumnModel(); 367 368 r.height = getHeight(); 369 370 if (column < 0) { 371 // x = width = 0; 372 if( !getComponentOrientation().isLeftToRight() ) { 373 r.x = getWidthInRightToLeft(); 374 } 375 } 376 else if (column >= cm.getColumnCount()) { 377 if( getComponentOrientation().isLeftToRight() ) { 378 r.x = getWidth(); 379 } 380 } 381 else { 382 for(int i = 0; i < column; i++) { 383 r.x += cm.getColumn(i).getWidth(); 384 } 385 if( !getComponentOrientation().isLeftToRight() ) { 386 r.x = getWidthInRightToLeft() - r.x - cm.getColumn(column).getWidth(); 387 } 388 389 r.width = cm.getColumn(column).getWidth(); 390 } 391 return r; 392 } 393 394 395 /** 396 * Allows the renderer's tips to be used if there is text set. 397 * @param event the location of the event identifies the proper 398 * renderer and, therefore, the proper tip 399 * @return the tool tip for this component 400 */ 401 public String getToolTipText(MouseEvent event) { 402 String tip = null; 403 Point p = event.getPoint(); 404 int column; 405 406 // Locate the renderer under the event location 407 if ((column = columnAtPoint(p)) != -1) { 408 TableColumn aColumn = columnModel.getColumn(column); 409 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 410 if (renderer == null) { 411 renderer = defaultRenderer; 412 } 413 Component component = renderer.getTableCellRendererComponent( 414 getTable(), aColumn.getHeaderValue(), false, false, 415 -1, column); 416 417 // Now have to see if the component is a JComponent before 418 // getting the tip 419 if (component instanceof JComponent) { 420 // Convert the event to the renderer's coordinate system 421 MouseEvent newEvent; 422 Rectangle cellRect = getHeaderRect(column); 423 424 p.translate(-cellRect.x, -cellRect.y); 425 newEvent = new MouseEvent(component, event.getID(), 426 event.getWhen(), event.getModifiers(), 427 p.x, p.y, event.getXOnScreen(), event.getYOnScreen(), 428 event.getClickCount(), 429 event.isPopupTrigger(), MouseEvent.NOBUTTON); 430 431 tip = ((JComponent)component).getToolTipText(newEvent); 432 } 433 } 434 435 // No tip from the renderer get our own tip 436 if (tip == null) 437 tip = getToolTipText(); 438 439 return tip; 440 } 441 442 // 443 // Managing TableHeaderUI 444 // 445 446 /** 447 * Returns the look and feel (L&F) object that renders this component. 448 * 449 * @return the <code>TableHeaderUI</code> object that renders this component 450 */ 451 public TableHeaderUI getUI() { 452 return (TableHeaderUI)ui; 453 } 454 455 /** 456 * Sets the look and feel (L&F) object that renders this component. 457 * 458 * @param ui the <code>TableHeaderUI</code> L&F object 459 * @see UIDefaults#getUI 460 */ 461 public void setUI(TableHeaderUI ui){ 462 if (this.ui != ui) { 463 super.setUI(ui); 464 repaint(); 465 } 466 } 467 468 /** 469 * Notification from the <code>UIManager</code> that the look and feel 470 * (L&F) has changed. 471 * Replaces the current UI object with the latest version from the 472 * <code>UIManager</code>. 473 * 474 * @see JComponent#updateUI 475 */ 476 public void updateUI(){ 477 setUI((TableHeaderUI)UIManager.getUI(this)); 478 479 TableCellRenderer renderer = getDefaultRenderer(); 480 if (renderer instanceof Component) { 481 SwingUtilities.updateComponentTreeUI((Component)renderer); 482 } 483 } 484 485 486 /** 487 * Returns the suffix used to construct the name of the look and feel 488 * (L&F) class used to render this component. 489 * @return the string "TableHeaderUI" 490 * 491 * @return "TableHeaderUI" 492 * @see JComponent#getUIClassID 493 * @see UIDefaults#getUI 494 */ 495 public String getUIClassID() { 496 return uiClassID; 497 } 498 499 500 // 501 // Managing models 502 // 503 504 505 /** 506 * Sets the column model for this table to <code>newModel</code> and registers 507 * for listener notifications from the new column model. 508 * 509 * @param columnModel the new data source for this table 510 * @exception IllegalArgumentException 511 * if <code>newModel</code> is <code>null</code> 512 * @see #getColumnModel 513 * @beaninfo 514 * bound: true 515 * description: The object governing the way columns appear in the view. 516 */ 517 public void setColumnModel(TableColumnModel columnModel) { 518 if (columnModel == null) { 519 throw new IllegalArgumentException("Cannot set a null ColumnModel"); 520 } 521 TableColumnModel old = this.columnModel; 522 if (columnModel != old) { 523 if (old != null) { 524 old.removeColumnModelListener(this); 525 } 526 this.columnModel = columnModel; 527 columnModel.addColumnModelListener(this); 528 529 firePropertyChange("columnModel", old, columnModel); 530 resizeAndRepaint(); 531 } 532 } 533 534 /** 535 * Returns the <code>TableColumnModel</code> that contains all column information 536 * of this table header. 537 * 538 * @return the <code>columnModel</code> property 539 * @see #setColumnModel 540 */ 541 public TableColumnModel getColumnModel() { 542 return columnModel; 543 } 544 545 // 546 // Implementing TableColumnModelListener interface 547 // 548 549 /** 550 * Invoked when a column is added to the table column model. 551 * <p> 552 * Application code will not use these methods explicitly, they 553 * are used internally by <code>JTable</code>. 554 * 555 * @param e the event received 556 * @see TableColumnModelListener 557 */ 558 public void columnAdded(TableColumnModelEvent e) { resizeAndRepaint(); } 559 560 561 /** 562 * Invoked when a column is removed from the table column model. 563 * <p> 564 * Application code will not use these methods explicitly, they 565 * are used internally by <code>JTable</code>. 566 * 567 * @param e the event received 568 * @see TableColumnModelListener 569 */ 570 public void columnRemoved(TableColumnModelEvent e) { resizeAndRepaint(); } 571 572 573 /** 574 * Invoked when a column is repositioned. 575 * <p> 576 * Application code will not use these methods explicitly, they 577 * are used internally by <code>JTable</code>. 578 * 579 * @param e the event received 580 * @see TableColumnModelListener 581 */ 582 public void columnMoved(TableColumnModelEvent e) { repaint(); } 583 584 585 /** 586 * Invoked when a column is moved due to a margin change. 587 * <p> 588 * Application code will not use these methods explicitly, they 589 * are used internally by <code>JTable</code>. 590 * 591 * @param e the event received 592 * @see TableColumnModelListener 593 */ 594 public void columnMarginChanged(ChangeEvent e) { resizeAndRepaint(); } 595 596 597 // --Redrawing the header is slow in cell selection mode. 598 // --Since header selection is ugly and it is always clear from the 599 // --view which columns are selected, don't redraw the header. 600 /** 601 * Invoked when the selection model of the <code>TableColumnModel</code> 602 * is changed. This method currently has no effect (the header is not 603 * redrawn). 604 * <p> 605 * Application code will not use these methods explicitly, they 606 * are used internally by <code>JTable</code>. 607 * 608 * @param e the event received 609 * @see TableColumnModelListener 610 */ 611 public void columnSelectionChanged(ListSelectionEvent e) { } // repaint(); } 612 613 // 614 // Package Methods 615 // 616 617 /** 618 * Returns the default column model object which is 619 * a <code>DefaultTableColumnModel</code>. A subclass can override this 620 * method to return a different column model object 621 * 622 * @return the default column model object 623 */ 624 protected TableColumnModel createDefaultColumnModel() { 625 return new DefaultTableColumnModel(); 626 } 627 628 /** 629 * Returns a default renderer to be used when no header renderer 630 * is defined by a <code>TableColumn</code>. 631 * 632 * @return the default table column renderer 633 * @since 1.3 634 */ 635 protected TableCellRenderer createDefaultRenderer() { 636 return new DefaultTableCellHeaderRenderer(); 637 } 638 639 640 /** 641 * Initializes the local variables and properties with default values. 642 * Used by the constructor methods. 643 */ 644 protected void initializeLocalVars() { 645 setOpaque(true); 646 table = null; 647 reorderingAllowed = true; 648 resizingAllowed = true; 649 draggedColumn = null; 650 draggedDistance = 0; 651 resizingColumn = null; 652 updateTableInRealTime = true; 653 654 // I'm registered to do tool tips so we can draw tips for the 655 // renderers 656 ToolTipManager toolTipManager = ToolTipManager.sharedInstance(); 657 toolTipManager.registerComponent(this); 658 setDefaultRenderer(createDefaultRenderer()); 659 } 660 661 /** 662 * Sizes the header and marks it as needing display. Equivalent 663 * to <code>revalidate</code> followed by <code>repaint</code>. 664 */ 665 public void resizeAndRepaint() { 666 revalidate(); 667 repaint(); 668 } 669 670 /** 671 * Sets the header's <code>draggedColumn</code> to <code>aColumn</code>. 672 * <p> 673 * Application code will not use this method explicitly, it is used 674 * internally by the column dragging mechanism. 675 * 676 * @param aColumn the column being dragged, or <code>null</code> if 677 * no column is being dragged 678 */ 679 public void setDraggedColumn(TableColumn aColumn) { 680 draggedColumn = aColumn; 681 } 682 683 /** 684 * Sets the header's <code>draggedDistance</code> to <code>distance</code>. 685 * @param distance the distance dragged 686 */ 687 public void setDraggedDistance(int distance) { 688 draggedDistance = distance; 689 } 690 691 /** 692 * Sets the header's <code>resizingColumn</code> to <code>aColumn</code>. 693 * <p> 694 * Application code will not use this method explicitly, it 695 * is used internally by the column sizing mechanism. 696 * 697 * @param aColumn the column being resized, or <code>null</code> if 698 * no column is being resized 699 */ 700 public void setResizingColumn(TableColumn aColumn) { 701 resizingColumn = aColumn; 702 } 703 704 /** 705 * See <code>readObject</code> and <code>writeObject</code> in 706 * <code>JComponent</code> for more 707 * information about serialization in Swing. 708 */ 709 private void writeObject(ObjectOutputStream s) throws IOException { 710 s.defaultWriteObject(); 711 if ((ui != null) && (getUIClassID().equals(uiClassID))) { 712 ui.installUI(this); 713 } 714 } 715 716 private int getWidthInRightToLeft() { 717 if ((table != null) && 718 (table.getAutoResizeMode() != JTable.AUTO_RESIZE_OFF)) { 719 return table.getWidth(); 720 } 721 return super.getWidth(); 722 } 723 724 /** 725 * Returns a string representation of this <code>JTableHeader</code>. This method 726 * is intended to be used only for debugging purposes, and the 727 * content and format of the returned string may vary between 728 * implementations. The returned string may be empty but may not 729 * be <code>null</code>. 730 * <P> 731 * Overriding <code>paramString</code> to provide information about the 732 * specific new aspects of the JFC components. 733 * 734 * @return a string representation of this <code>JTableHeader</code> 735 */ 736 protected String paramString() { 737 String reorderingAllowedString = (reorderingAllowed ? 738 "true" : "false"); 739 String resizingAllowedString = (resizingAllowed ? 740 "true" : "false"); 741 String updateTableInRealTimeString = (updateTableInRealTime ? 742 "true" : "false"); 743 744 return super.paramString() + 745 ",draggedDistance=" + draggedDistance + 746 ",reorderingAllowed=" + reorderingAllowedString + 747 ",resizingAllowed=" + resizingAllowedString + 748 ",updateTableInRealTime=" + updateTableInRealTimeString; 749 } 750 751 ///////////////// 752 // Accessibility support 753 //////////////// 754 755 /** 756 * Gets the AccessibleContext associated with this JTableHeader. 757 * For JTableHeaders, the AccessibleContext takes the form of an 758 * AccessibleJTableHeader. 759 * A new AccessibleJTableHeader instance is created if necessary. 760 * 761 * @return an AccessibleJTableHeader that serves as the 762 * AccessibleContext of this JTableHeader 763 */ 764 public AccessibleContext getAccessibleContext() { 765 if (accessibleContext == null) { 766 accessibleContext = new AccessibleJTableHeader(); 767 } 768 return accessibleContext; 769 } 770 771 // 772 // *** should also implement AccessibleSelection? 773 // *** and what's up with keyboard navigation/manipulation? 774 // 775 /** 776 * This class implements accessibility support for the 777 * <code>JTableHeader</code> class. It provides an implementation of the 778 * Java Accessibility API appropriate to table header user-interface 779 * elements. 780 * <p> 781 * <strong>Warning:</strong> 782 * Serialized objects of this class will not be compatible with 783 * future Swing releases. The current serialization support is 784 * appropriate for short term storage or RMI between applications running 785 * the same version of Swing. As of 1.4, support for long term storage 786 * of all JavaBeans™ 787 * has been added to the <code>java.beans</code> package. 788 * Please see {@link java.beans.XMLEncoder}. 789 */ 790 @SuppressWarnings("serial") // Same-version serialization only 791 protected class AccessibleJTableHeader extends AccessibleJComponent { 792 793 /** 794 * Get the role of this object. 795 * 796 * @return an instance of AccessibleRole describing the role of the 797 * object 798 * @see AccessibleRole 799 */ 800 public AccessibleRole getAccessibleRole() { 801 return AccessibleRole.PANEL; 802 } 803 804 /** 805 * Returns the Accessible child, if one exists, contained at the local 806 * coordinate Point. 807 * 808 * @param p The point defining the top-left corner of the Accessible, 809 * given in the coordinate space of the object's parent. 810 * @return the Accessible, if it exists, at the specified location; 811 * else null 812 */ 813 public Accessible getAccessibleAt(Point p) { 814 int column; 815 816 // Locate the renderer under the Point 817 if ((column = JTableHeader.this.columnAtPoint(p)) != -1) { 818 TableColumn aColumn = JTableHeader.this.columnModel.getColumn(column); 819 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 820 if (renderer == null) { 821 if (defaultRenderer != null) { 822 renderer = defaultRenderer; 823 } else { 824 return null; 825 } 826 } 827 Component component = renderer.getTableCellRendererComponent( 828 JTableHeader.this.getTable(), 829 aColumn.getHeaderValue(), false, false, 830 -1, column); 831 832 return new AccessibleJTableHeaderEntry(column, JTableHeader.this, JTableHeader.this.table); 833 } else { 834 return null; 835 } 836 } 837 838 /** 839 * Returns the number of accessible children in the object. If all 840 * of the children of this object implement Accessible, than this 841 * method should return the number of children of this object. 842 * 843 * @return the number of accessible children in the object. 844 */ 845 public int getAccessibleChildrenCount() { 846 return JTableHeader.this.columnModel.getColumnCount(); 847 } 848 849 /** 850 * Return the nth Accessible child of the object. 851 * 852 * @param i zero-based index of child 853 * @return the nth Accessible child of the object 854 */ 855 public Accessible getAccessibleChild(int i) { 856 if (i < 0 || i >= getAccessibleChildrenCount()) { 857 return null; 858 } else { 859 TableColumn aColumn = JTableHeader.this.columnModel.getColumn(i) 860 ; 861 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 862 if (renderer == null) { 863 if (defaultRenderer != null) { 864 renderer = defaultRenderer; 865 } else { 866 return null; 867 } 868 } 869 Component component = renderer.getTableCellRendererComponent( 870 JTableHeader.this.getTable(), 871 aColumn.getHeaderValue(), false, false, 872 -1, i); 873 874 return new AccessibleJTableHeaderEntry(i, JTableHeader.this, JTableHeader.this.table); 875 } 876 } 877 878 /** 879 * This class provides an implementation of the Java Accessibility 880 * API appropriate for JTableHeader entries. 881 */ 882 protected class AccessibleJTableHeaderEntry extends AccessibleContext 883 implements Accessible, AccessibleComponent { 884 885 private JTableHeader parent; 886 private int column; 887 private JTable table; 888 889 /** 890 * Constructs an AccessiblJTableHeaaderEntry 891 * @since 1.4 892 * 893 * @param c the column index 894 * @param p the parent <code>JTableHeader</code> 895 * @param t the table <code>JTable</code> 896 */ 897 public AccessibleJTableHeaderEntry(int c, JTableHeader p, JTable t) { 898 parent = p; 899 column = c; 900 table = t; 901 this.setAccessibleParent(parent); 902 } 903 904 /** 905 * Get the AccessibleContext associated with this object. 906 * In the implementation of the Java Accessibility API 907 * for this class, returns this object, which serves as 908 * its own AccessibleContext. 909 * 910 * @return this object 911 */ 912 public AccessibleContext getAccessibleContext() { 913 return this; 914 } 915 916 private AccessibleContext getCurrentAccessibleContext() { 917 TableColumnModel tcm = table.getColumnModel(); 918 if (tcm != null) { 919 // Fixes 4772355 - ArrayOutOfBoundsException in 920 // JTableHeader 921 if (column < 0 || column >= tcm.getColumnCount()) { 922 return null; 923 } 924 TableColumn aColumn = tcm.getColumn(column); 925 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 926 if (renderer == null) { 927 if (defaultRenderer != null) { 928 renderer = defaultRenderer; 929 } else { 930 return null; 931 } 932 } 933 Component c = renderer.getTableCellRendererComponent( 934 JTableHeader.this.getTable(), 935 aColumn.getHeaderValue(), false, false, 936 -1, column); 937 if (c instanceof Accessible) { 938 return ((Accessible) c).getAccessibleContext(); 939 } 940 } 941 return null; 942 } 943 944 private Component getCurrentComponent() { 945 TableColumnModel tcm = table.getColumnModel(); 946 if (tcm != null) { 947 // Fixes 4772355 - ArrayOutOfBoundsException in 948 // JTableHeader 949 if (column < 0 || column >= tcm.getColumnCount()) { 950 return null; 951 } 952 TableColumn aColumn = tcm.getColumn(column); 953 TableCellRenderer renderer = aColumn.getHeaderRenderer(); 954 if (renderer == null) { 955 if (defaultRenderer != null) { 956 renderer = defaultRenderer; 957 } else { 958 return null; 959 } 960 } 961 return renderer.getTableCellRendererComponent( 962 JTableHeader.this.getTable(), 963 aColumn.getHeaderValue(), false, false, 964 -1, column); 965 } else { 966 return null; 967 } 968 } 969 970 // AccessibleContext methods 971 972 public String getAccessibleName() { 973 AccessibleContext ac = getCurrentAccessibleContext(); 974 if (ac != null) { 975 String name = ac.getAccessibleName(); 976 if ((name != null) && (name != "")) { 977 // return the cell renderer's AccessibleName 978 return name; 979 } 980 } 981 if ((accessibleName != null) && (accessibleName != "")) { 982 return accessibleName; 983 } else { 984 // fall back to the client property 985 String name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY); 986 if (name != null) { 987 return name; 988 } else { 989 return table.getColumnName(column); 990 } 991 } 992 } 993 994 public void setAccessibleName(String s) { 995 AccessibleContext ac = getCurrentAccessibleContext(); 996 if (ac != null) { 997 ac.setAccessibleName(s); 998 } else { 999 super.setAccessibleName(s); 1000 } 1001 } 1002 1003 // 1004 // *** should check toolTip text for desc. (needs MouseEvent) 1005 // 1006 public String getAccessibleDescription() { 1007 AccessibleContext ac = getCurrentAccessibleContext(); 1008 if (ac != null) { 1009 return ac.getAccessibleDescription(); 1010 } else { 1011 return super.getAccessibleDescription(); 1012 } 1013 } 1014 1015 public void setAccessibleDescription(String s) { 1016 AccessibleContext ac = getCurrentAccessibleContext(); 1017 if (ac != null) { 1018 ac.setAccessibleDescription(s); 1019 } else { 1020 super.setAccessibleDescription(s); 1021 } 1022 } 1023 1024 public AccessibleRole getAccessibleRole() { 1025 AccessibleContext ac = getCurrentAccessibleContext(); 1026 if (ac != null) { 1027 return ac.getAccessibleRole(); 1028 } else { 1029 return AccessibleRole.COLUMN_HEADER; 1030 } 1031 } 1032 1033 public AccessibleStateSet getAccessibleStateSet() { 1034 AccessibleContext ac = getCurrentAccessibleContext(); 1035 if (ac != null) { 1036 AccessibleStateSet states = ac.getAccessibleStateSet(); 1037 if (isShowing()) { 1038 states.add(AccessibleState.SHOWING); 1039 } 1040 return states; 1041 } else { 1042 return new AccessibleStateSet(); // must be non null? 1043 } 1044 } 1045 1046 public int getAccessibleIndexInParent() { 1047 return column; 1048 } 1049 1050 public int getAccessibleChildrenCount() { 1051 AccessibleContext ac = getCurrentAccessibleContext(); 1052 if (ac != null) { 1053 return ac.getAccessibleChildrenCount(); 1054 } else { 1055 return 0; 1056 } 1057 } 1058 1059 public Accessible getAccessibleChild(int i) { 1060 AccessibleContext ac = getCurrentAccessibleContext(); 1061 if (ac != null) { 1062 Accessible accessibleChild = ac.getAccessibleChild(i); 1063 ac.setAccessibleParent(this); 1064 return accessibleChild; 1065 } else { 1066 return null; 1067 } 1068 } 1069 1070 public Locale getLocale() { 1071 AccessibleContext ac = getCurrentAccessibleContext(); 1072 if (ac != null) { 1073 return ac.getLocale(); 1074 } else { 1075 return null; 1076 } 1077 } 1078 1079 public void addPropertyChangeListener(PropertyChangeListener l) { 1080 AccessibleContext ac = getCurrentAccessibleContext(); 1081 if (ac != null) { 1082 ac.addPropertyChangeListener(l); 1083 } else { 1084 super.addPropertyChangeListener(l); 1085 } 1086 } 1087 1088 public void removePropertyChangeListener(PropertyChangeListener l) { 1089 AccessibleContext ac = getCurrentAccessibleContext(); 1090 if (ac != null) { 1091 ac.removePropertyChangeListener(l); 1092 } else { 1093 super.removePropertyChangeListener(l); 1094 } 1095 } 1096 1097 public AccessibleAction getAccessibleAction() { 1098 return getCurrentAccessibleContext().getAccessibleAction(); 1099 } 1100 1101 /** 1102 * Get the AccessibleComponent associated with this object. In the 1103 * implementation of the Java Accessibility API for this class, 1104 * return this object, which is responsible for implementing the 1105 * AccessibleComponent interface on behalf of itself. 1106 * 1107 * @return this object 1108 */ 1109 public AccessibleComponent getAccessibleComponent() { 1110 return this; // to override getBounds() 1111 } 1112 1113 public AccessibleSelection getAccessibleSelection() { 1114 return getCurrentAccessibleContext().getAccessibleSelection(); 1115 } 1116 1117 public AccessibleText getAccessibleText() { 1118 return getCurrentAccessibleContext().getAccessibleText(); 1119 } 1120 1121 public AccessibleValue getAccessibleValue() { 1122 return getCurrentAccessibleContext().getAccessibleValue(); 1123 } 1124 1125 1126 // AccessibleComponent methods 1127 1128 public Color getBackground() { 1129 AccessibleContext ac = getCurrentAccessibleContext(); 1130 if (ac instanceof AccessibleComponent) { 1131 return ((AccessibleComponent) ac).getBackground(); 1132 } else { 1133 Component c = getCurrentComponent(); 1134 if (c != null) { 1135 return c.getBackground(); 1136 } else { 1137 return null; 1138 } 1139 } 1140 } 1141 1142 public void setBackground(Color c) { 1143 AccessibleContext ac = getCurrentAccessibleContext(); 1144 if (ac instanceof AccessibleComponent) { 1145 ((AccessibleComponent) ac).setBackground(c); 1146 } else { 1147 Component cp = getCurrentComponent(); 1148 if (cp != null) { 1149 cp.setBackground(c); 1150 } 1151 } 1152 } 1153 1154 public Color getForeground() { 1155 AccessibleContext ac = getCurrentAccessibleContext(); 1156 if (ac instanceof AccessibleComponent) { 1157 return ((AccessibleComponent) ac).getForeground(); 1158 } else { 1159 Component c = getCurrentComponent(); 1160 if (c != null) { 1161 return c.getForeground(); 1162 } else { 1163 return null; 1164 } 1165 } 1166 } 1167 1168 public void setForeground(Color c) { 1169 AccessibleContext ac = getCurrentAccessibleContext(); 1170 if (ac instanceof AccessibleComponent) { 1171 ((AccessibleComponent) ac).setForeground(c); 1172 } else { 1173 Component cp = getCurrentComponent(); 1174 if (cp != null) { 1175 cp.setForeground(c); 1176 } 1177 } 1178 } 1179 1180 public Cursor getCursor() { 1181 AccessibleContext ac = getCurrentAccessibleContext(); 1182 if (ac instanceof AccessibleComponent) { 1183 return ((AccessibleComponent) ac).getCursor(); 1184 } else { 1185 Component c = getCurrentComponent(); 1186 if (c != null) { 1187 return c.getCursor(); 1188 } else { 1189 Accessible ap = getAccessibleParent(); 1190 if (ap instanceof AccessibleComponent) { 1191 return ((AccessibleComponent) ap).getCursor(); 1192 } else { 1193 return null; 1194 } 1195 } 1196 } 1197 } 1198 1199 public void setCursor(Cursor c) { 1200 AccessibleContext ac = getCurrentAccessibleContext(); 1201 if (ac instanceof AccessibleComponent) { 1202 ((AccessibleComponent) ac).setCursor(c); 1203 } else { 1204 Component cp = getCurrentComponent(); 1205 if (cp != null) { 1206 cp.setCursor(c); 1207 } 1208 } 1209 } 1210 1211 public Font getFont() { 1212 AccessibleContext ac = getCurrentAccessibleContext(); 1213 if (ac instanceof AccessibleComponent) { 1214 return ((AccessibleComponent) ac).getFont(); 1215 } else { 1216 Component c = getCurrentComponent(); 1217 if (c != null) { 1218 return c.getFont(); 1219 } else { 1220 return null; 1221 } 1222 } 1223 } 1224 1225 public void setFont(Font f) { 1226 AccessibleContext ac = getCurrentAccessibleContext(); 1227 if (ac instanceof AccessibleComponent) { 1228 ((AccessibleComponent) ac).setFont(f); 1229 } else { 1230 Component c = getCurrentComponent(); 1231 if (c != null) { 1232 c.setFont(f); 1233 } 1234 } 1235 } 1236 1237 public FontMetrics getFontMetrics(Font f) { 1238 AccessibleContext ac = getCurrentAccessibleContext(); 1239 if (ac instanceof AccessibleComponent) { 1240 return ((AccessibleComponent) ac).getFontMetrics(f); 1241 } else { 1242 Component c = getCurrentComponent(); 1243 if (c != null) { 1244 return c.getFontMetrics(f); 1245 } else { 1246 return null; 1247 } 1248 } 1249 } 1250 1251 public boolean isEnabled() { 1252 AccessibleContext ac = getCurrentAccessibleContext(); 1253 if (ac instanceof AccessibleComponent) { 1254 return ((AccessibleComponent) ac).isEnabled(); 1255 } else { 1256 Component c = getCurrentComponent(); 1257 if (c != null) { 1258 return c.isEnabled(); 1259 } else { 1260 return false; 1261 } 1262 } 1263 } 1264 1265 public void setEnabled(boolean b) { 1266 AccessibleContext ac = getCurrentAccessibleContext(); 1267 if (ac instanceof AccessibleComponent) { 1268 ((AccessibleComponent) ac).setEnabled(b); 1269 } else { 1270 Component c = getCurrentComponent(); 1271 if (c != null) { 1272 c.setEnabled(b); 1273 } 1274 } 1275 } 1276 1277 public boolean isVisible() { 1278 AccessibleContext ac = getCurrentAccessibleContext(); 1279 if (ac instanceof AccessibleComponent) { 1280 return ((AccessibleComponent) ac).isVisible(); 1281 } else { 1282 Component c = getCurrentComponent(); 1283 if (c != null) { 1284 return c.isVisible(); 1285 } else { 1286 return false; 1287 } 1288 } 1289 } 1290 1291 public void setVisible(boolean b) { 1292 AccessibleContext ac = getCurrentAccessibleContext(); 1293 if (ac instanceof AccessibleComponent) { 1294 ((AccessibleComponent) ac).setVisible(b); 1295 } else { 1296 Component c = getCurrentComponent(); 1297 if (c != null) { 1298 c.setVisible(b); 1299 } 1300 } 1301 } 1302 1303 public boolean isShowing() { 1304 if (isVisible() && JTableHeader.this.isShowing()) { 1305 return true; 1306 } else { 1307 return false; 1308 } 1309 } 1310 1311 public boolean contains(Point p) { 1312 AccessibleContext ac = getCurrentAccessibleContext(); 1313 if (ac instanceof AccessibleComponent) { 1314 Rectangle r = ((AccessibleComponent) ac).getBounds(); 1315 return r.contains(p); 1316 } else { 1317 Component c = getCurrentComponent(); 1318 if (c != null) { 1319 Rectangle r = c.getBounds(); 1320 return r.contains(p); 1321 } else { 1322 return getBounds().contains(p); 1323 } 1324 } 1325 } 1326 1327 public Point getLocationOnScreen() { 1328 if (parent != null) { 1329 Point parentLocation = parent.getLocationOnScreen(); 1330 Point componentLocation = getLocation(); 1331 componentLocation.translate(parentLocation.x, parentLocation.y); 1332 return componentLocation; 1333 } else { 1334 return null; 1335 } 1336 } 1337 1338 public Point getLocation() { 1339 AccessibleContext ac = getCurrentAccessibleContext(); 1340 if (ac instanceof AccessibleComponent) { 1341 Rectangle r = ((AccessibleComponent) ac).getBounds(); 1342 return r.getLocation(); 1343 } else { 1344 Component c = getCurrentComponent(); 1345 if (c != null) { 1346 Rectangle r = c.getBounds(); 1347 return r.getLocation(); 1348 } else { 1349 return getBounds().getLocation(); 1350 } 1351 } 1352 } 1353 1354 public void setLocation(Point p) { 1355 // if ((parent != null) && (parent.contains(p))) { 1356 // ensureIndexIsVisible(indexInParent); 1357 // } 1358 } 1359 1360 public Rectangle getBounds() { 1361 Rectangle r = table.getCellRect(-1, column, false); 1362 r.y = 0; 1363 return r; 1364 1365 // AccessibleContext ac = getCurrentAccessibleContext(); 1366 // if (ac instanceof AccessibleComponent) { 1367 // return ((AccessibleComponent) ac).getBounds(); 1368 // } else { 1369 // Component c = getCurrentComponent(); 1370 // if (c != null) { 1371 // return c.getBounds(); 1372 // } else { 1373 // Rectangle r = table.getCellRect(-1, column, false); 1374 // r.y = 0; 1375 // return r; 1376 // } 1377 // } 1378 } 1379 1380 public void setBounds(Rectangle r) { 1381 AccessibleContext ac = getCurrentAccessibleContext(); 1382 if (ac instanceof AccessibleComponent) { 1383 ((AccessibleComponent) ac).setBounds(r); 1384 } else { 1385 Component c = getCurrentComponent(); 1386 if (c != null) { 1387 c.setBounds(r); 1388 } 1389 } 1390 } 1391 1392 public Dimension getSize() { 1393 return getBounds().getSize(); 1394 // AccessibleContext ac = getCurrentAccessibleContext(); 1395 // if (ac instanceof AccessibleComponent) { 1396 // Rectangle r = ((AccessibleComponent) ac).getBounds(); 1397 // return r.getSize(); 1398 // } else { 1399 // Component c = getCurrentComponent(); 1400 // if (c != null) { 1401 // Rectangle r = c.getBounds(); 1402 // return r.getSize(); 1403 // } else { 1404 // return getBounds().getSize(); 1405 // } 1406 // } 1407 } 1408 1409 public void setSize (Dimension d) { 1410 AccessibleContext ac = getCurrentAccessibleContext(); 1411 if (ac instanceof AccessibleComponent) { 1412 ((AccessibleComponent) ac).setSize(d); 1413 } else { 1414 Component c = getCurrentComponent(); 1415 if (c != null) { 1416 c.setSize(d); 1417 } 1418 } 1419 } 1420 1421 public Accessible getAccessibleAt(Point p) { 1422 AccessibleContext ac = getCurrentAccessibleContext(); 1423 if (ac instanceof AccessibleComponent) { 1424 return ((AccessibleComponent) ac).getAccessibleAt(p); 1425 } else { 1426 return null; 1427 } 1428 } 1429 1430 @SuppressWarnings("deprecation") 1431 public boolean isFocusTraversable() { 1432 AccessibleContext ac = getCurrentAccessibleContext(); 1433 if (ac instanceof AccessibleComponent) { 1434 return ((AccessibleComponent) ac).isFocusTraversable(); 1435 } else { 1436 Component c = getCurrentComponent(); 1437 if (c != null) { 1438 return c.isFocusTraversable(); 1439 } else { 1440 return false; 1441 } 1442 } 1443 } 1444 1445 public void requestFocus() { 1446 AccessibleContext ac = getCurrentAccessibleContext(); 1447 if (ac instanceof AccessibleComponent) { 1448 ((AccessibleComponent) ac).requestFocus(); 1449 } else { 1450 Component c = getCurrentComponent(); 1451 if (c != null) { 1452 c.requestFocus(); 1453 } 1454 } 1455 } 1456 1457 public void addFocusListener(FocusListener l) { 1458 AccessibleContext ac = getCurrentAccessibleContext(); 1459 if (ac instanceof AccessibleComponent) { 1460 ((AccessibleComponent) ac).addFocusListener(l); 1461 } else { 1462 Component c = getCurrentComponent(); 1463 if (c != null) { 1464 c.addFocusListener(l); 1465 } 1466 } 1467 } 1468 1469 public void removeFocusListener(FocusListener l) { 1470 AccessibleContext ac = getCurrentAccessibleContext(); 1471 if (ac instanceof AccessibleComponent) { 1472 ((AccessibleComponent) ac).removeFocusListener(l); 1473 } else { 1474 Component c = getCurrentComponent(); 1475 if (c != null) { 1476 c.removeFocusListener(l); 1477 } 1478 } 1479 } 1480 1481 } // inner class AccessibleJTableHeaderElement 1482 1483 } // inner class AccessibleJTableHeader 1484 1485 } // End of Class JTableHeader