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.gui.components.util.FontHelper;
23  import com.cosylab.gui.components.util.PaintHelper;
24  
25  import com.cosylab.logging.DebugLogger;
26  
27  import java.awt.Dimension;
28  import java.awt.Font;
29  import java.awt.Graphics;
30  import java.awt.Graphics2D;
31  import java.awt.event.ComponentAdapter;
32  import java.awt.event.ComponentEvent;
33  import java.awt.event.HierarchyEvent;
34  import java.awt.event.HierarchyListener;
35  
36  import java.util.logging.Level;
37  import java.util.logging.Logger;
38  
39  import javax.swing.Icon;
40  import javax.swing.JLabel;
41  import javax.swing.SwingConstants;
42  
43  
44  /**
45   * A text area in which the text can dynamicaly adjust its font size to fill
46   * the whole area available. By default resizing is turn off.
47   *
48   * @author <a href="mailto:jernej.kamenik@cosylab.com">Jernej Kamenik</a>
49   * @version $id$
50   *
51   * @see javax.swing.JLabel
52   */
53  public class ResizableTextLabel extends JLabel
54  {
55  	private static final long serialVersionUID = 1L;
56  	private boolean resizable;
57  	private boolean enhanced;
58  	private int columns;
59  	private Dimension preferredSize;
60  	private Dimension minimumSize;
61  	private Font userFont;
62  	private int minFontSize = 0;
63  	private int maxFontSize = Integer.MAX_VALUE;
64  	private final Logger logger = DebugLogger.getLogger("RTL",
65  		    Level.OFF);
66  
67  	/**
68  	 * Helper class that notifies the resizable text label to  resize its font
69  	 * when itself is being resized.
70  	 *
71  	 * @author <a href="mailto:jernej.kamenik@cosylab.com">Jernej Kamenik</a>
72  	 * @version $id$
73  	 *
74  	 * @see java.awt.event.ComponentAdapter
75  	 */
76  	protected class ResizableAdapter extends ComponentAdapter implements HierarchyListener
77  	{
78  		/**
79  		 * Invoked when the label is being resized.
80  		 *
81  		 * @param e ComponentEvent
82  		 *
83  		 * @see java.awt.event.ComponentListener#componentResized(ComponentEvent)
84  		 */
85  		public void componentResized(ComponentEvent e)
86  		{
87  			if (resizable) {
88  				resize();
89  			}
90  		}
91  		
92  		/**
93  		 * Invoke resizing of the font when the hiearachy changes, because this
94  		 * action might as well change the size of the components, but the resize
95  		 * is not fired, because the component did not have parent prior to that.
96  		 * 
97  		 * @param e the event describing the hierarchy change
98  		 */
99  		public void hierarchyChanged(HierarchyEvent e) {
100 			if (resizable) {
101 				resize();
102 			}
103 			
104 		}
105 		
106 		
107 	}
108 
109 	/**
110 	 * Creates a resizable text label with text, icon and  predefined
111 	 * horizontal text aligment and resizable  font setting.
112 	 *
113 	 * @param text java.lang.String text to be displayed in  the label.
114 	 * @param icon Icon image to be displayed in the label.
115 	 * @param horizontalAlignment int horizontal aligment of the text in the
116 	 *        label.
117 	 */
118 	public ResizableTextLabel(String text, Icon icon, int horizontalAlignment)
119 	{
120 		super(text, icon, horizontalAlignment);
121 		addComponentListener(new ResizableAdapter());
122 		addHierarchyListener(new ResizableAdapter());
123 		setFont(FontHelper.getDefaultFont());
124 	}
125 
126 	/**
127 	 * Creates a resizable text label with text and predefined  horizontal text
128 	 * aligment.
129 	 *
130 	 * @param arg0 java.lang.String text to be displayed in  the label.
131 	 * @param arg1 int horizontal aligment of the text in the  label.
132 	 */
133 	public ResizableTextLabel(String arg0, int arg1)
134 	{
135 		this(arg0, null, arg1);
136 	}
137 
138 	/**
139 	 * Creates a resizable text label with text.
140 	 *
141 	 * @param arg0 java.lang.String text to be displayed in  the label.
142 	 */
143 	public ResizableTextLabel(String arg0)
144 	{
145 		this(arg0, null, SwingConstants.LEADING);
146 	}
147 
148 	/**
149 	 * Creates a resizable text label with icon and  predefined horizontal text
150 	 * aligment and resizable  font setting.
151 	 *
152 	 * @param image Icon image to be displayed in the label.
153 	 * @param horizontalAlignment int horizontal aligment of the text in the
154 	 *        label.
155 	 */
156 	public ResizableTextLabel(Icon image, int horizontalAlignment)
157 	{
158 		this(null, image, horizontalAlignment);
159 	}
160 
161 	/**
162 	 * Creates a resizable text label with an icon
163 	 *
164 	 * @param image Icon image to be displayed in the label.
165 	 */
166 	public ResizableTextLabel(Icon image)
167 	{
168 		this(null, image, SwingConstants.LEADING);
169 	}
170 
171 	/**
172 	 * Creates an empty label.
173 	 */
174 	public ResizableTextLabel()
175 	{
176 		this(" ", null, SwingConstants.LEADING);
177 	}
178 
179 	/**
180 	 * Sets the number of character columns to be displayed. This setting only
181 	 * has effect if resizable text font setting is enabled. Then the size of
182 	 * the font is adjusted to display the specified number of character
183 	 * columns.
184 	 *
185 	 * @param newColumns
186 	 */
187 	public void setColumns(int newColumns)
188 	{
189 		int oldColumns = columns;
190 
191 		if (oldColumns == newColumns) {
192 			return;
193 		}
194 
195 		columns = newColumns;
196 		firePropertyChange("columns", oldColumns, newColumns);
197 
198 		if (resizable) {
199 			resize();
200 		}
201 	}
202 
203 	/**
204 	 * Gets the number of character columns to be displayed.
205 	 *
206 	 * @return int
207 	 */
208 	public int getColumns()
209 	{
210 		return columns;
211 	}
212 
213 	/**
214 	 * Returns the resizable text font setting.
215 	 *
216 	 * @return boolean
217 	 */
218 	public boolean isResizable()
219 	{
220 		return resizable;
221 	}
222 
223 	/**
224 	 * Sets the resizable text font setting.
225 	 *
226 	 * @param newResizable
227 	 */
228 	public void setResizable(boolean newResizable)
229 	{
230 		boolean oldResizable = resizable;
231 
232 		if (oldResizable == newResizable) {
233 			return;
234 		}
235 
236 		resizable = newResizable;
237 		firePropertyChange("resizable", oldResizable, newResizable);
238 
239 		if (resizable) {
240 			resize();
241 		} else {
242 			if (userFont != null) {
243 				super.setFont(userFont);
244 			} else {
245 				super.setFont(FontHelper.getDefaultFont());
246 			}
247 		}
248 	}
249 
250 	/**
251 	 * Sets the enhanced mode setting. When true, the label is painted with
252 	 * anti-aliasing rendering hints.
253 	 *
254 	 * @param newEnhanced
255 	 */
256 	public void setEnhanced(boolean newEnhanced)
257 	{
258 		boolean oldEnhanced = enhanced;
259 
260 		if (oldEnhanced == newEnhanced) {
261 			return;
262 		}
263 
264 		enhanced = newEnhanced;
265 		firePropertyChange("enhanced", oldEnhanced, newEnhanced);
266 		repaint();
267 	}
268 
269 	/**
270 	 * Returns the enhanced mode setting.
271 	 *
272 	 * @return boolean
273 	 */
274 	public boolean isEnhanced()
275 	{
276 		return enhanced;
277 	}
278 
279 	/**
280 	 * This method was overriden to implement font resizing.
281 	 *
282 	 * @param text to be displayed.
283 	 *
284 	 * @see javax.swing.JLabel#setText(String)
285 	 */
286 	public void setText(String text)
287 	{
288 		if (text != null && text.length() < 1) {
289 			text = " ";
290 		}
291 
292 		super.setText(text);
293 
294 		if (resizable) {
295 			resize();
296 		}
297 	}
298 
299 	/**
300 	 * (This method may improve usage of columns field)  This method sets font
301 	 * size and columns to make this label fit to display wanted amount of
302 	 * characters in preferred font size. If string represented by text field
303 	 * is longer than expected, label still displays it, just fontsize is
304 	 * changed  (only if resizable); !!Event listeners should listen to
305 	 * component resized event to avoid some problems with fitting this label
306 	 * in the parent container.!!
307 	 *
308 	 * @param fontSize preferred font size
309 	 * @param newColumns columns of text to display
310 	 */
311 	public void adjustSizeToFont(int fontSize, int newColumns)
312 	{
313 		Font font = FontHelper.getFontWithSize(fontSize, getFont());
314 		int length = getFontMetrics(font).stringWidth("m") * newColumns;
315 
316 		super.setSize((int)(length / 0.9), fontSize * (20 / 14));
317 		setColumns(newColumns);
318 
319 		//resize() is called by setColumns(..) or setSize(..).
320 		if (!resizable) {
321 			super.setFont(font);
322 		}
323 	}
324 
325 	protected void resize()
326 	{
327 		logger.fine("resizing");
328 
329 		Font f = FontHelper.calculateFittingFont(this, getFont(), getText(),
330 			    columns, minFontSize, maxFontSize);
331 
332 		if (f != getFont()) {
333 			super.setFont(f);
334 		}
335 	}
336 
337 	/**
338 	 * This method was overriden to implement font resizing.
339 	 *
340 	 * @see javax.swing.JComponent#addNotify()
341 	 */
342 	public void addNotify()
343 	{
344 		super.addNotify();
345 
346 		if (resizable) {
347 			resize();
348 		}
349 	}
350 
351 	/**
352 	 * This method was overriden to implement font resizing.
353 	 *
354 	 * @return Dimension preferred size of the label
355 	 *
356 	 * @see javax.swing.JLabel#getPreferredSize()
357 	 */
358 	public Dimension getPreferredSize()
359 	{
360 		if (preferredSize != null) {
361 			return preferredSize;
362 		} else if (resizable) {
363 			Font font;
364 
365 			if (userFont == null) {
366 				font = FontHelper.getDefaultFont();
367 			} else {
368 				font = userFont;
369 			}
370 
371 			int height = font.getSize() * 20 / 13;
372 			int width = getFontMetrics(font).stringWidth("m") * 10 / 8 * columns;
373 
374 			if (columns == 0 && getText() != null) {
375 				width = getFontMetrics(font).stringWidth(getText()) * 10 / 8;
376 			}
377 
378 			if (width == 0) {
379 				width = 1;
380 			}
381 
382 			return new Dimension(width, height);
383 		} else {
384 			return super.getPreferredSize();
385 		}
386 	}
387 
388 	/**
389 	 * This method was overriden to implement font resizing.
390 	 *
391 	 * @see javax.swing.JComponent#setPreferredSize(Dimension)
392 	 */
393 	public void setPreferredSize(Dimension newPreferredSize)
394 	{
395 		preferredSize = newPreferredSize;
396 		super.setPreferredSize(newPreferredSize);
397 	}
398 
399 	/**
400 	 * This method was overriden to implement font resizing.
401 	 *
402 	 * @see java.awt.Component#getMinimumSize()
403 	 */
404 	public Dimension getMinimumSize()
405 	{
406 		if (minimumSize != null) {
407 			return minimumSize;
408 		} else if (resizable) {
409 			return getPreferredSize();
410 		} else {
411 			return super.getMinimumSize();
412 		}
413 	}
414 
415 	/**
416 	 * This method was overriden to implement font resizing.
417 	 *
418 	 * @see javax.swing.JComponent#setMinimumSize(Dimension)
419 	 */
420 	public void setMinimumSize(Dimension newMinimumSize)
421 	{
422 		minimumSize = newMinimumSize;
423 		super.setMinimumSize(newMinimumSize);
424 	}
425 
426 	/**
427 	 * This method hes been overriden to implement the feature  of enhanced
428 	 * anti-aliasing paint of the label.
429 	 *
430 	 * @see javax.swing.JComponent#paintComponent(Graphics)
431 	 */
432 	protected void paintComponent(Graphics g)
433 	{
434 		logger.fine("painting");
435 
436 		if (enhanced) {
437 			((Graphics2D)g).addRenderingHints(PaintHelper.getAntialiasingHints());
438 		}
439 
440 		super.paintComponent(g);
441 	}
442 
443 	/**
444 	 * Returns maximum font size text can reach.
445 	 *
446 	 * @return maximum font size text can reach
447 	 */
448 	public int getMaximumFontSize()
449 	{
450 		return maxFontSize;
451 	}
452 
453 	/**
454 	 * Returns minimum font size text can reach.
455 	 *
456 	 * @return minimum font size text can reach
457 	 */
458 	public int getMinimumFontSize()
459 	{
460 		return minFontSize;
461 	}
462 
463 	/**
464 	 * Sets maximum font size text can reach.
465 	 *
466 	 * @param newMax new maximum font size text can reach
467 	 */
468 	public void setMaximumFontSize(int newMax)
469 	{
470 		int oldMax = maxFontSize;
471 
472 		if (oldMax == newMax) {
473 			return;
474 		}
475 
476 		maxFontSize = newMax;
477 		firePropertyChange("maximumFontSize", oldMax, newMax);
478 		resize();
479 	}
480 
481 	/**
482 	 * minimum font size text can reach
483 	 *
484 	 * @param newMin new minimum font size text can reach
485 	 */
486 	public void setMinimumFontSize(int newMin)
487 	{
488 		int oldMin = minFontSize;
489 
490 		if (oldMin == newMin) {
491 			return;
492 		}
493 
494 		minFontSize = newMin;
495 		firePropertyChange("minimumFontSize", oldMin, newMin);
496 		resize();
497 	}
498 }
499 
500 /* __oOo__ */