Source Code Cross Referenced for ValidationComponentUtils.java in  » Swing-Library » jgoodies-validation » com » jgoodies » validation » view » 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 » jgoodies validation » com.jgoodies.validation.view 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright (c) 2003-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
0003:         *
0004:         * Redistribution and use in source and binary forms, with or without
0005:         * modification, are permitted provided that the following conditions are met:
0006:         *
0007:         *  o Redistributions of source code must retain the above copyright notice,
0008:         *    this list of conditions and the following disclaimer.
0009:         *
0010:         *  o Redistributions in binary form must reproduce the above copyright notice,
0011:         *    this list of conditions and the following disclaimer in the documentation
0012:         *    and/or other materials provided with the distribution.
0013:         *
0014:         *  o Neither the name of JGoodies Karsten Lentzsch nor the names of
0015:         *    its contributors may be used to endorse or promote products derived
0016:         *    from this software without specific prior written permission.
0017:         *
0018:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0020:         * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0021:         * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0022:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
0025:         * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
0026:         * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
0027:         * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0028:         * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029:         */
0030:
0031:        package com.jgoodies.validation.view;
0032:
0033:        import java.awt.Color;
0034:        import java.awt.Component;
0035:        import java.awt.Container;
0036:        import java.beans.PropertyChangeEvent;
0037:        import java.beans.PropertyChangeListener;
0038:        import java.util.HashMap;
0039:        import java.util.Map;
0040:
0041:        import javax.swing.*;
0042:        import javax.swing.border.Border;
0043:        import javax.swing.border.CompoundBorder;
0044:        import javax.swing.border.LineBorder;
0045:        import javax.swing.plaf.UIResource;
0046:        import javax.swing.plaf.basic.BasicBorders;
0047:        import javax.swing.text.JTextComponent;
0048:
0049:        import com.jgoodies.validation.Severity;
0050:        import com.jgoodies.validation.ValidationResult;
0051:        import com.jgoodies.validation.util.ValidationUtils;
0052:
0053:        /**
0054:         * Consists exclusively of static methods that provide convenience behavior for
0055:         * operating on components that present validation data. Methods that access
0056:         * component state utilize the {@link javax.swing.JComponent} client property
0057:         * mechanism as a backing store.
0058:         *
0059:         * @author Karsten Lentzsch
0060:         * @version $Revision: 1.13 $
0061:         *
0062:         * @see com.jgoodies.validation.ValidationMessage
0063:         * @see com.jgoodies.validation.ValidationMessage#key()
0064:         * @see com.jgoodies.validation.ValidationResult
0065:         * @see com.jgoodies.validation.ValidationResult#subResult(Object)
0066:         * @see com.jgoodies.validation.ValidationResult#keyMap()
0067:         */
0068:        public final class ValidationComponentUtils {
0069:
0070:            // Colors *****************************************************************
0071:
0072:            private static final Color MANDATORY_FOREGROUND = new Color(70, 70,
0073:                    210);
0074:
0075:            private static final Color MANDATORY_BACKGROUND = new Color(235,
0076:                    235, 255);
0077:
0078:            private static final Color ERROR_BACKGROUND = new Color(255, 215,
0079:                    215);
0080:
0081:            private static final Color WARNING_BACKGROUND = new Color(255, 235,
0082:                    205);
0083:
0084:            // Client Property Keys **************************************************
0085:
0086:            /**
0087:             * The JComponent client property key for the mandatory property
0088:             * that indicates whether a component's content is mandatory or optional.
0089:             *
0090:             * @see #isMandatory(JComponent)
0091:             * @see #isMandatoryAndBlank(JComponent)
0092:             * @see #setMandatory(JComponent, boolean)
0093:             */
0094:            private static final String MANDATORY_KEY = "validation.isMandatory";
0095:
0096:            /**
0097:             * The JComponent client property key used to associate a component
0098:             * with a set of ValidationMessages. Before the Validation 1.4,
0099:             * there was only one key per component. Since 1.4 multiple keys are
0100:             * allowed.
0101:             *
0102:             * @see #getMessageKeys(JComponent)
0103:             * @see #setMessageKey(JComponent, Object)
0104:             * @see #setMessageKeys(JComponent, Object...)
0105:             * @see com.jgoodies.validation.ValidationMessage#key()
0106:             * @see ValidationResult#subResult(Object)
0107:             * @see ValidationResult#keyMap()
0108:             */
0109:            private static final String MESSAGE_KEYS = "validation.messageKeys";
0110:
0111:            /**
0112:             * The JComponent client property key for the input hint text.
0113:             * The text stored under this key is intended to be displayed if and only if
0114:             * the component has the focus.
0115:             *
0116:             * @see #getInputHint(JComponent)
0117:             * @see #setInputHint(JComponent, Object)
0118:             */
0119:            private static final String INPUT_HINT_KEY = "validation.inputHint";
0120:
0121:            /**
0122:             * The JComponent client property key for the severity property.
0123:             * Once a component's severity state has been set by the method
0124:             * {@link #updateComponentTreeSeverity(Container, ValidationResult)}
0125:             * it can be used to display validation feedback, such as background
0126:             * changes, overlay information, etc. See for example
0127:             * {@link #updateComponentTreeSeverityBackground(Container, ValidationResult)}.
0128:             *
0129:             * @see #getSeverity(JComponent)
0130:             * @see #setSeverity(JComponent, Severity)
0131:             * @see #updateComponentTreeSeverity(Container, ValidationResult)
0132:             * @see #updateComponentTreeSeverityBackground(Container, ValidationResult)
0133:             */
0134:            private static final String SEVERITY_KEY = "validation.severity";
0135:
0136:            /**
0137:             * The JComponent client property key used to store a component's
0138:             * original background color. The stored background can be restored later.
0139:             *
0140:             * @see #getStoredBackground(JTextComponent)
0141:             * @see #restoreBackground(JTextComponent)
0142:             * @see #ensureCustomBackgroundStored(JTextComponent)
0143:             * @see #setMandatoryBackground(JTextComponent)
0144:             */
0145:            private static final String STORED_BACKGROUND_KEY = "validation.storedBackground";
0146:
0147:            /**
0148:             * Holds a cached Border that is used to indicate mandatory text components.
0149:             * It will be lazily created in method {@link #getMandatoryBorder()}.
0150:             *
0151:             * @see #getMandatoryBorder()
0152:             * @see #setMandatoryBorder(JTextComponent)
0153:             */
0154:            private static Border mandatoryBorder;
0155:
0156:            // A Map that holds reusable prototype text components ********************
0157:
0158:            /**
0159:             * Maps text component classes to prototype instances of such a class.
0160:             * Used to get the default background color of these component types.
0161:             *
0162:             * @see #getDefaultBackground(JTextComponent)
0163:             * @see #getPrototypeFor(Class)
0164:             */
0165:            private static final Map<Class<? extends JTextComponent>, JTextComponent> PROTOTYPE_COMPONENTS = new HashMap<Class<? extends JTextComponent>, JTextComponent>();
0166:
0167:            // Instance creation ******************************************************
0168:
0169:            private ValidationComponentUtils() {
0170:                // Override default constructor; prevents instantiation.
0171:            }
0172:
0173:            // Accessing Validation Properties ****************************************
0174:
0175:            /**
0176:             * Returns if the component has been marked as mandatory.
0177:             *
0178:             * @param comp    the component to be checked
0179:             * @return true if the component has been marked as mandatory
0180:             *
0181:             * @see #isMandatoryAndBlank(JComponent)
0182:             * @see #setMandatory(JComponent, boolean)
0183:             * @see #setMandatoryBackground(JTextComponent)
0184:             * @see #setMandatoryBorder(JTextComponent)
0185:             */
0186:            public static boolean isMandatory(JComponent comp) {
0187:                return Boolean.TRUE.equals(comp
0188:                        .getClientProperty(MANDATORY_KEY));
0189:            }
0190:
0191:            /**
0192:             * Returns if the component is a {@link JTextComponent} with blank content
0193:             * and has been marked as mandatory.
0194:             *
0195:             * @param comp  the component to be checked
0196:             * @return true if the component's has a blank content and has been marked
0197:             *     as mandatory
0198:             *
0199:             * @see #isMandatory(JComponent)
0200:             * @see #setMandatory(JComponent, boolean)
0201:             * @see #setMandatoryBackground(JTextComponent)
0202:             * @see #setMandatoryBorder(JTextComponent)
0203:             */
0204:            public static boolean isMandatoryAndBlank(JComponent comp) {
0205:                if (!(comp instanceof  JTextComponent)) {
0206:                    return false;
0207:                }
0208:                JTextComponent textComponent = (JTextComponent) comp;
0209:                return isMandatory(textComponent)
0210:                        && ValidationUtils.isBlank(textComponent.getText());
0211:            }
0212:
0213:            /**
0214:             * Marks the given component as mandatory or optional.
0215:             * The value will be stored as a client property value.
0216:             *
0217:             * @param comp        the component to be marked
0218:             * @param mandatory   true for mandatory, false for optional
0219:             *
0220:             * @see #isMandatory(JComponent)
0221:             * @see #isMandatoryAndBlank(JComponent)
0222:             * @see #setMandatoryBackground(JTextComponent)
0223:             * @see #setMandatoryBorder(JTextComponent)
0224:             */
0225:            public static void setMandatory(JComponent comp, boolean mandatory) {
0226:                boolean oldMandatory = isMandatory(comp);
0227:                if (oldMandatory != mandatory) {
0228:                    comp.putClientProperty(MANDATORY_KEY, Boolean
0229:                            .valueOf(mandatory));
0230:                }
0231:            }
0232:
0233:            /**
0234:             * Returns the component's {@link Severity} if it has been set before.
0235:             * Useful for validation-aware containers that render the component's
0236:             * validation state.
0237:             *
0238:             * @param comp   the component to be read
0239:             * @return the component's <code>Severity</code> as set before
0240:             *
0241:             * @see #setSeverity(JComponent, Severity)
0242:             * @see #updateComponentTreeSeverity(Container, ValidationResult)
0243:             * @see #updateComponentTreeSeverityBackground(Container, ValidationResult)
0244:             */
0245:            public static Severity getSeverity(JComponent comp) {
0246:                return (Severity) comp.getClientProperty(SEVERITY_KEY);
0247:            }
0248:
0249:            /**
0250:             * Marks the given component with the specified severity.
0251:             * The severity will be stored as a client property value.
0252:             * Useful for validation-aware containers that render the component's
0253:             * validation state once it has been set.
0254:             *
0255:             * @param comp      the component that shall be marked
0256:             * @param severity  the component's severity
0257:             *
0258:             * @see #getSeverity(JComponent)
0259:             * @see #updateComponentTreeSeverity(Container, ValidationResult)
0260:             * @see #updateComponentTreeSeverityBackground(Container, ValidationResult)
0261:             */
0262:            public static void setSeverity(JComponent comp, Severity severity) {
0263:                comp.putClientProperty(SEVERITY_KEY, severity);
0264:            }
0265:
0266:            /**
0267:             * Returns the message key that has been set to associate the given
0268:             * component with a set of ValidationMessages.
0269:             *
0270:             * @param comp  the component to be requested
0271:             * @return the component's validation association key
0272:             *
0273:             * @see #setMessageKey(JComponent, Object)
0274:             * @see com.jgoodies.validation.ValidationMessage
0275:             * @see com.jgoodies.validation.ValidationMessage#key()
0276:             * @see ValidationResult#subResult(Object)
0277:             * @see ValidationResult#keyMap()
0278:             */
0279:            public static Object[] getMessageKeys(JComponent comp) {
0280:                return (Object[]) comp.getClientProperty(MESSAGE_KEYS);
0281:            }
0282:
0283:            /**
0284:             * Associates the given component with the specified message key.
0285:             * That in turn will associate the component with all ValidationMessages
0286:             * that share this key. The latter can be checked by comparing this key
0287:             * with the key provided by a ValidationMessage.
0288:             *
0289:             * @param comp         the component that shall be associated with the key
0290:             * @param messageKey   the key to be set
0291:             *
0292:             * @see #getMessageKeys(JComponent)
0293:             * @see com.jgoodies.validation.ValidationMessage
0294:             * @see com.jgoodies.validation.ValidationMessage#key()
0295:             * @see ValidationResult#subResult(Object)
0296:             * @see ValidationResult#keyMap()
0297:             */
0298:            public static void setMessageKey(JComponent comp, Object messageKey) {
0299:                Object[] keyArray = messageKey == null ? null
0300:                        : new Object[] { messageKey };
0301:                setMessageKeys(comp, keyArray);
0302:            }
0303:
0304:            /**
0305:             * Associates the given component with the specified message keys.
0306:             * That in turn will associate the component with all ValidationMessages
0307:             * that share these keys. The latter can be checked by comparing the
0308:             * given (and stored) keys with the key provided by a ValidationMessage.
0309:             *
0310:             * @param comp         the component that shall be associated with the keys
0311:             * @param messageKeys  the keys to be set
0312:             *
0313:             * @see #getMessageKeys(JComponent)
0314:             * @see com.jgoodies.validation.ValidationMessage
0315:             * @see com.jgoodies.validation.ValidationMessage#key()
0316:             * @see ValidationResult#subResult(Object)
0317:             * @see ValidationResult#keyMap()
0318:             *
0319:             * @since 1.4
0320:             */
0321:            public static void setMessageKeys(JComponent comp,
0322:                    Object[] messageKeys) {
0323:                comp.putClientProperty(MESSAGE_KEYS, messageKeys);
0324:            }
0325:
0326:            /**
0327:             * Returns the component's input hint that is stored in a client property.
0328:             * Useful to indicate the format of valid data to the user.
0329:             * The input hint object can be a plain <code>String</code> or a
0330:             * compound object, for example that is able to localize the input hint
0331:             * for the active {@link java.util.Locale}.<p>
0332:             *
0333:             * To make use of this information an editor should register a
0334:             * listener with the focus management. Whenever the focused component
0335:             * changes, the mechanism can request the input hint for the focus owner
0336:             * using this service and can display the result hint in the user interface.
0337:             *
0338:             * @param comp    the component to be requested
0339:             * @return the component's input hint
0340:             *
0341:             * @see #setInputHint(JComponent, Object)
0342:             */
0343:            public static Object getInputHint(JComponent comp) {
0344:                return comp.getClientProperty(INPUT_HINT_KEY);
0345:            }
0346:
0347:            /**
0348:             * Sets the input hint for the given component. This hint can be later
0349:             * retrieved to indicate to the user the format of valid data for the
0350:             * focused component.
0351:             *
0352:             * @param comp    the component to set a hint for
0353:             * @param hint    the input hint to be associated with the component
0354:             *
0355:             * @see #getInputHint(JComponent)
0356:             */
0357:            public static void setInputHint(JComponent comp, Object hint) {
0358:                comp.putClientProperty(INPUT_HINT_KEY, hint);
0359:            }
0360:
0361:            /**
0362:             * Checks and answers if the specified component is associated with an
0363:             * error message in the given validation result. As a prerequisite,
0364:             * the component must have an <em>association key</em> set. That can
0365:             * be done using {@link #setMessageKey(JComponent, Object)} or
0366:             * {@link #setMessageKeys(JComponent, Object[])}.<p>
0367:             *
0368:             * <strong>Note:</strong> This method may become slow if invoked for larger
0369:             * validation results <em>and</em> multiple components. In this case,
0370:             * it is recommended to use {@link ValidationResult#keyMap()} instead.
0371:             * The latter iterates once over the validation result and can be used later
0372:             * to request the severity for multiple components in almost linear time.
0373:             *
0374:             * @param comp     used to get the association key from
0375:             * @param result   used to lookup the validation messages from
0376:             * @return true if the given component is associated with an error message
0377:             * @throws NullPointerException  if the component or validation result
0378:             *     is <code>null</code>
0379:             *
0380:             * @see #hasWarning(JComponent, ValidationResult)
0381:             * @see #getMessageKeys(JComponent)
0382:             */
0383:            public static boolean hasError(JComponent comp,
0384:                    ValidationResult result) {
0385:                return result.subResult(getMessageKeys(comp)).hasErrors();
0386:            }
0387:
0388:            /**
0389:             * Checks and answers if the specified component is associated with a
0390:             * warning message in the given validation result. As a prerequisite,
0391:             * the component must have a <em>message key</em> set. That can
0392:             * be done using {@link #setMessageKey(JComponent, Object)} or
0393:             * {@link #setMessageKeys(JComponent, Object[])}.<p>
0394:             *
0395:             * <strong>Note:</strong> This method may become slow if invoked for larger
0396:             * validation results <em>and</em> multiple components. In this case,
0397:             * it is recommended to use {@link ValidationResult#keyMap()} instead.
0398:             * The latter iterates once over the validation result and can be used later
0399:             * to request the severity for multiple components in almost linear time.
0400:             *
0401:             * @param comp     used to get the association key from
0402:             * @param result   used to lookup the validation messages from
0403:             * @return true if the given component is associated with a warning message
0404:             * @throws NullPointerException  if the component or validation result
0405:             *     is <code>null</code>
0406:             *
0407:             * @see #hasError(JComponent, ValidationResult)
0408:             * @see #getMessageKeys(JComponent)
0409:             */
0410:            public static boolean hasWarning(JComponent comp,
0411:                    ValidationResult result) {
0412:                return result.subResult(getMessageKeys(comp)).hasWarnings();
0413:            }
0414:
0415:            /**
0416:             * Returns a default background color that can be used as the component
0417:             * background for components with mandatory content. Typically this
0418:             * color will be used with instances of {@link JTextComponent}.<p>
0419:             *
0420:             * <strong>Note:</strong> The component background colors are managed
0421:             * by the look&amp;feel implementation. Many l&amp;fs will honor a
0422:             * custom background color. However, some l&amp;fs may ignore custom
0423:             * background colors. It is recommended to check the
0424:             * appearance in all l&amp;fs available in an application.
0425:             *
0426:             * @return a background color useful for components with mandatory content
0427:             *
0428:             * @see #getMandatoryForeground()
0429:             */
0430:            public static Color getMandatoryBackground() {
0431:                return MANDATORY_BACKGROUND;
0432:            }
0433:
0434:            /**
0435:             * Returns a default foreground color that can be used as the component
0436:             * foreground for components with mandatory content. Typically this
0437:             * color will be used with instances of {@link JTextComponent}.<p>
0438:             *
0439:             * <strong>Note:</strong> The component foreground and border colors are
0440:             * managed by the look&amp;feel implementation. Many l&amp;fs will honor a
0441:             * custom foreground color and custom border configuration. However, some
0442:             * l&amp;fs may ignore these custom settings. It is recommended to check
0443:             * the appearance in all l&amp;fs available in an application.
0444:             *
0445:             * @return a foreground color useful for components with mandatory content
0446:             *
0447:             * @see #getMandatoryBackground()
0448:             * @see #getMandatoryBorder()
0449:             */
0450:            public static Color getMandatoryForeground() {
0451:                return MANDATORY_FOREGROUND;
0452:            }
0453:
0454:            /**
0455:             * Sets the text component's background to a color that shall indicate
0456:             * that the component's content is mandatory.<p>
0457:             *
0458:             * <strong>Note:</strong> The component background colors are
0459:             * managed by the look&amp;feel implementation. Many l&amp;fs will honor a
0460:             * custom foreground color and custom border configuration. However, some
0461:             * l&amp;fs may ignore these custom settings. It is recommended to check
0462:             * the appearance in all l&amp;fs available in an application.
0463:             *
0464:             * @param comp   the text component that shall get a new background
0465:             *
0466:             * @see #setMandatoryBorder(JTextComponent)
0467:             * @see #setErrorBackground(JTextComponent)
0468:             * @see #setWarningBackground(JTextComponent)
0469:             */
0470:            public static void setMandatoryBackground(JTextComponent comp) {
0471:                comp.setBackground(MANDATORY_BACKGROUND);
0472:            }
0473:
0474:            /**
0475:             * Returns the error background color used to mark components
0476:             * that have an associated validation error.
0477:             *
0478:             * @return the error background color
0479:             *
0480:             * @see #getWarningBackground()
0481:             * @see #setErrorBackground(JTextComponent)
0482:             * @see #updateComponentTreeSeverityBackground(Container, ValidationResult)
0483:             *
0484:             * @since 1.0.2
0485:             */
0486:            public static Color getErrorBackground() {
0487:                return ERROR_BACKGROUND;
0488:            }
0489:
0490:            /**
0491:             * Sets the text component's background to a color that shall indicate
0492:             * that the component's content has is invalid with error severity.<p>
0493:             *
0494:             * <strong>Note:</strong> The component background colors are
0495:             * managed by the look&amp;feel implementation. Many l&amp;fs will honor a
0496:             * custom foreground color and custom border configuration. However, some
0497:             * l&amp;fs may ignore these custom settings. It is recommended to check
0498:             * the appearance in all l&amp;fs available in an application.
0499:             *
0500:             * @param comp   the text component that shall get a new background
0501:             *
0502:             * @see #setMandatoryBackground(JTextComponent)
0503:             * @see #setWarningBackground(JTextComponent)
0504:             */
0505:            public static void setErrorBackground(JTextComponent comp) {
0506:                comp.setBackground(ERROR_BACKGROUND);
0507:            }
0508:
0509:            /**
0510:             * Returns the warning background color used to mark components
0511:             * that have an associated validation warning.
0512:             *
0513:             * @return the warning background color
0514:             *
0515:             * @see #getErrorBackground()
0516:             * @see #setWarningBackground(JTextComponent)
0517:             * @see #updateComponentTreeSeverityBackground(Container, ValidationResult)
0518:             *
0519:             * @since 1.0.2
0520:             */
0521:            public static Color getWarningBackground() {
0522:                return WARNING_BACKGROUND;
0523:            }
0524:
0525:            /**
0526:             * Sets the text component's background to a color that shall indicate
0527:             * that the component's content is invalid with warning severity.<p>
0528:             *
0529:             * <strong>Note:</strong> The component background colors are
0530:             * managed by the look&amp;feel implementation. Many l&amp;fs will honor a
0531:             * custom foreground color and custom border configuration. However, some
0532:             * l&amp;fs may ignore these custom settings. It is recommended to check
0533:             * the appearance in all l&amp;fs available in an application.
0534:             *
0535:             * @param comp   the text component that shall get a new background
0536:             *
0537:             * @see #setMandatoryBackground(JTextComponent)
0538:             * @see #setErrorBackground(JTextComponent)
0539:             */
0540:            public static void setWarningBackground(JTextComponent comp) {
0541:                comp.setBackground(WARNING_BACKGROUND);
0542:            }
0543:
0544:            // Managing Borders *******************************************************
0545:
0546:            /**
0547:             * Sets the text component's border to use a new border that shall indicate
0548:             * that the component's content is mandatory.<p>
0549:             *
0550:             * <strong>Note:</strong> The component foreground and border colors are
0551:             * managed by the look&amp;feel implementation. Many l&amp;fs will honor a
0552:             * custom foreground color and custom border configuration. However, some
0553:             * l&amp;fs may ignore these custom settings. It is recommended to check
0554:             * the appearance in all l&amp;fs available in an application.
0555:             *
0556:             * @param comp   the component that gets a new border
0557:             *
0558:             * @see #setMandatoryBackground(JTextComponent)
0559:             * @see #getMandatoryBorder()
0560:             */
0561:            public static void setMandatoryBorder(JTextComponent comp) {
0562:                Container parent = comp.getParent();
0563:                if (parent instanceof  JViewport) {
0564:                    Container grandpa = parent.getParent();
0565:                    if (grandpa instanceof  JScrollPane) {
0566:                        ((JScrollPane) grandpa).setBorder(getMandatoryBorder());
0567:                        return;
0568:                    }
0569:                }
0570:                comp.setBorder(getMandatoryBorder());
0571:            }
0572:
0573:            /**
0574:             * Lazily creates and returns a {@link Border} instance that is used
0575:             * to indicate that a component's content is mandatory.
0576:             *
0577:             * @return a <code>Border</code> that is used to indicate that
0578:             *     a component's content is mandatory
0579:             */
0580:            public static Border getMandatoryBorder() {
0581:                if (mandatoryBorder == null) {
0582:                    mandatoryBorder = new CompoundBorder(new LineBorder(
0583:                            getMandatoryForeground()),
0584:                            new BasicBorders.MarginBorder());
0585:                }
0586:                return mandatoryBorder;
0587:            }
0588:
0589:            // Predefined Component Tree Updates **************************************
0590:
0591:            /**
0592:             * Traverses a component tree and sets mandatory backgrounds
0593:             * to text components that have been marked as mandatory
0594:             * with {@link #setMandatory(JComponent, boolean)} before.
0595:             * The iteration starts at the given container.
0596:             *
0597:             * @param container   the component tree root
0598:             *
0599:             * @see #setMandatory(JComponent, boolean)
0600:             * @see #setMandatoryBackground(JTextComponent)
0601:             */
0602:            public static void updateComponentTreeMandatoryBackground(
0603:                    Container container) {
0604:                visitComponentTree(container, null,
0605:                        new MandatoryBackgroundVisitor());
0606:            }
0607:
0608:            /**
0609:             * Traverses a component tree and sets mandatory backgrounds
0610:             * to text components that have blank content and have been marked
0611:             * as mandatory with {@link #setMandatory(JComponent, boolean)} before.
0612:             * The iteration starts at the given container.
0613:             *
0614:             * @param container   the component tree root
0615:             *
0616:             * @see #setMandatory(JComponent, boolean)
0617:             * @see #setMandatoryBackground(JTextComponent)
0618:             */
0619:            public static void updateComponentTreeMandatoryAndBlankBackground(
0620:                    Container container) {
0621:                visitComponentTree(container, null,
0622:                        new MandatoryAndBlankBackgroundVisitor());
0623:            }
0624:
0625:            /**
0626:             * Traverses a component tree and sets mandatory borders
0627:             * to text components that have been marked as mandatory
0628:             * with {@link #setMandatory(JComponent, boolean)} before.
0629:             * The iteration starts at the given container.
0630:             *
0631:             * @param container   the component tree root
0632:             *
0633:             * @see #setMandatory(JComponent, boolean)
0634:             * @see #setMandatoryBorder(JTextComponent)
0635:             */
0636:            public static void updateComponentTreeMandatoryBorder(
0637:                    Container container) {
0638:                visitComponentTree(container, null,
0639:                        new MandatoryBorderVisitor());
0640:            }
0641:
0642:            /**
0643:             * Traverses a component tree and sets the text component backgrounds
0644:             * according to the severity of an associated validation result - if any.
0645:             * The iteration starts at the given container.<p>
0646:             *
0647:             * The message keys used to associate components with validation messages
0648:             * should be set using {@link #setMessageKey(JComponent, Object)} before
0649:             * you call this method.
0650:             *
0651:             * @param container   the component tree root
0652:             * @param result      the validation result used to lookup the severities
0653:             *
0654:             * @see #setMandatory(JComponent, boolean)
0655:             * @see #setMessageKey(JComponent, Object)
0656:             * @see #setMandatoryBackground(JTextComponent)
0657:             * @see #setErrorBackground(JTextComponent)
0658:             * @see #setWarningBackground(JTextComponent)
0659:             *
0660:             * @since 1.0.2
0661:             */
0662:            public static void updateComponentTreeSeverityBackground(
0663:                    Container container, ValidationResult result) {
0664:                visitComponentTree(container, result.keyMap(),
0665:                        new SeverityBackgroundVisitor());
0666:            }
0667:
0668:            /**
0669:             * Traverses a component tree and sets the severity for all text components.
0670:             * The iteration starts at the given container. If a validation result is
0671:             * associated with a component, the result's severity is set. Otherwise
0672:             * the severity is set to <code>null</code>. The severity is set using
0673:             * {@link #setSeverity(JComponent, Severity)}.<p>
0674:             *
0675:             * Before you use this method, associate components with validation
0676:             * messages using {@link #setMessageKey(JComponent, Object)}.
0677:             *
0678:             * @param container   the component tree root
0679:             * @param result      the validation result that provides the associated messages
0680:             *
0681:             * @see #setSeverity(JComponent, Severity)
0682:             */
0683:            public static void updateComponentTreeSeverity(Container container,
0684:                    ValidationResult result) {
0685:                visitComponentTree(container, result.keyMap(),
0686:                        new SeverityVisitor());
0687:            }
0688:
0689:            // Visiting Text Components in a Component Tree ***************************
0690:
0691:            /**
0692:             * Traverses the component tree starting at the given container and invokes
0693:             * the given visitor's <code>#visit</code> method on each instance of
0694:             * {@link JTextComponent}. Useful to perform custom component tree updates
0695:             * that are not already provided by the <code>#updateComponentTreeXXX</code>
0696:             * methods.<p>
0697:             *
0698:             * The arguments passed to the #visit method are the visited component and
0699:             * its associated validation subresult. This subresult is requested from
0700:             * the specified <code>keyMap</code> using the component's message key.<p>
0701:             *
0702:             * Before you use this method, associate text component with validation
0703:             * messages using {@link #setMessageKey(JComponent, Object)}.
0704:             *
0705:             * @param container   the component tree root
0706:             * @param keyMap      maps messages keys to associated validation results
0707:             * @param visitor     the visitor that is applied to all text components
0708:             *
0709:             * @see #setMessageKey(JComponent, Object)
0710:             * @see Visitor
0711:             */
0712:            public static void visitComponentTree(Container container,
0713:                    Map<Object, ValidationResult> keyMap, Visitor visitor) {
0714:                int componentCount = container.getComponentCount();
0715:                for (int i = 0; i < componentCount; i++) {
0716:                    Component child = container.getComponent(i);
0717:                    if (child instanceof  JTextComponent) {
0718:                        JComponent component = (JComponent) child;
0719:                        visitor.visit(component, keyMap);
0720:                    } else if (child instanceof  Container) {
0721:                        visitComponentTree((Container) child, keyMap, visitor);
0722:                    }
0723:                }
0724:            }
0725:
0726:            // Helper Code ************************************************************
0727:
0728:            /**
0729:             * Returns the ValidationResult associated with the given component
0730:             * using the specified validation result key map,
0731:             * or <code>null</code> if the component has no message key set,
0732:             * or <code>ValidationResult.EMPTY</code> if the key map contains
0733:             * no result for the component.
0734:             *
0735:             * @param comp     the component may be marked with a validation message keys
0736:             * @param keyMap   maps validation message keys to ValidationResults
0737:             * @return the ValidationResult associated with the given component
0738:             *     as provided by the specified validation key map
0739:             *     or <code>null</code> if the component has no message key set,
0740:             *     or <code>ValidationResult.EMPTY</code> if no result is associated
0741:             *     with the component
0742:             *
0743:             * @since 1.4
0744:             */
0745:            public static ValidationResult getAssociatedResult(JComponent comp,
0746:                    Map<Object, ValidationResult> keyMap) {
0747:                Object[] messageKeys = getMessageKeys(comp);
0748:                if ((messageKeys == null) || (keyMap == null)) {
0749:                    return null;
0750:                }
0751:                if (messageKeys.length == 1) {
0752:                    ValidationResult result = keyMap.get(messageKeys[0]);
0753:                    return result == null ? ValidationResult.EMPTY : result; // already unmodifiable
0754:                }
0755:                ValidationResult result = null;
0756:                for (Object element : messageKeys) {
0757:                    ValidationResult subResult = keyMap.get(element);
0758:                    if (subResult != null) {
0759:                        if (result == null) {
0760:                            result = new ValidationResult();
0761:                        }
0762:                        result.addAllFrom(subResult);
0763:                    }
0764:                }
0765:                return result == null ? ValidationResult.EMPTY
0766:                        : ValidationResult.unmodifiableResult(result);
0767:            }
0768:
0769:            /**
0770:             * Returns a default background color that is requested from an instance
0771:             * of a prototype component of the same type as the given component.
0772:             * If such a component cannot be created, a JTextField is used.
0773:             * The prototype's enabled and editable state is then set to the state
0774:             * of the given component. Finally the prototype's background is returned.
0775:             *
0776:             * @param component   the component to get the default background for
0777:             * @return the background color of a prototype text component that has
0778:             *     the same state as the given component
0779:             *
0780:             * @see #restoreBackground(JTextComponent)
0781:             */
0782:            private static Color getDefaultBackground(JTextComponent component) {
0783:                JTextComponent prototype = getPrototypeFor(component.getClass());
0784:                prototype.setEnabled(component.isEnabled());
0785:                prototype.setEditable(component.isEditable());
0786:                return prototype.getBackground();
0787:            }
0788:
0789:            /**
0790:             * Lazily creates and returns a prototype text component instance
0791:             * of the given text component class. First ensures that the Look&amp;Feel
0792:             * change handler is registered that clears the prototype map if
0793:             * the L&amp;f changes.
0794:             *
0795:             * @param prototypeClass   the class of the prototype to be returned
0796:             * @return the lazily created prototype component
0797:             */
0798:            private static JTextComponent getPrototypeFor(
0799:                    Class<? extends JTextComponent> prototypeClass) {
0800:                ensureLookAndFeelChangeHandlerRegistered();
0801:                JTextComponent prototype = PROTOTYPE_COMPONENTS
0802:                        .get(prototypeClass);
0803:                if (prototype == null) {
0804:                    try {
0805:                        prototype = prototypeClass.newInstance();
0806:                    } catch (Exception e) {
0807:                        prototype = new JTextField();
0808:                    }
0809:                    PROTOTYPE_COMPONENTS.put(prototypeClass, prototype);
0810:                }
0811:                return prototype;
0812:            }
0813:
0814:            /**
0815:             * Returns the background color that has been previously stored for
0816:             * the given component, or <code>null</code> if none.
0817:             *
0818:             * @param comp  the component to be requested
0819:             * @return the background color that has been previously stored for
0820:             *     the given component, or <code>null</code> if none.
0821:             *
0822:             * @see #ensureCustomBackgroundStored(JTextComponent)
0823:             * @see #restoreBackground(JTextComponent)
0824:             */
0825:            private static Color getStoredBackground(JTextComponent comp) {
0826:                return (Color) comp.getClientProperty(STORED_BACKGROUND_KEY);
0827:            }
0828:
0829:            /**
0830:             * Ensures that a text component's custom background - if any -
0831:             * is stored as a client property. Used to store the background once only.
0832:             *
0833:             * @param comp  the component to be requested
0834:             *
0835:             * @see #getStoredBackground(JTextComponent)
0836:             * @see #restoreBackground(JTextComponent)
0837:             */
0838:            private static void ensureCustomBackgroundStored(JTextComponent comp) {
0839:                if (getStoredBackground(comp) != null) {
0840:                    return;
0841:                }
0842:                Color background = comp.getBackground();
0843:                if ((background == null) || (background instanceof  UIResource)
0844:                        || (background == WARNING_BACKGROUND)
0845:                        || (background == ERROR_BACKGROUND)) {
0846:                    return;
0847:                }
0848:                comp.putClientProperty(STORED_BACKGROUND_KEY, background);
0849:            }
0850:
0851:            /**
0852:             * Looks up and restores the text component's previously stored (original)
0853:             * background color.
0854:             *
0855:             * @param comp  the component that shall get its original background color
0856:             *
0857:             * @see #getStoredBackground(JTextComponent)
0858:             * @see #ensureCustomBackgroundStored(JTextComponent)
0859:             */
0860:            private static void restoreBackground(JTextComponent comp) {
0861:                Color storedBackground = getStoredBackground(comp);
0862:                comp
0863:                        .setBackground(storedBackground == null ? getDefaultBackground(comp)
0864:                                : storedBackground);
0865:            }
0866:
0867:            // Visitor Definition and Predefined Visitor Implementations **************
0868:
0869:            /**
0870:             * Describes visitors that visit a component tree.
0871:             * Visitor implementations are used to mark components,
0872:             * to change component background, to associate components
0873:             * with additional information; things that are not already
0874:             * provided by the <code>#updateComponentTreeXXX</code> methods
0875:             * and this class' predefined Visitor implementations.
0876:             */
0877:            public static interface Visitor {
0878:
0879:                /**
0880:                 * Visits the given component using the specified key map, that maps
0881:                 * message keys to associated validation subresults.
0882:                 * Typically an implementation will operate on the component state.
0883:                 *
0884:                 * @param component the component to be visited
0885:                 * @param keyMap    maps messages keys to associated validation results
0886:                 */
0887:                void visit(JComponent component,
0888:                        Map<Object, ValidationResult> keyMap);
0889:            }
0890:
0891:            /**
0892:             * A validation visitor that sets the background color of JTextComponents
0893:             * to mark mandatory components.
0894:             */
0895:            private static final class MandatoryBackgroundVisitor implements 
0896:                    Visitor {
0897:
0898:                /**
0899:                 * Sets the mandatory background to text components that have been marked
0900:                 * as mandatory.
0901:                 *
0902:                 * @param component   the component to be visited
0903:                 * @param keyMap      ignored
0904:                 */
0905:                public void visit(JComponent component,
0906:                        Map<Object, ValidationResult> keyMap) {
0907:                    if ((component instanceof  JTextComponent)
0908:                            && isMandatory(component)) {
0909:                        setMandatoryBackground((JTextComponent) component);
0910:                    }
0911:                }
0912:
0913:            }
0914:
0915:            /**
0916:             * A validation visitor that sets the background color of JTextComponents
0917:             * to indicate if mandatory components have a blank text or not.
0918:             */
0919:            private static final class MandatoryAndBlankBackgroundVisitor
0920:                    implements  Visitor {
0921:
0922:                /**
0923:                 * Sets the mandatory background to text components that have been marked
0924:                 * as mandatory if the content is blank, otherwise the original
0925:                 * background is restored.
0926:                 *
0927:                 * @param component   the component to be visited
0928:                 * @param keyMap      ignored
0929:                 */
0930:                public void visit(JComponent component,
0931:                        Map<Object, ValidationResult> keyMap) {
0932:                    JTextComponent textChild = (JTextComponent) component;
0933:                    if (isMandatoryAndBlank(textChild)) {
0934:                        setMandatoryBackground(textChild);
0935:                    } else {
0936:                        restoreBackground(textChild);
0937:                    }
0938:                }
0939:            }
0940:
0941:            /**
0942:             * A validation visitor that sets a mandatory border for JTextComponents
0943:             * that have been marked as mandatory.
0944:             */
0945:            private static final class MandatoryBorderVisitor implements 
0946:                    Visitor {
0947:
0948:                /**
0949:                 * Sets the mandatory border to text components that have been marked
0950:                 * as mandatory.
0951:                 *
0952:                 * @param component   the component to be visited
0953:                 * @param keyMap      ignored
0954:                 */
0955:                public void visit(JComponent component,
0956:                        Map<Object, ValidationResult> keyMap) {
0957:                    if ((component instanceof  JTextComponent)
0958:                            && isMandatory(component)) {
0959:                        setMandatoryBorder((JTextComponent) component);
0960:                    }
0961:                }
0962:            }
0963:
0964:            /**
0965:             * A validation visitor that sets the background color of JTextComponents
0966:             * according to the severity of an associated validation result - if any.
0967:             */
0968:            private static final class SeverityBackgroundVisitor implements 
0969:                    Visitor {
0970:
0971:                /**
0972:                 * Sets the component background according to the associated
0973:                 * validation result: default, error, warning.
0974:                 *
0975:                 * @param component  the component to be visited
0976:                 * @param keyMap     maps messages keys to associated validation results
0977:                 */
0978:                public void visit(JComponent component,
0979:                        Map<Object, ValidationResult> keyMap) {
0980:                    Object messageKeys = getMessageKeys(component);
0981:                    if (messageKeys == null) {
0982:                        return;
0983:                    }
0984:                    JTextComponent textChild = (JTextComponent) component;
0985:                    ensureCustomBackgroundStored(textChild);
0986:                    ValidationResult result = getAssociatedResult(component,
0987:                            keyMap);
0988:                    if ((result == null) || result.isEmpty()) {
0989:                        restoreBackground(textChild);
0990:                    } else if (result.hasErrors()) {
0991:                        setErrorBackground(textChild);
0992:                    } else if (result.hasWarnings()) {
0993:                        setWarningBackground(textChild);
0994:                    }
0995:                }
0996:            }
0997:
0998:            /**
0999:             * A validation visitor that sets each component's severity
1000:             * according to its associated validation result or to <code>null</code>
1001:             * if no message key is set for the component.
1002:             */
1003:            private static final class SeverityVisitor implements  Visitor {
1004:
1005:                /**
1006:                 * Sets the component's severity according to its associated
1007:                 * validation result, or <code>null</code> if the component
1008:                 * has no message key set.
1009:                 *
1010:                 * @param component  the component to be visited
1011:                 * @param keyMap     maps messages keys to associated validation results
1012:                 */
1013:                public void visit(JComponent component,
1014:                        Map<Object, ValidationResult> keyMap) {
1015:                    ValidationResult result = getAssociatedResult(component,
1016:                            keyMap);
1017:                    Severity severity = result == null ? null : result
1018:                            .getSeverity();
1019:                    setSeverity(component, severity);
1020:                }
1021:            }
1022:
1023:            // Handling L&f Changes ***************************************************
1024:
1025:            /**
1026:             * Describes whether the <code>LookAndFeelChangeHandler</code>
1027:             * has been registered with the <code>UIManager</code> or not.
1028:             * It is registered lazily when the first prototype component
1029:             * is requested in <code>#getPrototypeFor(Class)</code>.
1030:             */
1031:            private static boolean lafChangeHandlerRegistered = false;
1032:
1033:            private static synchronized void ensureLookAndFeelChangeHandlerRegistered() {
1034:                if (!lafChangeHandlerRegistered) {
1035:                    UIManager
1036:                            .addPropertyChangeListener(new LookAndFeelChangeHandler());
1037:                    lafChangeHandlerRegistered = true;
1038:                }
1039:            }
1040:
1041:            /**
1042:             * Clears the cached prototype components when the L&amp; changes.
1043:             */
1044:            private static final class LookAndFeelChangeHandler implements 
1045:                    PropertyChangeListener {
1046:
1047:                /**
1048:                 * Clears the cached prototype components, if the UIManager has fired
1049:                 * any property change event. Since we need to handle look&amp;feel
1050:                 * changes only, we check the event's property name to be
1051:                 * "lookAndFeel" or <code>null</code>. The check for null is necessary
1052:                 * to handle the special event where property name, old and new value
1053:                 * are all <code>null</code> to indicate that multiple properties
1054:                 * have changed.
1055:                 *
1056:                 * @param evt  describes the property change
1057:                 */
1058:                public void propertyChange(PropertyChangeEvent evt) {
1059:                    String propertyName = evt.getPropertyName();
1060:                    if ((propertyName == null)
1061:                            || propertyName.equals("lookAndFeel")) {
1062:                        PROTOTYPE_COMPONENTS.clear();
1063:                    }
1064:                }
1065:            }
1066:
1067:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.