KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdesktop > swing > binding > AbstractBinding


1 /*
2  * $Id: AbstractBinding.java,v 1.7 2005/02/28 21:10:33 rbair Exp $
3  *
4  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
5  * Santa Clara, California 95054, U.S.A. All rights reserved.
6  */

7
8 package org.jdesktop.swing.binding;
9
10 import org.jdesktop.swing.data.ConversionException;
11 import org.jdesktop.swing.data.Converter;
12 import org.jdesktop.swing.data.DataModel;
13 import org.jdesktop.swing.data.MetaData;
14 import org.jdesktop.swing.data.Validator;
15 import org.jdesktop.swing.data.ValueChangeEvent;
16 import org.jdesktop.swing.data.ValueChangeListener;
17 import java.beans.PropertyChangeListener JavaDoc;
18 import java.beans.PropertyChangeSupport JavaDoc;
19
20 import java.util.ArrayList JavaDoc;
21
22 import javax.swing.InputVerifier JavaDoc;
23 import javax.swing.JComponent JavaDoc;
24
25 /**
26  * Abstract base class which implements a default mechanism for binding
27  * user-interface components to elements in a data model.
28  *
29  * Note:
30  *
31  * @author Amy Fowler
32  * @version 1.0
33  */

34
35 public abstract class AbstractBinding implements Binding {
36
37     protected DataModel dataModel;
38     protected MetaData metaData;
39     private String JavaDoc fieldName;
40     protected Object JavaDoc cachedValue;
41     protected ArrayList JavaDoc errorList;
42     protected boolean modified = false;
43     protected int validState = UNVALIDATED;
44     protected boolean pulling = false;
45     protected boolean pushing = false;
46
47     private PropertyChangeSupport JavaDoc pcs;
48     private int validationPolicy;
49     private static final PropertyChangeListener JavaDoc[]
50         EMPTY_PROPERTY_CHANGE_LISTENER_ARRAY = new PropertyChangeListener JavaDoc[0];
51
52     /**
53      *
54      * @param component
55      * @param dataModel
56      * @param fieldName
57      * @param validationPolicy
58      * @throws NullPointerException if component, dataModel or
59      * fieldName is null
60      */

61     protected AbstractBinding(JComponent JavaDoc component,
62                               DataModel dataModel, String JavaDoc fieldName,
63                               int validationPolicy) {
64         checkNull(component, "component must not be null");
65         checkNull(dataModel, "model must not be null");
66         checkNull(fieldName, "fieldName must not be null");
67         installDataModel(dataModel, fieldName);
68         setComponent(component);
69         setValidationPolicy(validationPolicy);
70     }
71
72 //----------------------- implementing Binding
73

74     public DataModel getDataModel() {
75         return dataModel;
76     }
77
78     public String JavaDoc getFieldName() {
79         return fieldName;
80     }
81
82     /**
83      *
84      * @param policy
85      */

86     public void setValidationPolicy(int policy) {
87         int oldValidationPolicy = this.validationPolicy;
88         this.validationPolicy = policy;
89         installInputVerifier();
90         if (policy != oldValidationPolicy) {
91             firePropertyChange("validationPolicy",
92                                 new Integer JavaDoc(oldValidationPolicy),
93                                 new Integer JavaDoc(policy));
94         }
95     }
96
97
98     public int getValidationPolicy() {
99         return validationPolicy;
100     }
101
102     public boolean pull() {
103         pulling = true;
104 // if (metaData != null) {
105
cachedValue = dataModel.getValue(metaData.getName());
106             setComponentValue(cachedValue);
107 // }
108
setModified(false);
109         setValidState(UNVALIDATED);
110         // JW: initial check to force visual feedback on required
111
isValid();
112         pulling = false;
113         return true;
114     }
115
116     public boolean push() {
117         if (isValid()) {
118             pushing = true;
119             dataModel.setValue(metaData.getName(), cachedValue);
120             setModified(false);
121             pushing = false;
122             return true;
123         }
124         return false;
125     }
126     
127     public boolean isModified() {
128         return modified;
129     }
130
131     public boolean isValid() {
132         if (validState != UNVALIDATED) {
133             return validState == VALID;
134         }
135         // need to validate
136
clearValidationErrors();
137         Object JavaDoc componentValue = getComponentValue();
138
139         // step 1: ensure a required element has non-null value
140
boolean ok = checkRequired(componentValue);
141
142         // step 2: if necessary, convert value from component to data type
143
// appropriate for model
144
Object JavaDoc convertedValue = null;
145         if (ok) {
146             try {
147                 convertedValue = convertToModelType(componentValue);
148             } catch (Exception JavaDoc e) {
149                 ok = false;
150                 /**@todo aim: very nerdy message */
151                 addError("value must be type " + metaData.getElementClass().getName());
152             }
153         }
154
155         // step 3: run any registered element-level validators
156
if (ok) {
157             ok = executeValidators(convertedValue);
158         }
159
160         if (ok) {
161             cachedValue = convertedValue;
162         }
163         setValidState(ok? VALID : INVALID);
164
165         return validState == VALID;
166
167     }
168
169     public int getValidState() {
170         return validState;
171     }
172
173
174     public String JavaDoc[] getValidationErrors() {
175         if (errorList != null) {
176             return (String JavaDoc[])errorList.toArray(new String JavaDoc[1]);
177         }
178         return new String JavaDoc[0];
179     }
180
181     public void clearValidationErrors() {
182         if (errorList != null) {
183             errorList.clear();
184         }
185     }
186
187
188     /**
189      * Adds the specified property change listener to this binding object.
190      * @param pcl PropertyChangeListener object to receive events when binding
191      * properties change
192      */

193     public void addPropertyChangeListener(PropertyChangeListener JavaDoc pcl) {
194         if (pcs == null) {
195             pcs = new PropertyChangeSupport JavaDoc(this);
196
197         }
198         pcs.addPropertyChangeListener(pcl);
199     }
200
201     /**
202      * Removes the specified property change listener from this binding object.
203      * @param pcl PropertyChangeListener object to receive events when binding
204      * properties change
205      */

206     public void removePropertyChangeListener(PropertyChangeListener JavaDoc pcl) {
207         pcs.removePropertyChangeListener(pcl);
208     }
209
210     /**
211      *
212      * @return array containing the PropertyChangeListener objects registered
213      * on this binding object
214      */

215     public PropertyChangeListener JavaDoc[] getPropertyChangeListeners() {
216         if (pcs == null) return EMPTY_PROPERTY_CHANGE_LISTENER_ARRAY;
217         return pcs.getPropertyChangeListeners();
218     }
219
220     protected void firePropertyChange(String JavaDoc propertyName,
221                                       Object JavaDoc oldValue, Object JavaDoc newValue) {
222         if (pcs == null) return;
223         pcs.firePropertyChange(propertyName, oldValue, newValue);
224     }
225
226     
227 //----------------- component related access to implement by subclasses
228

229     /**
230      * set component and configures metaData dependent logic/constraint state.
231      * @param component
232      */

233     protected abstract void setComponent(JComponent JavaDoc component);
234     protected abstract Object JavaDoc getComponentValue();
235     protected abstract void setComponentValue(Object JavaDoc value);
236
237 //---------------------- update internal state: conversion/validation
238

239     protected boolean checkRequired(Object JavaDoc componentValue) {
240 // if (metaData != null) {
241
if (metaData.isRequired() && isEmpty(componentValue)) {
242                 addError("requires a value");
243                 return false;
244             }
245             return true;
246 // }
247
// return false;
248
}
249
250     protected boolean isEmpty(Object JavaDoc componentValue) {
251         return (componentValue == null ||
252          (componentValue instanceof String JavaDoc && ((String JavaDoc)componentValue).equals("")));
253     }
254
255     protected Object JavaDoc convertToModelType(Object JavaDoc componentValue) throws ConversionException {
256         Object JavaDoc convertedValue = null;
257         // if the element is not required and the value is null, then it's
258
// okay to skip conversion
259
if (isEmpty(componentValue)) {
260             return convertedValue;
261         }
262         Class JavaDoc elementClass = metaData.getElementClass();
263         if (componentValue instanceof String JavaDoc) {
264             String JavaDoc stringValue = (String JavaDoc) componentValue;
265             Converter converter = metaData.getConverter();
266             if (converter != null) {
267                 convertedValue = converter.decode(stringValue,
268                                                       metaData.getDecodeFormat());
269             } else if (metaData.getElementClass() == String JavaDoc.class) {
270                 convertedValue = componentValue;
271             }
272         }
273         else {
274             if (!elementClass.isAssignableFrom(componentValue.getClass())) {
275                 throw new ConversionException("cannot assign component value");
276             } else {
277                 convertedValue = componentValue;
278             }
279         }
280         return convertedValue;
281     }
282
283     protected String JavaDoc convertFromModelType(Object JavaDoc modelValue) {
284         if (modelValue != null) {
285             try {
286                 Converter converter = metaData.getConverter();
287                 return converter.encode(modelValue, metaData.getEncodeFormat());
288             }
289             catch (Exception JavaDoc e) {
290                 /**@todo aim: how to handle conversion failure? */
291                 return modelValue.toString();
292             }
293         }
294         return "";
295     }
296
297     protected boolean executeValidators(Object JavaDoc value) {
298         Validator validators[] = metaData.getValidators();
299         boolean isValid = true;
300         for (int i = 0; i < validators.length; i++) {
301             String JavaDoc error[] = new String JavaDoc[1];
302             boolean passed = validators[i].validate(value, null, error);
303             if (!passed) {
304                 String JavaDoc errorMessage = error[0];
305                 if (errorMessage != null) {
306                     addError(errorMessage);
307                 }
308                 isValid = false;
309             }
310         }
311         return isValid;
312     }
313
314     protected void addError(String JavaDoc error) {
315         if (errorList == null) {
316             errorList = new ArrayList JavaDoc();
317         }
318         errorList.add(error);
319     }
320
321
322     protected void setModified(boolean modified) {
323         // JW: commented to fix issue #78
324
// if (pulling) {
325
// return;
326
// }
327
boolean oldModified = this.modified;
328         this.modified = modified;
329         if (modified) {
330             cachedValue = null;
331             setValidState(UNVALIDATED);
332         }
333         if (oldModified != modified) {
334             firePropertyChange("modified",
335                                 Boolean.valueOf(oldModified),
336                                 Boolean.valueOf(modified));
337         }
338     }
339
340     protected void setValidState(int validState) {
341         int oldValidState = this.validState;
342         this.validState = validState;
343         if (oldValidState != validState &&
344             validState == UNVALIDATED) {
345             clearValidationErrors();
346         }
347         if (validState != oldValidState) {
348             firePropertyChange("validState",
349                                new Integer JavaDoc(oldValidState),
350                                new Integer JavaDoc(validState));
351         }
352     }
353
354     
355     /** installs an InputVerifier depending on
356      * validationPolicy.
357      */

358     protected void installInputVerifier() {
359         getComponent().setInputVerifier(new InputVerifier JavaDoc() {
360             public boolean verify(JComponent JavaDoc input) {
361                 if (validationPolicy != AUTO_VALIDATE_NONE) {
362                     boolean isValid = isValid();
363                     if (!isValid && validationPolicy == AUTO_VALIDATE_STRICT) {
364                         return false;
365                     }
366                     return true;
367                 }
368                 return true;
369             }
370         });
371     }
372
373 //---------------------- init models, listeners
374

375     protected void checkNull(Object JavaDoc component, String JavaDoc message) {
376         if (component == null) throw new NullPointerException JavaDoc(message);
377     }
378
379     protected void installDataModel(DataModel dataModel, String JavaDoc fieldName) {
380         this.dataModel = dataModel;
381         this.fieldName = fieldName;
382         metaData = dataModel.getMetaData(fieldName);
383         installDataModelListener();
384         installMetaDataListener();
385     }
386
387     protected void installDataModelListener() {
388         dataModel.addValueChangeListener(new ValueChangeListener() {
389             public void valueChanged(ValueChangeEvent e) {
390                 if (e.getFieldName().equals(fieldName) &&
391                       !pushing) {
392                     pull();
393                 }
394             }
395         });
396     }
397
398
399     /**
400      *
401      * here: does nothing
402      *
403      */

404     protected void installMetaDataListener() {
405 // metaData.addPropertyChangeListener(new PropertyChangeListener() {
406
//
407
// public void propertyChange(PropertyChangeEvent evt) {
408
// if (!"enabled".equals(evt.getPropertyName())) return;
409
// boolean enabled = ((Boolean) evt.getNewValue()).booleanValue();
410
// getComponent().setEnabled(enabled);
411
//
412
// }
413
//
414
// });
415
}
416     
417 }
418
Popular Tags