jdk/src/share/classes/javax/swing/JTabbedPane.java
changeset 2 90ce3da70b43
child 438 2ae294e4518c
child 466 6acd5ec503a8
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1997-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package javax.swing;
       
    27 
       
    28 import java.awt.*;
       
    29 import java.awt.event.*;
       
    30 import java.beans.*;
       
    31 import java.util.*;
       
    32 import javax.swing.event.*;
       
    33 import javax.swing.plaf.*;
       
    34 import javax.accessibility.*;
       
    35 import sun.swing.SwingUtilities2;
       
    36 
       
    37 import java.io.Serializable;
       
    38 import java.io.ObjectOutputStream;
       
    39 import java.io.ObjectInputStream;
       
    40 import java.io.IOException;
       
    41 
       
    42 /**
       
    43  * A component that lets the user switch between a group of components by
       
    44  * clicking on a tab with a given title and/or icon.
       
    45  * For examples and information on using tabbed panes see
       
    46  * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/tabbedpane.html">How to Use Tabbed Panes</a>,
       
    47  * a section in <em>The Java Tutorial</em>.
       
    48  * <p>
       
    49  * Tabs/components are added to a <code>TabbedPane</code> object by using the
       
    50  * <code>addTab</code> and <code>insertTab</code> methods.
       
    51  * A tab is represented by an index corresponding
       
    52  * to the position it was added in, where the first tab has an index equal to 0
       
    53  * and the last tab has an index equal to the tab count minus 1.
       
    54  * <p>
       
    55  * The <code>TabbedPane</code> uses a <code>SingleSelectionModel</code>
       
    56  * to represent the set
       
    57  * of tab indices and the currently selected index.  If the tab count
       
    58  * is greater than 0, then there will always be a selected index, which
       
    59  * by default will be initialized to the first tab.  If the tab count is
       
    60  * 0, then the selected index will be -1.
       
    61  * <p>
       
    62  * The tab title can be rendered by a <code>Component</code>.
       
    63  * For example, the following produce similar results:
       
    64  * <pre>
       
    65  * // In this case the look and feel renders the title for the tab.
       
    66  * tabbedPane.addTab("Tab", myComponent);
       
    67  * // In this case the custom component is responsible for rendering the
       
    68  * // title of the tab.
       
    69  * tabbedPane.addTab(null, myComponent);
       
    70  * tabbedPane.setTabComponentAt(0, new JLabel("Tab"));
       
    71  * </pre>
       
    72  * The latter is typically used when you want a more complex user interaction
       
    73  * that requires custom components on the tab.  For example, you could
       
    74  * provide a custom component that animates or one that has widgets for
       
    75  * closing the tab.
       
    76  * <p>
       
    77  * If you specify a component for a tab, the <code>JTabbedPane</code>
       
    78  * will not render any text or icon you have specified for the tab.
       
    79  * <p>
       
    80  * <strong>Note:</strong>
       
    81  * Do not use <code>setVisible</code> directly on a tab component to make it visible,
       
    82  * use <code>setSelectedComponent</code> or <code>setSelectedIndex</code> methods instead.
       
    83  * <p>
       
    84  * <strong>Warning:</strong> Swing is not thread safe. For more
       
    85  * information see <a
       
    86  * href="package-summary.html#threading">Swing's Threading
       
    87  * Policy</a>.
       
    88  * <p>
       
    89  * <strong>Warning:</strong>
       
    90  * Serialized objects of this class will not be compatible with
       
    91  * future Swing releases. The current serialization support is
       
    92  * appropriate for short term storage or RMI between applications running
       
    93  * the same version of Swing.  As of 1.4, support for long term storage
       
    94  * of all JavaBeans<sup><font size="-2">TM</font></sup>
       
    95  * has been added to the <code>java.beans</code> package.
       
    96  * Please see {@link java.beans.XMLEncoder}.
       
    97  *
       
    98  * @beaninfo
       
    99  *      attribute: isContainer true
       
   100  *    description: A component which provides a tab folder metaphor for
       
   101  *                 displaying one component from a set of components.
       
   102  *
       
   103  * @author Dave Moore
       
   104  * @author Philip Milne
       
   105  * @author Amy Fowler
       
   106  *
       
   107  * @see SingleSelectionModel
       
   108  */
       
   109 public class JTabbedPane extends JComponent
       
   110        implements Serializable, Accessible, SwingConstants {
       
   111 
       
   112    /**
       
   113     * The tab layout policy for wrapping tabs in multiple runs when all
       
   114     * tabs will not fit within a single run.
       
   115     */
       
   116     public static final int WRAP_TAB_LAYOUT = 0;
       
   117 
       
   118    /**
       
   119     * Tab layout policy for providing a subset of available tabs when all
       
   120     * the tabs will not fit within a single run.  If all the tabs do
       
   121     * not fit within a single run the look and feel will provide a way
       
   122     * to navigate to hidden tabs.
       
   123     */
       
   124     public static final int SCROLL_TAB_LAYOUT = 1;
       
   125 
       
   126 
       
   127     /**
       
   128      * @see #getUIClassID
       
   129      * @see #readObject
       
   130      */
       
   131     private static final String uiClassID = "TabbedPaneUI";
       
   132 
       
   133     /**
       
   134      * Where the tabs are placed.
       
   135      * @see #setTabPlacement
       
   136      */
       
   137     protected int tabPlacement = TOP;
       
   138 
       
   139     private int tabLayoutPolicy;
       
   140 
       
   141     /** The default selection model */
       
   142     protected SingleSelectionModel model;
       
   143 
       
   144     private boolean haveRegistered;
       
   145 
       
   146     /**
       
   147      * The <code>changeListener</code> is the listener we add to the
       
   148      * model.
       
   149      */
       
   150     protected ChangeListener changeListener = null;
       
   151 
       
   152     private final java.util.List<Page> pages;
       
   153 
       
   154     /* The component that is currently visible */
       
   155     private Component visComp = null;
       
   156 
       
   157     /**
       
   158      * Only one <code>ChangeEvent</code> is needed per <code>TabPane</code>
       
   159      * instance since the
       
   160      * event's only (read-only) state is the source property.  The source
       
   161      * of events generated here is always "this".
       
   162      */
       
   163     protected transient ChangeEvent changeEvent = null;
       
   164 
       
   165     /**
       
   166      * Creates an empty <code>TabbedPane</code> with a default
       
   167      * tab placement of <code>JTabbedPane.TOP</code>.
       
   168      * @see #addTab
       
   169      */
       
   170     public JTabbedPane() {
       
   171         this(TOP, WRAP_TAB_LAYOUT);
       
   172     }
       
   173 
       
   174     /**
       
   175      * Creates an empty <code>TabbedPane</code> with the specified tab placement
       
   176      * of either: <code>JTabbedPane.TOP</code>, <code>JTabbedPane.BOTTOM</code>,
       
   177      * <code>JTabbedPane.LEFT</code>, or <code>JTabbedPane.RIGHT</code>.
       
   178      *
       
   179      * @param tabPlacement the placement for the tabs relative to the content
       
   180      * @see #addTab
       
   181      */
       
   182     public JTabbedPane(int tabPlacement) {
       
   183         this(tabPlacement, WRAP_TAB_LAYOUT);
       
   184     }
       
   185 
       
   186     /**
       
   187      * Creates an empty <code>TabbedPane</code> with the specified tab placement
       
   188      * and tab layout policy.  Tab placement may be either:
       
   189      * <code>JTabbedPane.TOP</code>, <code>JTabbedPane.BOTTOM</code>,
       
   190      * <code>JTabbedPane.LEFT</code>, or <code>JTabbedPane.RIGHT</code>.
       
   191      * Tab layout policy may be either: <code>JTabbedPane.WRAP_TAB_LAYOUT</code>
       
   192      * or <code>JTabbedPane.SCROLL_TAB_LAYOUT</code>.
       
   193      *
       
   194      * @param tabPlacement the placement for the tabs relative to the content
       
   195      * @param tabLayoutPolicy the policy for laying out tabs when all tabs will not fit on one run
       
   196      * @exception IllegalArgumentException if tab placement or tab layout policy are not
       
   197      *            one of the above supported values
       
   198      * @see #addTab
       
   199      * @since 1.4
       
   200      */
       
   201     public JTabbedPane(int tabPlacement, int tabLayoutPolicy) {
       
   202         setTabPlacement(tabPlacement);
       
   203         setTabLayoutPolicy(tabLayoutPolicy);
       
   204         pages = new ArrayList<Page>(1);
       
   205         setModel(new DefaultSingleSelectionModel());
       
   206         updateUI();
       
   207     }
       
   208 
       
   209     /**
       
   210      * Returns the UI object which implements the L&F for this component.
       
   211      *
       
   212      * @return a <code>TabbedPaneUI</code> object
       
   213      * @see #setUI
       
   214      */
       
   215     public TabbedPaneUI getUI() {
       
   216         return (TabbedPaneUI)ui;
       
   217     }
       
   218 
       
   219     /**
       
   220      * Sets the UI object which implements the L&F for this component.
       
   221      *
       
   222      * @param ui the new UI object
       
   223      * @see UIDefaults#getUI
       
   224      * @beaninfo
       
   225      *        bound: true
       
   226      *       hidden: true
       
   227      *    attribute: visualUpdate true
       
   228      *  description: The UI object that implements the tabbedpane's LookAndFeel
       
   229      */
       
   230     public void setUI(TabbedPaneUI ui) {
       
   231         super.setUI(ui);
       
   232         // disabled icons are generated by LF so they should be unset here
       
   233         for (int i = 0; i < getTabCount(); i++) {
       
   234             Icon icon = pages.get(i).disabledIcon;
       
   235             if (icon instanceof UIResource) {
       
   236                 setDisabledIconAt(i, null);
       
   237             }
       
   238         }
       
   239     }
       
   240 
       
   241     /**
       
   242      * Resets the UI property to a value from the current look and feel.
       
   243      *
       
   244      * @see JComponent#updateUI
       
   245      */
       
   246     public void updateUI() {
       
   247         setUI((TabbedPaneUI)UIManager.getUI(this));
       
   248     }
       
   249 
       
   250 
       
   251     /**
       
   252      * Returns the name of the UI class that implements the
       
   253      * L&F for this component.
       
   254      *
       
   255      * @return the string "TabbedPaneUI"
       
   256      * @see JComponent#getUIClassID
       
   257      * @see UIDefaults#getUI
       
   258      */
       
   259     public String getUIClassID() {
       
   260         return uiClassID;
       
   261     }
       
   262 
       
   263 
       
   264     /**
       
   265      * We pass <code>ModelChanged</code> events along to the listeners with
       
   266      * the tabbedpane (instead of the model itself) as the event source.
       
   267      */
       
   268     protected class ModelListener implements ChangeListener, Serializable {
       
   269         public void stateChanged(ChangeEvent e) {
       
   270             fireStateChanged();
       
   271         }
       
   272     }
       
   273 
       
   274     /**
       
   275      * Subclasses that want to handle <code>ChangeEvents</code> differently
       
   276      * can override this to return a subclass of <code>ModelListener</code> or
       
   277      * another <code>ChangeListener</code> implementation.
       
   278      *
       
   279      * @see #fireStateChanged
       
   280      */
       
   281     protected ChangeListener createChangeListener() {
       
   282         return new ModelListener();
       
   283     }
       
   284 
       
   285     /**
       
   286      * Adds a <code>ChangeListener</code> to this tabbedpane.
       
   287      *
       
   288      * @param l the <code>ChangeListener</code> to add
       
   289      * @see #fireStateChanged
       
   290      * @see #removeChangeListener
       
   291      */
       
   292     public void addChangeListener(ChangeListener l) {
       
   293         listenerList.add(ChangeListener.class, l);
       
   294     }
       
   295 
       
   296     /**
       
   297      * Removes a <code>ChangeListener</code> from this tabbedpane.
       
   298      *
       
   299      * @param l the <code>ChangeListener</code> to remove
       
   300      * @see #fireStateChanged
       
   301      * @see #addChangeListener
       
   302      */
       
   303     public void removeChangeListener(ChangeListener l) {
       
   304         listenerList.remove(ChangeListener.class, l);
       
   305     }
       
   306 
       
   307    /**
       
   308      * Returns an array of all the <code>ChangeListener</code>s added
       
   309      * to this <code>JTabbedPane</code> with <code>addChangeListener</code>.
       
   310      *
       
   311      * @return all of the <code>ChangeListener</code>s added or an empty
       
   312      *         array if no listeners have been added
       
   313      * @since 1.4
       
   314      */
       
   315     public ChangeListener[] getChangeListeners() {
       
   316         return (ChangeListener[])listenerList.getListeners(
       
   317                 ChangeListener.class);
       
   318     }
       
   319 
       
   320     /**
       
   321      * Sends a {@code ChangeEvent}, with this {@code JTabbedPane} as the source,
       
   322      * to each registered listener. This method is called each time there is
       
   323      * a change to either the selected index or the selected tab in the
       
   324      * {@code JTabbedPane}. Usually, the selected index and selected tab change
       
   325      * together. However, there are some cases, such as tab addition, where the
       
   326      * selected index changes and the same tab remains selected. There are other
       
   327      * cases, such as deleting the selected tab, where the index remains the
       
   328      * same, but a new tab moves to that index. Events are fired for all of
       
   329      * these cases.
       
   330      *
       
   331      * @see #addChangeListener
       
   332      * @see EventListenerList
       
   333      */
       
   334     protected void fireStateChanged() {
       
   335         /* --- Begin code to deal with visibility --- */
       
   336 
       
   337         /* This code deals with changing the visibility of components to
       
   338          * hide and show the contents for the selected tab. It duplicates
       
   339          * logic already present in BasicTabbedPaneUI, logic that is
       
   340          * processed during the layout pass. This code exists to allow
       
   341          * developers to do things that are quite difficult to accomplish
       
   342          * with the previous model of waiting for the layout pass to process
       
   343          * visibility changes; such as requesting focus on the new visible
       
   344          * component.
       
   345          *
       
   346          * For the average code, using the typical JTabbedPane methods,
       
   347          * all visibility changes will now be processed here. However,
       
   348          * the code in BasicTabbedPaneUI still exists, for the purposes
       
   349          * of backward compatibility. Therefore, when making changes to
       
   350          * this code, ensure that the BasicTabbedPaneUI code is kept in
       
   351          * synch.
       
   352          */
       
   353 
       
   354         int selIndex = getSelectedIndex();
       
   355 
       
   356         /* if the selection is now nothing */
       
   357         if (selIndex < 0) {
       
   358             /* if there was a previous visible component */
       
   359             if (visComp != null && visComp.isVisible()) {
       
   360                 /* make it invisible */
       
   361                 visComp.setVisible(false);
       
   362             }
       
   363 
       
   364             /* now there's no visible component */
       
   365             visComp = null;
       
   366 
       
   367         /* else - the selection is now something */
       
   368         } else {
       
   369             /* Fetch the component for the new selection */
       
   370             Component newComp = getComponentAt(selIndex);
       
   371 
       
   372             /* if the new component is non-null and different */
       
   373             if (newComp != null && newComp != visComp) {
       
   374                 boolean shouldChangeFocus = false;
       
   375 
       
   376                 /* Note: the following (clearing of the old visible component)
       
   377                  * is inside this if-statement for good reason: Tabbed pane
       
   378                  * should continue to show the previously visible component
       
   379                  * if there is no component for the chosen tab.
       
   380                  */
       
   381 
       
   382                 /* if there was a previous visible component */
       
   383                 if (visComp != null) {
       
   384                     shouldChangeFocus =
       
   385                         (SwingUtilities.findFocusOwner(visComp) != null);
       
   386 
       
   387                     /* if it's still visible */
       
   388                     if (visComp.isVisible()) {
       
   389                         /* make it invisible */
       
   390                         visComp.setVisible(false);
       
   391                     }
       
   392                 }
       
   393 
       
   394                 if (!newComp.isVisible()) {
       
   395                     newComp.setVisible(true);
       
   396                 }
       
   397 
       
   398                 if (shouldChangeFocus) {
       
   399                     SwingUtilities2.tabbedPaneChangeFocusTo(newComp);
       
   400                 }
       
   401 
       
   402                 visComp = newComp;
       
   403             } /* else - the visible component shouldn't changed */
       
   404         }
       
   405 
       
   406         /* --- End code to deal with visibility --- */
       
   407 
       
   408         // Guaranteed to return a non-null array
       
   409         Object[] listeners = listenerList.getListenerList();
       
   410         // Process the listeners last to first, notifying
       
   411         // those that are interested in this event
       
   412         for (int i = listeners.length-2; i>=0; i-=2) {
       
   413             if (listeners[i]==ChangeListener.class) {
       
   414                 // Lazily create the event:
       
   415                 if (changeEvent == null)
       
   416                     changeEvent = new ChangeEvent(this);
       
   417                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
       
   418             }
       
   419         }
       
   420     }
       
   421 
       
   422     /**
       
   423      * Returns the model associated with this tabbedpane.
       
   424      *
       
   425      * @see #setModel
       
   426      */
       
   427     public SingleSelectionModel getModel() {
       
   428         return model;
       
   429     }
       
   430 
       
   431     /**
       
   432      * Sets the model to be used with this tabbedpane.
       
   433      *
       
   434      * @param model the model to be used
       
   435      * @see #getModel
       
   436      * @beaninfo
       
   437      *       bound: true
       
   438      * description: The tabbedpane's SingleSelectionModel.
       
   439      */
       
   440     public void setModel(SingleSelectionModel model) {
       
   441         SingleSelectionModel oldModel = getModel();
       
   442 
       
   443         if (oldModel != null) {
       
   444             oldModel.removeChangeListener(changeListener);
       
   445             changeListener = null;
       
   446         }
       
   447 
       
   448         this.model = model;
       
   449 
       
   450         if (model != null) {
       
   451             changeListener = createChangeListener();
       
   452             model.addChangeListener(changeListener);
       
   453         }
       
   454 
       
   455         firePropertyChange("model", oldModel, model);
       
   456         repaint();
       
   457     }
       
   458 
       
   459     /**
       
   460      * Returns the placement of the tabs for this tabbedpane.
       
   461      * @see #setTabPlacement
       
   462      */
       
   463     public int getTabPlacement() {
       
   464         return tabPlacement;
       
   465     }
       
   466 
       
   467     /**
       
   468      * Sets the tab placement for this tabbedpane.
       
   469      * Possible values are:<ul>
       
   470      * <li><code>JTabbedPane.TOP</code>
       
   471      * <li><code>JTabbedPane.BOTTOM</code>
       
   472      * <li><code>JTabbedPane.LEFT</code>
       
   473      * <li><code>JTabbedPane.RIGHT</code>
       
   474      * </ul>
       
   475      * The default value, if not set, is <code>SwingConstants.TOP</code>.
       
   476      *
       
   477      * @param tabPlacement the placement for the tabs relative to the content
       
   478      * @exception IllegalArgumentException if tab placement value isn't one
       
   479      *                          of the above valid values
       
   480      *
       
   481      * @beaninfo
       
   482      *    preferred: true
       
   483      *        bound: true
       
   484      *    attribute: visualUpdate true
       
   485      *         enum: TOP JTabbedPane.TOP
       
   486      *               LEFT JTabbedPane.LEFT
       
   487      *               BOTTOM JTabbedPane.BOTTOM
       
   488      *               RIGHT JTabbedPane.RIGHT
       
   489      *  description: The tabbedpane's tab placement.
       
   490      *
       
   491      */
       
   492     public void setTabPlacement(int tabPlacement) {
       
   493         if (tabPlacement != TOP && tabPlacement != LEFT &&
       
   494             tabPlacement != BOTTOM && tabPlacement != RIGHT) {
       
   495             throw new IllegalArgumentException("illegal tab placement: must be TOP, BOTTOM, LEFT, or RIGHT");
       
   496         }
       
   497         if (this.tabPlacement != tabPlacement) {
       
   498             int oldValue = this.tabPlacement;
       
   499             this.tabPlacement = tabPlacement;
       
   500             firePropertyChange("tabPlacement", oldValue, tabPlacement);
       
   501             revalidate();
       
   502             repaint();
       
   503         }
       
   504     }
       
   505 
       
   506     /**
       
   507      * Returns the policy used by the tabbedpane to layout the tabs when all the
       
   508      * tabs will not fit within a single run.
       
   509      * @see #setTabLayoutPolicy
       
   510      * @since 1.4
       
   511      */
       
   512     public int getTabLayoutPolicy() {
       
   513         return tabLayoutPolicy;
       
   514     }
       
   515 
       
   516    /**
       
   517      * Sets the policy which the tabbedpane will use in laying out the tabs
       
   518      * when all the tabs will not fit within a single run.
       
   519      * Possible values are:
       
   520      * <ul>
       
   521      * <li><code>JTabbedPane.WRAP_TAB_LAYOUT</code>
       
   522      * <li><code>JTabbedPane.SCROLL_TAB_LAYOUT</code>
       
   523      * </ul>
       
   524      *
       
   525      * The default value, if not set by the UI, is <code>JTabbedPane.WRAP_TAB_LAYOUT</code>.
       
   526      * <p>
       
   527      * Some look and feels might only support a subset of the possible
       
   528      * layout policies, in which case the value of this property may be
       
   529      * ignored.
       
   530      *
       
   531      * @param tabLayoutPolicy the policy used to layout the tabs
       
   532      * @exception IllegalArgumentException if layoutPolicy value isn't one
       
   533      *                          of the above valid values
       
   534      * @see #getTabLayoutPolicy
       
   535      * @since 1.4
       
   536      *
       
   537      * @beaninfo
       
   538      *    preferred: true
       
   539      *        bound: true
       
   540      *    attribute: visualUpdate true
       
   541      *         enum: WRAP_TAB_LAYOUT JTabbedPane.WRAP_TAB_LAYOUT
       
   542      *               SCROLL_TAB_LAYOUT JTabbedPane.SCROLL_TAB_LAYOUT
       
   543      *  description: The tabbedpane's policy for laying out the tabs
       
   544      *
       
   545      */
       
   546     public void setTabLayoutPolicy(int tabLayoutPolicy) {
       
   547         if (tabLayoutPolicy != WRAP_TAB_LAYOUT && tabLayoutPolicy != SCROLL_TAB_LAYOUT) {
       
   548             throw new IllegalArgumentException("illegal tab layout policy: must be WRAP_TAB_LAYOUT or SCROLL_TAB_LAYOUT");
       
   549         }
       
   550         if (this.tabLayoutPolicy != tabLayoutPolicy) {
       
   551             int oldValue = this.tabLayoutPolicy;
       
   552             this.tabLayoutPolicy = tabLayoutPolicy;
       
   553             firePropertyChange("tabLayoutPolicy", oldValue, tabLayoutPolicy);
       
   554             revalidate();
       
   555             repaint();
       
   556         }
       
   557     }
       
   558 
       
   559     /**
       
   560      * Returns the currently selected index for this tabbedpane.
       
   561      * Returns -1 if there is no currently selected tab.
       
   562      *
       
   563      * @return the index of the selected tab
       
   564      * @see #setSelectedIndex
       
   565      */
       
   566     public int getSelectedIndex() {
       
   567         return model.getSelectedIndex();
       
   568     }
       
   569 
       
   570     /**
       
   571      * Sets the selected index for this tabbedpane. The index must be
       
   572      * a valid tab index or -1, which indicates that no tab should be selected
       
   573      * (can also be used when there are no tabs in the tabbedpane).  If a -1
       
   574      * value is specified when the tabbedpane contains one or more tabs, then
       
   575      * the results will be implementation defined.
       
   576      *
       
   577      * @param index  the index to be selected
       
   578      * @exception IndexOutOfBoundsException if index is out of range
       
   579      *            (index < -1 || index >= tab count)
       
   580      *
       
   581      * @see #getSelectedIndex
       
   582      * @see SingleSelectionModel#setSelectedIndex
       
   583      * @beaninfo
       
   584      *   preferred: true
       
   585      * description: The tabbedpane's selected tab index.
       
   586      */
       
   587     public void setSelectedIndex(int index) {
       
   588         if (index != -1) {
       
   589             checkIndex(index);
       
   590         }
       
   591         setSelectedIndexImpl(index, true);
       
   592     }
       
   593 
       
   594 
       
   595     private void setSelectedIndexImpl(int index, boolean doAccessibleChanges) {
       
   596         int oldIndex = model.getSelectedIndex();
       
   597         Page oldPage = null, newPage = null;
       
   598         String oldName = null;
       
   599 
       
   600         doAccessibleChanges = doAccessibleChanges && (oldIndex != index);
       
   601 
       
   602         if (doAccessibleChanges) {
       
   603             if (accessibleContext != null) {
       
   604                 oldName = accessibleContext.getAccessibleName();
       
   605             }
       
   606 
       
   607             if (oldIndex >= 0) {
       
   608                 oldPage = pages.get(oldIndex);
       
   609             }
       
   610 
       
   611             if (index >= 0) {
       
   612                 newPage = pages.get(index);
       
   613             }
       
   614         }
       
   615 
       
   616         model.setSelectedIndex(index);
       
   617 
       
   618         if (doAccessibleChanges) {
       
   619             changeAccessibleSelection(oldPage, oldName, newPage);
       
   620         }
       
   621     }
       
   622 
       
   623     private void changeAccessibleSelection(Page oldPage, String oldName, Page newPage) {
       
   624         if (accessibleContext == null) {
       
   625             return;
       
   626         }
       
   627 
       
   628         if (oldPage != null) {
       
   629             oldPage.firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
       
   630                                        AccessibleState.SELECTED, null);
       
   631         }
       
   632 
       
   633         if (newPage != null) {
       
   634             newPage.firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
       
   635                                        null, AccessibleState.SELECTED);
       
   636         }
       
   637 
       
   638         accessibleContext.firePropertyChange(
       
   639             AccessibleContext.ACCESSIBLE_NAME_PROPERTY,
       
   640             oldName,
       
   641             accessibleContext.getAccessibleName());
       
   642     }
       
   643 
       
   644     /**
       
   645      * Returns the currently selected component for this tabbedpane.
       
   646      * Returns <code>null</code> if there is no currently selected tab.
       
   647      *
       
   648      * @return the component corresponding to the selected tab
       
   649      * @see #setSelectedComponent
       
   650      */
       
   651     public Component getSelectedComponent() {
       
   652         int index = getSelectedIndex();
       
   653         if (index == -1) {
       
   654             return null;
       
   655         }
       
   656         return getComponentAt(index);
       
   657     }
       
   658 
       
   659     /**
       
   660      * Sets the selected component for this tabbedpane.  This
       
   661      * will automatically set the <code>selectedIndex</code> to the index
       
   662      * corresponding to the specified component.
       
   663      *
       
   664      * @exception IllegalArgumentException if component not found in tabbed
       
   665      *          pane
       
   666      * @see #getSelectedComponent
       
   667      * @beaninfo
       
   668      *   preferred: true
       
   669      * description: The tabbedpane's selected component.
       
   670      */
       
   671     public void setSelectedComponent(Component c) {
       
   672         int index = indexOfComponent(c);
       
   673         if (index != -1) {
       
   674             setSelectedIndex(index);
       
   675         } else {
       
   676             throw new IllegalArgumentException("component not found in tabbed pane");
       
   677         }
       
   678     }
       
   679 
       
   680     /**
       
   681      * Inserts a new tab for the given component, at the given index,
       
   682      * represented by the given title and/or icon, either of which may
       
   683      * be {@code null}.
       
   684      *
       
   685      * @param title the title to be displayed on the tab
       
   686      * @param icon the icon to be displayed on the tab
       
   687      * @param component the component to be displayed when this tab is clicked.
       
   688      * @param tip the tooltip to be displayed for this tab
       
   689      * @param index the position to insert this new tab
       
   690      *       ({@code > 0 and <= getTabCount()})
       
   691      *
       
   692      * @throws IndexOutOfBoundsException if the index is out of range
       
   693      *         ({@code < 0 or > getTabCount()})
       
   694      *
       
   695      * @see #addTab
       
   696      * @see #removeTabAt
       
   697      */
       
   698     public void insertTab(String title, Icon icon, Component component, String tip, int index) {
       
   699         int newIndex = index;
       
   700 
       
   701         // If component already exists, remove corresponding
       
   702         // tab so that new tab gets added correctly
       
   703         // Note: we are allowing component=null because of compatibility,
       
   704         // but we really should throw an exception because much of the
       
   705         // rest of the JTabbedPane implementation isn't designed to deal
       
   706         // with null components for tabs.
       
   707         int removeIndex = indexOfComponent(component);
       
   708         if (component != null && removeIndex != -1) {
       
   709             removeTabAt(removeIndex);
       
   710             if (newIndex > removeIndex) {
       
   711                 newIndex--;
       
   712             }
       
   713         }
       
   714 
       
   715         int selectedIndex = getSelectedIndex();
       
   716 
       
   717         pages.add(
       
   718             newIndex,
       
   719             new Page(this, title != null? title : "", icon, null, component, tip));
       
   720 
       
   721 
       
   722         if (component != null) {
       
   723             addImpl(component, null, -1);
       
   724             component.setVisible(false);
       
   725         } else {
       
   726             firePropertyChange("indexForNullComponent", -1, index);
       
   727         }
       
   728 
       
   729         if (pages.size() == 1) {
       
   730             setSelectedIndex(0);
       
   731         }
       
   732 
       
   733         if (selectedIndex >= newIndex) {
       
   734             setSelectedIndexImpl(selectedIndex + 1, false);
       
   735         }
       
   736 
       
   737         if (!haveRegistered && tip != null) {
       
   738             ToolTipManager.sharedInstance().registerComponent(this);
       
   739             haveRegistered = true;
       
   740         }
       
   741 
       
   742         if (accessibleContext != null) {
       
   743             accessibleContext.firePropertyChange(
       
   744                     AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
       
   745                     null, component);
       
   746         }
       
   747         revalidate();
       
   748         repaint();
       
   749     }
       
   750 
       
   751     /**
       
   752      * Adds a <code>component</code> and <code>tip</code>
       
   753      * represented by a <code>title</code> and/or <code>icon</code>,
       
   754      * either of which can be <code>null</code>.
       
   755      * Cover method for <code>insertTab</code>.
       
   756      *
       
   757      * @param title the title to be displayed in this tab
       
   758      * @param icon the icon to be displayed in this tab
       
   759      * @param component the component to be displayed when this tab is clicked
       
   760      * @param tip the tooltip to be displayed for this tab
       
   761      *
       
   762      * @see #insertTab
       
   763      * @see #removeTabAt
       
   764      */
       
   765     public void addTab(String title, Icon icon, Component component, String tip) {
       
   766         insertTab(title, icon, component, tip, pages.size());
       
   767     }
       
   768 
       
   769     /**
       
   770      * Adds a <code>component</code> represented by a <code>title</code>
       
   771      * and/or <code>icon</code>, either of which can be <code>null</code>.
       
   772      * Cover method for <code>insertTab</code>.
       
   773      *
       
   774      * @param title the title to be displayed in this tab
       
   775      * @param icon the icon to be displayed in this tab
       
   776      * @param component the component to be displayed when this tab is clicked
       
   777      *
       
   778      * @see #insertTab
       
   779      * @see #removeTabAt
       
   780      */
       
   781     public void addTab(String title, Icon icon, Component component) {
       
   782         insertTab(title, icon, component, null, pages.size());
       
   783     }
       
   784 
       
   785     /**
       
   786      * Adds a <code>component</code> represented by a <code>title</code>
       
   787      * and no icon.
       
   788      * Cover method for <code>insertTab</code>.
       
   789      *
       
   790      * @param title the title to be displayed in this tab
       
   791      * @param component the component to be displayed when this tab is clicked
       
   792      *
       
   793      * @see #insertTab
       
   794      * @see #removeTabAt
       
   795      */
       
   796     public void addTab(String title, Component component) {
       
   797         insertTab(title, null, component, null, pages.size());
       
   798     }
       
   799 
       
   800     /**
       
   801      * Adds a <code>component</code> with a tab title defaulting to
       
   802      * the name of the component which is the result of calling
       
   803      * <code>component.getName</code>.
       
   804      * Cover method for <code>insertTab</code>.
       
   805      *
       
   806      * @param component the component to be displayed when this tab is clicked
       
   807      * @return the component
       
   808      *
       
   809      * @see #insertTab
       
   810      * @see #removeTabAt
       
   811      */
       
   812     public Component add(Component component) {
       
   813         if (!(component instanceof UIResource)) {
       
   814             addTab(component.getName(), component);
       
   815         } else {
       
   816             super.add(component);
       
   817         }
       
   818         return component;
       
   819     }
       
   820 
       
   821     /**
       
   822      * Adds a <code>component</code> with the specified tab title.
       
   823      * Cover method for <code>insertTab</code>.
       
   824      *
       
   825      * @param title the title to be displayed in this tab
       
   826      * @param component the component to be displayed when this tab is clicked
       
   827      * @return the component
       
   828      *
       
   829      * @see #insertTab
       
   830      * @see #removeTabAt
       
   831      */
       
   832     public Component add(String title, Component component) {
       
   833         if (!(component instanceof UIResource)) {
       
   834             addTab(title, component);
       
   835         } else {
       
   836             super.add(title, component);
       
   837         }
       
   838         return component;
       
   839     }
       
   840 
       
   841     /**
       
   842      * Adds a <code>component</code> at the specified tab index with a tab
       
   843      * title defaulting to the name of the component.
       
   844      * Cover method for <code>insertTab</code>.
       
   845      *
       
   846      * @param component the component to be displayed when this tab is clicked
       
   847      * @param index the position to insert this new tab
       
   848      * @return the component
       
   849      *
       
   850      * @see #insertTab
       
   851      * @see #removeTabAt
       
   852      */
       
   853     public Component add(Component component, int index) {
       
   854         if (!(component instanceof UIResource)) {
       
   855             // Container.add() interprets -1 as "append", so convert
       
   856             // the index appropriately to be handled by the vector
       
   857             insertTab(component.getName(), null, component, null,
       
   858                       index == -1? getTabCount() : index);
       
   859         } else {
       
   860             super.add(component, index);
       
   861         }
       
   862         return component;
       
   863     }
       
   864 
       
   865     /**
       
   866      * Adds a <code>component</code> to the tabbed pane.
       
   867      * If <code>constraints</code> is a <code>String</code> or an
       
   868      * <code>Icon</code>, it will be used for the tab title,
       
   869      * otherwise the component's name will be used as the tab title.
       
   870      * Cover method for <code>insertTab</code>.
       
   871      *
       
   872      * @param component the component to be displayed when this tab is clicked
       
   873      * @param constraints the object to be displayed in the tab
       
   874      *
       
   875      * @see #insertTab
       
   876      * @see #removeTabAt
       
   877      */
       
   878     public void add(Component component, Object constraints) {
       
   879         if (!(component instanceof UIResource)) {
       
   880             if (constraints instanceof String) {
       
   881                 addTab((String)constraints, component);
       
   882             } else if (constraints instanceof Icon) {
       
   883                 addTab(null, (Icon)constraints, component);
       
   884             } else {
       
   885                 add(component);
       
   886             }
       
   887         } else {
       
   888             super.add(component, constraints);
       
   889         }
       
   890     }
       
   891 
       
   892     /**
       
   893      * Adds a <code>component</code> at the specified tab index.
       
   894      * If <code>constraints</code> is a <code>String</code> or an
       
   895      * <code>Icon</code>, it will be used for the tab title,
       
   896      * otherwise the component's name will be used as the tab title.
       
   897      * Cover method for <code>insertTab</code>.
       
   898      *
       
   899      * @param component the component to be displayed when this tab is clicked
       
   900      * @param constraints the object to be displayed in the tab
       
   901      * @param index the position to insert this new tab
       
   902      *
       
   903      * @see #insertTab
       
   904      * @see #removeTabAt
       
   905      */
       
   906     public void add(Component component, Object constraints, int index) {
       
   907         if (!(component instanceof UIResource)) {
       
   908 
       
   909             Icon icon = constraints instanceof Icon? (Icon)constraints : null;
       
   910             String title = constraints instanceof String? (String)constraints : null;
       
   911             // Container.add() interprets -1 as "append", so convert
       
   912             // the index appropriately to be handled by the vector
       
   913             insertTab(title, icon, component, null, index == -1? getTabCount() : index);
       
   914         } else {
       
   915             super.add(component, constraints, index);
       
   916         }
       
   917     }
       
   918 
       
   919     /**
       
   920      * Removes the tab at <code>index</code>.
       
   921      * After the component associated with <code>index</code> is removed,
       
   922      * its visibility is reset to true to ensure it will be visible
       
   923      * if added to other containers.
       
   924      * @param index the index of the tab to be removed
       
   925      * @exception IndexOutOfBoundsException if index is out of range
       
   926      *            (index < 0 || index >= tab count)
       
   927      *
       
   928      * @see #addTab
       
   929      * @see #insertTab
       
   930      */
       
   931     public void removeTabAt(int index) {
       
   932         checkIndex(index);
       
   933 
       
   934         Component component = getComponentAt(index);
       
   935         boolean shouldChangeFocus = false;
       
   936         int selected = getSelectedIndex();
       
   937         String oldName = null;
       
   938 
       
   939         /* if we're about to remove the visible component */
       
   940         if (component == visComp) {
       
   941             shouldChangeFocus = (SwingUtilities.findFocusOwner(visComp) != null);
       
   942             visComp = null;
       
   943         }
       
   944 
       
   945         if (accessibleContext != null) {
       
   946             /* if we're removing the selected page */
       
   947             if (index == selected) {
       
   948                 /* fire an accessible notification that it's unselected */
       
   949                 pages.get(index).firePropertyChange(
       
   950                     AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
       
   951                     AccessibleState.SELECTED, null);
       
   952 
       
   953                 oldName = accessibleContext.getAccessibleName();
       
   954             }
       
   955 
       
   956             accessibleContext.firePropertyChange(
       
   957                     AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
       
   958                     component, null);
       
   959         }
       
   960 
       
   961         // Force the tabComponent to be cleaned up.
       
   962         setTabComponentAt(index, null);
       
   963         pages.remove(index);
       
   964 
       
   965         // NOTE 4/15/2002 (joutwate):
       
   966         // This fix is implemented using client properties since there is
       
   967         // currently no IndexPropertyChangeEvent.  Once
       
   968         // IndexPropertyChangeEvents have been added this code should be
       
   969         // modified to use it.
       
   970         putClientProperty("__index_to_remove__", new Integer(index));
       
   971 
       
   972         /* if the selected tab is after the removal */
       
   973         if (selected > index) {
       
   974             setSelectedIndexImpl(selected - 1, false);
       
   975 
       
   976         /* if the selected tab is the last tab */
       
   977         } else if (selected >= getTabCount()) {
       
   978             setSelectedIndexImpl(selected - 1, false);
       
   979             Page newSelected = (selected != 0)
       
   980                 ? pages.get(selected - 1)
       
   981                 : null;
       
   982 
       
   983             changeAccessibleSelection(null, oldName, newSelected);
       
   984 
       
   985         /* selected index hasn't changed, but the associated tab has */
       
   986         } else if (index == selected) {
       
   987             fireStateChanged();
       
   988             changeAccessibleSelection(null, oldName, pages.get(index));
       
   989         }
       
   990 
       
   991         // We can't assume the tab indices correspond to the
       
   992         // container's children array indices, so make sure we
       
   993         // remove the correct child!
       
   994         if (component != null) {
       
   995             Component components[] = getComponents();
       
   996             for (int i = components.length; --i >= 0; ) {
       
   997                 if (components[i] == component) {
       
   998                     super.remove(i);
       
   999                     component.setVisible(true);
       
  1000                     break;
       
  1001                 }
       
  1002             }
       
  1003         }
       
  1004 
       
  1005         if (shouldChangeFocus) {
       
  1006             SwingUtilities2.tabbedPaneChangeFocusTo(getSelectedComponent());
       
  1007         }
       
  1008 
       
  1009         revalidate();
       
  1010         repaint();
       
  1011     }
       
  1012 
       
  1013     /**
       
  1014      * Removes the specified <code>Component</code> from the
       
  1015      * <code>JTabbedPane</code>. The method does nothing
       
  1016      * if the <code>component</code> is null.
       
  1017      *
       
  1018      * @param component the component to remove from the tabbedpane
       
  1019      * @see #addTab
       
  1020      * @see #removeTabAt
       
  1021      */
       
  1022     public void remove(Component component) {
       
  1023         int index = indexOfComponent(component);
       
  1024         if (index != -1) {
       
  1025             removeTabAt(index);
       
  1026         } else {
       
  1027             // Container#remove(comp) invokes Container#remove(int)
       
  1028             // so make sure JTabbedPane#remove(int) isn't called here
       
  1029             Component children[] = getComponents();
       
  1030             for (int i=0; i < children.length; i++) {
       
  1031                 if (component == children[i]) {
       
  1032                     super.remove(i);
       
  1033                     break;
       
  1034                 }
       
  1035             }
       
  1036         }
       
  1037     }
       
  1038 
       
  1039     /**
       
  1040      * Removes the tab and component which corresponds to the specified index.
       
  1041      *
       
  1042      * @param index the index of the component to remove from the
       
  1043      *          <code>tabbedpane</code>
       
  1044      * @exception IndexOutOfBoundsException if index is out of range
       
  1045      *            (index < 0 || index >= tab count)
       
  1046      * @see #addTab
       
  1047      * @see #removeTabAt
       
  1048      */
       
  1049     public void remove(int index) {
       
  1050         removeTabAt(index);
       
  1051     }
       
  1052 
       
  1053     /**
       
  1054      * Removes all the tabs and their corresponding components
       
  1055      * from the <code>tabbedpane</code>.
       
  1056      *
       
  1057      * @see #addTab
       
  1058      * @see #removeTabAt
       
  1059      */
       
  1060     public void removeAll() {
       
  1061         setSelectedIndexImpl(-1, true);
       
  1062 
       
  1063         int tabCount = getTabCount();
       
  1064         // We invoke removeTabAt for each tab, otherwise we may end up
       
  1065         // removing Components added by the UI.
       
  1066         while (tabCount-- > 0) {
       
  1067             removeTabAt(tabCount);
       
  1068         }
       
  1069     }
       
  1070 
       
  1071     /**
       
  1072      * Returns the number of tabs in this <code>tabbedpane</code>.
       
  1073      *
       
  1074      * @return an integer specifying the number of tabbed pages
       
  1075      */
       
  1076     public int getTabCount() {
       
  1077         return pages.size();
       
  1078     }
       
  1079 
       
  1080     /**
       
  1081      * Returns the number of tab runs currently used to display
       
  1082      * the tabs.
       
  1083      * @return an integer giving the number of rows if the
       
  1084      *          <code>tabPlacement</code>
       
  1085      *          is <code>TOP</code> or <code>BOTTOM</code>
       
  1086      *          and the number of columns if
       
  1087      *          <code>tabPlacement</code>
       
  1088      *          is <code>LEFT</code> or <code>RIGHT</code>,
       
  1089      *          or 0 if there is no UI set on this <code>tabbedpane</code>
       
  1090      */
       
  1091     public int getTabRunCount() {
       
  1092         if (ui != null) {
       
  1093             return ((TabbedPaneUI)ui).getTabRunCount(this);
       
  1094         }
       
  1095         return 0;
       
  1096     }
       
  1097 
       
  1098 
       
  1099 // Getters for the Pages
       
  1100 
       
  1101     /**
       
  1102      * Returns the tab title at <code>index</code>.
       
  1103      *
       
  1104      * @param index  the index of the item being queried
       
  1105      * @return the title at <code>index</code>
       
  1106      * @exception IndexOutOfBoundsException if index is out of range
       
  1107      *            (index < 0 || index >= tab count)
       
  1108      * @see #setTitleAt
       
  1109      */
       
  1110     public String getTitleAt(int index) {
       
  1111         return pages.get(index).title;
       
  1112     }
       
  1113 
       
  1114     /**
       
  1115      * Returns the tab icon at <code>index</code>.
       
  1116      *
       
  1117      * @param index  the index of the item being queried
       
  1118      * @return the icon at <code>index</code>
       
  1119      * @exception IndexOutOfBoundsException if index is out of range
       
  1120      *            (index < 0 || index >= tab count)
       
  1121      *
       
  1122      * @see #setIconAt
       
  1123      */
       
  1124     public Icon getIconAt(int index) {
       
  1125         return pages.get(index).icon;
       
  1126     }
       
  1127 
       
  1128     /**
       
  1129      * Returns the tab disabled icon at <code>index</code>.
       
  1130      * If the tab disabled icon doesn't exist at <code>index</code>
       
  1131      * this will forward the call to the look and feel to construct
       
  1132      * an appropriate disabled Icon from the corresponding enabled
       
  1133      * Icon. Some look and feels might not render the disabled Icon,
       
  1134      * in which case it won't be created.
       
  1135      *
       
  1136      * @param index  the index of the item being queried
       
  1137      * @return the icon at <code>index</code>
       
  1138      * @exception IndexOutOfBoundsException if index is out of range
       
  1139      *            (index < 0 || index >= tab count)
       
  1140      *
       
  1141      * @see #setDisabledIconAt
       
  1142      */
       
  1143     public Icon getDisabledIconAt(int index) {
       
  1144         Page page = pages.get(index);
       
  1145         if (page.disabledIcon == null) {
       
  1146             page.disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, page.icon);
       
  1147         }
       
  1148         return page.disabledIcon;
       
  1149     }
       
  1150 
       
  1151     /**
       
  1152      * Returns the tab tooltip text at <code>index</code>.
       
  1153      *
       
  1154      * @param index  the index of the item being queried
       
  1155      * @return a string containing the tool tip text at <code>index</code>
       
  1156      * @exception IndexOutOfBoundsException if index is out of range
       
  1157      *            (index < 0 || index >= tab count)
       
  1158      *
       
  1159      * @see #setToolTipTextAt
       
  1160      * @since 1.3
       
  1161      */
       
  1162     public String getToolTipTextAt(int index) {
       
  1163         return pages.get(index).tip;
       
  1164     }
       
  1165 
       
  1166     /**
       
  1167      * Returns the tab background color at <code>index</code>.
       
  1168      *
       
  1169      * @param index  the index of the item being queried
       
  1170      * @return the <code>Color</code> of the tab background at
       
  1171      *          <code>index</code>
       
  1172      * @exception IndexOutOfBoundsException if index is out of range
       
  1173      *            (index < 0 || index >= tab count)
       
  1174      *
       
  1175      * @see #setBackgroundAt
       
  1176      */
       
  1177     public Color getBackgroundAt(int index) {
       
  1178         return pages.get(index).getBackground();
       
  1179     }
       
  1180 
       
  1181     /**
       
  1182      * Returns the tab foreground color at <code>index</code>.
       
  1183      *
       
  1184      * @param index  the index of the item being queried
       
  1185      * @return the <code>Color</code> of the tab foreground at
       
  1186      *          <code>index</code>
       
  1187      * @exception IndexOutOfBoundsException if index is out of range
       
  1188      *            (index < 0 || index >= tab count)
       
  1189      *
       
  1190      * @see #setForegroundAt
       
  1191      */
       
  1192     public Color getForegroundAt(int index) {
       
  1193         return pages.get(index).getForeground();
       
  1194     }
       
  1195 
       
  1196     /**
       
  1197      * Returns whether or not the tab at <code>index</code> is
       
  1198      * currently enabled.
       
  1199      *
       
  1200      * @param index  the index of the item being queried
       
  1201      * @return true if the tab at <code>index</code> is enabled;
       
  1202      *          false otherwise
       
  1203      * @exception IndexOutOfBoundsException if index is out of range
       
  1204      *            (index < 0 || index >= tab count)
       
  1205      *
       
  1206      * @see #setEnabledAt
       
  1207      */
       
  1208     public boolean isEnabledAt(int index) {
       
  1209         return pages.get(index).isEnabled();
       
  1210     }
       
  1211 
       
  1212     /**
       
  1213      * Returns the component at <code>index</code>.
       
  1214      *
       
  1215      * @param index  the index of the item being queried
       
  1216      * @return the <code>Component</code> at <code>index</code>
       
  1217      * @exception IndexOutOfBoundsException if index is out of range
       
  1218      *            (index < 0 || index >= tab count)
       
  1219      *
       
  1220      * @see #setComponentAt
       
  1221      */
       
  1222     public Component getComponentAt(int index) {
       
  1223         return pages.get(index).component;
       
  1224     }
       
  1225 
       
  1226     /**
       
  1227      * Returns the keyboard mnemonic for accessing the specified tab.
       
  1228      * The mnemonic is the key which when combined with the look and feel's
       
  1229      * mouseless modifier (usually Alt) will activate the specified
       
  1230      * tab.
       
  1231      *
       
  1232      * @since 1.4
       
  1233      * @param tabIndex the index of the tab that the mnemonic refers to
       
  1234      * @return the key code which represents the mnemonic;
       
  1235      *         -1 if a mnemonic is not specified for the tab
       
  1236      * @exception IndexOutOfBoundsException if index is out of range
       
  1237      *            (<code>tabIndex</code> &lt; 0 ||
       
  1238      *              <code>tabIndex</code> &gt;= tab count)
       
  1239      * @see #setDisplayedMnemonicIndexAt(int,int)
       
  1240      * @see #setMnemonicAt(int,int)
       
  1241      */
       
  1242     public int getMnemonicAt(int tabIndex) {
       
  1243         checkIndex(tabIndex);
       
  1244 
       
  1245         Page page = pages.get(tabIndex);
       
  1246         return page.getMnemonic();
       
  1247     }
       
  1248 
       
  1249     /**
       
  1250      * Returns the character, as an index, that the look and feel should
       
  1251      * provide decoration for as representing the mnemonic character.
       
  1252      *
       
  1253      * @since 1.4
       
  1254      * @param tabIndex the index of the tab that the mnemonic refers to
       
  1255      * @return index representing mnemonic character if one exists;
       
  1256      *    otherwise returns -1
       
  1257      * @exception IndexOutOfBoundsException if index is out of range
       
  1258      *            (<code>tabIndex</code> &lt; 0 ||
       
  1259      *              <code>tabIndex</code> &gt;= tab count)
       
  1260      * @see #setDisplayedMnemonicIndexAt(int,int)
       
  1261      * @see #setMnemonicAt(int,int)
       
  1262      */
       
  1263     public int getDisplayedMnemonicIndexAt(int tabIndex) {
       
  1264         checkIndex(tabIndex);
       
  1265 
       
  1266         Page page = pages.get(tabIndex);
       
  1267         return page.getDisplayedMnemonicIndex();
       
  1268     }
       
  1269 
       
  1270     /**
       
  1271      * Returns the tab bounds at <code>index</code>.  If the tab at
       
  1272      * this index is not currently visible in the UI, then returns
       
  1273      * <code>null</code>.
       
  1274      * If there is no UI set on this <code>tabbedpane</code>,
       
  1275      * then returns <code>null</code>.
       
  1276      *
       
  1277      * @param index the index to be queried
       
  1278      * @return a <code>Rectangle</code> containing the tab bounds at
       
  1279      *          <code>index</code>, or <code>null</code> if tab at
       
  1280      *          <code>index</code> is not currently visible in the UI,
       
  1281      *          or if there is no UI set on this <code>tabbedpane</code>
       
  1282      * @exception IndexOutOfBoundsException if index is out of range
       
  1283      *            (index &lt; 0 || index &gt;= tab count)
       
  1284      */
       
  1285     public Rectangle getBoundsAt(int index) {
       
  1286         checkIndex(index);
       
  1287         if (ui != null) {
       
  1288             return ((TabbedPaneUI)ui).getTabBounds(this, index);
       
  1289         }
       
  1290         return null;
       
  1291     }
       
  1292 
       
  1293 
       
  1294 // Setters for the Pages
       
  1295 
       
  1296     /**
       
  1297      * Sets the title at <code>index</code> to <code>title</code> which
       
  1298      * can be <code>null</code>.
       
  1299      * The title is not shown if a tab component for this tab was specified.
       
  1300      * An internal exception is raised if there is no tab at that index.
       
  1301      *
       
  1302      * @param index the tab index where the title should be set
       
  1303      * @param title the title to be displayed in the tab
       
  1304      * @exception IndexOutOfBoundsException if index is out of range
       
  1305      *            (index &lt; 0 || index &gt;= tab count)
       
  1306      *
       
  1307      * @see #getTitleAt
       
  1308      * @see #setTabComponentAt
       
  1309      * @beaninfo
       
  1310      *    preferred: true
       
  1311      *    attribute: visualUpdate true
       
  1312      *  description: The title at the specified tab index.
       
  1313      */
       
  1314     public void setTitleAt(int index, String title) {
       
  1315         Page page = pages.get(index);
       
  1316         String oldTitle =page.title;
       
  1317         page.title = title;
       
  1318 
       
  1319         if (oldTitle != title) {
       
  1320             firePropertyChange("indexForTitle", -1, index);
       
  1321         }
       
  1322         page.updateDisplayedMnemonicIndex();
       
  1323         if ((oldTitle != title) && (accessibleContext != null)) {
       
  1324             accessibleContext.firePropertyChange(
       
  1325                     AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
       
  1326                     oldTitle, title);
       
  1327         }
       
  1328         if (title == null || oldTitle == null ||
       
  1329             !title.equals(oldTitle)) {
       
  1330             revalidate();
       
  1331             repaint();
       
  1332         }
       
  1333     }
       
  1334 
       
  1335     /**
       
  1336      * Sets the icon at <code>index</code> to <code>icon</code> which can be
       
  1337      * <code>null</code>. This does not set disabled icon at <code>icon</code>.
       
  1338      * If the new Icon is different than the current Icon and disabled icon
       
  1339      * is not explicitly set, the LookAndFeel will be asked to generate a disabled
       
  1340      * Icon. To explicitly set disabled icon, use <code>setDisableIconAt()</code>.
       
  1341      * The icon is not shown if a tab component for this tab was specified.
       
  1342      * An internal exception is raised if there is no tab at that index.
       
  1343      *
       
  1344      * @param index the tab index where the icon should be set
       
  1345      * @param icon the icon to be displayed in the tab
       
  1346      * @exception IndexOutOfBoundsException if index is out of range
       
  1347      *            (index < 0 || index >= tab count)
       
  1348      *
       
  1349      * @see #setDisabledIconAt
       
  1350      * @see #getIconAt
       
  1351      * @see #getDisabledIconAt
       
  1352      * @see #setTabComponentAt
       
  1353      * @beaninfo
       
  1354      *    preferred: true
       
  1355      *    attribute: visualUpdate true
       
  1356      *  description: The icon at the specified tab index.
       
  1357      */
       
  1358     public void setIconAt(int index, Icon icon) {
       
  1359         Page page = pages.get(index);
       
  1360         Icon oldIcon = page.icon;
       
  1361         if (icon != oldIcon) {
       
  1362             page.icon = icon;
       
  1363 
       
  1364             /* If the default icon has really changed and we had
       
  1365              * generated the disabled icon for this page, then
       
  1366              * clear the disabledIcon field of the page.
       
  1367              */
       
  1368             if (page.disabledIcon instanceof UIResource) {
       
  1369                 page.disabledIcon = null;
       
  1370             }
       
  1371 
       
  1372             // Fire the accessibility Visible data change
       
  1373             if (accessibleContext != null) {
       
  1374                 accessibleContext.firePropertyChange(
       
  1375                         AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
       
  1376                         oldIcon, icon);
       
  1377             }
       
  1378             revalidate();
       
  1379             repaint();
       
  1380         }
       
  1381     }
       
  1382 
       
  1383     /**
       
  1384      * Sets the disabled icon at <code>index</code> to <code>icon</code>
       
  1385      * which can be <code>null</code>.
       
  1386      * An internal exception is raised if there is no tab at that index.
       
  1387      *
       
  1388      * @param index the tab index where the disabled icon should be set
       
  1389      * @param disabledIcon the icon to be displayed in the tab when disabled
       
  1390      * @exception IndexOutOfBoundsException if index is out of range
       
  1391      *            (index &lt; 0 || index &gt;= tab count)
       
  1392      *
       
  1393      * @see #getDisabledIconAt
       
  1394      * @beaninfo
       
  1395      *    preferred: true
       
  1396      *    attribute: visualUpdate true
       
  1397      *  description: The disabled icon at the specified tab index.
       
  1398      */
       
  1399     public void setDisabledIconAt(int index, Icon disabledIcon) {
       
  1400         Icon oldIcon = pages.get(index).disabledIcon;
       
  1401         pages.get(index).disabledIcon = disabledIcon;
       
  1402         if (disabledIcon != oldIcon && !isEnabledAt(index)) {
       
  1403             revalidate();
       
  1404             repaint();
       
  1405         }
       
  1406     }
       
  1407 
       
  1408     /**
       
  1409      * Sets the tooltip text at <code>index</code> to <code>toolTipText</code>
       
  1410      * which can be <code>null</code>.
       
  1411      * An internal exception is raised if there is no tab at that index.
       
  1412      *
       
  1413      * @param index the tab index where the tooltip text should be set
       
  1414      * @param toolTipText the tooltip text to be displayed for the tab
       
  1415      * @exception IndexOutOfBoundsException if index is out of range
       
  1416      *            (index &lt; 0 || index &gt;= tab count)
       
  1417      *
       
  1418      * @see #getToolTipTextAt
       
  1419      * @beaninfo
       
  1420      *    preferred: true
       
  1421      *  description: The tooltip text at the specified tab index.
       
  1422      * @since 1.3
       
  1423      */
       
  1424     public void setToolTipTextAt(int index, String toolTipText) {
       
  1425         String oldToolTipText = pages.get(index).tip;
       
  1426         pages.get(index).tip = toolTipText;
       
  1427 
       
  1428         if ((oldToolTipText != toolTipText) && (accessibleContext != null)) {
       
  1429             accessibleContext.firePropertyChange(
       
  1430                     AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
       
  1431                     oldToolTipText, toolTipText);
       
  1432         }
       
  1433         if (!haveRegistered && toolTipText != null) {
       
  1434             ToolTipManager.sharedInstance().registerComponent(this);
       
  1435             haveRegistered = true;
       
  1436         }
       
  1437     }
       
  1438 
       
  1439     /**
       
  1440      * Sets the background color at <code>index</code> to
       
  1441      * <code>background</code>
       
  1442      * which can be <code>null</code>, in which case the tab's background color
       
  1443      * will default to the background color of the <code>tabbedpane</code>.
       
  1444      * An internal exception is raised if there is no tab at that index.
       
  1445      * @param index the tab index where the background should be set
       
  1446      * @param background the color to be displayed in the tab's background
       
  1447      * @exception IndexOutOfBoundsException if index is out of range
       
  1448      *            (index &lt; 0 || index &gt;= tab count)
       
  1449      *
       
  1450      * @see #getBackgroundAt
       
  1451      * @beaninfo
       
  1452      *    preferred: true
       
  1453      *    attribute: visualUpdate true
       
  1454      *  description: The background color at the specified tab index.
       
  1455      */
       
  1456     public void setBackgroundAt(int index, Color background) {
       
  1457         Color oldBg = pages.get(index).background;
       
  1458         pages.get(index).setBackground(background);
       
  1459         if (background == null || oldBg == null ||
       
  1460             !background.equals(oldBg)) {
       
  1461             Rectangle tabBounds = getBoundsAt(index);
       
  1462             if (tabBounds != null) {
       
  1463                 repaint(tabBounds);
       
  1464             }
       
  1465         }
       
  1466     }
       
  1467 
       
  1468     /**
       
  1469      * Sets the foreground color at <code>index</code> to
       
  1470      * <code>foreground</code> which can be
       
  1471      * <code>null</code>, in which case the tab's foreground color
       
  1472      * will default to the foreground color of this <code>tabbedpane</code>.
       
  1473      * An internal exception is raised if there is no tab at that index.
       
  1474      *
       
  1475      * @param index the tab index where the foreground should be set
       
  1476      * @param foreground the color to be displayed as the tab's foreground
       
  1477      * @exception IndexOutOfBoundsException if index is out of range
       
  1478      *            (index &lt; 0 || index &gt;= tab count)
       
  1479      *
       
  1480      * @see #getForegroundAt
       
  1481      * @beaninfo
       
  1482      *    preferred: true
       
  1483      *    attribute: visualUpdate true
       
  1484      *  description: The foreground color at the specified tab index.
       
  1485      */
       
  1486     public void setForegroundAt(int index, Color foreground) {
       
  1487         Color oldFg = pages.get(index).foreground;
       
  1488         pages.get(index).setForeground(foreground);
       
  1489         if (foreground == null || oldFg == null ||
       
  1490             !foreground.equals(oldFg)) {
       
  1491             Rectangle tabBounds = getBoundsAt(index);
       
  1492             if (tabBounds != null) {
       
  1493                 repaint(tabBounds);
       
  1494             }
       
  1495         }
       
  1496     }
       
  1497 
       
  1498     /**
       
  1499      * Sets whether or not the tab at <code>index</code> is enabled.
       
  1500      * An internal exception is raised if there is no tab at that index.
       
  1501      *
       
  1502      * @param index the tab index which should be enabled/disabled
       
  1503      * @param enabled whether or not the tab should be enabled
       
  1504      * @exception IndexOutOfBoundsException if index is out of range
       
  1505      *            (index &lt; 0 || index &gt;= tab count)
       
  1506      *
       
  1507      * @see #isEnabledAt
       
  1508      */
       
  1509     public void setEnabledAt(int index, boolean enabled) {
       
  1510         boolean oldEnabled = pages.get(index).isEnabled();
       
  1511         pages.get(index).setEnabled(enabled);
       
  1512         if (enabled != oldEnabled) {
       
  1513             revalidate();
       
  1514             repaint();
       
  1515         }
       
  1516     }
       
  1517 
       
  1518     /**
       
  1519      * Sets the component at <code>index</code> to <code>component</code>.
       
  1520      * An internal exception is raised if there is no tab at that index.
       
  1521      *
       
  1522      * @param index the tab index where this component is being placed
       
  1523      * @param component the component for the tab
       
  1524      * @exception IndexOutOfBoundsException if index is out of range
       
  1525      *            (index &lt; 0 || index &gt;= tab count)
       
  1526      *
       
  1527      * @see #getComponentAt
       
  1528      * @beaninfo
       
  1529      *    attribute: visualUpdate true
       
  1530      *  description: The component at the specified tab index.
       
  1531      */
       
  1532     public void setComponentAt(int index, Component component) {
       
  1533         Page page = pages.get(index);
       
  1534         if (component != page.component) {
       
  1535             boolean shouldChangeFocus = false;
       
  1536 
       
  1537             if (page.component != null) {
       
  1538                 shouldChangeFocus =
       
  1539                     (SwingUtilities.findFocusOwner(page.component) != null);
       
  1540 
       
  1541                 // REMIND(aim): this is really silly;
       
  1542                 // why not if (page.component.getParent() == this) remove(component)
       
  1543                 synchronized(getTreeLock()) {
       
  1544                     int count = getComponentCount();
       
  1545                     Component children[] = getComponents();
       
  1546                     for (int i = 0; i < count; i++) {
       
  1547                         if (children[i] == page.component) {
       
  1548                             super.remove(i);
       
  1549                         }
       
  1550                     }
       
  1551                 }
       
  1552             }
       
  1553 
       
  1554             page.component = component;
       
  1555             boolean selectedPage = (getSelectedIndex() == index);
       
  1556 
       
  1557             if (selectedPage) {
       
  1558                 this.visComp = component;
       
  1559             }
       
  1560 
       
  1561             if (component != null) {
       
  1562                 component.setVisible(selectedPage);
       
  1563                 addImpl(component, null, -1);
       
  1564 
       
  1565                 if (shouldChangeFocus) {
       
  1566                     SwingUtilities2.tabbedPaneChangeFocusTo(component);
       
  1567                 }
       
  1568             } else {
       
  1569                 repaint();
       
  1570             }
       
  1571 
       
  1572             revalidate();
       
  1573         }
       
  1574     }
       
  1575 
       
  1576     /**
       
  1577      * Provides a hint to the look and feel as to which character in the
       
  1578      * text should be decorated to represent the mnemonic. Not all look and
       
  1579      * feels may support this. A value of -1 indicates either there is
       
  1580      * no mnemonic for this tab, or you do not wish the mnemonic to be
       
  1581      * displayed for this tab.
       
  1582      * <p>
       
  1583      * The value of this is updated as the properties relating to the
       
  1584      * mnemonic change (such as the mnemonic itself, the text...).
       
  1585      * You should only ever have to call this if
       
  1586      * you do not wish the default character to be underlined. For example, if
       
  1587      * the text at tab index 3 was 'Apple Price', with a mnemonic of 'p',
       
  1588      * and you wanted the 'P'
       
  1589      * to be decorated, as 'Apple <u>P</u>rice', you would have to invoke
       
  1590      * <code>setDisplayedMnemonicIndex(3, 6)</code> after invoking
       
  1591      * <code>setMnemonicAt(3, KeyEvent.VK_P)</code>.
       
  1592      * <p>Note that it is the programmer's responsibility to ensure
       
  1593      * that each tab has a unique mnemonic or unpredictable results may
       
  1594      * occur.
       
  1595      *
       
  1596      * @since 1.4
       
  1597      * @param tabIndex the index of the tab that the mnemonic refers to
       
  1598      * @param mnemonicIndex index into the <code>String</code> to underline
       
  1599      * @exception IndexOutOfBoundsException if <code>tabIndex</code> is
       
  1600      *            out of range (<code>tabIndex < 0 || tabIndex >= tab
       
  1601      *            count</code>)
       
  1602      * @exception IllegalArgumentException will be thrown if
       
  1603      *            <code>mnemonicIndex</code> is &gt;= length of the tab
       
  1604      *            title , or &lt; -1
       
  1605      * @see #setMnemonicAt(int,int)
       
  1606      * @see #getDisplayedMnemonicIndexAt(int)
       
  1607      *
       
  1608      * @beaninfo
       
  1609      *        bound: true
       
  1610      *    attribute: visualUpdate true
       
  1611      *  description: the index into the String to draw the keyboard character
       
  1612      *               mnemonic at
       
  1613      */
       
  1614     public void setDisplayedMnemonicIndexAt(int tabIndex, int mnemonicIndex) {
       
  1615         checkIndex(tabIndex);
       
  1616 
       
  1617         Page page = pages.get(tabIndex);
       
  1618 
       
  1619         page.setDisplayedMnemonicIndex(mnemonicIndex);
       
  1620     }
       
  1621 
       
  1622     /**
       
  1623      * Sets the keyboard mnemonic for accessing the specified tab.
       
  1624      * The mnemonic is the key which when combined with the look and feel's
       
  1625      * mouseless modifier (usually Alt) will activate the specified
       
  1626      * tab.
       
  1627      * <p>
       
  1628      * A mnemonic must correspond to a single key on the keyboard
       
  1629      * and should be specified using one of the <code>VK_XXX</code>
       
  1630      * keycodes defined in <code>java.awt.event.KeyEvent</code>.
       
  1631      * Mnemonics are case-insensitive, therefore a key event
       
  1632      * with the corresponding keycode would cause the button to be
       
  1633      * activated whether or not the Shift modifier was pressed.
       
  1634      * <p>
       
  1635      * This will update the displayed mnemonic property for the specified
       
  1636      * tab.
       
  1637      *
       
  1638      * @since 1.4
       
  1639      * @param tabIndex the index of the tab that the mnemonic refers to
       
  1640      * @param mnemonic the key code which represents the mnemonic
       
  1641      * @exception IndexOutOfBoundsException if <code>tabIndex</code> is out
       
  1642      *            of range (<code>tabIndex < 0 || tabIndex >= tab count</code>)
       
  1643      * @see #getMnemonicAt(int)
       
  1644      * @see #setDisplayedMnemonicIndexAt(int,int)
       
  1645      *
       
  1646      * @beaninfo
       
  1647      *        bound: true
       
  1648      *    attribute: visualUpdate true
       
  1649      *  description: The keyboard mnenmonic, as a KeyEvent VK constant,
       
  1650      *               for the specified tab
       
  1651      */
       
  1652     public void setMnemonicAt(int tabIndex, int mnemonic) {
       
  1653         checkIndex(tabIndex);
       
  1654 
       
  1655         Page page = pages.get(tabIndex);
       
  1656         page.setMnemonic(mnemonic);
       
  1657 
       
  1658         firePropertyChange("mnemonicAt", null, null);
       
  1659     }
       
  1660 
       
  1661 // end of Page setters
       
  1662 
       
  1663     /**
       
  1664      * Returns the first tab index with a given <code>title</code>,  or
       
  1665      * -1 if no tab has this title.
       
  1666      *
       
  1667      * @param title the title for the tab
       
  1668      * @return the first tab index which matches <code>title</code>, or
       
  1669      *          -1 if no tab has this title
       
  1670      */
       
  1671     public int indexOfTab(String title) {
       
  1672         for(int i = 0; i < getTabCount(); i++) {
       
  1673             if (getTitleAt(i).equals(title == null? "" : title)) {
       
  1674                 return i;
       
  1675             }
       
  1676         }
       
  1677         return -1;
       
  1678     }
       
  1679 
       
  1680     /**
       
  1681      * Returns the first tab index with a given <code>icon</code>,
       
  1682      * or -1 if no tab has this icon.
       
  1683      *
       
  1684      * @param icon the icon for the tab
       
  1685      * @return the first tab index which matches <code>icon</code>,
       
  1686      *          or -1 if no tab has this icon
       
  1687      */
       
  1688     public int indexOfTab(Icon icon) {
       
  1689         for(int i = 0; i < getTabCount(); i++) {
       
  1690             Icon tabIcon = getIconAt(i);
       
  1691             if ((tabIcon != null && tabIcon.equals(icon)) ||
       
  1692                 (tabIcon == null && tabIcon == icon)) {
       
  1693                 return i;
       
  1694             }
       
  1695         }
       
  1696         return -1;
       
  1697     }
       
  1698 
       
  1699     /**
       
  1700      * Returns the index of the tab for the specified component.
       
  1701      * Returns -1 if there is no tab for this component.
       
  1702      *
       
  1703      * @param component the component for the tab
       
  1704      * @return the first tab which matches this component, or -1
       
  1705      *          if there is no tab for this component
       
  1706      */
       
  1707     public int indexOfComponent(Component component) {
       
  1708         for(int i = 0; i < getTabCount(); i++) {
       
  1709             Component c = getComponentAt(i);
       
  1710             if ((c != null && c.equals(component)) ||
       
  1711                 (c == null && c == component)) {
       
  1712                 return i;
       
  1713             }
       
  1714         }
       
  1715         return -1;
       
  1716     }
       
  1717 
       
  1718     /**
       
  1719      * Returns the tab index corresponding to the tab whose bounds
       
  1720      * intersect the specified location.  Returns -1 if no tab
       
  1721      * intersects the location.
       
  1722      *
       
  1723      * @param x the x location relative to this tabbedpane
       
  1724      * @param y the y location relative to this tabbedpane
       
  1725      * @return the tab index which intersects the location, or
       
  1726      *         -1 if no tab intersects the location
       
  1727      * @since 1.4
       
  1728      */
       
  1729     public int indexAtLocation(int x, int y) {
       
  1730         if (ui != null) {
       
  1731             return ((TabbedPaneUI)ui).tabForCoordinate(this, x, y);
       
  1732         }
       
  1733         return -1;
       
  1734     }
       
  1735 
       
  1736 
       
  1737     /**
       
  1738      * Returns the tooltip text for the component determined by the
       
  1739      * mouse event location.
       
  1740      *
       
  1741      * @param event  the <code>MouseEvent</code> that tells where the
       
  1742      *          cursor is lingering
       
  1743      * @return the <code>String</code> containing the tooltip text
       
  1744      */
       
  1745     public String getToolTipText(MouseEvent event) {
       
  1746         if (ui != null) {
       
  1747             int index = ((TabbedPaneUI)ui).tabForCoordinate(this, event.getX(), event.getY());
       
  1748 
       
  1749             if (index != -1) {
       
  1750                 return pages.get(index).tip;
       
  1751             }
       
  1752         }
       
  1753         return super.getToolTipText(event);
       
  1754     }
       
  1755 
       
  1756     private void checkIndex(int index) {
       
  1757         if (index < 0 || index >= pages.size()) {
       
  1758             throw new IndexOutOfBoundsException("Index: "+index+", Tab count: "+pages.size());
       
  1759         }
       
  1760     }
       
  1761 
       
  1762 
       
  1763     /**
       
  1764      * See <code>readObject</code> and <code>writeObject</code> in
       
  1765      * <code>JComponent</code> for more
       
  1766      * information about serialization in Swing.
       
  1767      */
       
  1768     private void writeObject(ObjectOutputStream s) throws IOException {
       
  1769         s.defaultWriteObject();
       
  1770         if (getUIClassID().equals(uiClassID)) {
       
  1771             byte count = JComponent.getWriteObjCounter(this);
       
  1772             JComponent.setWriteObjCounter(this, --count);
       
  1773             if (count == 0 && ui != null) {
       
  1774                 ui.installUI(this);
       
  1775             }
       
  1776         }
       
  1777     }
       
  1778 
       
  1779     /* Called from the <code>JComponent</code>'s
       
  1780      * <code>EnableSerializationFocusListener</code> to
       
  1781      * do any Swing-specific pre-serialization configuration.
       
  1782      */
       
  1783     void compWriteObjectNotify() {
       
  1784         super.compWriteObjectNotify();
       
  1785         // If ToolTipText != null, then the tooltip has already been
       
  1786         // unregistered by JComponent.compWriteObjectNotify()
       
  1787         if (getToolTipText() == null && haveRegistered) {
       
  1788             ToolTipManager.sharedInstance().unregisterComponent(this);
       
  1789         }
       
  1790     }
       
  1791 
       
  1792     /**
       
  1793      * See <code>readObject</code> and <code>writeObject</code> in
       
  1794      * <code>JComponent</code> for more
       
  1795      * information about serialization in Swing.
       
  1796      */
       
  1797     private void readObject(ObjectInputStream s)
       
  1798         throws IOException, ClassNotFoundException
       
  1799     {
       
  1800         s.defaultReadObject();
       
  1801         if ((ui != null) && (getUIClassID().equals(uiClassID))) {
       
  1802             ui.installUI(this);
       
  1803         }
       
  1804         // If ToolTipText != null, then the tooltip has already been
       
  1805         // registered by JComponent.readObject()
       
  1806         if (getToolTipText() == null && haveRegistered) {
       
  1807             ToolTipManager.sharedInstance().registerComponent(this);
       
  1808         }
       
  1809     }
       
  1810 
       
  1811 
       
  1812     /**
       
  1813      * Returns a string representation of this <code>JTabbedPane</code>.
       
  1814      * This method
       
  1815      * is intended to be used only for debugging purposes, and the
       
  1816      * content and format of the returned string may vary between
       
  1817      * implementations. The returned string may be empty but may not
       
  1818      * be <code>null</code>.
       
  1819      *
       
  1820      * @return  a string representation of this JTabbedPane.
       
  1821      */
       
  1822     protected String paramString() {
       
  1823         String tabPlacementString;
       
  1824         if (tabPlacement == TOP) {
       
  1825             tabPlacementString = "TOP";
       
  1826         } else if (tabPlacement == BOTTOM) {
       
  1827             tabPlacementString = "BOTTOM";
       
  1828         } else if (tabPlacement == LEFT) {
       
  1829             tabPlacementString = "LEFT";
       
  1830         } else if (tabPlacement == RIGHT) {
       
  1831             tabPlacementString = "RIGHT";
       
  1832         } else tabPlacementString = "";
       
  1833         String haveRegisteredString = (haveRegistered ?
       
  1834                                        "true" : "false");
       
  1835 
       
  1836         return super.paramString() +
       
  1837         ",haveRegistered=" + haveRegisteredString +
       
  1838         ",tabPlacement=" + tabPlacementString;
       
  1839     }
       
  1840 
       
  1841 /////////////////
       
  1842 // Accessibility support
       
  1843 ////////////////
       
  1844 
       
  1845     /**
       
  1846      * Gets the AccessibleContext associated with this JTabbedPane.
       
  1847      * For tabbed panes, the AccessibleContext takes the form of an
       
  1848      * AccessibleJTabbedPane.
       
  1849      * A new AccessibleJTabbedPane instance is created if necessary.
       
  1850      *
       
  1851      * @return an AccessibleJTabbedPane that serves as the
       
  1852      *         AccessibleContext of this JTabbedPane
       
  1853      */
       
  1854     public AccessibleContext getAccessibleContext() {
       
  1855         if (accessibleContext == null) {
       
  1856             accessibleContext = new AccessibleJTabbedPane();
       
  1857 
       
  1858             // initialize AccessibleContext for the existing pages
       
  1859             int count = getTabCount();
       
  1860             for (int i = 0; i < count; i++) {
       
  1861                 pages.get(i).initAccessibleContext();
       
  1862             }
       
  1863         }
       
  1864         return accessibleContext;
       
  1865     }
       
  1866 
       
  1867     /**
       
  1868      * This class implements accessibility support for the
       
  1869      * <code>JTabbedPane</code> class.  It provides an implementation of the
       
  1870      * Java Accessibility API appropriate to tabbed pane user-interface
       
  1871      * elements.
       
  1872      * <p>
       
  1873      * <strong>Warning:</strong>
       
  1874      * Serialized objects of this class will not be compatible with
       
  1875      * future Swing releases. The current serialization support is
       
  1876      * appropriate for short term storage or RMI between applications running
       
  1877      * the same version of Swing.  As of 1.4, support for long term storage
       
  1878      * of all JavaBeans<sup><font size="-2">TM</font></sup>
       
  1879      * has been added to the <code>java.beans</code> package.
       
  1880      * Please see {@link java.beans.XMLEncoder}.
       
  1881      */
       
  1882     protected class AccessibleJTabbedPane extends AccessibleJComponent
       
  1883         implements AccessibleSelection, ChangeListener {
       
  1884 
       
  1885         /**
       
  1886          * Returns the accessible name of this object, or {@code null} if
       
  1887          * there is no accessible name.
       
  1888          *
       
  1889          * @return the accessible name of this object, nor {@code null}.
       
  1890          * @since 1.6
       
  1891          */
       
  1892         public String getAccessibleName() {
       
  1893             if (accessibleName != null) {
       
  1894                 return accessibleName;
       
  1895             }
       
  1896 
       
  1897             String cp = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
       
  1898 
       
  1899             if (cp != null) {
       
  1900                 return cp;
       
  1901             }
       
  1902 
       
  1903             int index = getSelectedIndex();
       
  1904 
       
  1905             if (index >= 0) {
       
  1906                 return pages.get(index).getAccessibleName();
       
  1907             }
       
  1908 
       
  1909             return super.getAccessibleName();
       
  1910         }
       
  1911 
       
  1912         /**
       
  1913          *  Constructs an AccessibleJTabbedPane
       
  1914          */
       
  1915         public AccessibleJTabbedPane() {
       
  1916             super();
       
  1917             JTabbedPane.this.model.addChangeListener(this);
       
  1918         }
       
  1919 
       
  1920         public void stateChanged(ChangeEvent e) {
       
  1921             Object o = e.getSource();
       
  1922             firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
       
  1923                                null, o);
       
  1924         }
       
  1925 
       
  1926         /**
       
  1927          * Get the role of this object.
       
  1928          *
       
  1929          * @return an instance of AccessibleRole describing the role of
       
  1930          *          the object
       
  1931          */
       
  1932         public AccessibleRole getAccessibleRole() {
       
  1933             return AccessibleRole.PAGE_TAB_LIST;
       
  1934         }
       
  1935 
       
  1936         /**
       
  1937          * Returns the number of accessible children in the object.
       
  1938          *
       
  1939          * @return the number of accessible children in the object.
       
  1940          */
       
  1941         public int getAccessibleChildrenCount() {
       
  1942             return getTabCount();
       
  1943         }
       
  1944 
       
  1945         /**
       
  1946          * Return the specified Accessible child of the object.
       
  1947          *
       
  1948          * @param i zero-based index of child
       
  1949          * @return the Accessible child of the object
       
  1950          * @exception IllegalArgumentException if index is out of bounds
       
  1951          */
       
  1952         public Accessible getAccessibleChild(int i) {
       
  1953             if (i < 0 || i >= getTabCount()) {
       
  1954                 return null;
       
  1955             }
       
  1956             return pages.get(i);
       
  1957         }
       
  1958 
       
  1959         /**
       
  1960          * Gets the <code>AccessibleSelection</code> associated with
       
  1961          * this object.  In the implementation of the Java
       
  1962          * Accessibility API for this class,
       
  1963          * returns this object, which is responsible for implementing the
       
  1964          * <code>AccessibleSelection</code> interface on behalf of itself.
       
  1965          *
       
  1966          * @return this object
       
  1967          */
       
  1968         public AccessibleSelection getAccessibleSelection() {
       
  1969            return this;
       
  1970         }
       
  1971 
       
  1972         /**
       
  1973          * Returns the <code>Accessible</code> child contained at
       
  1974          * the local coordinate <code>Point</code>, if one exists.
       
  1975          * Otherwise returns the currently selected tab.
       
  1976          *
       
  1977          * @return the <code>Accessible</code> at the specified
       
  1978          *    location, if it exists
       
  1979          */
       
  1980         public Accessible getAccessibleAt(Point p) {
       
  1981             int tab = ((TabbedPaneUI) ui).tabForCoordinate(JTabbedPane.this,
       
  1982                                                            p.x, p.y);
       
  1983             if (tab == -1) {
       
  1984                 tab = getSelectedIndex();
       
  1985             }
       
  1986             return getAccessibleChild(tab);
       
  1987         }
       
  1988 
       
  1989         public int getAccessibleSelectionCount() {
       
  1990             return 1;
       
  1991         }
       
  1992 
       
  1993         public Accessible getAccessibleSelection(int i) {
       
  1994             int index = getSelectedIndex();
       
  1995             if (index == -1) {
       
  1996                 return null;
       
  1997             }
       
  1998             return pages.get(index);
       
  1999         }
       
  2000 
       
  2001         public boolean isAccessibleChildSelected(int i) {
       
  2002             return (i == getSelectedIndex());
       
  2003         }
       
  2004 
       
  2005         public void addAccessibleSelection(int i) {
       
  2006            setSelectedIndex(i);
       
  2007         }
       
  2008 
       
  2009         public void removeAccessibleSelection(int i) {
       
  2010            // can't do
       
  2011         }
       
  2012 
       
  2013         public void clearAccessibleSelection() {
       
  2014            // can't do
       
  2015         }
       
  2016 
       
  2017         public void selectAllAccessibleSelection() {
       
  2018            // can't do
       
  2019         }
       
  2020     }
       
  2021 
       
  2022     private class Page extends AccessibleContext
       
  2023         implements Serializable, Accessible, AccessibleComponent {
       
  2024         String title;
       
  2025         Color background;
       
  2026         Color foreground;
       
  2027         Icon icon;
       
  2028         Icon disabledIcon;
       
  2029         JTabbedPane parent;
       
  2030         Component component;
       
  2031         String tip;
       
  2032         boolean enabled = true;
       
  2033         boolean needsUIUpdate;
       
  2034         int mnemonic = -1;
       
  2035         int mnemonicIndex = -1;
       
  2036         Component tabComponent;
       
  2037 
       
  2038         Page(JTabbedPane parent,
       
  2039              String title, Icon icon, Icon disabledIcon, Component component, String tip) {
       
  2040             this.title = title;
       
  2041             this.icon = icon;
       
  2042             this.disabledIcon = disabledIcon;
       
  2043             this.parent = parent;
       
  2044             this.setAccessibleParent(parent);
       
  2045             this.component = component;
       
  2046             this.tip = tip;
       
  2047 
       
  2048             initAccessibleContext();
       
  2049         }
       
  2050 
       
  2051         /*
       
  2052          * initializes the AccessibleContext for the page
       
  2053          */
       
  2054         void initAccessibleContext() {
       
  2055             if (JTabbedPane.this.accessibleContext != null &&
       
  2056                 component instanceof Accessible) {
       
  2057                 /*
       
  2058                  * Do initialization if the AccessibleJTabbedPane
       
  2059                  * has been instantiated. We do not want to load
       
  2060                  * Accessibility classes unnecessarily.
       
  2061                  */
       
  2062                 AccessibleContext ac;
       
  2063                 ac = ((Accessible) component).getAccessibleContext();
       
  2064                 if (ac != null) {
       
  2065                     ac.setAccessibleParent(this);
       
  2066                 }
       
  2067             }
       
  2068         }
       
  2069 
       
  2070         void setMnemonic(int mnemonic) {
       
  2071             this.mnemonic = mnemonic;
       
  2072             updateDisplayedMnemonicIndex();
       
  2073         }
       
  2074 
       
  2075         int getMnemonic() {
       
  2076             return mnemonic;
       
  2077         }
       
  2078 
       
  2079         /*
       
  2080          * Sets the page displayed mnemonic index
       
  2081          */
       
  2082         void setDisplayedMnemonicIndex(int mnemonicIndex) {
       
  2083             if (this.mnemonicIndex != mnemonicIndex) {
       
  2084                 if (mnemonicIndex != -1 && (title == null ||
       
  2085                         mnemonicIndex < 0 ||
       
  2086                         mnemonicIndex >= title.length())) {
       
  2087                     throw new IllegalArgumentException(
       
  2088                                 "Invalid mnemonic index: " + mnemonicIndex);
       
  2089                 }
       
  2090                 this.mnemonicIndex = mnemonicIndex;
       
  2091                 JTabbedPane.this.firePropertyChange("displayedMnemonicIndexAt",
       
  2092                                                     null, null);
       
  2093             }
       
  2094         }
       
  2095 
       
  2096         /*
       
  2097          * Returns the page displayed mnemonic index
       
  2098          */
       
  2099         int getDisplayedMnemonicIndex() {
       
  2100             return this.mnemonicIndex;
       
  2101         }
       
  2102 
       
  2103         void updateDisplayedMnemonicIndex() {
       
  2104             setDisplayedMnemonicIndex(
       
  2105                 SwingUtilities.findDisplayedMnemonicIndex(title, mnemonic));
       
  2106         }
       
  2107 
       
  2108         /////////////////
       
  2109         // Accessibility support
       
  2110         ////////////////
       
  2111 
       
  2112         public AccessibleContext getAccessibleContext() {
       
  2113             return this;
       
  2114         }
       
  2115 
       
  2116 
       
  2117         // AccessibleContext methods
       
  2118 
       
  2119         public String getAccessibleName() {
       
  2120             if (accessibleName != null) {
       
  2121                 return accessibleName;
       
  2122             } else if (title != null) {
       
  2123                 return title;
       
  2124             }
       
  2125             return null;
       
  2126         }
       
  2127 
       
  2128         public String getAccessibleDescription() {
       
  2129             if (accessibleDescription != null) {
       
  2130                 return accessibleDescription;
       
  2131             } else if (tip != null) {
       
  2132                 return tip;
       
  2133             }
       
  2134             return null;
       
  2135         }
       
  2136 
       
  2137         public AccessibleRole getAccessibleRole() {
       
  2138             return AccessibleRole.PAGE_TAB;
       
  2139         }
       
  2140 
       
  2141         public AccessibleStateSet getAccessibleStateSet() {
       
  2142             AccessibleStateSet states;
       
  2143             states = parent.getAccessibleContext().getAccessibleStateSet();
       
  2144             states.add(AccessibleState.SELECTABLE);
       
  2145             int i = parent.indexOfTab(title);
       
  2146             if (i == parent.getSelectedIndex()) {
       
  2147                 states.add(AccessibleState.SELECTED);
       
  2148             }
       
  2149             return states;
       
  2150         }
       
  2151 
       
  2152         public int getAccessibleIndexInParent() {
       
  2153             return parent.indexOfTab(title);
       
  2154         }
       
  2155 
       
  2156         public int getAccessibleChildrenCount() {
       
  2157             if (component instanceof Accessible) {
       
  2158                 return 1;
       
  2159             } else {
       
  2160                 return 0;
       
  2161             }
       
  2162         }
       
  2163 
       
  2164         public Accessible getAccessibleChild(int i) {
       
  2165             if (component instanceof Accessible) {
       
  2166                 return (Accessible) component;
       
  2167             } else {
       
  2168                 return null;
       
  2169             }
       
  2170         }
       
  2171 
       
  2172         public Locale getLocale() {
       
  2173             return parent.getLocale();
       
  2174         }
       
  2175 
       
  2176         public AccessibleComponent getAccessibleComponent() {
       
  2177             return this;
       
  2178         }
       
  2179 
       
  2180 
       
  2181         // AccessibleComponent methods
       
  2182 
       
  2183         public Color getBackground() {
       
  2184             return background != null? background : parent.getBackground();
       
  2185         }
       
  2186 
       
  2187         public void setBackground(Color c) {
       
  2188             background = c;
       
  2189         }
       
  2190 
       
  2191         public Color getForeground() {
       
  2192             return foreground != null? foreground : parent.getForeground();
       
  2193         }
       
  2194 
       
  2195         public void setForeground(Color c) {
       
  2196             foreground = c;
       
  2197         }
       
  2198 
       
  2199         public Cursor getCursor() {
       
  2200             return parent.getCursor();
       
  2201         }
       
  2202 
       
  2203         public void setCursor(Cursor c) {
       
  2204             parent.setCursor(c);
       
  2205         }
       
  2206 
       
  2207         public Font getFont() {
       
  2208             return parent.getFont();
       
  2209         }
       
  2210 
       
  2211         public void setFont(Font f) {
       
  2212             parent.setFont(f);
       
  2213         }
       
  2214 
       
  2215         public FontMetrics getFontMetrics(Font f) {
       
  2216             return parent.getFontMetrics(f);
       
  2217         }
       
  2218 
       
  2219         public boolean isEnabled() {
       
  2220             return enabled;
       
  2221         }
       
  2222 
       
  2223         public void setEnabled(boolean b) {
       
  2224             enabled = b;
       
  2225         }
       
  2226 
       
  2227         public boolean isVisible() {
       
  2228             return parent.isVisible();
       
  2229         }
       
  2230 
       
  2231         public void setVisible(boolean b) {
       
  2232             parent.setVisible(b);
       
  2233         }
       
  2234 
       
  2235         public boolean isShowing() {
       
  2236             return parent.isShowing();
       
  2237         }
       
  2238 
       
  2239         public boolean contains(Point p) {
       
  2240             Rectangle r = getBounds();
       
  2241             return r.contains(p);
       
  2242         }
       
  2243 
       
  2244         public Point getLocationOnScreen() {
       
  2245              Point parentLocation = parent.getLocationOnScreen();
       
  2246              Point componentLocation = getLocation();
       
  2247              componentLocation.translate(parentLocation.x, parentLocation.y);
       
  2248              return componentLocation;
       
  2249         }
       
  2250 
       
  2251         public Point getLocation() {
       
  2252              Rectangle r = getBounds();
       
  2253              return new Point(r.x, r.y);
       
  2254         }
       
  2255 
       
  2256         public void setLocation(Point p) {
       
  2257             // do nothing
       
  2258         }
       
  2259 
       
  2260         public Rectangle getBounds() {
       
  2261             return parent.getUI().getTabBounds(parent,
       
  2262                                                parent.indexOfTab(title));
       
  2263         }
       
  2264 
       
  2265         public void setBounds(Rectangle r) {
       
  2266             // do nothing
       
  2267         }
       
  2268 
       
  2269         public Dimension getSize() {
       
  2270             Rectangle r = getBounds();
       
  2271             return new Dimension(r.width, r.height);
       
  2272         }
       
  2273 
       
  2274         public void setSize(Dimension d) {
       
  2275             // do nothing
       
  2276         }
       
  2277 
       
  2278         public Accessible getAccessibleAt(Point p) {
       
  2279             if (component instanceof Accessible) {
       
  2280                 return (Accessible) component;
       
  2281             } else {
       
  2282                 return null;
       
  2283             }
       
  2284         }
       
  2285 
       
  2286         public boolean isFocusTraversable() {
       
  2287             return false;
       
  2288         }
       
  2289 
       
  2290         public void requestFocus() {
       
  2291             // do nothing
       
  2292         }
       
  2293 
       
  2294         public void addFocusListener(FocusListener l) {
       
  2295             // do nothing
       
  2296         }
       
  2297 
       
  2298         public void removeFocusListener(FocusListener l) {
       
  2299             // do nothing
       
  2300         }
       
  2301 
       
  2302         // TIGER - 4732339
       
  2303         /**
       
  2304          * Returns an AccessibleIcon
       
  2305          *
       
  2306          * @return the enabled icon if one exists and the page
       
  2307          * is enabled. Otherwise, returns the disabled icon if
       
  2308          * one exists and the page is disabled.  Otherwise, null
       
  2309          * is returned.
       
  2310          */
       
  2311         public AccessibleIcon [] getAccessibleIcon() {
       
  2312             AccessibleIcon accessibleIcon = null;
       
  2313             if (enabled && icon instanceof ImageIcon) {
       
  2314                 AccessibleContext ac =
       
  2315                     ((ImageIcon)icon).getAccessibleContext();
       
  2316                 accessibleIcon = (AccessibleIcon)ac;
       
  2317             } else if (!enabled && disabledIcon instanceof ImageIcon) {
       
  2318                 AccessibleContext ac =
       
  2319                     ((ImageIcon)disabledIcon).getAccessibleContext();
       
  2320                 accessibleIcon = (AccessibleIcon)ac;
       
  2321             }
       
  2322             if (accessibleIcon != null) {
       
  2323                 AccessibleIcon [] returnIcons = new AccessibleIcon[1];
       
  2324                 returnIcons[0] = accessibleIcon;
       
  2325                 return returnIcons;
       
  2326             } else {
       
  2327                 return null;
       
  2328             }
       
  2329         }
       
  2330     }
       
  2331 
       
  2332     /**
       
  2333     * Sets the component that is responsible for rendering the
       
  2334     * title for the specified tab.  A null value means
       
  2335     * <code>JTabbedPane</code> will render the title and/or icon for
       
  2336     * the specified tab.  A non-null value means the component will
       
  2337     * render the title and <code>JTabbedPane</code> will not render
       
  2338     * the title and/or icon.
       
  2339     * <p>
       
  2340     * Note: The component must not be one that the developer has
       
  2341     *       already added to the tabbed pane.
       
  2342     *
       
  2343     * @param index the tab index where the component should be set
       
  2344     * @param component the component to render the title for the
       
  2345     *                  specified tab
       
  2346     * @exception IndexOutOfBoundsException if index is out of range
       
  2347     *            (index < 0 || index >= tab count)
       
  2348     * @exception IllegalArgumentException if component has already been
       
  2349     *            added to this <code>JTabbedPane</code>
       
  2350     *
       
  2351     * @see #getTabComponentAt
       
  2352     * @beaninfo
       
  2353     *    preferred: true
       
  2354     *    attribute: visualUpdate true
       
  2355     *  description: The tab component at the specified tab index.
       
  2356     * @since 1.6
       
  2357     */
       
  2358     public void setTabComponentAt(int index, Component component) {
       
  2359         if (component != null && indexOfComponent(component) != -1) {
       
  2360             throw new IllegalArgumentException("Component is already added to this JTabbedPane");
       
  2361         }
       
  2362         Component oldValue = getTabComponentAt(index);
       
  2363         if (component != oldValue) {
       
  2364             int tabComponentIndex = indexOfTabComponent(component);
       
  2365             if (tabComponentIndex != -1) {
       
  2366                 setTabComponentAt(tabComponentIndex, null);
       
  2367             }
       
  2368             pages.get(index).tabComponent = component;
       
  2369             firePropertyChange("indexForTabComponent", -1, index);
       
  2370         }
       
  2371     }
       
  2372 
       
  2373     /**
       
  2374      * Returns the tab component at <code>index</code>.
       
  2375      *
       
  2376      * @param index  the index of the item being queried
       
  2377      * @return the tab component at <code>index</code>
       
  2378      * @exception IndexOutOfBoundsException if index is out of range
       
  2379      *            (index < 0 || index >= tab count)
       
  2380      *
       
  2381      * @see #setTabComponentAt
       
  2382      * @since 1.6
       
  2383      */
       
  2384     public Component getTabComponentAt(int index) {
       
  2385         return pages.get(index).tabComponent;
       
  2386     }
       
  2387 
       
  2388     /**
       
  2389      * Returns the index of the tab for the specified tab component.
       
  2390      * Returns -1 if there is no tab for this tab component.
       
  2391      *
       
  2392      * @param tabComponent the tab component for the tab
       
  2393      * @return the first tab which matches this tab component, or -1
       
  2394      *          if there is no tab for this tab component
       
  2395      * @see #setTabComponentAt
       
  2396      * @see #getTabComponentAt
       
  2397      * @since 1.6
       
  2398      */
       
  2399      public int indexOfTabComponent(Component tabComponent) {
       
  2400         for(int i = 0; i < getTabCount(); i++) {
       
  2401             Component c = getTabComponentAt(i);
       
  2402             if (c == tabComponent) {
       
  2403                 return i;
       
  2404             }
       
  2405         }
       
  2406         return -1;
       
  2407     }
       
  2408 }