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