Source Code Cross Referenced for DefaultUnitConverter.java in  » Swing-Library » abeille-forms-designer » com » jgoodies » forms » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Swing Library » abeille forms designer » com.jgoodies.forms.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright (c) 2002-2004 JGoodies Karsten Lentzsch. All Rights Reserved.
003:         *
004:         * Redistribution and use in source and binary forms, with or without 
005:         * modification, are permitted provided that the following conditions are met:
006:         * 
007:         *  o Redistributions of source code must retain the above copyright notice, 
008:         *    this list of conditions and the following disclaimer. 
009:         *     
010:         *  o Redistributions in binary form must reproduce the above copyright notice, 
011:         *    this list of conditions and the following disclaimer in the documentation 
012:         *    and/or other materials provided with the distribution. 
013:         *     
014:         *  o Neither the name of JGoodies Karsten Lentzsch nor the names of 
015:         *    its contributors may be used to endorse or promote products derived 
016:         *    from this software without specific prior written permission. 
017:         *     
018:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
019:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
020:         * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
021:         * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
022:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
023:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
024:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
025:         * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
026:         * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
027:         * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
028:         * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
029:         */
030:
031:        package com.jgoodies.forms.util;
032:
033:        import java.awt.Component;
034:        import java.awt.Font;
035:        import java.awt.FontMetrics;
036:        import java.beans.PropertyChangeEvent;
037:        import java.beans.PropertyChangeListener;
038:        import java.beans.PropertyChangeSupport;
039:        import java.util.HashMap;
040:        import java.util.Map;
041:
042:        import javax.swing.JButton;
043:        import javax.swing.JPanel;
044:        import javax.swing.UIManager;
045:
046:        /**
047:         * This is the default implementation of the {@link UnitConverter} interface. It
048:         * converts horizontal and vertical dialog base units to pixels.
049:         * <p>
050:         * 
051:         * The horizontal base unit is equal to the average width, in pixels, of the
052:         * characters in the system font; the vertical base unit is equal to the height,
053:         * in pixels, of the font. Each horizontal base unit is equal to 4 horizontal
054:         * dialog units; each vertical base unit is equal to 8 vertical dialog units.
055:         * <p>
056:         * 
057:         * The DefaultUnitConverter computes dialog base units using a default font and
058:         * a test string for the average character width. You can configure the font and
059:         * the test string via the bound Bean properties <em>defaultDialogFont</em>
060:         * and <em>averageCharacterWidthTestString</em>.
061:         * 
062:         * @version $Revision: 1.2 $
063:         * @author Karsten Lentzsch
064:         * @see UnitConverter
065:         * @see com.jgoodies.forms.layout.Size
066:         * @see com.jgoodies.forms.layout.Sizes
067:         */
068:        public final class DefaultUnitConverter extends AbstractUnitConverter {
069:
070:            // public static final String UPPERCASE_ALPHABET =
071:            // "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
072:            //
073:            // public static final String LOWERCASE_ALPHABET =
074:            // "abcdefghijklmnopqrstuvwxyz";
075:
076:            /**
077:             * Holds the sole instance that will be lazily instantiated.
078:             */
079:            private static DefaultUnitConverter instance;
080:
081:            /**
082:             * Holds the string that is used to compute the average character width. By
083:             * default this is just &quot;X&quot;.
084:             */
085:            private String averageCharWidthTestString = "X";
086:
087:            /**
088:             * Holds the font that is used to compute the global dialog base units. By
089:             * default it is lazily created in method #getDefaultDialogFont, which in
090:             * turn looks up a font in method #lookupDefaultDialogFont.
091:             */
092:            private Font defaultDialogFont;
093:
094:            /**
095:             * If any <code>PropertyChangeListeners</code> have been registered, the
096:             * <code>changeSupport</code> field describes them.
097:             * 
098:             * @serial
099:             * @see #addPropertyChangeListener(PropertyChangeListener)
100:             * @see #addPropertyChangeListener(String, PropertyChangeListener)
101:             * @see #removePropertyChangeListener(PropertyChangeListener)
102:             * @see #removePropertyChangeListener(String, PropertyChangeListener)
103:             */
104:            private PropertyChangeSupport changeSupport;
105:
106:            // Cached *****************************************************************
107:
108:            /**
109:             * Holds the cached global dialog base units that are used if a component is
110:             * not (yet) available - for example in a Border.
111:             */
112:            private DialogBaseUnits cachedGlobalDialogBaseUnits = computeGlobalDialogBaseUnits();
113:
114:            /**
115:             * Maps <code>FontMetrics</code> to horizontal dialog base units. This is
116:             * a second-level cache, that stores dialog base units for a
117:             * <code>FontMetrics</code> object.
118:             */
119:            private Map cachedDialogBaseUnits = new HashMap();
120:
121:            // Instance Creation and Access *******************************************
122:
123:            /**
124:             * Constructs a <code>DefaultFontUnitConverter</code> and registers a
125:             * listener that handles changes in the look&amp;feel.
126:             */
127:            private DefaultUnitConverter() {
128:                UIManager
129:                        .addPropertyChangeListener(new LookAndFeelChangeHandler());
130:                changeSupport = new PropertyChangeSupport(this );
131:            }
132:
133:            /**
134:             * Lazily instantiates and returns the sole instance.
135:             * 
136:             * @return the lazily instantiated sole instance
137:             */
138:            public static DefaultUnitConverter getInstance() {
139:                if (instance == null) {
140:                    instance = new DefaultUnitConverter();
141:                }
142:                return instance;
143:            }
144:
145:            // Access to Bound Properties *********************************************
146:
147:            /**
148:             * Returns the string used to compute the average character width. By
149:             * default it is initialized to &quot;X&quot;.
150:             * 
151:             * @return the test string used to compute the average character width
152:             */
153:            public String getAverageCharacterWidthTestString() {
154:                return averageCharWidthTestString;
155:            }
156:
157:            /**
158:             * Sets a string that will be used to compute the average character width.
159:             * By default it is initialized to &quot;X&quot;. You can provide other test
160:             * strings, for example:
161:             * <ul>
162:             * <li>&quot;Xximeee&quot;</li>
163:             * <li>&quot;ABCEDEFHIJKLMNOPQRSTUVWXYZ&quot;</li>
164:             * <li>&quot;abcdefghijklmnopqrstuvwxyz&quot;</li>
165:             * </ul>
166:             * 
167:             * @param newTestString
168:             *            the test string to be used
169:             * @throws IllegalArgumentException
170:             *             if the test string is empty
171:             * @throws NullPointerException
172:             *             if the test string is <code>null</code>
173:             */
174:            public void setAverageCharacterWidthTestString(String newTestString) {
175:                if (newTestString == null)
176:                    throw new NullPointerException(
177:                            "The test string must not be null.");
178:                if (newTestString.length() == 0)
179:                    throw new IllegalArgumentException(
180:                            "The test string must not be empty.");
181:
182:                String oldTestString = averageCharWidthTestString;
183:                averageCharWidthTestString = newTestString;
184:                changeSupport.firePropertyChange(
185:                        "averageCharacterWidthTestString", oldTestString,
186:                        newTestString);
187:            }
188:
189:            /**
190:             * Lazily creates and returns the dialog font used to compute the dialog
191:             * base units.
192:             * 
193:             * @return the font used to compute the dialog base units
194:             */
195:            public Font getDefaultDialogFont() {
196:                if (defaultDialogFont == null) {
197:                    defaultDialogFont = lookupDefaultDialogFont();
198:                }
199:                return defaultDialogFont;
200:            }
201:
202:            /**
203:             * Sets a dialog font that will be used to compute the dialog base units.
204:             * 
205:             * @param newFont
206:             *            the default dialog font to be set
207:             */
208:            public void setDefaultDialogFont(Font newFont) {
209:                Font oldFont = defaultDialogFont; // Don't use the getter
210:                defaultDialogFont = newFont;
211:                changeSupport.firePropertyChange("defaultDialogFont", oldFont,
212:                        newFont);
213:            }
214:
215:            // Implementing Abstract Superclass Behavior ******************************
216:
217:            /**
218:             * Returns the cached or computed horizontal dialog base units.
219:             * 
220:             * @param component
221:             *            a Component that provides the font and graphics
222:             * @return the horizontal dialog base units
223:             */
224:            protected double getDialogBaseUnitsX(Component component) {
225:                return getDialogBaseUnits(component).x;
226:            }
227:
228:            /**
229:             * Returns the cached or computed vertical dialog base units for the given
230:             * component.
231:             * 
232:             * @param component
233:             *            a Component that provides the font and graphics
234:             * @return the vertical dialog base units
235:             */
236:            protected double getDialogBaseUnitsY(Component component) {
237:                return getDialogBaseUnits(component).y;
238:            }
239:
240:            // Compute and Cache Global and Components Dialog Base Units **************
241:
242:            /**
243:             * Lazily computes and answer the global dialog base units. Should be
244:             * re-computed if the l&amp;f, platform, or screen changes.
245:             * 
246:             * @return a cached DialogBaseUnits object used globally if no container is
247:             *         available
248:             */
249:            private DialogBaseUnits getGlobalDialogBaseUnits() {
250:                if (cachedGlobalDialogBaseUnits == null) {
251:                    cachedGlobalDialogBaseUnits = computeGlobalDialogBaseUnits();
252:                }
253:                return cachedGlobalDialogBaseUnits;
254:            }
255:
256:            /**
257:             * Looks up and returns the dialog base units for the given component. In
258:             * case the component is <code>null</code> the global dialog base units
259:             * are answered.
260:             * <p>
261:             * 
262:             * Before we compute the dialog base units we check whether they have been
263:             * computed and cached before - for the same component
264:             * <code>FontMetrics</code>.
265:             * 
266:             * @param c
267:             *            the component that provides the graphics object
268:             * @return the DialogBaseUnits object for the given component
269:             */
270:            private DialogBaseUnits getDialogBaseUnits(Component c) {
271:                if (c == null) { // || (font = c.getFont()) == null) {
272:                    logInfo("Missing font metrics: " + c);
273:                    return getGlobalDialogBaseUnits();
274:                }
275:                FontMetrics fm = c.getFontMetrics(getDefaultDialogFont());
276:                DialogBaseUnits dialogBaseUnits = (DialogBaseUnits) cachedDialogBaseUnits
277:                        .get(fm);
278:                if (dialogBaseUnits == null) {
279:                    dialogBaseUnits = computeDialogBaseUnits(fm);
280:                    cachedDialogBaseUnits.put(fm, dialogBaseUnits);
281:                }
282:                return dialogBaseUnits;
283:            }
284:
285:            /**
286:             * Computes and returns the horizontal dialog base units. Honors the font,
287:             * font size and resolution.
288:             * <p>
289:             * 
290:             * Implementation Note: 14dluY map to 22 pixel for 8pt Tahoma on 96 dpi. I
291:             * could not yet manage to compute the Microsoft compliant font height.
292:             * Therefore this method adds a correction value that seems to work well
293:             * with the vast majority of desktops.
294:             * <p>
295:             * 
296:             * TODO: revise the computation of vertical base untis, as soon as there are
297:             * more information about the original computation in Microsoft
298:             * environments.
299:             * 
300:             * @param metrics
301:             *            the FontMetrics used to measure the dialog font
302:             * @return the horizontal and vertical dialog base units
303:             */
304:            private DialogBaseUnits computeDialogBaseUnits(FontMetrics metrics) {
305:                double averageCharWidth = computeAverageCharWidth(metrics,
306:                        averageCharWidthTestString);
307:                int ascent = metrics.getAscent();
308:                double height = ascent > 14 ? ascent : ascent + (15 - ascent)
309:                        / 3;
310:                DialogBaseUnits dialogBaseUnits = new DialogBaseUnits(
311:                        averageCharWidth, height);
312:                logInfo("Computed dialog base units " + dialogBaseUnits
313:                        + " for: " + metrics.getFont());
314:                return dialogBaseUnits;
315:            }
316:
317:            /**
318:             * Computes the global dialog base units. The current implementation assumes
319:             * a fixed 8pt font and on 96 or 120 dpi. A better implementation should ask
320:             * for the main dialog font and should honor the current screen resolution.
321:             * <p>
322:             * 
323:             * Should be re-computed if the l&amp;f, platform, or screen changes.
324:             * 
325:             * @return a DialogBaseUnits object used globally if no container is
326:             *         available
327:             */
328:            private DialogBaseUnits computeGlobalDialogBaseUnits() {
329:                logInfo("Computing global dialog base units...");
330:                Font dialogFont = getDefaultDialogFont();
331:                FontMetrics metrics = createDefaultGlobalComponent()
332:                        .getFontMetrics(dialogFont);
333:                DialogBaseUnits globalDialogBaseUnits = computeDialogBaseUnits(metrics);
334:                return globalDialogBaseUnits;
335:            }
336:
337:            /**
338:             * Looks up and returns the font used by buttons. First, tries to request
339:             * the button font from the UIManager; if this fails a JButton is created
340:             * and asked for its font.
341:             * 
342:             * @return the font used for a standard button
343:             */
344:            private Font lookupDefaultDialogFont() {
345:                Font buttonFont = UIManager.getFont("Button.font");
346:                return buttonFont != null ? buttonFont : new JButton()
347:                        .getFont();
348:            }
349:
350:            /**
351:             * Creates and returns a component that is used to lookup the default font
352:             * metrics. The current implementation creates a <code>JPanel</code>.
353:             * Since this panel has no parent, it has no toolkit assigned. And so,
354:             * requesting the font metrics will end up using the default toolkit and its
355:             * deprecated method <code>ToolKit#getFontMetrics()</code>.
356:             * <p>
357:             * 
358:             * TODO: Consider publishing this method and providing a setter, so that an
359:             * API user can set a realized component that has a toolkit assigned.
360:             * 
361:             * @return a component used to compute the default font metrics
362:             */
363:            private Component createDefaultGlobalComponent() {
364:                return new JPanel();
365:            }
366:
367:            /**
368:             * Invalidates the caches. Resets the global dialog base units and clears
369:             * the Map from <code>FontMetrics</code> to dialog base units. This is
370:             * invoked after a change of the look&amp;feel.
371:             */
372:            private void invalidateCaches() {
373:                cachedGlobalDialogBaseUnits = null;
374:                cachedDialogBaseUnits.clear();
375:            }
376:
377:            // Managing Property Change Listeners **********************************
378:
379:            /**
380:             * Adds a PropertyChangeListener to the listener list. The listener is
381:             * registered for all bound properties of this class.
382:             * <p>
383:             * 
384:             * If listener is null, no exception is thrown and no action is performed.
385:             * 
386:             * @param listener
387:             *            the PropertyChangeListener to be added
388:             * 
389:             * @see #removePropertyChangeListener(PropertyChangeListener)
390:             * @see #removePropertyChangeListener(String, PropertyChangeListener)
391:             * @see #addPropertyChangeListener(String, PropertyChangeListener)
392:             */
393:            public final synchronized void addPropertyChangeListener(
394:                    PropertyChangeListener listener) {
395:                changeSupport.addPropertyChangeListener(listener);
396:            }
397:
398:            /**
399:             * Removes a PropertyChangeListener from the listener list. This method
400:             * should be used to remove PropertyChangeListeners that were registered for
401:             * all bound properties of this class.
402:             * <p>
403:             * 
404:             * If listener is null, no exception is thrown and no action is performed.
405:             * 
406:             * @param listener
407:             *            the PropertyChangeListener to be removed
408:             * 
409:             * @see #addPropertyChangeListener(PropertyChangeListener)
410:             * @see #addPropertyChangeListener(String, PropertyChangeListener)
411:             * @see #removePropertyChangeListener(String, PropertyChangeListener)
412:             */
413:            public final synchronized void removePropertyChangeListener(
414:                    PropertyChangeListener listener) {
415:                changeSupport.removePropertyChangeListener(listener);
416:            }
417:
418:            /**
419:             * Adds a PropertyChangeListener to the listener list for a specific
420:             * property. The specified property may be user-defined.
421:             * <p>
422:             * 
423:             * Note that if this Model is inheriting a bound property, then no event
424:             * will be fired in response to a change in the inherited property.
425:             * <p>
426:             * 
427:             * If listener is null, no exception is thrown and no action is performed.
428:             * 
429:             * @param propertyName
430:             *            one of the property names listed above
431:             * @param listener
432:             *            the PropertyChangeListener to be added
433:             * 
434:             * @see #removePropertyChangeListener(java.lang.String,
435:             *      java.beans.PropertyChangeListener)
436:             * @see #addPropertyChangeListener(java.lang.String,
437:             *      java.beans.PropertyChangeListener)
438:             */
439:            public final synchronized void addPropertyChangeListener(
440:                    String propertyName, PropertyChangeListener listener) {
441:                changeSupport.addPropertyChangeListener(propertyName, listener);
442:            }
443:
444:            /**
445:             * Removes a PropertyChangeListener from the listener list for a specific
446:             * property. This method should be used to remove PropertyChangeListeners
447:             * that were registered for a specific bound property.
448:             * <p>
449:             * 
450:             * If listener is null, no exception is thrown and no action is performed.
451:             * 
452:             * @param propertyName
453:             *            a valid property name
454:             * @param listener
455:             *            the PropertyChangeListener to be removed
456:             * 
457:             * @see #addPropertyChangeListener(java.lang.String,
458:             *      java.beans.PropertyChangeListener)
459:             * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
460:             */
461:            public final synchronized void removePropertyChangeListener(
462:                    String propertyName, PropertyChangeListener listener) {
463:                changeSupport.removePropertyChangeListener(propertyName,
464:                        listener);
465:            }
466:
467:            // Helper Code ************************************************************
468:
469:            /**
470:             * Logs an info message to the console.
471:             * 
472:             * @param message
473:             *            the message to log
474:             */
475:            private void logInfo(String message) {
476:                // System.out.println("INFO (DefaultUnitConverter) " + message);
477:            }
478:
479:            // Describes horizontal and vertical dialog base units.
480:            private static class DialogBaseUnits {
481:
482:                final double x;
483:                final double y;
484:
485:                DialogBaseUnits(double dialogBaseUnitsX, double dialogBaseUnitsY) {
486:                    this .x = dialogBaseUnitsX;
487:                    this .y = dialogBaseUnitsY;
488:                }
489:
490:                public String toString() {
491:                    return "DBU(x=" + x + "; y=" + y + ")";
492:                }
493:            }
494:
495:            // Listens to changes of the Look and Feel and invalidates the cache
496:            private class LookAndFeelChangeHandler implements 
497:                    PropertyChangeListener {
498:                public void propertyChange(PropertyChangeEvent evt) {
499:                    invalidateCaches();
500:                }
501:            }
502:
503:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.