001: /*
002: * Copyright (c) 2001-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.looks.windows;
032:
033: import java.awt.Component;
034: import java.awt.Insets;
035: import java.awt.LayoutManager;
036:
037: import javax.swing.*;
038: import javax.swing.border.EmptyBorder;
039: import javax.swing.plaf.ComponentUI;
040:
041: import com.jgoodies.looks.LookUtils;
042: import com.jgoodies.looks.common.ExtBasicArrowButtonHandler;
043: import com.jgoodies.looks.common.ExtBasicSpinnerLayout;
044:
045: /**
046: * The JGoodies Windows L&F implementation of <code>SpinnerUI</code>.
047: * Configures the default editor to adjust font baselines and component
048: * bounds, by setting an empty border with the default text insets.
049: *
050: * @author Karsten Lentzsch
051: * @version $Revision: 1.4 $
052: */
053: public final class WindowsSpinnerUI extends
054: com.sun.java.swing.plaf.windows.WindowsSpinnerUI {
055:
056: public static ComponentUI createUI(JComponent b) {
057: return new WindowsSpinnerUI();
058: }
059:
060: /**
061: * The mouse/action listeners that are added to the spinner's arrow
062: * buttons. These listeners are shared by all spinner arrow buttons.
063: *
064: * @see #createNextButton
065: * @see #createPreviousButton
066: */
067: private static final ExtBasicArrowButtonHandler NEXT_BUTTON_HANDLER = new ExtBasicArrowButtonHandler(
068: "increment", true);
069: private static final ExtBasicArrowButtonHandler PREVIOUS_BUTTON_HANDLER = new ExtBasicArrowButtonHandler(
070: "decrement", false);
071:
072: /**
073: * Create a component that will replace the spinner models value with the
074: * object returned by <code>spinner.getPreviousValue</code>. By default
075: * the <code>previousButton</code> is a JButton who's <code>ActionListener</code>
076: * updates it's <code>JSpinner</code> ancestors model. If a
077: * previousButton isn't needed (in a subclass) then override this method to
078: * return null.
079: *
080: * @return a component that will replace the spinners model with the next
081: * value in the sequence, or null
082: * @see #installUI
083: * @see #createNextButton
084: */
085: protected Component createPreviousButton() {
086: if (LookUtils.IS_LAF_WINDOWS_XP_ENABLED)
087: return super .createPreviousButton();
088:
089: JButton b = new WindowsArrowButton(SwingConstants.SOUTH);
090: b.addActionListener(PREVIOUS_BUTTON_HANDLER);
091: b.addMouseListener(PREVIOUS_BUTTON_HANDLER);
092: return b;
093: }
094:
095: /**
096: * Create a component that will replace the spinner models value with the
097: * object returned by <code>spinner.getNextValue</code>. By default the
098: * <code>nextButton</code> is a JButton who's <code>ActionListener</code>
099: * updates it's <code>JSpinner</code> ancestors model. If a nextButton
100: * isn't needed (in a subclass) then override this method to return null.
101: *
102: * @return a component that will replace the spinners model with the next
103: * value in the sequence, or null
104: * @see #installUI
105: * @see #createPreviousButton
106: */
107: protected Component createNextButton() {
108: if (LookUtils.IS_LAF_WINDOWS_XP_ENABLED)
109: return super .createNextButton();
110:
111: JButton b = new WindowsArrowButton(SwingConstants.NORTH);
112: b.addActionListener(NEXT_BUTTON_HANDLER);
113: b.addMouseListener(NEXT_BUTTON_HANDLER);
114: return b;
115: }
116:
117: /**
118: * This method is called by installUI to get the editor component of the
119: * <code>JSpinner</code>. By default it just returns <code>JSpinner.getEditor()</code>.
120: * Subclasses can override <code>createEditor</code> to return a
121: * component that contains the spinner's editor or null, if they're going
122: * to handle adding the editor to the <code>JSpinner</code> in an <code>installUI</code>
123: * override.
124: * <p>
125: * Typically this method would be overridden to wrap the editor with a
126: * container with a custom border, since one can't assume that the editors
127: * border can be set directly.
128: * <p>
129: * The <code>replaceEditor</code> method is called when the spinners
130: * editor is changed with <code>JSpinner.setEditor</code>. If you've
131: * overriden this method, then you'll probably want to override <code>replaceEditor</code>
132: * as well.
133: *
134: * @return the JSpinners editor JComponent, spinner.getEditor() by default
135: * @see #installUI
136: * @see #replaceEditor
137: * @see JSpinner#getEditor
138: */
139: protected JComponent createEditor() {
140: JComponent editor = spinner.getEditor();
141: configureEditorBorder(editor);
142: return editor;
143: }
144:
145: /**
146: * Create a <code>LayoutManager</code> that manages the <code>editor</code>,
147: * <code>nextButton</code>, and <code>previousButton</code> children
148: * of the JSpinner. These three children must be added with a constraint
149: * that identifies their role: "Editor", "Next", and "Previous". The
150: * default layout manager can handle the absence of any of these children.
151: *
152: * @return a LayoutManager for the editor, next button, and previous
153: * button.
154: * @see #createNextButton
155: * @see #createPreviousButton
156: * @see #createEditor
157: */
158: protected LayoutManager createLayout() {
159: return new ExtBasicSpinnerLayout();
160: }
161:
162: /**
163: * Called by the <code>PropertyChangeListener</code> when the <code>JSpinner</code>
164: * editor property changes. It's the responsibility of this method to
165: * remove the old editor and add the new one. By default this operation is
166: * just:
167: *
168: * <pre>
169: * spinner.remove(oldEditor); spinner.add(newEditor, "Editor");
170: * </pre>
171: *
172: *
173: * The implementation of <code>replaceEditor</code> should be coordinated
174: * with the <code>createEditor</code> method.
175: *
176: * @see #createEditor
177: * @see #createPropertyChangeListener
178: */
179: protected void replaceEditor(JComponent oldEditor,
180: JComponent newEditor) {
181: spinner.remove(oldEditor);
182: configureEditorBorder(newEditor);
183: spinner.add(newEditor, "Editor");
184: }
185:
186: /**
187: * Sets an empty border with consistent insets.
188: */
189: private void configureEditorBorder(JComponent editor) {
190: if ((editor instanceof JSpinner.DefaultEditor)) {
191: JSpinner.DefaultEditor defaultEditor = (JSpinner.DefaultEditor) editor;
192: JTextField editorField = defaultEditor.getTextField();
193: Insets insets = UIManager
194: .getInsets("Spinner.defaultEditorInsets");
195: editorField.setBorder(new EmptyBorder(insets));
196: } else if ((editor instanceof JPanel)
197: && (editor.getBorder() == null)
198: && (editor.getComponentCount() > 0)) {
199: JComponent editorField = (JComponent) editor
200: .getComponent(0);
201: Insets insets = UIManager
202: .getInsets("Spinner.defaultEditorInsets");
203: editorField.setBorder(new EmptyBorder(insets));
204: }
205: }
206:
207: }
|