1062 lines · 39.2 KB · Java
RawDownload
/* * Copyright (c) 2000, 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.plaf.basic; import java.awt.*;import java.awt.event.*;import java.text.ParseException; import javax.swing.*;import javax.swing.border.*;import javax.swing.event.*;import javax.swing.plaf.*;import javax.swing.text.*; import java.beans.*;import java.text.*;import java.util.*;import sun.swing.DefaultLookup;  /** * The default Spinner UI delegate. * * @author Hans Muller * @since 1.4 */public class BasicSpinnerUI extends SpinnerUI{    /**     * The spinner that we're a UI delegate for.  Initialized by     * the <code>installUI</code> method, and reset to null     * by <code>uninstallUI</code>.     *     * @see #installUI     * @see #uninstallUI     */    protected JSpinner spinner;    private Handler handler;      /**     * The mouse/action listeners that are added to the spinner's     * arrow buttons.  These listeners are shared by all     * spinner arrow buttons.     *     * @see #createNextButton     * @see #createPreviousButton     */    private static final ArrowButtonHandler nextButtonHandler = new ArrowButtonHandler("increment", true);    private static final ArrowButtonHandler previousButtonHandler = new ArrowButtonHandler("decrement", false);    private PropertyChangeListener propertyChangeListener;      /**     * Used by the default LayoutManager class - SpinnerLayout for     * missing (null) editor/nextButton/previousButton children.     */    private static final Dimension zeroSize = new Dimension(0, 0);      /**     * Returns a new instance of BasicSpinnerUI.  SpinnerListUI     * delegates are allocated one per JSpinner.     *     * @param c the JSpinner (not used)     * @see ComponentUI#createUI     * @return a new BasicSpinnerUI object     */    public static ComponentUI createUI(JComponent c) {        return new BasicSpinnerUI();    }      private void maybeAdd(Component c, String s) {        if (c != null) {            spinner.add(c, s);        }    }      /**     * Calls <code>installDefaults</code>, <code>installListeners</code>,     * and then adds the components returned by <code>createNextButton</code>,     * <code>createPreviousButton</code>, and <code>createEditor</code>.     *     * @param c the JSpinner     * @see #installDefaults     * @see #installListeners     * @see #createNextButton     * @see #createPreviousButton     * @see #createEditor     */    public void installUI(JComponent c) {        this.spinner = (JSpinner)c;        installDefaults();        installListeners();        maybeAdd(createNextButton(), "Next");        maybeAdd(createPreviousButton(), "Previous");        maybeAdd(createEditor(), "Editor");        updateEnabledState();        installKeyboardActions();    }      /**     * Calls <code>uninstallDefaults</code>, <code>uninstallListeners</code>,     * and then removes all of the spinners children.     *     * @param c the JSpinner (not used)     */    public void uninstallUI(JComponent c) {        uninstallDefaults();        uninstallListeners();        this.spinner = null;        c.removeAll();    }      /**     * Initializes <code>PropertyChangeListener</code> with     * a shared object that delegates interesting PropertyChangeEvents     * to protected methods.     * <p>     * This method is called by <code>installUI</code>.     *     * @see #replaceEditor     * @see #uninstallListeners     */    protected void installListeners() {        propertyChangeListener = createPropertyChangeListener();        spinner.addPropertyChangeListener(propertyChangeListener);        if (DefaultLookup.getBoolean(spinner, this,            "Spinner.disableOnBoundaryValues", false)) {            spinner.addChangeListener(getHandler());        }        JComponent editor = spinner.getEditor();        if (editor != null && editor instanceof JSpinner.DefaultEditor) {            JTextField tf = ((JSpinner.DefaultEditor)editor).getTextField();            if (tf != null) {                tf.addFocusListener(nextButtonHandler);                tf.addFocusListener(previousButtonHandler);            }        }    }      /**     * Removes the <code>PropertyChangeListener</code> added     * by installListeners.     * <p>     * This method is called by <code>uninstallUI</code>.     *     * @see #installListeners     */    protected void uninstallListeners() {        spinner.removePropertyChangeListener(propertyChangeListener);        spinner.removeChangeListener(handler);        JComponent editor = spinner.getEditor();        removeEditorBorderListener(editor);        if (editor instanceof JSpinner.DefaultEditor) {            JTextField tf = ((JSpinner.DefaultEditor)editor).getTextField();            if (tf != null) {                tf.removeFocusListener(nextButtonHandler);                tf.removeFocusListener(previousButtonHandler);            }        }        propertyChangeListener = null;        handler = null;    }      /**     * Initialize the <code>JSpinner</code> <code>border</code>,     * <code>foreground</code>, and <code>background</code>, properties     * based on the corresponding "Spinner.*" properties from defaults table.     * The <code>JSpinners</code> layout is set to the value returned by     * <code>createLayout</code>.  This method is called by <code>installUI</code>.     *     * @see #uninstallDefaults     * @see #installUI     * @see #createLayout     * @see LookAndFeel#installBorder     * @see LookAndFeel#installColors     */    protected void installDefaults() {        spinner.setLayout(createLayout());        LookAndFeel.installBorder(spinner, "Spinner.border");        LookAndFeel.installColorsAndFont(spinner, "Spinner.background", "Spinner.foreground", "Spinner.font");        LookAndFeel.installProperty(spinner, "opaque", Boolean.TRUE);    }      /**     * Sets the <code>JSpinner's</code> layout manager to null.  This     * method is called by <code>uninstallUI</code>.     *     * @see #installDefaults     * @see #uninstallUI     */    protected void uninstallDefaults() {        spinner.setLayout(null);    }      private Handler getHandler() {        if (handler == null) {            handler = new Handler();        }        return handler;    }      /**     * Installs the necessary listeners on the next button, <code>c</code>,     * to update the <code>JSpinner</code> in response to a user gesture.     *     * @param c Component to install the listeners on     * @throws NullPointerException if <code>c</code> is null.     * @see #createNextButton     * @since 1.5     */    protected void installNextButtonListeners(Component c) {        installButtonListeners(c, nextButtonHandler);    }     /**     * Installs the necessary listeners on the previous button, <code>c</code>,     * to update the <code>JSpinner</code> in response to a user gesture.     *     * @param c Component to install the listeners on.     * @throws NullPointerException if <code>c</code> is null.     * @see #createPreviousButton     * @since 1.5     */    protected void installPreviousButtonListeners(Component c) {        installButtonListeners(c, previousButtonHandler);    }     private void installButtonListeners(Component c,                                        ArrowButtonHandler handler) {        if (c instanceof JButton) {            ((JButton)c).addActionListener(handler);        }        c.addMouseListener(handler);    }     /**     * Creates a <code>LayoutManager</code> that manages the <code>editor</code>,     * <code>nextButton</code>, and <code>previousButton</code>     * children of the JSpinner.  These three children must be     * added with a constraint that identifies their role:     * "Editor", "Next", and "Previous". The default layout manager     * can handle the absence of any of these children.     *     * @return a LayoutManager for the editor, next button, and previous button.     * @see #createNextButton     * @see #createPreviousButton     * @see #createEditor     */    protected LayoutManager createLayout() {        return getHandler();    }      /**     * Creates a <code>PropertyChangeListener</code> that can be     * added to the JSpinner itself.  Typically, this listener     * will call replaceEditor when the "editor" property changes,     * since it's the <code>SpinnerUI's</code> responsibility to     * add the editor to the JSpinner (and remove the old one).     * This method is called by <code>installListeners</code>.     *     * @return A PropertyChangeListener for the JSpinner itself     * @see #installListeners     */    protected PropertyChangeListener createPropertyChangeListener() {        return getHandler();    }      /**     * Creates a decrement button, i.e. component that replaces the spinner     * value with the object returned by <code>spinner.getPreviousValue</code>.     * By default the <code>previousButton</code> is a {@code JButton}. If the     * decrement button is not needed this method should return {@code null}.     *     * @return a component that will replace the spinner's value with the     *     previous value in the sequence, or {@code null}     * @see #installUI     * @see #createNextButton     * @see #installPreviousButtonListeners     */    protected Component createPreviousButton() {        Component c = createArrowButton(SwingConstants.SOUTH);        c.setName("Spinner.previousButton");        installPreviousButtonListeners(c);        return c;    }      /**     * Creates an increment button, i.e. component that replaces the spinner     * value with the object returned by <code>spinner.getNextValue</code>.     * By default the <code>nextButton</code> is a {@code JButton}. If the     * increment button is not needed this method should return {@code null}.     *     * @return a component that will replace the spinner's value with the     *     next value in the sequence, or {@code null}     * @see #installUI     * @see #createPreviousButton     * @see #installNextButtonListeners     */    protected Component createNextButton() {        Component c = createArrowButton(SwingConstants.NORTH);        c.setName("Spinner.nextButton");        installNextButtonListeners(c);        return c;    }     private Component createArrowButton(int direction) {        JButton b = new BasicArrowButton(direction);        Border buttonBorder = UIManager.getBorder("Spinner.arrowButtonBorder");        if (buttonBorder instanceof UIResource) {            // Wrap the border to avoid having the UIResource be replaced by            // the ButtonUI. This is the opposite of using BorderUIResource.            b.setBorder(new CompoundBorder(buttonBorder, null));        } else {            b.setBorder(buttonBorder);        }        b.setInheritsPopupMenu(true);        return b;    }      /**     * This method is called by installUI to get the editor component     * of the <code>JSpinner</code>.  By default it just returns     * <code>JSpinner.getEditor()</code>.  Subclasses can override     * <code>createEditor</code> to return a component that contains     * the spinner's editor or null, if they're going to handle adding     * the editor to the <code>JSpinner</code> in an     * <code>installUI</code> override.     * <p>     * Typically this method would be overridden to wrap the editor     * with a container with a custom border, since one can't assume     * that the editors border can be set directly.     * <p>     * The <code>replaceEditor</code> method is called when the spinners     * editor is changed with <code>JSpinner.setEditor</code>.  If you've     * overriden this method, then you'll probably want to override     * <code>replaceEditor</code> as well.     *     * @return the JSpinners editor JComponent, spinner.getEditor() by default     * @see #installUI     * @see #replaceEditor     * @see JSpinner#getEditor     */    protected JComponent createEditor() {        JComponent editor = spinner.getEditor();        maybeRemoveEditorBorder(editor);        installEditorBorderListener(editor);        editor.setInheritsPopupMenu(true);        updateEditorAlignment(editor);        return editor;    }      /**     * Called by the <code>PropertyChangeListener</code> when the     * <code>JSpinner</code> editor property changes.  It's the responsibility     * of this method to remove the old editor and add the new one.  By     * default this operation is just:     * <pre>     * spinner.remove(oldEditor);     * spinner.add(newEditor, "Editor");     * </pre>     * The implementation of <code>replaceEditor</code> should be coordinated     * with the <code>createEditor</code> method.     *     * @see #createEditor     * @see #createPropertyChangeListener     */    protected void replaceEditor(JComponent oldEditor, JComponent newEditor) {        spinner.remove(oldEditor);        maybeRemoveEditorBorder(newEditor);        installEditorBorderListener(newEditor);        newEditor.setInheritsPopupMenu(true);        spinner.add(newEditor, "Editor");    }     private void updateEditorAlignment(JComponent editor) {        if (editor instanceof JSpinner.DefaultEditor) {            // if editor alignment isn't set in LAF, we get 0 (CENTER) here            int alignment = UIManager.getInt("Spinner.editorAlignment");            JTextField text = ((JSpinner.DefaultEditor)editor).getTextField();            text.setHorizontalAlignment(alignment);        }    }     /**     * Remove the border around the inner editor component for LaFs     * that install an outside border around the spinner,     */    private void maybeRemoveEditorBorder(JComponent editor) {        if (!UIManager.getBoolean("Spinner.editorBorderPainted")) {            if (editor instanceof JPanel &&                editor.getBorder() == null &&                editor.getComponentCount() > 0) {                 editor = (JComponent)editor.getComponent(0);            }             if (editor != null && editor.getBorder() instanceof UIResource) {                editor.setBorder(null);            }        }    }     /**     * Remove the border around the inner editor component for LaFs     * that install an outside border around the spinner,     */    private void installEditorBorderListener(JComponent editor) {        if (!UIManager.getBoolean("Spinner.editorBorderPainted")) {            if (editor instanceof JPanel &&                editor.getBorder() == null &&                editor.getComponentCount() > 0) {                 editor = (JComponent)editor.getComponent(0);            }            if (editor != null &&                (editor.getBorder() == null ||                 editor.getBorder() instanceof UIResource)) {                editor.addPropertyChangeListener(getHandler());            }        }    }     private void removeEditorBorderListener(JComponent editor) {        if (!UIManager.getBoolean("Spinner.editorBorderPainted")) {            if (editor instanceof JPanel &&                editor.getComponentCount() > 0) {                 editor = (JComponent)editor.getComponent(0);            }            if (editor != null) {                editor.removePropertyChangeListener(getHandler());            }        }    }      /**     * Updates the enabled state of the children Components based on the     * enabled state of the <code>JSpinner</code>.     */    private void updateEnabledState() {        updateEnabledState(spinner, spinner.isEnabled());    }      /**     * Recursively updates the enabled state of the child     * <code>Component</code>s of <code>c</code>.     */    private void updateEnabledState(Container c, boolean enabled) {        for (int counter = c.getComponentCount() - 1; counter >= 0;counter--) {            Component child = c.getComponent(counter);             if (DefaultLookup.getBoolean(spinner, this,                "Spinner.disableOnBoundaryValues", false)) {                SpinnerModel model = spinner.getModel();                if (child.getName() == "Spinner.nextButton" &&                    model.getNextValue() == null) {                    child.setEnabled(false);                }                else if (child.getName() == "Spinner.previousButton" &&

Lines 1–500 of 1062.