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  */
  25 package javax.swing.table;
  26 
  27 import sun.swing.table.DefaultTableCellHeaderRenderer;
  28 
  29 import java.util.*;
  30 import java.awt.*;
  31 import java.awt.event.*;
  32 
  33 import javax.swing.*;
  34 import javax.swing.event.*;
  35 import javax.swing.plaf.*;
  36 import javax.accessibility.*;
  37 
  38 import java.beans.BeanProperty;
  39 import java.beans.PropertyChangeListener;
  40 import java.beans.Transient;
  41 
  42 import java.io.ObjectOutputStream;
  43 import 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&trade;
  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
  62 public 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&amp;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&amp;F) object that renders this component.
 464      *
 465      * @param ui  the <code>TableHeaderUI</code> L&amp;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&amp;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&amp;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&trade;
 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