View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of CosyBeans-Common.
5    *
6    * CosyBeans-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * CosyBeans-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with CosyBeans-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.gui.components;
21  
22  import java.awt.BorderLayout;
23  import java.awt.Color;
24  import java.awt.event.ActionListener;
25  import java.awt.event.WindowAdapter;
26  import java.awt.event.WindowEvent;
27  
28  import javax.swing.JComponent;
29  import javax.swing.JFrame;
30  import javax.swing.JTextField;
31  import javax.swing.SwingConstants;
32  
33  import com.cosylab.application.state.State;
34  import com.cosylab.events.SetListener;
35  import com.cosylab.gui.components.customizer.AbstractCustomizerPanel;
36  import com.cosylab.gui.components.numberfield.NumberDescriptor;
37  import com.cosylab.gui.components.util.PopupManageable;
38  
39  /**
40   * <code>LabelledNumberField</code> is extended <code>NumberField</code> with
41   * title label and units label.
42   *
43   * @author <a href="mailto:igor.kriznar@cosylab.com">Igor Kriznar</a>
44   * @author <a href="mailto:jernej.kamenik@cosylab.com">Jernej Kamenik</a>
45   * @version $id$
46   */
47  public class LabelledNumberField extends AbstractNumericDisplayerPanel implements PopupManageable
48  { 
49  	private static final long serialVersionUID = 1L;
50  	private NumberField number;
51  	private AbstractCustomizerPanel customizer;
52  
53  	/**
54  	 * Creates a new LabelledNumberField object.
55  	 */
56  	public LabelledNumberField()
57  	{
58  		this(null, "3.2f", null, null, false);
59  	}
60  
61  	/**
62  	 * Creates a new LabelledNumberField object.
63  	 *
64  	 * @param format initial format
65  	 */
66  	public LabelledNumberField(String format)
67  	{
68  		this(null, format, null, null, false);
69  	}
70  
71  	/**
72  	 * Creates a new LabelledNumberField object.
73  	 *
74  	 * @param value initial value
75  	 */
76  	public LabelledNumberField(Number value)
77  	{
78  		this(value, "3.2f", null, null, false);
79  	}
80  
81  	/**
82  	 * Creates a new LabelledNumberField object.
83  	 *
84  	 * @param value initial value
85  	 * @param format initial format
86  	 */
87  	public LabelledNumberField(Number value, String format)
88  	{
89  		this(value, format, null, null);
90  	}
91  
92  	/**
93  	 * Creates a new LabelledNumberField object.
94  	 *
95  	 * @param value initial value
96  	 * @param format initial format
97  	 * @param title initial title
98  	 * @param units initial units
99  	 */
100 	public LabelledNumberField(Number value, String format, String title,
101 	    String units)
102 	{
103 		this(value, format, title, units, false);
104 	}
105 
106 	/**
107 	 * Creates a new LabelledNumberField object.
108 	 *
109 	 * @param value initial value
110 	 * @param format initial format
111 	 * @param title initial title
112 	 * @param units initial units
113 	 * @param unitsWithTitle if <code>true</code> units shown in title label
114 	 *        and not in separate label
115 	 */
116 	public LabelledNumberField(Number value, String format, String title,
117 	    String units, boolean unitsWithTitle)
118 	{
119 		this(value, format, title, units, true, true, true, unitsWithTitle);
120 	}
121 
122 	/**
123 	 * Creates a new LabelledNumberField object.
124 	 *
125 	 * @param value initial value
126 	 * @param format initial format
127 	 * @param title initial title
128 	 * @param units initial units
129 	 * @param resizable inital resizable
130 	 * @param enchanced inital enchanced
131 	 * @param editable initial editable
132 	 * @param unitsWithTitle if <code>true</code> units shown in title label
133 	 *        and not in separate label
134 	 */
135 	public LabelledNumberField(Number value, String format, String title,
136 	    String units, boolean resizable, boolean enchanced, boolean editable,
137 	    boolean unitsWithTitle)
138 	{
139 		super(title, true, HORIZONTAL_LAYOUT, resizable, true, enchanced, 1,
140 		    Integer.MAX_VALUE, units, !unitsWithTitle, unitsWithTitle);
141 
142 		setEditable(editable);
143 		setFormat(format);
144 		setMaximumValue(new Double(Double.MAX_VALUE));
145 		setMinimumValue(new Double(-Double.MAX_VALUE));
146 
147 		if (value != null) {
148 			setNumberType(value.getClass());
149 			setNumberValue(value);
150 		}
151 
152 		
153 	}
154 
155 	/*
156 	 * (non-Javadoc)
157 	 * @see com.cosylab.gui.components.AbstractDisplayerPanel#getCustomizer()
158 	 */
159 	public AbstractCustomizerPanel getCustomizer()
160 	{
161 		if (customizer == null) {
162 			customizer = AbstractCustomizerPanel.findCustomizer(this);
163 		}
164 
165 		return customizer;
166 	}
167 	
168 	/**
169 	 * Sets number of columns on the <code>NumberField</code>.
170 	 *
171 	 * @see NumberField#setColumns(int)
172 	 */
173 	public void setColumns(int columns)
174 	{
175 		int oldValue = getColumns();
176 		getNumber().setColumns(columns);
177 		firePropertyChange("columns", oldValue, columns);
178 	}
179 
180 	/**
181 	 * Returns number of columns on the <code>NumberField</code>.
182 	 *
183 	 * @see JTextField#getColumns()
184 	 */
185 	public int getColumns()
186 	{
187 		return getNumber().getColumns();
188 	}
189 
190 	/**
191 	 * Sets the value of type <code>double</code> to be displayed.
192 	 *
193 	 * @param newValue
194 	 */
195 	public void setDoubleValue(double newValue)
196 	{
197 		double oldValue = getDoubleValue();
198 		getNumber().setDoubleValue(newValue);
199 		firePropertyChange("doubleValue", oldValue, newValue);
200 	}
201 
202 	/**
203 	 * Returns the value of type <code>double</code>
204 	 *
205 	 * @return double
206 	 */
207 	public double getDoubleValue()
208 	{
209 		return getNumber().getDoubleValue();
210 	}
211 
212 	/**
213 	 * Enables/disables user editing of number.
214 	 *
215 	 * @param editable if <code>true</code> user is allowed to set value.
216 	 */
217 	public void setEditable(boolean editable)
218 	{
219 		boolean oldValue = isEditable();
220 		getNumber().setEditable(editable);
221 		firePropertyChange("editable", oldValue, editable);
222 	}
223 
224 	/**
225 	 * Returns <code>true</code> if user is allowed to set value.
226 	 *
227 	 * @return boolean <code>true</code> if user is allowed to input number
228 	 */
229 	public boolean isEditable()
230 	{
231 		return getNumber().isEditable();
232 	}
233 
234 	/**
235 	 * Sets the value of type <code>long</code> to be displayed.
236 	 *
237 	 * @param newValue
238 	 */
239 	public void setLongValue(long newValue)
240 	{
241 		long oldValue = getLongValue();
242 		getNumber().setLongValue(newValue);
243 		firePropertyChange("longValue", oldValue, newValue);
244 	}
245 
246 	/**
247 	 * Returns the value of type <code>long</code>
248 	 *
249 	 * @return long
250 	 */
251 	public long getLongValue()
252 	{
253 		return getNumber().getLongValue();
254 	}
255 
256 	/**
257 	 * Sets the maximum allowed value that can be entered in this NumberField.
258 	 * Setting maximum to null means no maximum is set. This method does not
259 	 * check for validity of the limit. If maximum is set less than minimum
260 	 * then no value can be set.
261 	 *
262 	 * @param newMaximum Number
263 	 */
264 	public void setMaximumValue(Number newMaximum)
265 	{
266 		Number oldValue = getMaximumValue();
267 		getNumber().setMaximum(newMaximum);
268 		super.setMaximumValue(number.getMaximum());
269 		firePropertyChange("maximumValue", oldValue, newMaximum);
270 	}
271 
272 	/**
273 	 * Returns the maximum value allowed by this NumberField. Can be null if no
274 	 * maximum is set.
275 	 *
276 	 * @return Number maximum allowed value.
277 	 */
278 	public Number getMaximumValue()
279 	{
280 		return getNumber().getMaximum();
281 	}
282 
283 	/**
284 	 * Sets the minimum allowed value that can be entered in this NumberField.
285 	 * Setting minimum to null means no minimum is set. This method does not
286 	 * check for validity of the limit. If minimum is set more than maximum
287 	 * then no value can be set.
288 	 *
289 	 * @param newMinimum Number
290 	 */
291 	public void setMinimumValue(Number newMinimum)
292 	{
293 		Number oldValue = getMinimumValue();
294 		getNumber().setMinimum(newMinimum);
295 		super.setMinimumValue(number.getMinimum());
296 		firePropertyChange("minimumValue", oldValue, newMinimum);
297 	}
298 
299 	/**
300 	 * Returns the minimum value allowed by this NumberField. Can be null if no
301 	 * miminum is set.
302 	 *
303 	 * @return Number minimum allowed value
304 	 */
305 	public Number getMinimumValue()
306 	{
307 		return getNumber().getMinimum();
308 	}
309 
310 	/**
311 	 * Sets the number format.
312 	 *
313 	 * @param newNumberFormat
314 	 */
315 	public void setNumberType(Class<? extends Number> newNumberFormat)
316 	{
317 		Class<? extends Number> oldValue = getNumberType();
318 		getNumber().setNumberType(newNumberFormat);
319 		super.setNumberType(newNumberFormat);
320 		firePropertyChange("numberType", oldValue, newNumberFormat);
321 	}
322 
323 	/**
324 	 * Returns the type of displayed number.
325 	 *
326 	 * @return type of displayed number
327 	 */
328 	public Class<? extends Number> getNumberType()
329 	{
330 		return getNumber().getNumberType();
331 	}
332 
333 	/**
334 	 * Sets the numeric value for this component. New value is subject to
335 	 * min/max test if any of them is set. If new value does not fall within
336 	 * these bounds, setting value will do nothing.
337 	 *
338 	 * @param newValue Number
339 	 */
340 	public void setNumberValue(Number newValue)
341 	{
342 		Number oldValue = getNumberValue();
343 		getNumber().setValue(newValue);
344 		firePropertyChange("numberValue", oldValue, newValue);
345 	}
346 
347 	/**
348 	 * Returns generic representation of the value using the
349 	 * <code>Number</code> class.
350 	 *
351 	 * @return java.lang.Number
352 	 */
353 	public Number getNumberValue()
354 	{
355 		return getNumber().getValue();
356 	}
357 
358 	/*
359 	 * (non-Javadoc)
360 	 * @see com.cosylab.gui.components.AbstractNumericDisplayerPanel#setState(com.cosylab.application.state.State)
361 	 */
362 	public void setState(State state)
363 	{
364 		super.setState(state);
365 
366 		setEditable(state.getBoolean("editable", isEditable()));
367 		setColumns(state.getInt("columns", getColumns()));
368 		setTiltingEnabled(state.getBoolean("tiltingEnabled", isTiltingEnabled()));
369 	}
370 
371 	/**
372 	 * Enables/disables tilting when value is out of bounds.
373 	 * 
374 	 * @param b true if tilting should be enabled
375 	 * @see NumberField#setTiltingEnabled(boolean)
376 	 */
377 	public void setTiltingEnabled(boolean b)
378 	{
379 		if (isTiltingEnabled() == b) return;
380 		getNumber().setTiltingEnabled(b);
381 		firePropertyChange("tiltingEnabled", !b, b);
382 	}
383 
384 	/*
385 	 * (non-Javadoc)
386 	 * @see com.cosylab.gui.components.AbstractNumericDisplayerPanel#getState()
387 	 */
388 	public State getState()
389 	{
390 		State state = super.getState();
391 
392 		state.putBoolean("editable", isEditable());
393 		state.putBoolean("tiltingEnabled", isTiltingEnabled());
394 		state.putInt("columns", getColumns());
395 
396 		return state;
397 	}
398 
399 	/**
400 	 * Returns true if tilting is enabled.
401 	 * 
402 	 * @return true if tilting enabled
403 	 * @see #setTiltingEnabled(boolean)
404 	 * @see NumberField#isTiltingEnabled()
405 	 */
406 	public boolean isTiltingEnabled()
407 	{
408 		return getNumber().isTiltingEnabled();
409 	}
410 
411 	/**
412 	 * Adds action listener on <code>NumberField</code>.
413 	 *
414 	 * @param l
415 	 */
416 	public void addActionListener(ActionListener l)
417 	{
418 		number.addActionListener(l);
419 	}
420 
421 	/**
422 	 * Adds set listener to the <code>NumberField</code>.
423 	 *
424 	 * @see NumberField#addSetListener(SetListener)
425 	 */
426 	public void addSetListener(SetListener l)
427 	{
428 		getNumber().addSetListener(l);
429 	}
430 
431 	/**
432 	 * Removes action listener from <code>NumberField</code>.
433 	 *
434 	 * @param l
435 	 */
436 	public void removeActionListener(ActionListener l)
437 	{
438 		number.removeActionListener(l);
439 	}
440 
441 	/**
442 	 * Removes set listener from the <code>NumberField</code>.
443 	 *
444 	 * @see NumberField#removeSetListener(SetListener)
445 	 */
446 	public void removeSetListener(SetListener l)
447 	{
448 		getNumber().removeSetListener(l);
449 	}
450 
451 	/**
452 	 * The <code>NumberField</code> component, that does number editing and
453 	 * rendering.
454 	 *
455 	 * @return the <code>NumberField</code> component
456 	 */
457 	protected NumberField getNumber()
458 	{
459 		if (number == null) {
460 			number = new NumberField();
461 			number.setResizable(true);
462 			number.setSettingPolicy(NumberField.SET_ON_APPLY);
463 			number.setHorizontalAlignment(SwingConstants.RIGHT);
464 
465 			//			number.addPropertyChangeListener(new PropertyChangeListener() {
466 			//					public void propertyChange(PropertyChangeEvent evt)
467 			//					{
468 			//						if (("preferredSize").equals(evt.getPropertyName())) {
469 			//							setPreferredSize(new Dimension(
470 			//							        (int)(getNumber().getPreferredSize().width * 1.05),
471 			//							        (int)(getNumber().getPreferredSize().height * 1.05)));
472 			//						}
473 			//
474 			//						firePropertyChange(evt.getPropertyName(),
475 			//						    evt.getOldValue(), evt.getNewValue());
476 			//
477 			//						if (NumberField.VALUE.equals(evt.getPropertyName())) {
478 			//							LabelledNumberField.this.doLayout();
479 			//						}
480 			//					}
481 			//				});
482 			number.addMouseListener(getPopupManager().getMouseHook());
483 		}
484 
485 		return number;
486 	}
487 	
488 	/* (non-Javadoc)
489 	 * @see com.cosylab.gui.components.DisplayerPanel#getValueComponent()
490 	 */
491 	protected JComponent getValueComponent()
492 	{
493 		return getNumber();
494 	}
495 	
496 	/*
497 	 * (non-Javadoc)
498 	 * @see com.cosylab.gui.components.AbstractNumericDisplayerPanel#internalSetEnabled()
499 	 */
500 	protected void internalSetEnabled()
501 	{
502 		super.internalSetEnabled();
503 		getNumber().setEnabled(isEnabled());
504 	}
505 
506 	/*
507 	 * (non-Javadoc)
508 	 * @see com.cosylab.gui.components.AbstractNumericDisplayerPanel#internalSetEnhanced()
509 	 */
510 	protected void internalSetEnhanced()
511 	{
512 		super.internalSetEnhanced();
513 		getNumber().setEnhanced(isEnhanced());
514 	}
515 
516 	/*
517 	 * (non-Javadoc)
518 	 * @see com.cosylab.gui.components.AbstractNumericDisplayerPanel#internalSetFormat()
519 	 */
520 	protected void internalSetFormat()
521 	{
522 		super.internalSetFormat();
523 
524 		String tFormat = getFormat();
525 
526 		if (tFormat == null) {
527 			tFormat = NumberField.createDefaultFormat(getNumberType());
528 		}
529 
530 		getNumber().setFormat(tFormat);
531 	}
532 
533 	/*
534 	 * (non-Javadoc)
535 	 * @see com.cosylab.gui.components.AbstractNumericDisplayerPanel#internalSetResizable()
536 	 */
537 	protected void internalSetResizable()
538 	{
539 		super.internalSetResizable();
540 		getNumber().setResizable(isResizable());
541 		getNumber().revalidate();
542 	}
543 
544 	/**
545 	 * Returns descriptor object, to which visualization of number as strring
546 	 * is dlegated.
547 	 *
548 	 * @return number visualization
549 	 */
550 	public NumberDescriptor getNumberDescriptor()
551 	{
552 		return getNumber().getNumberDescriptor();
553 	}
554 
555 	/**
556 	 * When this is set with non-null value, this NumberField uses this
557 	 * descriptor to convert Number to string and back. By this user can
558 	 * define his own visualization of Number.
559 	 *
560 	 * @param numberDescriptor new Number visualization, can be
561 	 *        <code>null</code>
562 	 */
563 	public void setNumberDescriptor(NumberDescriptor numberDescriptor)
564 	{
565 		NumberDescriptor oldValue = getNumberDescriptor();
566 		getNumber().setNumberDescriptor(numberDescriptor);
567 		firePropertyChange("numberDescriptor", oldValue, numberDescriptor);
568 	}
569 	/**
570 	 * Sets the setting policy of thi Numberdisplayer. SET_AS_TYPED updates the
571 	 * Numberfield value when typed. SET_ON_APPLY updates the Numberfield only
572 	 * on actionPerformed events (when the user presses ENTER) SET_ON_EXIT
573 	 * updates the numberfield when it loses focus
574 	 *
575 	 * @param newPolicy new policy
576 	 * @see NumberField#setSettingPolicy(int)
577 	 * @throws IllegalArgumentException
578 	 */
579 	public void setSettingPolicy(int newPolicy)
580 	{
581 		int oldValue = getSettingPolicy();
582 		getNumber().setSettingPolicy(newPolicy);
583 		firePropertyChange("settingPolicy", oldValue, newPolicy);
584 	}
585 	/**
586 	 * Returns the currently used seting policy by this Numberfield
587 	 *
588 	 * @return int currently used setting policy.
589 	 * @see NumberField#getSettingPolicy()
590 	 */
591 	public int getSettingPolicy()
592 	{
593 		return getNumber().getSettingPolicy();
594 	}
595 	
596 	/**
597 	 * If warnOutOfBounds is set to true, user will be notified when a
598 	 * value is set ot of the preset bounds.
599 	 * 
600 	 * @param b true if warnings are turned on
601 	 */
602 	public void setWarnOutOfBounds(Boolean b) {
603 		Boolean oldValue = isWarnOutOfBounds();
604 		getNumber().setWarnOutOfBounds(b);
605 		firePropertyChange("warnOutOfBounds", oldValue, b);
606 	}
607 	
608 	/**
609 	 * Returns true if the displayer shows a warning when out of bounds.
610 	 * 
611 	 * @return true if warning is shown
612 	 */
613 	public boolean isWarnOutOfBounds() {
614 		return getNumber().isWarnOutOfBounds();
615 	}
616 	
617 	/**
618 	 * Sets the color which indicates the out of bounds state.
619 	 * 
620 	 * @param c new out of bounds state color
621 	 */
622 	public void setOutOfBoundsColor(Color c) {
623 		Color oldValue = getOutOfBoundsColor();
624 		getNumber().setOutOfBoundsColor(c);
625 		firePropertyChange("outOfBoundColor", oldValue, c);
626 	}
627 	
628 	/**
629 	 * Returns th color which indicates the out of bounds state.
630 	 * @return
631 	 */
632 	public Color getOutOfBoundsColor() {
633 		return getNumber().getWarningColor();
634 	}
635 	
636 	/*
637 	 * (non-Javadoc)
638 	 * @see com.cosylab.gui.components.AbstractNumericDisplayerPanel#setBackground(java.awt.Color)
639 	 */
640 	@Override
641 	public void setBackground(Color bg) {
642 		Color fieldBg = getNumber().getBackground();
643 		super.setBackground(bg);
644 		getNumber().setBackground(fieldBg);
645 	}
646 		
647 	/**
648 	 * Run test applet.
649 	 *
650 	 * @param args command line parameters
651 	 */
652 	public static void main(String[] args)
653 	{
654 		JFrame frame = new JFrame("NumberField Testing Applet");
655 		frame.getContentPane().setLayout(new BorderLayout(10, 10));
656 
657 		//frame.getContentPane().add(new LabelledNumberField(new Long(10), "%3d",
658 		//        "Teddy", "Bears"), BorderLayout.CENTER);
659 		final LabelledNumberField field= new LabelledNumberField(new Double(10),
660         "%1.0f", "Current", "A",true);
661 		field.setTitleMaximumFontSize(12);
662 		field.setMaximumValue(1000);
663 		field.setMinimumValue(0);
664 		field.setDoubleValue(0);
665 		field.setUnitsVisible(true);
666 		field.setTiltingEnabled(true);
667 		frame.getContentPane().add(field, BorderLayout.CENTER);
668 		frame.setSize(300, 100);
669 		frame.addWindowListener(new WindowAdapter() {
670 				public void windowClosing(WindowEvent e)
671 				{
672 					System.exit(0);
673 				}
674 			});
675 		frame.setVisible(true);
676 		
677 		new Thread(new Runnable(){
678 			public void run() {
679 				double i = 0;
680 				while(true) {
681 					
682 					
683 					try {
684 						Thread.sleep(10000);
685 					} catch (InterruptedException e) {
686 						// TODO Auto-generated catch block
687 						e.printStackTrace();
688 					}
689 					field.setDoubleValue(i+=1500);
690 				}
691 				
692 			}
693 		}).start();
694 	}
695 
696 }
697 
698 /* __oOo__ */