001/* 002 * $Id: JSpinField.java,v 1.2 2011/03/24 16:06:33 davep Exp $ 003 * 004 * This file is part of McIDAS-V 005 * 006 * Copyright 2007-2011 007 * Space Science and Engineering Center (SSEC) 008 * University of Wisconsin - Madison 009 * 1225 W. Dayton Street, Madison, WI 53706, USA 010 * https://www.ssec.wisc.edu/mcidas 011 * 012 * All Rights Reserved 013 * 014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 015 * some McIDAS-V source code is based on IDV and VisAD source code. 016 * 017 * McIDAS-V is free software; you can redistribute it and/or modify 018 * it under the terms of the GNU Lesser Public License as published by 019 * the Free Software Foundation; either version 3 of the License, or 020 * (at your option) any later version. 021 * 022 * McIDAS-V is distributed in the hope that it will be useful, 023 * but WITHOUT ANY WARRANTY; without even the implied warranty of 024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 025 * GNU Lesser Public License for more details. 026 * 027 * You should have received a copy of the GNU Lesser Public License 028 * along with this program. If not, see http://www.gnu.org/licenses. 029 */ 030 031package edu.wisc.ssec.mcidasv.data.dateChooser; 032 033import java.awt.BorderLayout; 034import java.awt.Color; 035import java.awt.Component; 036import java.awt.Dimension; 037import java.awt.Font; 038import java.awt.event.ActionEvent; 039import java.awt.event.ActionListener; 040import java.awt.event.FocusEvent; 041import java.awt.event.FocusListener; 042 043import javax.swing.BorderFactory; 044import javax.swing.JFrame; 045import javax.swing.JPanel; 046import javax.swing.JSpinner; 047import javax.swing.JTextField; 048import javax.swing.SpinnerNumberModel; 049import javax.swing.SwingConstants; 050import javax.swing.UIManager; 051import javax.swing.event.CaretEvent; 052import javax.swing.event.CaretListener; 053import javax.swing.event.ChangeEvent; 054import javax.swing.event.ChangeListener; 055 056/** 057 * JSpinField is a numeric field with 2 spin buttons to increase or decrease the 058 * value. It has the same interface as the "old" JSpinField but uses a JSpinner 059 * internally (since J2SE SDK 1.4) rather than a scrollbar for emulating the 060 * spin buttons. 061 * 062 * @author Kai Toedter 063 * @version $LastChangedRevision: 85 $ 064 * @version $LastChangedDate: 2006-04-28 13:50:52 +0200 (Fr, 28 Apr 2006) $ 065 */ 066public class JSpinField extends JPanel implements ChangeListener, CaretListener, ActionListener, 067 FocusListener { 068 private static final long serialVersionUID = 1694904792717740650L; 069 070 protected JSpinner spinner; 071 072 /** the text (number) field */ 073 protected JTextField textField; 074 protected int min; 075 protected int max; 076 protected int value; 077 protected Color darkGreen; 078 079 /** 080 * Default JSpinField constructor. The valid value range is between 081 * Integer.MIN_VALUE and Integer.MAX_VALUE. The initial value is 0. 082 */ 083 public JSpinField() { 084 this(Integer.MIN_VALUE, Integer.MAX_VALUE); 085 } 086 087 /** 088 * JSpinField constructor with given minimum and maximum vaues and initial 089 * value 0. 090 */ 091 public JSpinField(int min, int max) { 092 super(); 093 setName("JSpinField"); 094 this.min = min; 095 if (max < min) 096 max = min; 097 this.max = max; 098 value = 0; 099 if (value < min) 100 value = min; 101 if (value > max) 102 value = max; 103 104 darkGreen = new Color(0, 150, 0); 105 setLayout(new BorderLayout()); 106 textField = new JTextField(); 107 textField.addCaretListener(this); 108 textField.addActionListener(this); 109 textField.setHorizontalAlignment(SwingConstants.RIGHT); 110 textField.setBorder(BorderFactory.createEmptyBorder()); 111 textField.setText(Integer.toString(value)); 112 textField.addFocusListener(this); 113 spinner = new JSpinner() { 114 private static final long serialVersionUID = -6287709243342021172L; 115 private JTextField textField = new JTextField(); 116 117 public Dimension getPreferredSize() { 118 Dimension size = super.getPreferredSize(); 119 return new Dimension(size.width, textField.getPreferredSize().height); 120 } 121 }; 122 spinner.setEditor(textField); 123 spinner.addChangeListener(this); 124 // spinner.setSize(spinner.getWidth(), textField.getHeight()); 125 add(spinner, BorderLayout.CENTER); 126 } 127 128 public void adjustWidthToMaximumValue() { 129 JTextField testTextField = new JTextField(Integer.toString(max)); 130 int width = testTextField.getPreferredSize().width; 131 int height = testTextField.getPreferredSize().height; 132 textField.setPreferredSize(new Dimension(width, height)); 133 textField.revalidate(); 134 } 135 136 /** 137 * Is invoked when the spinner model changes 138 * 139 * @param e 140 * the ChangeEvent 141 */ 142 public void stateChanged(ChangeEvent e) { 143 SpinnerNumberModel model = (SpinnerNumberModel) spinner.getModel(); 144 int value = model.getNumber().intValue(); 145 setValue(value); 146 } 147 148 /** 149 * Sets the value attribute of the JSpinField object. 150 * 151 * @param newValue 152 * The new value 153 * @param updateTextField 154 * true if text field should be updated 155 */ 156 protected void setValue(int newValue, boolean updateTextField, boolean firePropertyChange) { 157 int oldValue = value; 158 if (newValue < min) { 159 value = min; 160 } else if (newValue > max) { 161 value = max; 162 } else { 163 value = newValue; 164 } 165 166 if (updateTextField) { 167 textField.setText(Integer.toString(value)); 168 textField.setForeground(Color.black); 169 } 170 171 if (firePropertyChange) { 172 firePropertyChange("value", oldValue, value); 173 } 174 } 175 176 /** 177 * Sets the value. This is a bound property. 178 * 179 * @param newValue 180 * the new value 181 * 182 * @see #getValue 183 */ 184 public void setValue(int newValue) { 185 setValue(newValue, true, true); 186 spinner.setValue(new Integer(value)); 187 } 188 189 /** 190 * Returns the value. 191 * 192 * @return the value value 193 */ 194 public int getValue() { 195 return value; 196 } 197 198 /** 199 * Sets the minimum value. 200 * 201 * @param newMinimum 202 * the new minimum value 203 * 204 * @see #getMinimum 205 */ 206 public void setMinimum(int newMinimum) { 207 min = newMinimum; 208 } 209 210 /** 211 * Returns the minimum value. 212 * 213 * @return the minimum value 214 */ 215 public int getMinimum() { 216 return min; 217 } 218 219 /** 220 * Sets the maximum value and adjusts the preferred width. 221 * 222 * @param newMaximum 223 * the new maximum value 224 * 225 * @see #getMaximum 226 */ 227 public void setMaximum(int newMaximum) { 228 max = newMaximum; 229 } 230 231 /** 232 * Sets the horizontal alignment of the displayed value. 233 * 234 * @param alignment 235 * the horizontal alignment 236 */ 237 public void setHorizontalAlignment(int alignment) { 238 textField.setHorizontalAlignment(alignment); 239 } 240 241 /** 242 * Returns the maximum value. 243 * 244 * @return the maximum value 245 */ 246 public int getMaximum() { 247 return max; 248 } 249 250 /** 251 * Sets the font property. 252 * 253 * @param font 254 * the new font 255 */ 256 public void setFont(Font font) { 257 if (textField != null) { 258 textField.setFont(font); 259 } 260 } 261 262 /** 263 * Sets the foreground 264 * 265 * @param fg 266 * the foreground 267 */ 268 public void setForeground(Color fg) { 269 if (textField != null) { 270 textField.setForeground(fg); 271 } 272 } 273 274 /** 275 * After any user input, the value of the textfield is proofed. Depending on 276 * being an integer, the value is colored green or red. 277 * 278 * @param e 279 * the caret event 280 */ 281 public void caretUpdate(CaretEvent e) { 282 try { 283 int testValue = Integer.valueOf(textField.getText()).intValue(); 284 285 if ((testValue >= min) && (testValue <= max)) { 286 textField.setForeground(darkGreen); 287 setValue(testValue, false, true); 288 } else { 289 textField.setForeground(Color.red); 290 } 291 } catch (Exception ex) { 292 if (ex instanceof NumberFormatException) { 293 textField.setForeground(Color.red); 294 } 295 296 // Ignore all other exceptions, e.g. illegal state exception 297 } 298 299 textField.repaint(); 300 } 301 302 /** 303 * After any user input, the value of the textfield is proofed. Depending on 304 * being an integer, the value is colored green or red. If the textfield is 305 * green, the enter key is accepted and the new value is set. 306 * 307 * @param e 308 * Description of the Parameter 309 */ 310 public void actionPerformed(ActionEvent e) { 311 if (textField.getForeground().equals(darkGreen)) { 312 setValue(Integer.valueOf(textField.getText()).intValue()); 313 } 314 } 315 316 /** 317 * Enable or disable the JSpinField. 318 * 319 * @param enabled 320 * The new enabled value 321 */ 322 public void setEnabled(boolean enabled) { 323 super.setEnabled(enabled); 324 spinner.setEnabled(enabled); 325 textField.setEnabled(enabled); 326 /* 327 * Fixes the background bug 328 * 4991597 and sets the background explicitely to a 329 * TextField.inactiveBackground. 330 */ 331 if (!enabled) { 332 textField.setBackground(UIManager.getColor("TextField.inactiveBackground")); 333 } 334 } 335 336 /** 337 * Returns the year chooser's spinner (which allow the focus to be set to 338 * it). 339 * 340 * @return Component the spinner or null, if the month chooser has no 341 * spinner 342 */ 343 public Component getSpinner() { 344 return spinner; 345 } 346 347 /** 348 * Creates a JFrame with a JSpinField inside and can be used for testing. 349 * 350 * @param s 351 * The command line arguments 352 */ 353 public static void main(String[] s) { 354 JFrame frame = new JFrame("JSpinField"); 355 frame.getContentPane().add(new JSpinField()); 356 frame.pack(); 357 frame.setVisible(true); 358 } 359 360 /* 361 * (non-Javadoc) 362 * 363 * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent) 364 */ 365 public void focusGained(FocusEvent e) { 366 } 367 368 /** 369 * The value of the text field is checked against a valid (green) value. If 370 * valid, the value is set and a property change is fired. 371 */ 372 public void focusLost(FocusEvent e) { 373 actionPerformed(null); 374 } 375}