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