Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ErrorBindingListener |
|
| 2.3333333333333335;2.333 |
1 | /* | |
2 | * Copyright (c) 2009, Swiss Federal Department of Defence Civil Protection and Sport | |
3 | * (http://www.vbs.admin.ch) | |
4 | * Copyright (c) 2009, Ergon Informatik AG (http://www.ergon.ch) | |
5 | * All rights reserved. | |
6 | * | |
7 | * Licensed under the Open Permis License which accompanies this distribution, | |
8 | * and is available at http://www.openpermis.org/BSDlicenceKent.txt | |
9 | */ | |
10 | package org.openpermis.editor.policy.gui.binding; | |
11 | ||
12 | import java.awt.Color; | |
13 | import java.awt.Component; | |
14 | import java.awt.Container; | |
15 | ||
16 | import javax.swing.JComponent; | |
17 | ||
18 | import org.jdesktop.application.ResourceMap; | |
19 | import org.jdesktop.beansbinding.AbstractBindingListener; | |
20 | import org.jdesktop.beansbinding.Binding; | |
21 | import org.jdesktop.beansbinding.Binding.SyncFailure; | |
22 | ||
23 | ||
24 | /** | |
25 | * Binding listener that updates the background of a component if a sync fails. | |
26 | * <p>Also sets a component property to indicate that there was an error.</p> | |
27 | * @see #hasError(JComponent) | |
28 | * @see #hasAnyError(JComponent) | |
29 | * @since 0.1.0 | |
30 | */ | |
31 | public class ErrorBindingListener | |
32 | extends AbstractBindingListener | |
33 | { | |
34 | ||
35 | //---- Static | |
36 | ||
37 | /** | |
38 | * Property of type {@link Boolean} set at components to indicate an error. | |
39 | * @since 0.1.0 | |
40 | */ | |
41 | private static final String ERROR_STATE_PROPERTY_KEY = "bindingSyncErrorState"; | |
42 | ||
43 | /** | |
44 | * Property of type {@link String} set at components if they have an error. | |
45 | * @since 0.1.0 | |
46 | */ | |
47 | private static final String ERROR_MESSAGE_PROPERTY_KEY = "bindingSyncErrorMessage"; | |
48 | ||
49 | /** | |
50 | * Returns the error message of a component that has an error. | |
51 | * @param component the component for wich to retrieve the error message. | |
52 | * @return the error message or {@code null} if the component has no error. | |
53 | * @since 0.1.0 | |
54 | */ | |
55 | public static String getErrorMessage (JComponent component) { | |
56 | 0 | return (String) component.getClientProperty(ERROR_MESSAGE_PROPERTY_KEY); |
57 | } | |
58 | ||
59 | /** | |
60 | * Check if the specified or any child component has a synchronization error. | |
61 | * @param component the component to check. | |
62 | * @return {@code true} if at least one component has an error, {@code false} otherwise. | |
63 | * @since 0.1.0 | |
64 | */ | |
65 | public static boolean hasAnyError (JComponent component) { | |
66 | 0 | return hasError(component) || primHasAnyError(component); |
67 | } | |
68 | ||
69 | /** | |
70 | * Primitive to traverse the child list of the specified container and check for errors. | |
71 | * @param container the container to traverse. | |
72 | * @return {@code true} if at least one component has an error, {@code false} otherwise. | |
73 | * @since 0.1.0 | |
74 | */ | |
75 | private static boolean primHasAnyError (Container container) { | |
76 | 0 | for (Component child : container.getComponents()) { |
77 | 0 | if (child instanceof JComponent && hasAnyError((JComponent) child)) { |
78 | 0 | return true; |
79 | 0 | } else if (child instanceof Container && primHasAnyError((Container) child)) { |
80 | 0 | return true; |
81 | } | |
82 | } | |
83 | 0 | return false; |
84 | } | |
85 | ||
86 | /** | |
87 | * Check if the specified component has a synchronization error. | |
88 | * @param component the component to check. | |
89 | * @return {@code true} if it has an error, {@code false} otherwise. | |
90 | * @since 0.1.0 | |
91 | */ | |
92 | public static boolean hasError (JComponent component) { | |
93 | 0 | return Boolean.TRUE.equals(component.getClientProperty(ERROR_STATE_PROPERTY_KEY)); |
94 | } | |
95 | ||
96 | /** | |
97 | * Marks the component with a synchronization error state. | |
98 | * @param component the component to set the state for. | |
99 | * @param message the message describing the error. | |
100 | * @since 0.1.0 | |
101 | */ | |
102 | private static void markError (JComponent component, String message) { | |
103 | 0 | component.putClientProperty(ERROR_STATE_PROPERTY_KEY, Boolean.TRUE); |
104 | 0 | component.putClientProperty(ERROR_MESSAGE_PROPERTY_KEY, message); |
105 | 0 | } |
106 | ||
107 | /** | |
108 | * Clears the synchronization error state of a component. | |
109 | * @param component the component to clear the state for. | |
110 | * @since 0.1.0 | |
111 | */ | |
112 | private static void clearError (JComponent component) { | |
113 | 0 | component.putClientProperty(ERROR_STATE_PROPERTY_KEY, null); |
114 | 0 | component.putClientProperty(ERROR_MESSAGE_PROPERTY_KEY, null); |
115 | 0 | } |
116 | ||
117 | //---- State | |
118 | ||
119 | /** | |
120 | * The component this error binding listener modifies. | |
121 | * @since 0.1.0 | |
122 | */ | |
123 | private final JComponent component; | |
124 | ||
125 | /** | |
126 | * The error color to use. | |
127 | * @since 0.1.0 | |
128 | */ | |
129 | private final Color errorColor; | |
130 | ||
131 | /** | |
132 | * The error message in case of a failure. | |
133 | * @since 0.1.0 | |
134 | */ | |
135 | private final String errorMessage; | |
136 | ||
137 | /** | |
138 | * The error reporter to use. | |
139 | * @since 0.1.0 | |
140 | */ | |
141 | private final ErrorReporter errorReporter; | |
142 | ||
143 | /** | |
144 | * The original background color of the component. | |
145 | * @since 0.1.0 | |
146 | */ | |
147 | private Color backgroundColor; | |
148 | ||
149 | //---- Constructors | |
150 | ||
151 | /** | |
152 | * Creates a new error binding listener for the specified component. | |
153 | * @param reporter the error reporter to use if not {@code null}. | |
154 | * @param resourceMap resource map used to configure display properties. | |
155 | * @param component the component this error binding listener modifies. | |
156 | * @param errorKey key in the resource map to a translation of the error type, | |
157 | * may be {@code null} for a generic error message. | |
158 | * @since 0.1.0 | |
159 | */ | |
160 | public ErrorBindingListener ( | |
161 | ErrorReporter reporter, ResourceMap resourceMap, JComponent component, String errorKey | |
162 | 0 | ) { |
163 | 0 | this.component = component; |
164 | 0 | this.errorColor = resourceMap.getColor("errorBackgroundColor"); |
165 | 0 | this.errorMessage = resourceMap.getString(errorKey == null ? "errorMessage" : errorKey); |
166 | 0 | this.errorReporter = reporter; |
167 | 0 | } |
168 | ||
169 | //---- AbstractBindingListener | |
170 | ||
171 | /** | |
172 | * @since 0.1.0 | |
173 | */ | |
174 | @Override | |
175 | @SuppressWarnings("unchecked") | |
176 | public void synced (Binding binding) { | |
177 | 0 | if (hasError(this.component)) { |
178 | 0 | this.component.setBackground(this.backgroundColor); |
179 | 0 | clearError(this.component); |
180 | } | |
181 | 0 | } |
182 | ||
183 | /** | |
184 | * @since 0.1.0 | |
185 | */ | |
186 | @Override | |
187 | @SuppressWarnings("unchecked") | |
188 | public void syncFailed (Binding binding, final SyncFailure failure) { | |
189 | 0 | if (!hasError(this.component)) { |
190 | 0 | this.backgroundColor = this.component.getBackground(); |
191 | 0 | this.component.setBackground(this.errorColor); |
192 | 0 | markError(this.component, this.errorMessage); |
193 | 0 | if (this.errorReporter != null) { |
194 | 0 | this.errorReporter.showStatusError(this.errorMessage); |
195 | } | |
196 | } | |
197 | 0 | } |
198 | ||
199 | } |