1 /*
2 * Scope: a generic MVC framework.
3 * Copyright (c) 2000-2002, The Scope team
4 * All rights reserved.
5 *
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * Neither the name "Scope" nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 *
36 * $Id: SPasswordField.java,v 1.11 2002/09/13 17:04:41 ludovicc Exp $
37 */
38 package org.scopemvc.view.swing;
39
40
41 import java.awt.event.ActionEvent;
42 import java.awt.event.ActionListener;
43 import java.awt.event.FocusEvent;
44 import java.awt.event.FocusListener;
45 import java.beans.Beans;
46 import javax.swing.JPasswordField;
47 import javax.swing.JToolTip;
48 import org.apache.commons.logging.Log;
49 import org.apache.commons.logging.LogFactory;
50 import org.scopemvc.core.Control;
51 import org.scopemvc.core.Controller;
52 import org.scopemvc.core.PropertyView;
53 import org.scopemvc.core.Selector;
54 import org.scopemvc.util.Debug;
55 import org.scopemvc.util.convertor.StringConvertor;
56 import org.scopemvc.util.convertor.StringConvertors;
57 import org.scopemvc.view.util.ModelBindable;
58
59 /***
60 * <P>
61 *
62 * A JPasswordField that works the same way as {@link STextField}. </P> <P>
63 *
64 * Note this is a copy/paste from STextField because no multiple inheritance and
65 * JPasswordField plaf objects depend on instanceof JPasswordField (which isn't
66 * an interface... doh!). </P>
67 *
68 * @author <A HREF="mailto:smeyfroi@users.sourceforge.net">Steve Meyfroidt</A>
69 * @created 05 September 2002
70 * @version $Revision: 1.11 $ $Date: 2002/09/13 17:04:41 $
71 * @see STextField
72 */
73 public class SPasswordField extends JPasswordField
74 implements PropertyView, FocusListener, ActionListener, ModelBindable, Refreshable {
75
76 private static final Log LOG = LogFactory.getLog(SPasswordField.class);
77
78 /***
79 * Helper to manage model to view binding.
80 */
81 private SwingBoundModel boundModel = new SwingBoundModel(this);
82
83 /***
84 * Helper to manage validation state.
85 */
86 private ValidationHelper validationHelper = new ValidationHelper(this);
87
88 /***
89 * ID of the Control issued when user hits Enter in the STextField.
90 */
91 private String controlID;
92
93 /***
94 * STextField can "hold" a null when bound to a property that happens to be
95 * null.
96 */
97 private boolean valueIsNull = false;
98
99 /***
100 * Does this textfield disable itself if the model property it is bound to
101 * becomes null?
102 */
103 private boolean disableOnNull = false;
104
105 /***
106 * The StringConvertor used to convert the model property to and from the
107 * String representation that the user edits in the textfield.
108 */
109 private StringConvertor stringConvertor;
110
111
112 /***
113 * Constructor for the SPasswordField object
114 */
115 public SPasswordField() {
116 setEnabled(Beans.isDesignTime());
117 addFocusListener(this);
118 addActionListener(this);
119 }
120
121
122 /***
123 * @return true if the textfield should be disabled when it edits a null
124 * property value. Otherwise, a null property is treated as an empty
125 * String.
126 */
127 public final boolean isDisableOnNull() {
128 return disableOnNull;
129 }
130
131
132 // ------------------- Delegate to BoundModel -------------------
133
134 /***
135 * Gets the bound model
136 *
137 * @return The boundModel value
138 */
139 public final Object getBoundModel() {
140 return boundModel.getBoundModel();
141 }
142
143
144 /***
145 * Gets the selector
146 *
147 * @return The selector value
148 */
149 public final Selector getSelector() {
150 return boundModel.getSelector();
151 }
152
153
154 // ---------- Issue a Control when user hits Enter in the STextfield --------------
155
156 /***
157 * Gets the control ID
158 *
159 * @return The controlID value
160 */
161 public final String getControlID() {
162 return controlID;
163 }
164
165
166 /***
167 * Get the current value (what would be set as a property of the bound model
168 * object) being presented on the View.
169 *
170 * @return property value from parsing the textfield's current String
171 * representation.
172 * @exception IllegalArgumentException if the conversion from String fails.
173 */
174 public Object getViewValue() throws IllegalArgumentException {
175 String text = new String(getPassword());
176
177 if (stringConvertor == null
178 || valueIsNull
179 || (isDisableOnNull() && text.length() < 1)) {
180 return null;
181 }
182
183 return stringConvertor.stringAsValue(text);
184 }
185
186
187 /***
188 * Don't assign a Controller to STextField, instead delegate to the
189 * containing SwingView that has a parent Controller.
190 *
191 * @return The controller value
192 */
193 public Controller getController() {
194 return null;
195 }
196
197
198 /***
199 * Don't assign a Controller to STextField, instead delegate to the
200 * containing SwingView that has a parent Controller.
201 *
202 * @param inControl TODO: Describe the Parameter
203 */
204 public void issueControl(Control inControl) {
205 SwingUtil.issueControl(this, inControl);
206 }
207
208
209 // ------------ Convenience -------------------
210
211 /***
212 * Gets the password text
213 *
214 * @return The passwordText value
215 */
216 public String getPasswordText() {
217 return new String(getPassword());
218 }
219
220
221 /***
222 * Set this to true if the textfield should be disabled when it edits a null
223 * property value. Otherwise, a null property is treated as an empty String.
224 *
225 * @param inDisable The new disableOnNull value
226 */
227 public final void setDisableOnNull(boolean inDisable) {
228 disableOnNull = inDisable;
229 }
230
231
232 /***
233 * Sets the bound model
234 *
235 * @param inModel The new boundModel value
236 */
237 public final void setBoundModel(Object inModel) {
238 boundModel.setBoundModel(inModel);
239 setupStringConvertor();
240 }
241
242
243 /***
244 * Sets the selector
245 *
246 * @param inSelector The new selector value
247 */
248 public final void setSelector(Selector inSelector) {
249 boundModel.setSelector(inSelector);
250 setupStringConvertor();
251 }
252
253
254 /***
255 * Sets the selector string
256 *
257 * @param inSelectorString The new selectorString value
258 */
259 public final void setSelectorString(String inSelectorString) {
260 boundModel.setSelectorString(inSelectorString);
261 setupStringConvertor();
262 }
263
264
265 /***
266 * Set the ID of the Control that will be issued when Enter key is pressed
267 * in this STextField. If null no Control will be issued.
268 *
269 * @param inControlID The new controlID value
270 */
271 public final void setControlID(String inControlID) {
272 controlID = inControlID;
273 }
274
275
276 /***
277 * Override to call super.setText() only if new value not equals() old
278 * value.
279 *
280 * @param t new text.
281 */
282 public void setText(String t) {
283 if (Debug.ON) {
284 Debug.assertTrue(getPassword() != null, "null getPassword()");
285 }
286 if (!new String(getPassword()).equals(t)) {
287 super.setText(t);
288 }
289 }
290
291 /***
292 * Don't assign a Controller to this component, instead delegate to the
293 * containing SwingView that has a parent Controller.
294 *
295 * @param inController The new controller value
296 */
297 public void setController(Controller inController) {
298 throw new UnsupportedOperationException("Can't assign a Controller to a " + getClass());
299 }
300
301 // --------------------- Implement ModelBindable ----------------------
302
303 /***
304 * Converts the incoming value to a String via appropriate {@link
305 * org.scopemvc.util.convertor.StringConvertor}. For incoming null either
306 * disable field or set text to empty String.
307 *
308 * @param inValue TODO: Describe the Parameter
309 * @param inReadOnly TODO: Describe the Parameter
310 */
311 public void updateFromProperty(Object inValue, boolean inReadOnly) {
312 if (LOG.isDebugEnabled()) {
313 LOG.debug("updateFromProperty: " + inValue + ", " + inReadOnly);
314 }
315
316 if (stringConvertor == null) {
317 valueIsNull = true;
318 // ?
319 setEnabled(false);
320 // setText("");
321 return;
322 }
323
324 if (inValue == null && isDisableOnNull()) {
325 valueIsNull = true;
326 setEnabled(false);
327 // setText("");
328 return;
329 }
330
331 valueIsNull = false;
332 //(inValue == null);
333 setEnabled(!inReadOnly);
334 try {
335 String text = stringConvertor.valueAsString(inValue);
336 setText(text);
337 } catch (IllegalArgumentException e) {
338 // should never happen normally -- comes from getValue() but the
339 // ... property value must always be convertible to String?
340 LOG.error("updateFromProperty", e);
341 setEnabled(false);
342 }
343 }
344
345
346 /***
347 * TODO: document the method
348 *
349 * @param inException TODO: Describe the Parameter
350 */
351 public void validationFailed(Exception inException) {
352 validationHelper.validationFailed(inException);
353 }
354
355
356 /***
357 * TODO: document the method
358 */
359 public void validationSuccess() {
360 validationHelper.validationSuccess();
361 }
362
363
364 /***
365 * TODO: document the method
366 *
367 * @return TODO: Describe the Return Value
368 */
369 public JToolTip createToolTip() {
370 return validationHelper.createToolTip(super.createToolTip());
371 }
372
373
374 // ---------------------- View to model ----------------------
375
376 /***
377 * TODO: document the method
378 *
379 * @param inEvent TODO: Describe the Parameter
380 */
381 public void focusLost(FocusEvent inEvent) {
382 if (LOG.isDebugEnabled()) {
383 LOG.debug("focusLost");
384 }
385
386 if (!inEvent.isTemporary()) {
387 boundModel.updateModel();
388 }
389 }
390
391
392 /***
393 * TODO: document the method
394 *
395 * @param inEvent TODO: Describe the Parameter
396 */
397 public void focusGained(FocusEvent inEvent) { }
398
399
400 /***
401 * Sync model object to View and issue a Control if ControlID set.
402 *
403 * @param e TODO: Describe the Parameter
404 */
405 public void actionPerformed(ActionEvent e) {
406 boundModel.updateModel();
407 // ... then do the sync to model
408
409 if (controlID != null) {
410 Control control = new Control(controlID);
411 issueControl(control);
412 }
413 }
414
415
416 // ------------------ Refreshable -------------------------
417
418 /***
419 * TODO: document the method
420 */
421 public void refresh() {
422 Object propertyValue = boundModel.getPropertyValue();
423 boolean propertyReadOnly = boundModel.getPropertyReadOnly();
424 updateFromProperty(propertyValue, propertyReadOnly);
425 }
426
427
428 /***
429 * TODO: document the method
430 */
431 protected void setupStringConvertor() {
432 try {
433 Object m = getBoundModel();
434 Selector s = getSelector();
435 if (m != null) {
436 Class clazz = boundModel.getPropertyManager().getPropertyClass(m, s);
437 stringConvertor = StringConvertors.forClass(clazz);
438 }
439 } catch (Exception e) {
440 stringConvertor = null;
441 }
442 }
443 }
This page was automatically generated by Maven