/* * JSpinField.java - A spin field using a JSpinner (JDK 1.4) Copyright (C) 2004 * Kai Toedter kai@toedter.com www.toedter.com This program is free software; * you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. This program * 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 Lesser General Public License for more * details. You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.freeplane.core.ui.components.calendar; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * JSpinField is a numeric field with 2 spin buttons to increase or decrease the * value. It has the same interface as the "old" JSpinField but uses a JSpinner * internally (since J2SE SDK 1.4) rather than a scrollbar for emulating the * spin buttons. * * @author Kai Toedter * @version $LastChangedRevision: 85 $ * @version $LastChangedDate: 2006-04-28 13:50:52 +0200 (Fr, 28 Apr 2006) $ */ class JSpinField extends JPanel implements ChangeListener, CaretListener, ActionListener, FocusListener { /** * */ private static final long serialVersionUID = 1L; /** * Creates a JFrame with a JSpinField inside and can be used for testing. * * @param s * The command line arguments */ public static void main(final String[] s) { final JFrame frame = new JFrame("JSpinField"); frame.getContentPane().add(new JSpinField()); frame.pack(); frame.setVisible(true); } private Color darkGreen; private int max; private int min; private int minWidth; int getMinWidth() { return minWidth; } void setMinWidth(int minWidth) { this.minWidth = minWidth; } protected JSpinner spinner; /** the text (number) field */ private JTextField textField; protected int value; /** * Default JSpinField constructor. The valid value range is between * Integer.MIN_VALUE and Integer.MAX_VALUE. The initial value is 0. */ public JSpinField() { this(Integer.MIN_VALUE, Integer.MAX_VALUE); } /** * JSpinField constructor with given minimum and maximum vaues and initial * value 0. */ public JSpinField(final int min, int max) { super(); setName("JSpinField"); this.min = min; if (max < min) { max = min; } this.max = max; value = 0; if (value < min) { value = min; } if (value > max) { value = max; } darkGreen = new Color(0, 150, 0); setLayout(new BorderLayout()); textField = new JTextField(){ private static final long serialVersionUID = 1L; @Override public void setText(String t) { if(minWidth <= t.length()){ super.setText(t); } else{ StringBuilder sb = new StringBuilder(minWidth); for(int i = minWidth; i > t.length(); i--){ sb.append('0'); } sb.append(t); super.setText(sb.toString()); } } }; textField.addCaretListener(this); textField.addActionListener(this); textField.setHorizontalAlignment(SwingConstants.RIGHT); textField.setBorder(BorderFactory.createEmptyBorder()); textField.setText(Integer.toString(value)); textField.addFocusListener(this); spinner = new JSpinner() { /** * */ private static final long serialVersionUID = 1L; final private JTextField textField = new JTextField(); @Override public Dimension getPreferredSize() { final Dimension size = super.getPreferredSize(); return new Dimension(size.width, textField.getPreferredSize().height); } }; spinner.setEditor(textField); spinner.addChangeListener(this); add(spinner, BorderLayout.CENTER); } /** * After any user input, the value of the textfield is proofed. Depending on * being an integer, the value is colored green or red. If the textfield is * green, the enter key is accepted and the new value is set. * * @param e * Description of the Parameter */ public void actionPerformed(final ActionEvent e) { if (textField.getForeground().equals(darkGreen)) { setValue(Integer.valueOf(textField.getText()).intValue()); } } public void adjustWidthToMaximumValue() { final JTextField testTextField = new JTextField(Integer.toString(max)); final int width = testTextField.getPreferredSize().width; final int height = testTextField.getPreferredSize().height; textField.setPreferredSize(new Dimension(width, height)); textField.revalidate(); } /** * After any user input, the value of the textfield is proofed. Depending on * being an integer, the value is colored green or red. * * @param e * the caret event */ public void caretUpdate(final CaretEvent e) { try { final int testValue = Integer.valueOf(textField.getText()).intValue(); if ((testValue >= min) && (testValue <= max)) { textField.setForeground(darkGreen); setValue(testValue, false, true); } else { textField.setForeground(Color.red); } } catch (final Exception ex) { if (ex instanceof NumberFormatException) { textField.setForeground(Color.red); } } textField.repaint(); } /* * (non-Javadoc) * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent) */ public void focusGained(final FocusEvent e) { } /** * The value of the text field is checked against a valid (green) value. If * valid, the value is set and a property change is fired. */ public void focusLost(final FocusEvent e) { actionPerformed(null); } /** * Returns the maximum value. * * @return the maximum value */ public int getMaximum() { return max; } /** * Returns the minimum value. * * @return the minimum value */ public int getMinimum() { return min; } /** * Returns the year chooser's spinner (which allow the focus to be set to * it). * * @return Component the spinner or null, if the month chooser has no * spinner */ public Component getSpinner() { return spinner; } /** * Returns the value. * * @return the value value */ public int getValue() { return value; } /** * Enable or disable the JSpinField. * * @param enabled * The new enabled value */ @Override public void setEnabled(final boolean enabled) { super.setEnabled(enabled); spinner.setEnabled(enabled); textField.setEnabled(enabled); /* * Fixes the background bug 4991597 and sets the background explicitely * to a TextField.inactiveBackground. */ if (!enabled) { textField.setBackground(UIManager.getColor("TextField.inactiveBackground")); } } /** * Sets the font property. * * @param font * the new font */ @Override public void setFont(final Font font) { if (textField != null) { textField.setFont(font); } } /** * Sets the foreground * * @param fg * the foreground */ @Override public void setForeground(final Color fg) { if (textField != null) { textField.setForeground(fg); } } /** * Sets the horizontal alignment of the displayed value. * * @param alignment * the horizontal alignment */ public void setHorizontalAlignment(final int alignment) { textField.setHorizontalAlignment(alignment); } /** * Sets the maximum value and adjusts the preferred width. * * @param newMaximum * the new maximum value * @see #getMaximum */ public void setMaximum(final int newMaximum) { max = newMaximum; } /** * Sets the minimum value. * * @param newMinimum * the new minimum value * @see #getMinimum */ public void setMinimum(final int newMinimum) { min = newMinimum; } /** * Sets the value. This is a bound property. * * @param newValue * the new value * @see #getValue */ public void setValue(final int newValue) { setValue(newValue, true, true); spinner.setValue(new Integer(value)); } /** * Sets the value attribute of the JSpinField object. * * @param newValue * The new value * @param updateTextField * true if text field should be updated */ protected void setValue(final int newValue, final boolean updateTextField, final boolean firePropertyChange) { final int oldValue = value; if (newValue < min) { value = min; } else if (newValue > max) { value = max; } else { value = newValue; } if (updateTextField) { textField.setText(Integer.toString(value)); textField.setForeground(Color.black); } if (firePropertyChange) { firePropertyChange("value", oldValue, value); } } /** * Is invoked when the spinner model changes * * @param e * the ChangeEvent */ public void stateChanged(final ChangeEvent e) { final SpinnerNumberModel model = (SpinnerNumberModel) spinner.getModel(); final int value = model.getNumber().intValue(); setValue(value); } }