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: STextArea.java,v 1.13 2002/09/13 17:04:42 ludovicc Exp $
37 */
38 package org.scopemvc.view.swing;
39
40
41 import java.awt.event.FocusEvent;
42 import java.awt.event.FocusListener;
43 import java.beans.Beans;
44 import javax.swing.JTextArea;
45 import javax.swing.JToolTip;
46 import org.apache.commons.logging.Log;
47 import org.apache.commons.logging.LogFactory;
48 import org.scopemvc.core.Control;
49 import org.scopemvc.core.Controller;
50 import org.scopemvc.core.PropertyView;
51 import org.scopemvc.core.Selector;
52 import org.scopemvc.util.Debug;
53 import org.scopemvc.util.convertor.StringConvertor;
54 import org.scopemvc.util.convertor.StringConvertors;
55 import org.scopemvc.view.util.ModelBindable;
56
57 /***
58 * <P>
59 *
60 * A JTextArea linked to a property of a bound model object. The property must
61 * have a StringConvertor to handle conversion to and from a String
62 * representation that will be edited in the textarea. Updates to the textarea
63 * result in changes to the model property when focus is lost. </P> <P>
64 *
65 * STextArea responds to the bound model object or the particular bound property
66 * becoming read-only by disabling itself. An STextArea is also disabled if it
67 * has no bound model or property. </P> <P>
68 *
69 * Null properties are handled in one of two ways:
70 * <OL>
71 * <LI> The textarea is disabled to prevent editing. </LI>
72 * <LI> The textarea is populated with an empty String. In this case, the
73 * bound property will contain an empty String not a null, if the textarea is
74 * populated with an empty string. </LI>
75 * </OL>
76 * The second option is the default but that can be changed by calling {@link
77 * #setDisableOnNull}. </P>
78 *
79 * @author <A HREF="mailto:smeyfroi@users.sourceforge.net">Steve Meyfroidt</A>
80 * @created 05 September 2002
81 * @version $Revision: 1.13 $ $Date: 2002/09/13 17:04:42 $
82 * @see SwingView
83 */
84 public class STextArea extends JTextArea implements PropertyView, FocusListener, ModelBindable, Refreshable {
85
86 private static final Log LOG = LogFactory.getLog(STextArea.class);
87
88 /***
89 * Helper to manage model to view binding.
90 */
91 private SwingBoundModel boundModel = new SwingBoundModel(this);
92
93 /***
94 * Helper to manage validation state.
95 */
96 private ValidationHelper validationHelper = new ValidationHelper(this);
97
98 /***
99 * STextArea can "hold" a null when bound to a property that happens to be
100 * null.
101 */
102 private boolean valueIsNull = false;
103
104 /***
105 * Does this textarea disable itself if the model property it is bound to
106 * becomes null?
107 */
108 private boolean disableOnNull = false;
109
110 /***
111 * The StringConvertor used to convert the model property to and from the
112 * String representation that the user edits in the textarea.
113 */
114 private StringConvertor stringConvertor;
115
116
117 /***
118 * Constructor for the STextArea object
119 */
120 public STextArea() {
121 this(0, 0);
122 }
123
124
125 /***
126 * Constructor for the STextArea object
127 *
128 * @param rows TODO: Describe the Parameter
129 * @param columns TODO: Describe the Parameter
130 */
131 public STextArea(int rows, int columns) {
132 super(rows, columns);
133 setEnabled(Beans.isDesignTime());
134 addFocusListener(this);
135 }
136
137
138 /***
139 * @return true if the textarea should be disabled when it edits a null
140 * property value. Otherwise, a null property is treated as an empty
141 * String.
142 */
143 public final boolean isDisableOnNull() {
144 return disableOnNull;
145 }
146
147
148 // ------------------- Delegate to BoundModel -------------------
149
150 /***
151 * Gets the bound model
152 *
153 * @return The boundModel value
154 */
155 public final Object getBoundModel() {
156 return boundModel.getBoundModel();
157 }
158
159
160 /***
161 * Gets the selector
162 *
163 * @return The selector value
164 */
165 public final Selector getSelector() {
166 return boundModel.getSelector();
167 }
168
169
170 /***
171 * Get the current value (what would be set as a property of the bound model
172 * object) being presented on the View.
173 *
174 * @return property value from parsing the textarea's current String
175 * representation.
176 * @exception IllegalArgumentException if the conversion from String fails.
177 */
178 public Object getViewValue() throws IllegalArgumentException {
179 String text = getText();
180
181 if (stringConvertor == null
182 || valueIsNull
183 || (isDisableOnNull() && text.length() < 1)) {
184 return null;
185 }
186
187 return stringConvertor.stringAsValue(text);
188 }
189
190
191 /***
192 * Don't assign a Controller to STextArea.
193 *
194 * @return The controller value
195 */
196 public Controller getController() {
197 return null;
198 }
199
200
201 /***
202 * STextArea can't issue Controls.
203 *
204 * @param inControl TODO: Describe the Parameter
205 */
206 public void issueControl(Control inControl) {
207 throw new UnsupportedOperationException("STextArea can't issue Controls.");
208 }
209
210
211 /***
212 * Set this to true if the textarea should be disabled when it edits a null
213 * String. Otherwise, a null property is treated as an empty String.
214 *
215 * @param inDisable The new disableOnNull value
216 */
217 public final void setDisableOnNull(boolean inDisable) {
218 disableOnNull = inDisable;
219 }
220
221
222 /***
223 * Sets the bound model
224 *
225 * @param inModel The new boundModel value
226 */
227 public final void setBoundModel(Object inModel) {
228 boundModel.setBoundModel(inModel);
229 setupStringConvertor();
230 }
231
232
233 /***
234 * Sets the selector
235 *
236 * @param inSelector The new selector value
237 */
238 public final void setSelector(Selector inSelector) {
239 boundModel.setSelector(inSelector);
240 setupStringConvertor();
241 }
242
243
244 /***
245 * Sets the selector string
246 *
247 * @param inSelectorString The new selectorString value
248 */
249 public final void setSelectorString(String inSelectorString) {
250 boundModel.setSelectorString(inSelectorString);
251 setupStringConvertor();
252 }
253
254
255 /***
256 * Override to call super.setText() only if new value not equals() old
257 * value.
258 *
259 * @param t new text.
260 */
261 public void setText(String t) {
262 if (Debug.ON) {
263 Debug.assertTrue(getText() != null, "null getText()");
264 }
265 if (!getText().equals(t)) {
266 super.setText(t);
267 }
268 }
269
270
271 // ------------------------ Implement View -----------------------
272
273 /***
274 * Don't assign a Controller to this component, instead delegate to the
275 * containing SwingView that has a parent Controller.
276 *
277 * @param inController The new controller value
278 */
279 public void setController(Controller inController) {
280 throw new UnsupportedOperationException("Can't assign a Controller to a " + getClass());
281 }
282
283 // --------------------- Implement ModelBindable ----------------------
284
285 /***
286 * Converts the incoming value to a String via appropriate {@link
287 * org.scopemvc.util.convertor.StringConvertor}. For incoming null either
288 * disable field or set text to empty String.
289 *
290 * @param inValue TODO: Describe the Parameter
291 * @param inReadOnly TODO: Describe the Parameter
292 */
293 public void updateFromProperty(Object inValue, boolean inReadOnly) {
294 if (LOG.isDebugEnabled()) {
295 LOG.debug("updateFromProperty: " + inValue + ", " + inReadOnly);
296 }
297
298 // ***** Hack. Need to revisit PropertyManager to traverse nulls and use metadata etc
299 setupStringConvertor();
300
301 if (stringConvertor == null) {
302 valueIsNull = true;
303 // ?
304 setEnabled(false);
305 // setText("");
306 return;
307 }
308
309 if (inValue == null && isDisableOnNull()) {
310 valueIsNull = true;
311 setEnabled(false);
312 // setText("");
313 return;
314 }
315
316 valueIsNull = false;
317 //(inValue == null);
318 setEnabled(!inReadOnly);
319 try {
320 if (LOG.isDebugEnabled()) {
321 LOG.debug("updateFromProperty: inValue: " + inValue);
322 }
323 String text = stringConvertor.valueAsString(inValue);
324 if (LOG.isDebugEnabled()) {
325 LOG.debug("updateFromProperty: text: " + text);
326 }
327 setText(text);
328 } catch (IllegalArgumentException e) {
329 // should never happen normally -- comes from getValue() but the
330 // ... property value must always be convertible to String?
331 LOG.error("updateFromProperty", e);
332 setEnabled(false);
333 }
334 }
335
336
337 /***
338 * TODO: document the method
339 *
340 * @param inException TODO: Describe the Parameter
341 */
342 public void validationFailed(Exception inException) {
343 validationHelper.validationFailed(inException);
344 }
345
346
347 /***
348 * TODO: document the method
349 */
350 public void validationSuccess() {
351 validationHelper.validationSuccess();
352 }
353
354
355 /***
356 * TODO: document the method
357 *
358 * @return TODO: Describe the Return Value
359 */
360 public JToolTip createToolTip() {
361 return validationHelper.createToolTip(super.createToolTip());
362 }
363
364
365 // ---------------------- View to model ----------------------
366
367 /***
368 * TODO: document the method
369 *
370 * @param inEvent TODO: Describe the Parameter
371 */
372 public void focusLost(FocusEvent inEvent) {
373 if (LOG.isDebugEnabled()) {
374 LOG.debug("focusLost");
375 }
376
377 // if (! inEvent.isTemporary()) {
378 boundModel.updateModel();
379 // }
380 }
381
382
383 /***
384 * TODO: document the method
385 *
386 * @param inEvent TODO: Describe the Parameter
387 */
388 public void focusGained(FocusEvent inEvent) { }
389
390
391 // ------------------ Refreshable -------------------------
392
393 /***
394 * TODO: document the method
395 */
396 public void refresh() {
397 Object propertyValue = boundModel.getPropertyValue();
398 boolean propertyReadOnly = boundModel.getPropertyReadOnly();
399 updateFromProperty(propertyValue, propertyReadOnly);
400 }
401
402
403 /***
404 * TODO: document the method
405 */
406 protected void setupStringConvertor() {
407 try {
408 Object m = getBoundModel();
409 Selector s = getSelector();
410 if (m != null) {
411 Class clazz = boundModel.getPropertyManager().getPropertyClass(m, s);
412 stringConvertor = StringConvertors.forClass(clazz);
413 }
414 } catch (Exception e) {
415 stringConvertor = null;
416 }
417 }
418 }
419
This page was automatically generated by Maven