2418 lines · 82.2 KB · Java
RawDownload
/* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import java.awt.*;import java.awt.event.*;import java.beans.Transient;import java.util.*;import javax.swing.event.*;import javax.swing.plaf.*;import javax.accessibility.*;import sun.swing.SwingUtilities2; import java.io.Serializable;import java.io.ObjectOutputStream;import java.io.ObjectInputStream;import java.io.IOException; /** * A component that lets the user switch between a group of components by * clicking on a tab with a given title and/or icon. * For examples and information on using tabbed panes see * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/tabbedpane.html">How to Use Tabbed Panes</a>, * a section in <em>The Java Tutorial</em>. * <p> * Tabs/components are added to a <code>TabbedPane</code> object by using the * <code>addTab</code> and <code>insertTab</code> methods. * A tab is represented by an index corresponding * to the position it was added in, where the first tab has an index equal to 0 * and the last tab has an index equal to the tab count minus 1. * <p> * The <code>TabbedPane</code> uses a <code>SingleSelectionModel</code> * to represent the set * of tab indices and the currently selected index.  If the tab count * is greater than 0, then there will always be a selected index, which * by default will be initialized to the first tab.  If the tab count is * 0, then the selected index will be -1. * <p> * The tab title can be rendered by a <code>Component</code>. * For example, the following produce similar results: * <pre> * // In this case the look and feel renders the title for the tab. * tabbedPane.addTab("Tab", myComponent); * // In this case the custom component is responsible for rendering the * // title of the tab. * tabbedPane.addTab(null, myComponent); * tabbedPane.setTabComponentAt(0, new JLabel("Tab")); * </pre> * The latter is typically used when you want a more complex user interaction * that requires custom components on the tab.  For example, you could * provide a custom component that animates or one that has widgets for * closing the tab. * <p> * If you specify a component for a tab, the <code>JTabbedPane</code> * will not render any text or icon you have specified for the tab. * <p> * <strong>Note:</strong> * Do not use <code>setVisible</code> directly on a tab component to make it visible, * use <code>setSelectedComponent</code> or <code>setSelectedIndex</code> methods instead. * <p> * <strong>Warning:</strong> Swing is not thread safe. For more * information see <a * href="package-summary.html#threading">Swing's Threading * Policy</a>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing.  As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @beaninfo *      attribute: isContainer true *    description: A component which provides a tab folder metaphor for *                 displaying one component from a set of components. * * @author Dave Moore * @author Philip Milne * @author Amy Fowler * * @see SingleSelectionModel */public class JTabbedPane extends JComponent       implements Serializable, Accessible, SwingConstants {    /**    * The tab layout policy for wrapping tabs in multiple runs when all    * tabs will not fit within a single run.    */    public static final int WRAP_TAB_LAYOUT = 0;    /**    * Tab layout policy for providing a subset of available tabs when all    * the tabs will not fit within a single run.  If all the tabs do    * not fit within a single run the look and feel will provide a way    * to navigate to hidden tabs.    */    public static final int SCROLL_TAB_LAYOUT = 1;      /**     * @see #getUIClassID     * @see #readObject     */    private static final String uiClassID = "TabbedPaneUI";     /**     * Where the tabs are placed.     * @see #setTabPlacement     */    protected int tabPlacement = TOP;     private int tabLayoutPolicy;     /** The default selection model */    protected SingleSelectionModel model;     private boolean haveRegistered;     /**     * The <code>changeListener</code> is the listener we add to the     * model.     */    protected ChangeListener changeListener = null;     private final java.util.List<Page> pages;     /* The component that is currently visible */    private Component visComp = null;     /**     * Only one <code>ChangeEvent</code> is needed per <code>TabPane</code>     * instance since the     * event's only (read-only) state is the source property.  The source     * of events generated here is always "this".     */    protected transient ChangeEvent changeEvent = null;     /**     * Creates an empty <code>TabbedPane</code> with a default     * tab placement of <code>JTabbedPane.TOP</code>.     * @see #addTab     */    public JTabbedPane() {        this(TOP, WRAP_TAB_LAYOUT);    }     /**     * Creates an empty <code>TabbedPane</code> with the specified tab placement     * of either: <code>JTabbedPane.TOP</code>, <code>JTabbedPane.BOTTOM</code>,     * <code>JTabbedPane.LEFT</code>, or <code>JTabbedPane.RIGHT</code>.     *     * @param tabPlacement the placement for the tabs relative to the content     * @see #addTab     */    public JTabbedPane(int tabPlacement) {        this(tabPlacement, WRAP_TAB_LAYOUT);    }     /**     * Creates an empty <code>TabbedPane</code> with the specified tab placement     * and tab layout policy.  Tab placement may be either:     * <code>JTabbedPane.TOP</code>, <code>JTabbedPane.BOTTOM</code>,     * <code>JTabbedPane.LEFT</code>, or <code>JTabbedPane.RIGHT</code>.     * Tab layout policy may be either: <code>JTabbedPane.WRAP_TAB_LAYOUT</code>     * or <code>JTabbedPane.SCROLL_TAB_LAYOUT</code>.     *     * @param tabPlacement the placement for the tabs relative to the content     * @param tabLayoutPolicy the policy for laying out tabs when all tabs will not fit on one run     * @exception IllegalArgumentException if tab placement or tab layout policy are not     *            one of the above supported values     * @see #addTab     * @since 1.4     */    public JTabbedPane(int tabPlacement, int tabLayoutPolicy) {        setTabPlacement(tabPlacement);        setTabLayoutPolicy(tabLayoutPolicy);        pages = new ArrayList<Page>(1);        setModel(new DefaultSingleSelectionModel());        updateUI();    }     /**     * Returns the UI object which implements the L&F for this component.     *     * @return a <code>TabbedPaneUI</code> object     * @see #setUI     */    public TabbedPaneUI getUI() {        return (TabbedPaneUI)ui;    }     /**     * Sets the UI object which implements the L&F for this component.     *     * @param ui the new UI object     * @see UIDefaults#getUI     * @beaninfo     *        bound: true     *       hidden: true     *    attribute: visualUpdate true     *  description: The UI object that implements the tabbedpane's LookAndFeel     */    public void setUI(TabbedPaneUI ui) {        super.setUI(ui);        // disabled icons are generated by LF so they should be unset here        for (int i = 0; i < getTabCount(); i++) {            Icon icon = pages.get(i).disabledIcon;            if (icon instanceof UIResource) {                setDisabledIconAt(i, null);            }        }    }     /**     * Resets the UI property to a value from the current look and feel.     *     * @see JComponent#updateUI     */    public void updateUI() {        setUI((TabbedPaneUI)UIManager.getUI(this));    }      /**     * Returns the name of the UI class that implements the     * L&F for this component.     *     * @return the string "TabbedPaneUI"     * @see JComponent#getUIClassID     * @see UIDefaults#getUI     */    public String getUIClassID() {        return uiClassID;    }      /**     * We pass <code>ModelChanged</code> events along to the listeners with     * the tabbedpane (instead of the model itself) as the event source.     */    protected class ModelListener implements ChangeListener, Serializable {        public void stateChanged(ChangeEvent e) {            fireStateChanged();        }    }     /**     * Subclasses that want to handle <code>ChangeEvents</code> differently     * can override this to return a subclass of <code>ModelListener</code> or     * another <code>ChangeListener</code> implementation.     *     * @see #fireStateChanged     */    protected ChangeListener createChangeListener() {        return new ModelListener();    }     /**     * Adds a <code>ChangeListener</code> to this tabbedpane.     *     * @param l the <code>ChangeListener</code> to add     * @see #fireStateChanged     * @see #removeChangeListener     */    public void addChangeListener(ChangeListener l) {        listenerList.add(ChangeListener.class, l);    }     /**     * Removes a <code>ChangeListener</code> from this tabbedpane.     *     * @param l the <code>ChangeListener</code> to remove     * @see #fireStateChanged     * @see #addChangeListener     */    public void removeChangeListener(ChangeListener l) {        listenerList.remove(ChangeListener.class, l);    }    /**     * Returns an array of all the <code>ChangeListener</code>s added     * to this <code>JTabbedPane</code> with <code>addChangeListener</code>.     *     * @return all of the <code>ChangeListener</code>s added or an empty     *         array if no listeners have been added     * @since 1.4     */    public ChangeListener[] getChangeListeners() {        return listenerList.getListeners(ChangeListener.class);    }     /**     * Sends a {@code ChangeEvent}, with this {@code JTabbedPane} as the source,     * to each registered listener. This method is called each time there is     * a change to either the selected index or the selected tab in the     * {@code JTabbedPane}. Usually, the selected index and selected tab change     * together. However, there are some cases, such as tab addition, where the     * selected index changes and the same tab remains selected. There are other     * cases, such as deleting the selected tab, where the index remains the     * same, but a new tab moves to that index. Events are fired for all of     * these cases.     *     * @see #addChangeListener     * @see EventListenerList     */    protected void fireStateChanged() {        /* --- Begin code to deal with visibility --- */         /* This code deals with changing the visibility of components to         * hide and show the contents for the selected tab. It duplicates         * logic already present in BasicTabbedPaneUI, logic that is         * processed during the layout pass. This code exists to allow         * developers to do things that are quite difficult to accomplish         * with the previous model of waiting for the layout pass to process         * visibility changes; such as requesting focus on the new visible         * component.         *         * For the average code, using the typical JTabbedPane methods,         * all visibility changes will now be processed here. However,         * the code in BasicTabbedPaneUI still exists, for the purposes         * of backward compatibility. Therefore, when making changes to         * this code, ensure that the BasicTabbedPaneUI code is kept in         * synch.         */         int selIndex = getSelectedIndex();         /* if the selection is now nothing */        if (selIndex < 0) {            /* if there was a previous visible component */            if (visComp != null && visComp.isVisible()) {                /* make it invisible */                visComp.setVisible(false);            }             /* now there's no visible component */            visComp = null;         /* else - the selection is now something */        } else {            /* Fetch the component for the new selection */            Component newComp = getComponentAt(selIndex);             /* if the new component is non-null and different */            if (newComp != null && newComp != visComp) {                boolean shouldChangeFocus = false;                 /* Note: the following (clearing of the old visible component)                 * is inside this if-statement for good reason: Tabbed pane                 * should continue to show the previously visible component                 * if there is no component for the chosen tab.                 */                 /* if there was a previous visible component */                if (visComp != null) {                    shouldChangeFocus =                        (SwingUtilities.findFocusOwner(visComp) != null);                     /* if it's still visible */                    if (visComp.isVisible()) {                        /* make it invisible */                        visComp.setVisible(false);                    }                }                 if (!newComp.isVisible()) {                    newComp.setVisible(true);                }                 if (shouldChangeFocus) {                    SwingUtilities2.tabbedPaneChangeFocusTo(newComp);                }                 visComp = newComp;            } /* else - the visible component shouldn't changed */        }         /* --- End code to deal with visibility --- */         // Guaranteed to return a non-null array        Object[] listeners = listenerList.getListenerList();        // Process the listeners last to first, notifying        // those that are interested in this event        for (int i = listeners.length-2; i>=0; i-=2) {            if (listeners[i]==ChangeListener.class) {                // Lazily create the event:                if (changeEvent == null)                    changeEvent = new ChangeEvent(this);                ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);            }        }    }     /**     * Returns the model associated with this tabbedpane.     *     * @see #setModel     */    public SingleSelectionModel getModel() {        return model;    }     /**     * Sets the model to be used with this tabbedpane.     *     * @param model the model to be used     * @see #getModel     * @beaninfo     *       bound: true     * description: The tabbedpane's SingleSelectionModel.     */    public void setModel(SingleSelectionModel model) {        SingleSelectionModel oldModel = getModel();         if (oldModel != null) {            oldModel.removeChangeListener(changeListener);            changeListener = null;        }         this.model = model;         if (model != null) {            changeListener = createChangeListener();            model.addChangeListener(changeListener);        }         firePropertyChange("model", oldModel, model);        repaint();    }     /**     * Returns the placement of the tabs for this tabbedpane.     * @see #setTabPlacement     */    public int getTabPlacement() {        return tabPlacement;    }     /**     * Sets the tab placement for this tabbedpane.     * Possible values are:<ul>     * <li><code>JTabbedPane.TOP</code>     * <li><code>JTabbedPane.BOTTOM</code>     * <li><code>JTabbedPane.LEFT</code>     * <li><code>JTabbedPane.RIGHT</code>     * </ul>     * The default value, if not set, is <code>SwingConstants.TOP</code>.     *     * @param tabPlacement the placement for the tabs relative to the content     * @exception IllegalArgumentException if tab placement value isn't one     *                          of the above valid values     *     * @beaninfo     *    preferred: true     *        bound: true     *    attribute: visualUpdate true     *         enum: TOP JTabbedPane.TOP     *               LEFT JTabbedPane.LEFT     *               BOTTOM JTabbedPane.BOTTOM     *               RIGHT JTabbedPane.RIGHT     *  description: The tabbedpane's tab placement.     *     */    public void setTabPlacement(int tabPlacement) {        if (tabPlacement != TOP && tabPlacement != LEFT &&            tabPlacement != BOTTOM && tabPlacement != RIGHT) {            throw new IllegalArgumentException("illegal tab placement: must be TOP, BOTTOM, LEFT, or RIGHT");        }        if (this.tabPlacement != tabPlacement) {            int oldValue = this.tabPlacement;            this.tabPlacement = tabPlacement;            firePropertyChange("tabPlacement", oldValue, tabPlacement);            revalidate();

Lines 1–500 of 2418.