4632N/A/*
4632N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
4632N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4632N/A *
4632N/A * This code is free software; you can redistribute it and/or modify it
4632N/A * under the terms of the GNU General Public License version 2 only, as
4632N/A * published by the Free Software Foundation. Oracle designates this
4632N/A * particular file as subject to the "Classpath" exception as provided
4632N/A * by Oracle in the LICENSE file that accompanied this code.
4632N/A *
4632N/A * This code is distributed in the hope that it will be useful, but WITHOUT
4632N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4632N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4632N/A * version 2 for more details (a copy is included in the LICENSE file that
4632N/A * accompanied this code).
4632N/A *
4632N/A * You should have received a copy of the GNU General Public License version
4632N/A * 2 along with this work; if not, write to the Free Software Foundation,
4632N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4632N/A *
4632N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4632N/A * or visit www.oracle.com if you need additional information or have any
4632N/A * questions.
4632N/A */
4632N/A
4632N/Apackage com.apple.laf;
4632N/A
4632N/Aimport java.awt.*;
4632N/Aimport java.awt.event.*;
4632N/Aimport java.beans.*;
4632N/Aimport java.text.*;
4632N/Aimport java.text.AttributedCharacterIterator.Attribute;
4632N/Aimport java.text.Format.Field;
4632N/Aimport java.util.*;
4632N/A
4632N/Aimport javax.swing.*;
4632N/Aimport javax.swing.JSpinner.DefaultEditor;
4632N/Aimport javax.swing.plaf.*;
4632N/Aimport javax.swing.text.InternationalFormatter;
4632N/A
4632N/Aimport apple.laf.*;
4632N/Aimport apple.laf.JRSUIConstants.*;
4632N/A
4632N/Aimport com.apple.laf.AquaUtils.RecyclableSingleton;
4632N/Aimport com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
4632N/A
4632N/A/**
4632N/A * This is originally derived from BasicSpinnerUI, but they made everything private
4632N/A * so we can't subclass!
4632N/A */
4632N/Apublic class AquaSpinnerUI extends SpinnerUI {
4632N/A private static final RecyclableSingleton<? extends PropertyChangeListener> propertyChangeListener = new RecyclableSingletonFromDefaultConstructor<PropertyChangeHandler>(PropertyChangeHandler.class);
4632N/A static PropertyChangeListener getPropertyChangeListener() {
4632N/A return propertyChangeListener.get();
4632N/A }
4632N/A
4632N/A private static final RecyclableSingleton<ArrowButtonHandler> nextButtonHandler = new RecyclableSingleton<ArrowButtonHandler>() {
4632N/A @Override
4632N/A protected ArrowButtonHandler getInstance() {
4632N/A return new ArrowButtonHandler("increment", true);
4632N/A }
4632N/A };
4632N/A static ArrowButtonHandler getNextButtonHandler() {
4632N/A return nextButtonHandler.get();
4632N/A }
4632N/A private static final RecyclableSingleton<ArrowButtonHandler> previousButtonHandler = new RecyclableSingleton<ArrowButtonHandler>() {
4632N/A @Override
4632N/A protected ArrowButtonHandler getInstance() {
4632N/A return new ArrowButtonHandler("decrement", false);
4632N/A }
4632N/A };
4632N/A static ArrowButtonHandler getPreviousButtonHandler() {
4632N/A return previousButtonHandler.get();
4632N/A }
4632N/A
4632N/A JSpinner spinner;
4632N/A SpinPainter spinPainter;
4632N/A
4632N/A public static ComponentUI createUI(final JComponent c) {
4632N/A return new AquaSpinnerUI();
4632N/A }
4632N/A
4632N/A private void maybeAdd(final Component c, final String s) {
4632N/A if (c != null) {
4632N/A spinner.add(c, s);
4632N/A }
4632N/A }
4632N/A
4632N/A boolean wasOpaque;
4632N/A public void installUI(final JComponent c) {
4632N/A this.spinner = (JSpinner)c;
4632N/A installDefaults();
4632N/A installListeners();
4632N/A final TransparentButton next = createNextButton();
4632N/A final TransparentButton prev = createPreviousButton();
4632N/A spinPainter = new SpinPainter(next, prev);
4632N/A
4632N/A maybeAdd(next, "Next");
4632N/A maybeAdd(prev, "Previous");
4632N/A maybeAdd(createEditor(), "Editor");
4632N/A maybeAdd(spinPainter, "Painter");
4632N/A
4632N/A updateEnabledState();
4632N/A installKeyboardActions();
4632N/A
4632N/A // this doesn't work because JSpinner calls setOpaque(true) directly in it's constructor
4632N/A // LookAndFeel.installProperty(spinner, "opaque", Boolean.FALSE);
4632N/A
4632N/A // ...so we have to handle the is/was opaque ourselves
4632N/A wasOpaque = spinner.isOpaque();
4632N/A spinner.setOpaque(false);
4632N/A }
4632N/A
4632N/A public void uninstallUI(final JComponent c) {
4632N/A uninstallDefaults();
4632N/A uninstallListeners();
4632N/A spinner.setOpaque(wasOpaque);
4632N/A spinner = null;
4632N/A c.removeAll();
4632N/A }
4632N/A
4632N/A protected void installListeners() {
4632N/A spinner.addPropertyChangeListener(getPropertyChangeListener());
4632N/A }
4632N/A
4632N/A protected void uninstallListeners() {
4632N/A spinner.removePropertyChangeListener(getPropertyChangeListener());
4632N/A }
4632N/A
4632N/A protected void installDefaults() {
4632N/A spinner.setLayout(createLayout());
4632N/A LookAndFeel.installBorder(spinner, "Spinner.border");
4632N/A LookAndFeel.installColorsAndFont(spinner, "Spinner.background", "Spinner.foreground", "Spinner.font");
4632N/A }
4632N/A
4632N/A protected void uninstallDefaults() {
4632N/A spinner.setLayout(null);
4632N/A }
4632N/A
4632N/A protected LayoutManager createLayout() {
4632N/A return new SpinnerLayout();
4632N/A }
4632N/A
4632N/A protected PropertyChangeListener createPropertyChangeListener() {
4632N/A return new PropertyChangeHandler();
4632N/A }
4632N/A
4632N/A protected TransparentButton createPreviousButton() {
4632N/A final TransparentButton b = new TransparentButton();
4632N/A b.addActionListener(getPreviousButtonHandler());
4632N/A b.addMouseListener(getPreviousButtonHandler());
4639N/A b.setInheritsPopupMenu(true);
4632N/A return b;
4632N/A }
4632N/A
4632N/A protected TransparentButton createNextButton() {
4632N/A final TransparentButton b = new TransparentButton();
4632N/A b.addActionListener(getNextButtonHandler());
4632N/A b.addMouseListener(getNextButtonHandler());
4639N/A b.setInheritsPopupMenu(true);
4632N/A return b;
4632N/A }
4632N/A
4778N/A /**
4778N/A * {@inheritDoc}
4778N/A */
4778N/A public int getBaseline(JComponent c, int width, int height) {
4778N/A super.getBaseline(c, width, height);
4778N/A JComponent editor = spinner.getEditor();
4778N/A Insets insets = spinner.getInsets();
4778N/A width = width - insets.left - insets.right;
4778N/A height = height - insets.top - insets.bottom;
4778N/A if (width >= 0 && height >= 0) {
4778N/A int baseline = editor.getBaseline(width, height);
4778N/A if (baseline >= 0) {
4778N/A return insets.top + baseline;
4778N/A }
4778N/A }
4778N/A return -1;
4778N/A }
4778N/A
4778N/A /**
4778N/A * {@inheritDoc}
4778N/A */
4778N/A public Component.BaselineResizeBehavior getBaselineResizeBehavior(
4778N/A JComponent c) {
4778N/A super.getBaselineResizeBehavior(c);
4778N/A return spinner.getEditor().getBaselineResizeBehavior();
4778N/A }
4778N/A
4632N/A class TransparentButton extends JButton implements SwingConstants {
4632N/A boolean interceptRepaints = false;
4632N/A
4632N/A public TransparentButton() {
4632N/A super();
4632N/A setFocusable(false);
4632N/A // only intercept repaints if we are after this has been initialized
4632N/A // otherwise we can't talk to our containing class
4632N/A interceptRepaints = true;
4632N/A }
4632N/A
4632N/A public void paint(final Graphics g) {}
4632N/A
4632N/A public void repaint() {
4632N/A // only intercept repaints if we are after this has been initialized
4632N/A // otherwise we can't talk to our containing class
4632N/A if (interceptRepaints) {
4632N/A if (spinPainter == null) return;
4632N/A spinPainter.repaint();
4632N/A }
4632N/A super.repaint();
4632N/A }
4632N/A }
4632N/A
4632N/A protected JComponent createEditor() {
4632N/A final JComponent editor = spinner.getEditor();
4632N/A fixupEditor(editor);
4632N/A return editor;
4632N/A }
4632N/A
4632N/A protected void replaceEditor(final JComponent oldEditor, final JComponent newEditor) {
4632N/A spinner.remove(oldEditor);
4632N/A fixupEditor(newEditor);
4632N/A spinner.add(newEditor, "Editor");
4632N/A }
4632N/A
4632N/A protected void fixupEditor(final JComponent editor) {
4632N/A if (!(editor instanceof DefaultEditor)) return;
4632N/A
4632N/A editor.setOpaque(false);
4639N/A editor.setInheritsPopupMenu(true);
4639N/A
4639N/A if (editor.getFont() instanceof UIResource) {
4639N/A editor.setFont(spinner.getFont());
4639N/A }
4632N/A
4632N/A final JFormattedTextField editorTextField = ((DefaultEditor)editor).getTextField();
4675N/A if (editorTextField.getFont() instanceof UIResource) {
4675N/A editorTextField.setFont(spinner.getFont());
4675N/A }
4632N/A final InputMap spinnerInputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
4632N/A final InputMap editorInputMap = editorTextField.getInputMap();
4632N/A final KeyStroke[] keys = spinnerInputMap.keys();
4632N/A for (final KeyStroke k : keys) {
4632N/A editorInputMap.put(k, spinnerInputMap.get(k));
4632N/A }
4632N/A }
4632N/A
4632N/A void updateEnabledState() {
4632N/A updateEnabledState(spinner, spinner.isEnabled());
4632N/A }
4632N/A
4632N/A private void updateEnabledState(final Container c, final boolean enabled) {
4632N/A for (int counter = c.getComponentCount() - 1; counter >= 0; counter--) {
4632N/A final Component child = c.getComponent(counter);
4632N/A
4632N/A child.setEnabled(enabled);
4632N/A if (child instanceof Container) {
4632N/A updateEnabledState((Container)child, enabled);
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A private void installKeyboardActions() {
4632N/A final InputMap iMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
4632N/A SwingUtilities.replaceUIInputMap(spinner, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, iMap);
4632N/A SwingUtilities.replaceUIActionMap(spinner, getActionMap());
4632N/A }
4632N/A
4632N/A private InputMap getInputMap(final int condition) {
4632N/A if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
4632N/A return (InputMap)UIManager.get("Spinner.ancestorInputMap");
4632N/A }
4632N/A return null;
4632N/A }
4632N/A
4632N/A private ActionMap getActionMap() {
4632N/A ActionMap map = (ActionMap)UIManager.get("Spinner.actionMap");
4632N/A
4632N/A if (map == null) {
4632N/A map = createActionMap();
4632N/A if (map != null) {
4632N/A UIManager.getLookAndFeelDefaults().put("Spinner.actionMap", map);
4632N/A }
4632N/A }
4632N/A return map;
4632N/A }
4632N/A
4632N/A private ActionMap createActionMap() {
4632N/A final ActionMap map = new ActionMapUIResource();
4632N/A map.put("increment", getNextButtonHandler());
4632N/A map.put("decrement", getPreviousButtonHandler());
4632N/A return map;
4632N/A }
4632N/A
4632N/A private static class ArrowButtonHandler extends AbstractAction implements MouseListener {
4632N/A final javax.swing.Timer autoRepeatTimer;
4632N/A final boolean isNext;
4632N/A JSpinner spinner = null;
4632N/A
4632N/A ArrowButtonHandler(final String name, final boolean isNext) {
4632N/A super(name);
4632N/A this.isNext = isNext;
4632N/A autoRepeatTimer = new javax.swing.Timer(60, this);
4632N/A autoRepeatTimer.setInitialDelay(300);
4632N/A }
4632N/A
4632N/A private JSpinner eventToSpinner(final AWTEvent e) {
4632N/A Object src = e.getSource();
4632N/A while ((src instanceof Component) && !(src instanceof JSpinner)) {
4632N/A src = ((Component)src).getParent();
4632N/A }
4632N/A return (src instanceof JSpinner) ? (JSpinner)src : null;
4632N/A }
4632N/A
4632N/A public void actionPerformed(final ActionEvent e) {
4632N/A if (!(e.getSource() instanceof javax.swing.Timer)) {
4632N/A // Most likely resulting from being in ActionMap.
4632N/A spinner = eventToSpinner(e);
4632N/A }
4632N/A
4632N/A if (spinner == null) return;
4632N/A
4632N/A try {
4632N/A final int calendarField = getCalendarField(spinner);
4632N/A spinner.commitEdit();
4632N/A if (calendarField != -1) {
4632N/A ((SpinnerDateModel)spinner.getModel()).setCalendarField(calendarField);
4632N/A }
4632N/A final Object value = (isNext) ? spinner.getNextValue() : spinner.getPreviousValue();
4632N/A if (value != null) {
4632N/A spinner.setValue(value);
4632N/A select(spinner);
4632N/A }
4632N/A } catch (final IllegalArgumentException iae) {
4632N/A UIManager.getLookAndFeel().provideErrorFeedback(spinner);
4632N/A } catch (final ParseException pe) {
4632N/A UIManager.getLookAndFeel().provideErrorFeedback(spinner);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * If the spinner's editor is a DateEditor, this selects the field
4632N/A * associated with the value that is being incremented.
4632N/A */
4632N/A private void select(final JSpinner spinnerComponent) {
4632N/A final JComponent editor = spinnerComponent.getEditor();
4632N/A if (!(editor instanceof JSpinner.DateEditor)) return;
4632N/A
4632N/A final JSpinner.DateEditor dateEditor = (JSpinner.DateEditor)editor;
4632N/A final JFormattedTextField ftf = dateEditor.getTextField();
4632N/A final Format format = dateEditor.getFormat();
4632N/A Object value;
4632N/A if (format == null || (value = spinnerComponent.getValue()) == null) return;
4632N/A
4632N/A final SpinnerDateModel model = dateEditor.getModel();
4632N/A final DateFormat.Field field = DateFormat.Field.ofCalendarField(model.getCalendarField());
4632N/A if (field == null) return;
4632N/A
4632N/A try {
4632N/A final AttributedCharacterIterator iterator = format.formatToCharacterIterator(value);
4632N/A if (!select(ftf, iterator, field) && field == DateFormat.Field.HOUR0) {
4632N/A select(ftf, iterator, DateFormat.Field.HOUR1);
4632N/A }
4632N/A } catch (final IllegalArgumentException iae) {}
4632N/A }
4632N/A
4632N/A /**
4632N/A * Selects the passed in field, returning true if it is found,
4632N/A * false otherwise.
4632N/A */
4632N/A private boolean select(final JFormattedTextField ftf, final AttributedCharacterIterator iterator, final DateFormat.Field field) {
4632N/A final int max = ftf.getDocument().getLength();
4632N/A
4632N/A iterator.first();
4632N/A do {
4632N/A final Map<Attribute,Object> attrs = iterator.getAttributes();
4632N/A if (attrs == null || !attrs.containsKey(field)) continue;
4632N/A
4632N/A final int start = iterator.getRunStart(field);
4632N/A final int end = iterator.getRunLimit(field);
4632N/A if (start != -1 && end != -1 && start <= max && end <= max) {
4632N/A ftf.select(start, end);
4632N/A }
4632N/A
4632N/A return true;
4632N/A } while (iterator.next() != CharacterIterator.DONE);
4632N/A return false;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the calendarField under the start of the selection, or
4632N/A * -1 if there is no valid calendar field under the selection (or
4632N/A * the spinner isn't editing dates.
4632N/A */
4632N/A private int getCalendarField(final JSpinner spinnerComponent) {
4632N/A final JComponent editor = spinnerComponent.getEditor();
4632N/A if (!(editor instanceof JSpinner.DateEditor)) return -1;
4632N/A
4632N/A final JSpinner.DateEditor dateEditor = (JSpinner.DateEditor)editor;
4632N/A final JFormattedTextField ftf = dateEditor.getTextField();
4632N/A final int start = ftf.getSelectionStart();
4632N/A final JFormattedTextField.AbstractFormatter formatter = ftf.getFormatter();
4632N/A if (!(formatter instanceof InternationalFormatter)) return -1;
4632N/A
4632N/A final Format.Field[] fields = ((InternationalFormatter)formatter).getFields(start);
4632N/A for (final Field element : fields) {
4632N/A if (!(element instanceof DateFormat.Field)) continue;
4632N/A int calendarField;
4632N/A
4632N/A if (element == DateFormat.Field.HOUR1) {
4632N/A calendarField = Calendar.HOUR;
4632N/A } else {
4632N/A calendarField = ((DateFormat.Field)element).getCalendarField();
4632N/A }
4632N/A
4632N/A if (calendarField != -1) {
4632N/A return calendarField;
4632N/A }
4632N/A }
4632N/A return -1;
4632N/A }
4632N/A
4632N/A public void mousePressed(final MouseEvent e) {
4632N/A if (!SwingUtilities.isLeftMouseButton(e) || !e.getComponent().isEnabled()) return;
4632N/A spinner = eventToSpinner(e);
4632N/A autoRepeatTimer.start();
4632N/A
4632N/A focusSpinnerIfNecessary();
4632N/A }
4632N/A
4632N/A public void mouseReleased(final MouseEvent e) {
4632N/A autoRepeatTimer.stop();
4632N/A spinner = null;
4632N/A }
4632N/A
4632N/A public void mouseClicked(final MouseEvent e) {}
4632N/A public void mouseEntered(final MouseEvent e) {}
4632N/A public void mouseExited(final MouseEvent e) {}
4632N/A
4632N/A /**
4632N/A * Requests focus on a child of the spinner if the spinner doesn't
4632N/A * have focus.
4632N/A */
4632N/A private void focusSpinnerIfNecessary() {
4632N/A final Component fo = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
4632N/A if (!spinner.isRequestFocusEnabled() || (fo != null && (SwingUtilities.isDescendingFrom(fo, spinner)))) return;
4632N/A Container root = spinner;
4632N/A
4632N/A if (!root.isFocusCycleRoot()) {
4632N/A root = root.getFocusCycleRootAncestor();
4632N/A }
4632N/A
4632N/A if (root == null) return;
4632N/A final FocusTraversalPolicy ftp = root.getFocusTraversalPolicy();
4632N/A final Component child = ftp.getComponentAfter(root, spinner);
4632N/A
4632N/A if (child != null && SwingUtilities.isDescendingFrom(child, spinner)) {
4632N/A child.requestFocus();
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A class SpinPainter extends JComponent {
4632N/A final AquaPainter<JRSUIState> painter = AquaPainter.create(JRSUIStateFactory.getSpinnerArrows());
4632N/A
4632N/A ButtonModel fTopModel;
4632N/A ButtonModel fBottomModel;
4632N/A
4632N/A boolean fPressed = false;
4632N/A boolean fTopPressed = false;
4632N/A
4632N/A Dimension kPreferredSize = new Dimension(15, 24); // 19,27 before trimming
4632N/A
4632N/A public SpinPainter(final AbstractButton top, final AbstractButton bottom) {
4632N/A if (top != null) {
4632N/A fTopModel = top.getModel();
4632N/A }
4632N/A
4632N/A if (bottom != null) {
4632N/A fBottomModel = bottom.getModel();
4632N/A }
4632N/A }
4632N/A
4632N/A public void paint(final Graphics g) {
4632N/A if (spinner.isOpaque()) {
4632N/A g.setColor(spinner.getBackground());
4632N/A g.fillRect(0, 0, getWidth(), getHeight());
4632N/A }
4632N/A
4632N/A AquaUtilControlSize.applySizeForControl(spinner, painter);
4632N/A
4632N/A if (isEnabled()) {
4632N/A if (fTopModel != null && fTopModel.isPressed()) {
4632N/A painter.state.set(State.PRESSED);
4632N/A painter.state.set(BooleanValue.NO);
4632N/A } else if (fBottomModel != null && fBottomModel.isPressed()) {
4632N/A painter.state.set(State.PRESSED);
4632N/A painter.state.set(BooleanValue.YES);
4632N/A } else {
4632N/A painter.state.set(State.ACTIVE);
4632N/A }
4632N/A } else {
4632N/A painter.state.set(State.DISABLED);
4632N/A }
4632N/A
4632N/A final Rectangle bounds = getBounds();
4632N/A painter.paint(g, spinner, 0, 0, bounds.width, bounds.height);
4632N/A }
4632N/A
4632N/A public Dimension getPreferredSize() {
4632N/A final Size size = AquaUtilControlSize.getUserSizeFrom(this);
4632N/A
4632N/A if (size == Size.MINI) {
4632N/A return new Dimension(kPreferredSize.width, kPreferredSize.height - 8);
4632N/A }
4632N/A
4632N/A return kPreferredSize;
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * A simple layout manager for the editor and the next/previous buttons.
4632N/A * See the AquaSpinnerUI javadoc for more information about exactly
4632N/A * how the components are arranged.
4632N/A */
4632N/A static class SpinnerLayout implements LayoutManager {
4632N/A private Component nextButton = null;
4632N/A private Component previousButton = null;
4632N/A private Component editor = null;
4632N/A private Component painter = null;
4632N/A
4632N/A public void addLayoutComponent(final String name, final Component c) {
4632N/A if ("Next".equals(name)) {
4632N/A nextButton = c;
4632N/A } else if ("Previous".equals(name)) {
4632N/A previousButton = c;
4632N/A } else if ("Editor".equals(name)) {
4632N/A editor = c;
4632N/A } else if ("Painter".equals(name)) {
4632N/A painter = c;
4632N/A }
4632N/A }
4632N/A
4632N/A public void removeLayoutComponent(Component c) {
4632N/A if (c == nextButton) {
4632N/A c = null;
4632N/A } else if (c == previousButton) {
4632N/A previousButton = null;
4632N/A } else if (c == editor) {
4632N/A editor = null;
4632N/A } else if (c == painter) {
4632N/A painter = null;
4632N/A }
4632N/A }
4632N/A
4632N/A private Dimension preferredSize(final Component c) {
4632N/A return (c == null) ? new Dimension(0, 0) : c.getPreferredSize();
4632N/A }
4632N/A
4632N/A public Dimension preferredLayoutSize(final Container parent) {
4632N/A// Dimension nextD = preferredSize(nextButton);
4632N/A// Dimension previousD = preferredSize(previousButton);
4632N/A final Dimension editorD = preferredSize(editor);
4632N/A final Dimension painterD = preferredSize(painter);
4632N/A
4632N/A /* Force the editors height to be a multiple of 2
4632N/A */
4632N/A editorD.height = ((editorD.height + 1) / 2) * 2;
4632N/A
4632N/A final Dimension size = new Dimension(editorD.width, Math.max(painterD.height, editorD.height));
4632N/A size.width += painterD.width; //Math.max(nextD.width, previousD.width);
4632N/A final Insets insets = parent.getInsets();
4632N/A size.width += insets.left + insets.right;
4632N/A size.height += insets.top + insets.bottom;
4632N/A return size;
4632N/A }
4632N/A
4632N/A public Dimension minimumLayoutSize(final Container parent) {
4632N/A return preferredLayoutSize(parent);
4632N/A }
4632N/A
4632N/A private void setBounds(final Component c, final int x, final int y, final int width, final int height) {
4632N/A if (c != null) {
4632N/A c.setBounds(x, y, width, height);
4632N/A }
4632N/A }
4632N/A
4632N/A public void layoutContainer(final Container parent) {
4632N/A final Insets insets = parent.getInsets();
4632N/A final int availWidth = parent.getWidth() - (insets.left + insets.right);
4632N/A final int availHeight = parent.getHeight() - (insets.top + insets.bottom);
4632N/A
4632N/A final Dimension painterD = preferredSize(painter);
4632N/A// Dimension nextD = preferredSize(nextButton);
4632N/A// Dimension previousD = preferredSize(previousButton);
4632N/A final int nextHeight = availHeight / 2;
4632N/A final int previousHeight = availHeight - nextHeight;
4632N/A final int buttonsWidth = painterD.width; //Math.max(nextD.width, previousD.width);
4632N/A final int editorWidth = availWidth - buttonsWidth;
4632N/A
4632N/A /* Deal with the spinners componentOrientation property.
4632N/A */
4632N/A int editorX, buttonsX;
4632N/A if (parent.getComponentOrientation().isLeftToRight()) {
4632N/A editorX = insets.left;
4632N/A buttonsX = editorX + editorWidth;
4632N/A } else {
4632N/A buttonsX = insets.left;
4632N/A editorX = buttonsX + buttonsWidth;
4632N/A }
4632N/A
4632N/A final int previousY = insets.top + nextHeight;
4632N/A final int painterTop = previousY - (painterD.height / 2);
4632N/A setBounds(editor, editorX, insets.top, editorWidth, availHeight);
4632N/A setBounds(nextButton, buttonsX, insets.top, buttonsWidth, nextHeight);
4632N/A setBounds(previousButton, buttonsX, previousY, buttonsWidth, previousHeight);
4632N/A setBounds(painter, buttonsX, painterTop, buttonsWidth, painterD.height);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * Detect JSpinner property changes we're interested in and delegate. Subclasses
4632N/A * shouldn't need to replace the default propertyChangeListener (although they
4632N/A * can by overriding createPropertyChangeListener) since all of the interesting
4632N/A * property changes are delegated to protected methods.
4632N/A */
4632N/A static class PropertyChangeHandler implements PropertyChangeListener {
4632N/A public void propertyChange(final PropertyChangeEvent e) {
4632N/A final String propertyName = e.getPropertyName();
4632N/A final JSpinner spinner = (JSpinner)(e.getSource());
4632N/A final SpinnerUI spinnerUI = spinner.getUI();
4632N/A
4632N/A if (spinnerUI instanceof AquaSpinnerUI) {
4632N/A final AquaSpinnerUI ui = (AquaSpinnerUI)spinnerUI;
4632N/A
4632N/A if ("editor".equals(propertyName)) {
4632N/A final JComponent oldEditor = (JComponent)e.getOldValue();
4632N/A final JComponent newEditor = (JComponent)e.getNewValue();
4632N/A ui.replaceEditor(oldEditor, newEditor);
4632N/A ui.updateEnabledState();
4632N/A } else if ("enabled".equals(propertyName)) {
4632N/A ui.updateEnabledState();
4632N/A } else if (JComponent.TOOL_TIP_TEXT_KEY.equals(propertyName)) {
4632N/A ui.updateToolTipTextForChildren(spinner);
4639N/A } else if ("font".equals(propertyName)) {
4639N/A JComponent editor = spinner.getEditor();
4639N/A if (editor != null && editor instanceof JSpinner.DefaultEditor) {
4639N/A JTextField tf =
4639N/A ((JSpinner.DefaultEditor) editor).getTextField();
4639N/A if (tf != null) {
4639N/A if (tf.getFont() instanceof UIResource) {
4639N/A tf.setFont(spinner.getFont());
4639N/A }
4639N/A }
4639N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A // Syncronizes the ToolTip text for the components within the spinner
4632N/A // to be the same value as the spinner ToolTip text.
4632N/A void updateToolTipTextForChildren(final JComponent spinnerComponent) {
4632N/A final String toolTipText = spinnerComponent.getToolTipText();
4632N/A final Component[] children = spinnerComponent.getComponents();
4632N/A for (final Component element : children) {
4632N/A if (element instanceof JSpinner.DefaultEditor) {
4632N/A final JTextField tf = ((JSpinner.DefaultEditor)element).getTextField();
4632N/A if (tf != null) {
4632N/A tf.setToolTipText(toolTipText);
4632N/A }
4632N/A } else if (element instanceof JComponent) {
4632N/A ((JComponent)element).setToolTipText(toolTipText);
4632N/A }
4632N/A }
4632N/A }
4632N/A}