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 com.cosylab.application.state.State;
23  import com.cosylab.gui.components.util.CosyTransferHandler;
24  
25  import com.cosylab.util.Debug;
26  import com.cosylab.util.PrintfFormat;
27  
28  import java.awt.Color;
29  import java.awt.GridBagConstraints;
30  import java.awt.Insets;
31  
32  import java.beans.Beans;
33  
34  import javax.swing.JComponent;
35  import javax.swing.JLabel;
36  import javax.swing.TransferHandler;
37  
38  
39  /**
40   * An extension of AbstractDisplayerPanel used for numerical displayers.
41   *
42   * @author <a href="mailto:jernej.kamenik@cosylab.com">Jernej Kamenik</a>
43   * @version $id$
44   */
45  public abstract class AbstractNumericDisplayerPanel
46  	extends AbstractDisplayerPanel
47  {
48  	private static final long serialVersionUID = 1L;
49  	private Class<? extends Number> numberType = Double.class;
50  	private Number max = null;
51  	private Number min = null;
52  	private PrintfFormat formatter = null;
53  	private ResizableTextLabel maxLabel = null;
54  	private ResizableTextLabel minLabel = null;
55  	private ResizableTextLabel unitsLabel = null;
56  	private String format = null;
57  	private String units = null;
58  	private boolean boundsVisible;
59  	private boolean unitsVisible;
60  	private boolean unitsShownWithTitle;
61  
62  	/**
63  	 * Default constructor.
64  	 */
65  	public AbstractNumericDisplayerPanel()
66  	{
67  		this(null, false, DYNAMIC_LAYOUT, true, true, true, 1,
68  		    Integer.MAX_VALUE, null, true, false);
69  	}
70  
71  	/**
72  	 * Creates a new AbstractNumericDisplayerPanel object with initial
73  	 * parameters.
74  	 *
75  	 * @param title initial value
76  	 * @param titleVisible initial value
77  	 * @param layoutOrientation initial value
78  	 * @param resizable initial value
79  	 * @param enabled initial value
80  	 * @param enchanced initial value
81  	 * @param minTitleFontSize initial value
82  	 * @param maxTitleFontSize initial value
83  	 * @param units initial value
84  	 * @param unitsVisible initial value
85  	 * @param unitsShownWithTitle initial value
86  	 */
87  	public AbstractNumericDisplayerPanel(String title, boolean titleVisible,
88  	    int layoutOrientation, boolean resizable, boolean enabled,
89  	    boolean enchanced, int minTitleFontSize, int maxTitleFontSize,
90  	    String units, boolean unitsVisible, boolean unitsShownWithTitle)
91  	{
92  		super(title, titleVisible, layoutOrientation, resizable, enabled,
93  		    enchanced, minTitleFontSize, maxTitleFontSize);
94  
95  		formatter = new PrintfFormat("%3.2f");
96  
97  		max = new Double(Double.POSITIVE_INFINITY);
98  		min = new Double(Double.NEGATIVE_INFINITY);
99  
100 		internalSetFormat();
101 		internalSetMaximum();
102 		internalSetMinimum();
103 
104 		setUnits(units);
105 		setUnitsVisible(unitsVisible);
106 		setUnitsShownWithTitle(unitsShownWithTitle);
107 	}
108 
109 	/**
110 	 * Sets the visibility of the numerical bounds.
111 	 *
112 	 * @param b wether the bounds should be displayed in the panel.
113 	 */
114 	public void setBoundsVisible(boolean b)
115 	{
116 		if (b == boundsVisible) {
117 			return;
118 		}
119 
120 		boundsVisible = b;
121 		layoutDisplayer();
122 		firePropertyChange("boundsVisible", !b, b);
123 	}
124 
125 	/**
126 	 * Determines wether the component should display the numerical bounds of
127 	 * the value component
128 	 *
129 	 * @return <code>true</code> if the bounds are displayed,
130 	 *         <code>false</code> otherwise.
131 	 */
132 	public boolean isBoundsVisible()
133 	{
134 		return boundsVisible;
135 	}
136 
137 	/**
138 	 * Sets the C-style format String used for formatting numerical values
139 	 *
140 	 * @param value format String
141 	 */
142 	public void setFormat(String value)
143 	{
144 		if (value == null && format == null
145 		    || value != null && value.equals(format)) {
146 			return;
147 		}
148 
149 		String oldVal = format;
150 		format = value;
151 		internalSetFormat();
152 		layoutDisplayer();
153 		firePropertyChange("format", oldVal, getFormat());
154 	}
155 
156 	/**
157 	 * Gets the C-style format string used for formatting numerical display
158 	 *
159 	 * @return the C-style format String
160 	 */
161 	public String getFormat()
162 	{
163 		return format;
164 	}
165 
166 	/*
167 	 * TODO temporary bugfix by unknown
168 	 *
169 	 * @see com.cosylab.gui.components.DisplayerPanel#setLayoutOrientation(int)
170 	 */
171 	public void setLayoutOrientation(int i)
172 	{
173 		if (isBoundsVisible() && (i != VERTICAL_LAYOUT)) {
174 			return;
175 		}
176 
177 		super.setLayoutOrientation(i);
178 	}
179 
180 	/*
181 	 * TODO temporary bugfix by unknown
182 	 *
183 	 * @see com.cosylab.gui.components.DisplayerPanel#getLayoutOrientation()
184 	 */
185 	public int getLayoutOrientation()
186 	{
187 		if (boundsVisible) {
188 			return VERTICAL_LAYOUT;
189 		}
190 
191 		return super.getLayoutOrientation();
192 	}
193 
194 	/*
195 	 * (non-Javadoc)
196 	 * @see com.cosylab.gui.components.AbstractDisplayerPanel#setState(com.cosylab.application.state.State)
197 	 */
198 	public void setState(State state)
199 	{
200 		super.setState(state);
201 
202 		setBoundsVisible(state.getBoolean("boundsVisible", isBoundsVisible()));
203 		setUnitsVisible(state.getBoolean("unitsVisible", isUnitsVisible()));
204 		setUnits(state.getString("units", getUnits()));
205 		setFormat(state.getString("format", getFormat()));
206 	}
207 
208 	/*
209 	 * (non-Javadoc)
210 	 * @see com.cosylab.gui.components.AbstractDisplayerPanel#getState()
211 	 */
212 	public State getState()
213 	{
214 		State state = super.getState();
215 
216 		state.putBoolean("boundsVisible", isBoundsVisible());
217 		state.putBoolean("unitsVisible", isUnitsVisible());
218 		state.putString("units", getUnits());
219 		state.putString("format", getFormat());
220 
221 		return state;
222 	}
223 
224 	/**
225 	 * Sets the units String to denote the physical units of numerical values
226 	 * displayed
227 	 *
228 	 * @param value units String
229 	 */
230 	public void setUnits(String value)
231 	{
232 		if (value == null && units == null
233 		    || value != null && value.equals(units)) {
234 			return;
235 		}
236 
237 		units = value;
238 
239 		internalSetUnits();
240 		layoutDisplayer();
241 
242 		firePropertyChange("units", null, value);
243 	}
244 
245 	/**
246 	 * Gets the physical units of the value displayed by the numeric component
247 	 *
248 	 * @return units String of numeric value displayed
249 	 */
250 	public String getUnits()
251 	{
252 		return units;
253 	}
254 
255 	/**
256 	 * Set to <code>true</code> to display units.
257 	 *
258 	 * @param b <code>true</code> if units are to be displayed.
259 	 */
260 	public void setUnitsVisible(boolean b)
261 	{
262 		if (b == unitsVisible) {
263 			return;
264 		}
265 
266 		unitsVisible = b;
267 		layoutDisplayer();
268 		firePropertyChange("unitsVisible", !b, b);
269 		repaint();
270 	}
271 
272 	/**
273 	 * Returns <code>true</code> if units are displayed.
274 	 *
275 	 * @return boolean <code>true</code> if units are displayed.
276 	 */
277 	public boolean isUnitsVisible()
278 	{
279 		return unitsVisible;
280 	}
281 
282 	/**
283 	 * Gets the component displaying the maximum numerical value. This method
284 	 * is used by the NumericDisplayerPanelLayout.
285 	 *
286 	 * @return the component displaying the nuemrical maximum
287 	 */
288 	protected JComponent getMaxComponent()
289 	{
290 		if (maxLabel == null) {
291 			maxLabel = new ResizableTextLabel();
292 			maxLabel.setHorizontalAlignment(JLabel.CENTER);
293 			maxLabel.addMouseListener(getPopupManager().getMouseHook());
294 			maxLabel.setResizable(isResizable());
295 			maxLabel.setEnabled(isEnabled());
296 			maxLabel.setEnhanced(isEnhanced());
297 //			maxLabel.setVisible(isBoundsVisible());
298 			maxLabel.setMaximumFontSize(getTitleMaximumFontSize());
299 			maxLabel.setMinimumFontSize(getTitleMinimumFontSize());
300 			maxLabel.setBackground(getBackground());
301 			maxLabel.setForeground(getForeground());
302 			internalSetMaximum();
303 		}
304 
305 		return maxLabel;
306 	}
307 
308 	/*
309 	 * Auxilary method to be used for changing the dispalyed numerical bounds.
310 	 */
311 	protected void setMaximumValue(Number value)
312 	{
313 		if (value == null) {
314 			if (numberType == Double.class) {
315 				value = new Double(Double.POSITIVE_INFINITY);
316 			}
317 
318 			if (numberType == Long.class) {
319 				value = new Long(Long.MAX_VALUE);
320 			}
321 		}
322 
323 		max = value;
324 		internalSetMaximum();
325 	}
326 
327 	/*
328 	 * Auxilary method to be used for changing the dispalyed numerical bounds.
329 	 */
330 	protected Number getMaximumValue()
331 	{
332 		return max;
333 	}
334 
335 	/**
336 	 * Returns the component displaying the minimum numerical value. This method
337 	 * is used by the NumericDisplayerPanelLayout.
338 	 *
339 	 * @return the component displaying the nuemrical minimum
340 	 */
341 	protected JComponent getMinComponent()
342 	{
343 		if (minLabel == null) {
344 			minLabel = new ResizableTextLabel();
345 			minLabel.setHorizontalAlignment(JLabel.CENTER);
346 			minLabel.addMouseListener(getPopupManager().getMouseHook());
347 			minLabel.setResizable(isResizable());
348 			minLabel.setEnabled(isEnabled());
349 			minLabel.setEnhanced(isEnhanced());
350 //			minLabel.setVisible(isBoundsVisible());
351 			minLabel.setMaximumFontSize(getTitleMaximumFontSize());
352 			minLabel.setMinimumFontSize(getTitleMinimumFontSize());
353 			minLabel.setBackground(getBackground());
354 			minLabel.setForeground(getForeground());
355 			internalSetMinimum();
356 		}
357 
358 		return minLabel;
359 	}
360 
361 	/*
362 	 * Auxilary method to be used for changing the dispalyed numerical bounds.
363 	 */
364 	protected void setMinimumValue(Number value)
365 	{
366 		if (value == null) {
367 			if (numberType == Double.class) {
368 				value = new Double(Double.NEGATIVE_INFINITY);
369 			}
370 
371 			if (numberType == Long.class) {
372 				value = new Long(-Long.MAX_VALUE);
373 			}
374 		}
375 
376 		min = value;
377 		internalSetMinimum();
378 	}
379 
380 	/*
381 	 * Auxilary method to be used for changing the dispalyed numerical bounds.
382 	 */
383 	protected Number getMinimumValue()
384 	{
385 		return min;
386 	}
387 
388 	/*
389 	 * Sets a new Number type to the panel.
390 	 *
391 	 * @param class1 can be any of <code>double.class</code>,
392 	 *        <code>long.class</code><code>Double.class</code> or
393 	 *        <code>Long.class</code> otherwise an
394 	 *        <code>IllegalArgumentException</code> is thrown. <i>Primitive
395 	 *        type classes are automatically converted to wrapper type
396 	 *        classes.</i>
397 	 *
398 	 * @throws IllegalArgumentException if the type entered is not Long.class,
399 	 * long.class, Double.class or double.class
400 	 */
401 	protected void setNumberType(Class<? extends Number> class1)
402 	{
403 		if (class1 == null) {
404 			throw new IllegalArgumentException("Number type must not be null.");
405 		}
406 
407 		if (class1 != Double.class && class1 != double.class
408 		    && class1 != Long.class && class1 != long.class) {
409 			throw new IllegalArgumentException(
410 			    "Class must represent a  valid number type.");
411 		}
412 
413 		if (class1 == numberType) {
414 			return;
415 		}
416 
417 		if ((class1 == Double.class) || (class1 == double.class)) {
418 			numberType = Double.class;
419 			min = new Double(min.doubleValue());
420 			max = new Double(max.doubleValue());
421 		} else if ((class1 == Long.class) || (class1 == long.class)) {
422 			numberType = Long.class;
423 			min = new Long(min.longValue());
424 			max = new Long(max.longValue());
425 		} else {
426 			throw new IllegalArgumentException("Number type.");
427 		}
428 
429 		if (getFormat() != null) {
430 			setFormat(null);
431 		} 
432 		internalSetFormat();
433 	}
434 
435 	/**
436 	 * Determines the number type currently set to this NumericDispalyerPanel.
437 	 * Only Numbers of selected type can be dispalyed by the component.
438 	 *
439 	 * @return <code>Double.class</code> or <code>Long.class</code>
440 	 */
441 	protected Class<? extends Number> getNumberType()
442 	{
443 		return numberType;
444 	}
445 
446 	/**
447 	 * Returns the GUI component diplaying units.
448 	 *
449 	 * @return the GUI component diplaying units
450 	 */
451 	protected JComponent getUnitsComponent()
452 	{
453 		if (unitsLabel == null) {
454 			unitsLabel = new ResizableTextLabel();
455 			unitsLabel.setHorizontalAlignment(JLabel.LEFT);
456 			unitsLabel.addMouseListener(getPopupManager().getMouseHook());
457 			unitsLabel.setResizable(isResizable());
458 			unitsLabel.setEnhanced(isEnhanced());
459 			unitsLabel.setEnabled(isEnabled());
460 			unitsLabel.setVisible(isUnitsVisible());
461 			unitsLabel.setMaximumFontSize(getTitleMaximumFontSize());
462 			unitsLabel.setMinimumFontSize(getTitleMinimumFontSize());
463 			unitsLabel.setBackground(getBackground());
464 			unitsLabel.setForeground(getForeground());
465 			internalSetUnits();
466 		}
467 
468 		return unitsLabel;
469 	}
470 
471 	/**
472 	 * Overriden to enable/disable min/max labels.
473 	 */
474 	protected void internalSetEnabled()
475 	{
476 		super.internalSetEnabled();
477 
478 		if (maxLabel != null) {
479 			maxLabel.setEnabled(isEnabled());
480 		}
481 
482 		if (minLabel != null) {
483 			minLabel.setEnabled(isEnabled());
484 		}
485 
486 		if (unitsLabel != null) {
487 			unitsLabel.setEnabled(isEnabled());
488 		}
489 	}
490 
491 	/**
492 	 * Overriden to set enahnced mode to min/max labels.
493 	 */
494 	protected void internalSetEnhanced()
495 	{
496 		super.internalSetEnhanced();
497 
498 		if (maxLabel != null) {
499 			maxLabel.setEnhanced(isEnhanced());
500 		}
501 
502 		if (minLabel != null) {
503 			minLabel.setEnhanced(isEnhanced());
504 		}
505 
506 		if (unitsLabel != null) {
507 			unitsLabel.setEnhanced(isEnhanced());
508 		}
509 	}
510 
511 	protected void internalSetFormat()
512 	{
513 		String tFormat = format;
514 
515 		if (format == null) {
516 			tFormat = NumberField.createDefaultFormat(getNumberType());
517 			format = tFormat;
518 		}
519 		
520 		formatter = new PrintfFormat(tFormat);
521 
522 		internalSetMaximum();
523 		internalSetMinimum();
524 	}
525 
526 	protected void internalSetMaximum()
527 	{
528 		if (maxLabel != null && formatter != null) {
529 			try {
530 				maxLabel.setText(formatter.sprintf(getMaximumValue()));
531 			} catch (IllegalArgumentException iae) {
532 				Debug.out("Bad format '" + format + "': " + iae);
533 			}
534 		}
535 	}
536 
537 	protected void internalSetMinimum()
538 	{
539 		if (minLabel != null && formatter != null) {
540 			try {
541 				minLabel.setText(formatter.sprintf(getMinimumValue()));
542 			} catch (IllegalArgumentException iae) {
543 				Debug.out("Bad format '" + format + "': " + iae);
544 			}
545 		}
546 	}
547 
548 	/**
549 	 * Overriden to implement additional functionality.
550 	 *
551 	 * @see com.cosylab.gui.components.AbstractDisplayerPanel#setResizable(boolean)
552 	 */
553 	protected void internalSetResizable()
554 	{
555 		super.internalSetResizable();
556 
557 		if (minLabel != null) {
558 			minLabel.setResizable(isResizable());
559 		}
560 
561 		if (maxLabel != null) {
562 			maxLabel.setResizable(isResizable());
563 		}
564 
565 		if (unitsLabel != null) {
566 			unitsLabel.setResizable(isResizable());
567 		}
568 	}
569 
570 	protected void internalSetUnits()
571 	{
572 		if (unitsLabel != null) {
573 			String tUnits = units;
574 
575 			if (units == null && Beans.isDesignTime()) {
576 				tUnits = "<u>";
577 			}
578 
579 			//if (tUnits == null) {
580 			//	tUnits = "";
581 			//}
582 			unitsLabel.setText(tUnits);
583 		}
584 	}
585 	
586 	/*
587 	 * (non-Javadoc)
588 	 * @see com.cosylab.gui.components.AbstractDisplayerPanel#internalSetTitle()
589 	 */
590 	protected void internalSetTitle()
591 	{
592 		super.internalSetTitle();
593 
594 		String u = units;
595 
596 		if (unitsShownWithTitle) {
597 			if (units == null && Beans.isDesignTime()) {
598 				u = "<u>";
599 			}
600 
601 			getTitleComponent().setText(getTitleComponent().getText() + " ["
602 			    + u + "]");
603 		}
604 	}
605 
606 	/* (non-Javadoc)
607 	 * @see com.cosylab.gui.components.DisplayerPanel#layoutDisplayer()
608 	 */
609 	protected void layoutDisplayer()
610 	{
611 		if (isUnitsVisible() && isTitleVisible() && isBoundsVisible()
612 		    && getTitle() != null && getUnits() != null
613 		    && getTitle().length() > 0 && getUnits().length() > 0) {
614 			layoutValueAndTitleAndUnitsAndBounds();
615 		} else if (isUnitsVisible() && isBoundsVisible() && getUnits() != null
616 		    && getUnits().length() > 0) {
617 			layoutValueAndUnitsAndBounds();
618 		} else if (isUnitsVisible() && isTitleVisible() && getTitle() != null
619 		    && getUnits() != null && getTitle().length() > 0
620 		    && getUnits().length() > 0) {
621 			layoutValueAndTitleAndUnits();
622 		} else if (isUnitsVisible() && getUnits() != null
623 		    && getUnits().length() > 0) {
624 			layoutValueAndUnits();
625 		} else if (isBoundsVisible() && isTitleVisible() && getTitle() != null
626 		    && getTitle().length() > 0) {
627 			layoutValueAndTitleAndBounds();
628 		} else if (isBoundsVisible()) {
629 			layoutValueAndBounds();
630 		} else {
631 			super.layoutDisplayer();
632 		}
633 	}
634 
635 	/*
636 	 * Lays out both value and bounds components.
637 	 */
638 	protected void layoutValueAndBounds()
639 	{
640 		removeAll();
641 
642 		Insets insets = (!isResizable()) ? new Insets(2, 2, 2, 2)
643 			: new Insets((getSize().height * 3) / 100,
644 			    (getSize().width * 3) / 100, (getSize().height * 3) / 100,
645 			    (getSize().width * 3) / 100);
646 		int fill = (isResizable() ? GridBagConstraints.BOTH
647 			: GridBagConstraints.NONE);
648 		double w = isResizable() ? 1.0 : 0.0;
649 
650 		add(getValueComponent(),
651 		    new GridBagConstraints(1, 1, 2, 1, w, w * 1.2,
652 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
653 		add(getMinComponent(),
654 		    new GridBagConstraints(1, 2, 1, 1, w, w * 0.5,
655 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
656 		add(getMaxComponent(),
657 		    new GridBagConstraints(2, 2, 1, 1, w, w * 0.5,
658 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
659 	}
660 
661 	/*
662 	 * Lays out both value, title and bounds components.
663 	 */
664 	protected void layoutValueAndTitleAndBounds()
665 	{
666 		removeAll();
667 
668 		Insets insets = (!isResizable()) ? new Insets(2, 2, 2, 2)
669 			: new Insets((getSize().height * 3) / 100,
670 			    (getSize().width * 3) / 100, (getSize().height * 3) / 100,
671 			    (getSize().width * 3) / 100);
672 		int fill = (isResizable() ? GridBagConstraints.BOTH
673 			: GridBagConstraints.NONE);
674 		double w = isResizable() ? 1.0 : 0.0;
675 
676 		add(getTitleComponent(),
677 		    new GridBagConstraints(1, 1, 2, 1, w, w, GridBagConstraints.CENTER,
678 		        fill, insets, 0, 0));
679 		add(getValueComponent(),
680 		    new GridBagConstraints(1, 2, 2, 1, w, w * 1.2,
681 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
682 		add(getMinComponent(),
683 		    new GridBagConstraints(1, 3, 1, 1, w, w * 0.5,
684 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
685 		add(getMaxComponent(),
686 		    new GridBagConstraints(2, 3, 1, 1, w, w * 0.5,
687 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
688 	}
689 
690 	protected void layoutValueAndTitleAndUnits()
691 	{
692 		removeAll();
693 
694 		Insets insets = !isResizable() ? new Insets(2, 2, 2, 2)
695 			: new Insets(getSize().height * 3 / 100, getSize().width * 3 / 100,
696 			    getSize().height * 3 / 100, getSize().width * 3 / 100);
697 		int fill = (isResizable() ? GridBagConstraints.BOTH
698 			: GridBagConstraints.NONE);
699 		double w = isResizable() ? 1.0 : 0.0;
700 
701 		if (getLayoutOrientation() == HORIZONTAL_LAYOUT
702 		    || (1. * getSize().height) / (getTitleComponent().getPreferredSize().height
703 		    + getValueComponent().getPreferredSize().height) < (1. * getSize().width
704 		    - insets.left - insets.right) / (getTitleComponent()
705 		    .getPreferredSize().width
706 		    + getValueComponent().getPreferredSize().width
707 		    + getUnitsComponent().getPreferredSize().width)
708 		    && getLayoutOrientation() == DYNAMIC_LAYOUT) {
709 			add(getTitleComponent(),
710 			    new GridBagConstraints(1, 1, 1, 1, w, w,
711 			        GridBagConstraints.CENTER, fill, insets, 0, 0));
712 			add(getValueComponent(),
713 			    new GridBagConstraints(2, 1, 1, 1, w * 1.2, w,
714 			        GridBagConstraints.EAST, fill, insets, 0, 0));
715 			add(getUnitsComponent(),
716 			    new GridBagConstraints(3, 1, 1, 1, w * 0.33, w * 0.33,
717 			        GridBagConstraints.WEST, fill, insets, 0, 0));
718 		} else {
719 			add(getTitleComponent(),
720 			    new GridBagConstraints(1, 1, 2, 1, w, w,
721 			        GridBagConstraints.CENTER, fill, insets, 0, 0));
722 			add(getValueComponent(),
723 			    new GridBagConstraints(1, 2, 1, 1, w * 1.2, w * 1.2,
724 			        GridBagConstraints.EAST, fill, insets, 0, 0));
725 			add(getUnitsComponent(),
726 			    new GridBagConstraints(2, 2, 1, 1, w * 0.33, w * 0.33,
727 			        GridBagConstraints.WEST, fill, insets, 0, 0));
728 		}
729 	}
730 
731 	protected void layoutValueAndTitleAndUnitsAndBounds()
732 	{
733 		removeAll();
734 
735 		Insets insets = !isResizable() ? new Insets(2, 2, 2, 2)
736 			: new Insets(getSize().height * 3 / 100, getSize().width * 3 / 100,
737 			    getSize().height * 3 / 100, getSize().width * 3 / 100);
738 		int fill = (isResizable() ? GridBagConstraints.BOTH
739 			: GridBagConstraints.NONE);
740 		double w = isResizable() ? 1.0 : 0.0;
741 
742 		add(getTitleComponent(),
743 		    new GridBagConstraints(1, 1, 2, 1, w, w, GridBagConstraints.CENTER,
744 		        fill, insets, 0, 0));
745 		add(getValueComponent(),
746 		    new GridBagConstraints(1, 2, 2, 1, w * 1.2, w * 1.2,
747 		        GridBagConstraints.EAST, fill, insets, 0, 0));
748 		add(getUnitsComponent(),
749 		    new GridBagConstraints(2, 2, 1, 1, w, w, GridBagConstraints.WEST,
750 		        fill, insets, 0, 0));
751 		add(getMinComponent(),
752 		    new GridBagConstraints(1, 3, 1, 1, w, w * 0.5,
753 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
754 		add(getMaxComponent(),
755 		    new GridBagConstraints(2, 3, 1, 1, w, w * 0.5,
756 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
757 	}
758 
759 	protected void layoutValueAndUnits()
760 	{
761 		removeAll();
762 
763 		Insets insets = !isResizable() ? new Insets(2, 2, 2, 2)
764 			: new Insets(getSize().height * 3 / 100, getSize().width * 3 / 100,
765 			    getSize().height * 3 / 100, getSize().width * 3 / 100);
766 		int fill = (isResizable() ? GridBagConstraints.BOTH
767 			: GridBagConstraints.NONE);
768 		double w = isResizable() ? 1.0 : 0.0;
769 
770 		add(getValueComponent(),
771 		    new GridBagConstraints(1, 1, 1, 1, w * 1.2, w,
772 		        GridBagConstraints.EAST, fill, insets, 0, 0));
773 		add(getUnitsComponent(),
774 		    new GridBagConstraints(2, 1, 1, 1, w * 0.33, w,
775 		        GridBagConstraints.WEST, fill, insets, 0, 0));
776 	}
777 
778 	protected void layoutValueAndUnitsAndBounds()
779 	{
780 		removeAll();
781 
782 		Insets insets = !isResizable() ? new Insets(2, 2, 2, 2)
783 			: new Insets(getSize().height * 3 / 100, getSize().width * 3 / 100,
784 			    getSize().height * 3 / 100, getSize().width * 3 / 100);
785 		int fill = (isResizable() ? GridBagConstraints.BOTH
786 			: GridBagConstraints.NONE);
787 		double w = isResizable() ? 1.0 : 0.0;
788 
789 		add(getValueComponent(),
790 		    new GridBagConstraints(1, 1, 2, 1, w * 1.2, w * 1.2,
791 		        GridBagConstraints.EAST, fill, insets, 0, 0));
792 		add(getUnitsComponent(),
793 		    new GridBagConstraints(2, 1, 1, 1, w, w * 1.2,
794 		        GridBagConstraints.WEST, fill, insets, 0, 0));
795 		add(getMinComponent(),
796 		    new GridBagConstraints(1, 2, 1, 1, w, w * 0.5,
797 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
798 		add(getMaxComponent(),
799 		    new GridBagConstraints(2, 2, 1, 1, w, w * 0.5,
800 		        GridBagConstraints.CENTER, fill, insets, 0, 0));
801 	}
802 
803 	/**
804 	 * If <code>true</code> units will be shown in title label.
805 	 *
806 	 * @return if <code>true</code> units will be shown in title label
807 	 */
808 	public boolean isUnitsShownWithTitle()
809 	{
810 		return unitsShownWithTitle;
811 	}
812 
813 	/**
814 	 * If set to <code>true</code> units will be shown in title label
815 	 *
816 	 * @param unitsShownWithTitle if <code>true</code> units will be shown in
817 	 *        title label
818 	 */
819 	public void setUnitsShownWithTitle(boolean unitsShownWithTitle)
820 	{
821 		if (unitsShownWithTitle == this.unitsShownWithTitle) {
822 			return;
823 		}
824 
825 		this.unitsShownWithTitle = unitsShownWithTitle;
826 		internalSetTitle();
827 		layoutDisplayer();
828 		firePropertyChange("unitsShownWithTitle", !unitsShownWithTitle,
829 		    unitsShownWithTitle);
830 	}
831 	
832 	/* (non-Javadoc)
833      * @see com.cosylab.gui.components.AbstractDisplayerPanel#setTitleMaximumFontSize(int)
834      */
835     public void setTitleMaximumFontSize(int max) {
836 		if (maxLabel!=null) maxLabel.setMaximumFontSize(max);
837 		if (minLabel!=null) minLabel.setMaximumFontSize(max);
838 		if (unitsLabel!=null) unitsLabel.setMaximumFontSize(max);
839         super.setTitleMaximumFontSize(max);
840     }
841     
842     /* (non-Javadoc)
843      * @see com.cosylab.gui.components.AbstractDisplayerPanel#setTitleMinimumFontSize(int)
844      */
845     public void setTitleMinimumFontSize(int min) {
846 		if (maxLabel!=null) maxLabel.setMinimumFontSize(min);
847 		if (minLabel!=null) minLabel.setMinimumFontSize(min);
848 		if (unitsLabel!=null) unitsLabel.setMinimumFontSize(min);
849         super.setTitleMinimumFontSize(min);
850     }
851     
852     /* (non-Javadoc)
853      * @see javax.swing.JComponent#setTransferHandler(javax.swing.TransferHandler)
854      */
855     @Override
856     public void setTransferHandler(TransferHandler newHandler) {
857     	super.setTransferHandler(newHandler);
858     	CosyTransferHandler.registerTransferHandler(this,newHandler,new JComponent[]{getMaxComponent(),getMinComponent(),getUnitsComponent()});
859     }
860     
861     /*
862      * (non-Javadoc)
863      * @see com.cosylab.gui.components.AbstractDisplayerPanel#setBackground(java.awt.Color)
864      */
865     @Override
866     public void setBackground(Color bg) {
867     	super.setBackground(bg);
868     	getUnitsComponent().setBackground(bg);
869     	getMinComponent().setBackground(bg);
870     	getMaxComponent().setBackground(bg);
871     }
872     
873     /*
874      * (non-Javadoc)
875      * @see com.cosylab.gui.components.AbstractDisplayerPanel#setForeground(java.awt.Color)
876      */
877     @Override
878     public void setForeground(Color fg) {
879     	super.setForeground(fg);
880     	getUnitsComponent().setForeground(fg);
881     	getMinComponent().setForeground(fg);
882     	getMaxComponent().setForeground(fg);
883     }
884 }
885 
886 /* __oOo__ */