summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java')
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java561
1 files changed, 561 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java
new file mode 100644
index 000000000..00c8537cc
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java
@@ -0,0 +1,561 @@
+/* BasicSpinnerUI.java --
+ Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JSpinner;
+import javax.swing.LookAndFeel;
+import javax.swing.Timer;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.SpinnerUI;
+
+/**
+ * A UI delegate for the {@link JSpinner} component.
+ *
+ * @author Ka-Hing Cheung
+ *
+ * @since 1.4
+ */
+public class BasicSpinnerUI extends SpinnerUI
+{
+ /**
+ * Creates a new <code>BasicSpinnerUI</code> for the specified
+ * <code>JComponent</code>
+ *
+ * @param c the component (ignored).
+ *
+ * @return A new instance of {@link BasicSpinnerUI}.
+ */
+ public static ComponentUI createUI(JComponent c)
+ {
+ return new BasicSpinnerUI();
+ }
+
+ /**
+ * Creates an editor component. Really, it just returns
+ * <code>JSpinner.getEditor()</code>
+ *
+ * @return a JComponent as an editor
+ *
+ * @see javax.swing.JSpinner#getEditor
+ */
+ protected JComponent createEditor()
+ {
+ return spinner.getEditor();
+ }
+
+ /**
+ * Creates a <code>LayoutManager</code> that layouts the sub components. The
+ * subcomponents are identifies by the constraint "Next", "Previous" and
+ * "Editor"
+ *
+ * @return a LayoutManager
+ *
+ * @see java.awt.LayoutManager
+ */
+ protected LayoutManager createLayout()
+ {
+ return new DefaultLayoutManager();
+ }
+
+ /**
+ * Creates the "Next" button
+ *
+ * @return the next button component
+ */
+ protected Component createNextButton()
+ {
+ JButton button = new BasicArrowButton(BasicArrowButton.NORTH);
+ return button;
+ }
+
+ /**
+ * Creates the "Previous" button
+ *
+ * @return the previous button component
+ */
+ protected Component createPreviousButton()
+ {
+ JButton button = new BasicArrowButton(BasicArrowButton.SOUTH);
+ return button;
+ }
+
+ /**
+ * Creates the <code>PropertyChangeListener</code> that will be attached by
+ * <code>installListeners</code>. It should watch for the "editor"
+ * property, when it's changed, replace the old editor with the new one,
+ * probably by calling <code>replaceEditor</code>
+ *
+ * @return a PropertyChangeListener
+ *
+ * @see #replaceEditor
+ */
+ protected PropertyChangeListener createPropertyChangeListener()
+ {
+ return new PropertyChangeListener()
+ {
+ public void propertyChange(PropertyChangeEvent event)
+ {
+ // FIXME: Add check for enabled property change. Need to
+ // disable the buttons.
+ if ("editor".equals(event.getPropertyName()))
+ BasicSpinnerUI.this.replaceEditor((JComponent) event.getOldValue(),
+ (JComponent) event.getNewValue());
+ // FIXME: Handle 'font' property change
+ }
+ };
+ }
+
+ /**
+ * Called by <code>installUI</code>. This should set various defaults
+ * obtained from <code>UIManager.getLookAndFeelDefaults</code>, as well as
+ * set the layout obtained from <code>createLayout</code>
+ *
+ * @see javax.swing.UIManager#getLookAndFeelDefaults
+ * @see #createLayout
+ * @see #installUI
+ */
+ protected void installDefaults()
+ {
+ LookAndFeel.installColorsAndFont(spinner, "Spinner.background",
+ "Spinner.foreground", "Spinner.font");
+ LookAndFeel.installBorder(spinner, "Spinner.border");
+ JComponent e = spinner.getEditor();
+ if (e instanceof JSpinner.DefaultEditor)
+ {
+ JSpinner.DefaultEditor de = (JSpinner.DefaultEditor) e;
+ de.getTextField().setBorder(null);
+ }
+ spinner.setLayout(createLayout());
+ spinner.setOpaque(true);
+ }
+
+ /*
+ * Called by <code>installUI</code>, which basically adds the
+ * <code>PropertyChangeListener</code> created by
+ * <code>createPropertyChangeListener</code>
+ *
+ * @see #createPropertyChangeListener
+ * @see #installUI
+ */
+ protected void installListeners()
+ {
+ spinner.addPropertyChangeListener(listener);
+ }
+
+ /*
+ * Install listeners to the next button so that it increments the model
+ */
+ protected void installNextButtonListeners(Component c)
+ {
+ c.addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent evt)
+ {
+ if (! spinner.isEnabled())
+ return;
+ increment();
+ timer.setInitialDelay(500);
+ timer.start();
+ }
+
+ public void mouseReleased(MouseEvent evt)
+ {
+ timer.stop();
+ }
+
+ void increment()
+ {
+ Object next = BasicSpinnerUI.this.spinner.getNextValue();
+ if (next != null)
+ BasicSpinnerUI.this.spinner.getModel().setValue(next);
+ }
+
+ volatile boolean mouseDown;
+ Timer timer = new Timer(50,
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ increment();
+ }
+ });
+ });
+ }
+
+ /*
+ * Install listeners to the previous button so that it decrements the model
+ */
+ protected void installPreviousButtonListeners(Component c)
+ {
+ c.addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent evt)
+ {
+ if (! spinner.isEnabled())
+ return;
+ decrement();
+ timer.setInitialDelay(500);
+ timer.start();
+ }
+
+ public void mouseReleased(MouseEvent evt)
+ {
+ timer.stop();
+ }
+
+ void decrement()
+ {
+ Object prev = BasicSpinnerUI.this.spinner.getPreviousValue();
+ if (prev != null)
+ BasicSpinnerUI.this.spinner.getModel().setValue(prev);
+ }
+
+ volatile boolean mouseDown;
+ Timer timer = new Timer(50,
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ decrement();
+ }
+ });
+ });
+ }
+
+ /**
+ * Install this UI to the <code>JComponent</code>, which in reality, is a
+ * <code>JSpinner</code>. Calls <code>installDefaults</code>,
+ * <code>installListeners</code>, and also adds the buttons and editor.
+ *
+ * @param c DOCUMENT ME!
+ *
+ * @see #installDefaults
+ * @see #installListeners
+ * @see #createNextButton
+ * @see #createPreviousButton
+ * @see #createEditor
+ */
+ public void installUI(JComponent c)
+ {
+ super.installUI(c);
+
+ spinner = (JSpinner) c;
+
+ installDefaults();
+ installListeners();
+
+ Component next = createNextButton();
+ Component previous = createPreviousButton();
+
+ installNextButtonListeners(next);
+ installPreviousButtonListeners(previous);
+
+ c.add(createEditor(), "Editor");
+ c.add(next, "Next");
+ c.add(previous, "Previous");
+ }
+
+ /**
+ * Replace the old editor with the new one
+ *
+ * @param oldEditor the old editor
+ * @param newEditor the new one to replace with
+ */
+ protected void replaceEditor(JComponent oldEditor, JComponent newEditor)
+ {
+ spinner.remove(oldEditor);
+ spinner.add(newEditor);
+ }
+
+ /**
+ * The reverse of <code>installDefaults</code>. Called by
+ * <code>uninstallUI</code>
+ */
+ protected void uninstallDefaults()
+ {
+ spinner.setLayout(null);
+ }
+
+ /**
+ * The reverse of <code>installListeners</code>, called by
+ * <code>uninstallUI</code>
+ */
+ protected void uninstallListeners()
+ {
+ spinner.removePropertyChangeListener(listener);
+ }
+
+ /**
+ * Called when the current L&F is replaced with another one, should call
+ * <code>uninstallDefaults</code> and <code>uninstallListeners</code> as
+ * well as remove the next/previous buttons and the editor
+ *
+ * @param c DOCUMENT ME!
+ */
+ public void uninstallUI(JComponent c)
+ {
+ super.uninstallUI(c);
+
+ uninstallDefaults();
+ uninstallListeners();
+ c.removeAll();
+ }
+
+ /** The spinner for this UI */
+ protected JSpinner spinner;
+
+ /** DOCUMENT ME! */
+ private PropertyChangeListener listener = createPropertyChangeListener();
+
+ /**
+ * A layout manager for the {@link JSpinner} component. The spinner has
+ * three subcomponents: an editor, a 'next' button and a 'previous' button.
+ */
+ private class DefaultLayoutManager implements LayoutManager
+ {
+ /**
+ * Layout the spinners inner parts.
+ *
+ * @param parent The parent container
+ */
+ public void layoutContainer(Container parent)
+ {
+ synchronized (parent.getTreeLock())
+ {
+ Insets i = parent.getInsets();
+ boolean l2r = parent.getComponentOrientation().isLeftToRight();
+ /*
+ -------------- --------------
+ | | n | | n | |
+ | e | - | or | - | e |
+ | | p | | p | |
+ -------------- --------------
+ */
+ Dimension e = prefSize(editor);
+ Dimension n = prefSize(next);
+ Dimension p = prefSize(previous);
+ Dimension s = parent.getSize();
+
+ int x = l2r ? i.left : i.right;
+ int y = i.top;
+ int w = Math.max(p.width, n.width);
+ int h = (s.height - i.bottom) / 2;
+ int e_width = s.width - w - i.left - i.right;
+
+ if (l2r)
+ {
+ setBounds(editor, x, y, e_width, 2 * h);
+ x += e_width;
+ setBounds(next, x, y, w, h);
+ y += h;
+ setBounds(previous, x, y, w, h);
+ }
+ else
+ {
+ setBounds(next, x, y + (s.height - e.height) / 2, w, h);
+ y += h;
+ setBounds(previous, x, y + (s.height - e.height) / 2, w, h);
+ x += w;
+ y -= h;
+ setBounds(editor, x, y, e_width, e.height);
+ }
+ }
+ }
+
+ /**
+ * Calculates the minimum layout size.
+ *
+ * @param parent the parent.
+ *
+ * @return The minimum layout size.
+ */
+ public Dimension minimumLayoutSize(Container parent)
+ {
+ Dimension d = new Dimension();
+
+ if (editor != null)
+ {
+ Dimension tmp = editor.getMinimumSize();
+ d.width += tmp.width;
+ d.height = tmp.height;
+ }
+
+ int nextWidth = 0;
+ int previousWidth = 0;
+
+ if (next != null)
+ {
+ Dimension tmp = next.getMinimumSize();
+ nextWidth = tmp.width;
+ }
+ if (previous != null)
+ {
+ Dimension tmp = previous.getMinimumSize();
+ previousWidth = tmp.width;
+ }
+
+ d.width += Math.max(nextWidth, previousWidth);
+
+ return d;
+ }
+
+ /**
+ * Returns the preferred layout size of the container.
+ *
+ * @param parent DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public Dimension preferredLayoutSize(Container parent)
+ {
+ Dimension d = new Dimension();
+
+ if (editor != null)
+ {
+ Dimension tmp = editor.getPreferredSize();
+ d.width += Math.max(tmp.width, 40);
+ d.height = tmp.height;
+ }
+
+ int nextWidth = 0;
+ int previousWidth = 0;
+
+ if (next != null)
+ {
+ Dimension tmp = next.getPreferredSize();
+ nextWidth = tmp.width;
+ }
+ if (previous != null)
+ {
+ Dimension tmp = previous.getPreferredSize();
+ previousWidth = tmp.width;
+ }
+
+ d.width += Math.max(nextWidth, previousWidth);
+ Insets insets = parent.getInsets();
+ d.width = d.width + insets.left + insets.right;
+ d.height = d.height + insets.top + insets.bottom;
+ return d;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param child DOCUMENT ME!
+ */
+ public void removeLayoutComponent(Component child)
+ {
+ if (child == editor)
+ editor = null;
+ else if (child == next)
+ next = null;
+ else if (previous == child)
+ previous = null;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param name DOCUMENT ME!
+ * @param child DOCUMENT ME!
+ */
+ public void addLayoutComponent(String name, Component child)
+ {
+ if ("Editor".equals(name))
+ editor = child;
+ else if ("Next".equals(name))
+ next = child;
+ else if ("Previous".equals(name))
+ previous = child;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param c DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ private Dimension prefSize(Component c)
+ {
+ if (c == null)
+ return new Dimension();
+ else
+ return c.getPreferredSize();
+ }
+
+ /**
+ * Sets the bounds for the specified component.
+ *
+ * @param c the component.
+ * @param x the x-coordinate for the top-left of the component bounds.
+ * @param y the y-coordinate for the top-left of the component bounds.
+ * @param w the width of the bounds.
+ * @param h the height of the bounds.
+ */
+ private void setBounds(Component c, int x, int y, int w, int h)
+ {
+ if (c != null)
+ c.setBounds(x, y, w, h);
+ }
+
+ /** The editor component. */
+ private Component editor;
+
+ /** The next button. */
+ private Component next;
+
+ /** The previous button. */
+ private Component previous;
+ }
+}