View Javadoc

1   /*
2    * Ext GWT 2.2.5 - Ext for GWT
3    * Copyright(c) 2007-2010, Ext JS, LLC.
4    * licensing@extjs.com
5    * 
6    * http://extjs.com/license
7    */
8   package com.extjs.gxt.ui.client.binding;
9   
10  import org.vectomatic.svg.edit.client.SvgrealApp;
11  import org.vectomatic.svg.edit.client.command.ICommandFactory;
12  import org.vectomatic.svg.edit.client.command.IFactoryInstantiator;
13  import org.vectomatic.svg.edit.client.model.IMetadata;
14  import org.vectomatic.svg.edit.client.model.ValidationError;
15  import org.vectomatic.svg.edit.client.model.svg.SVGElementModel;
16  
17  import com.extjs.gxt.ui.client.data.ChangeEvent;
18  import com.extjs.gxt.ui.client.data.ChangeEventSource;
19  import com.extjs.gxt.ui.client.data.ChangeListener;
20  import com.extjs.gxt.ui.client.data.Model;
21  import com.extjs.gxt.ui.client.data.ModelData;
22  import com.extjs.gxt.ui.client.data.PropertyChangeEvent;
23  import com.extjs.gxt.ui.client.event.Events;
24  import com.extjs.gxt.ui.client.event.FieldEvent;
25  import com.extjs.gxt.ui.client.event.Listener;
26  import com.extjs.gxt.ui.client.store.Record;
27  import com.extjs.gxt.ui.client.store.Store;
28  import com.extjs.gxt.ui.client.widget.form.Field;
29  
30  /**
31   * A two-way binding between a ModelData and Field instance. The binding will be
32   * 1-way when the bound model does not support change events.
33   * 
34   * @see ModelData
35   * @see Field
36   */
37  @SuppressWarnings({"unchecked","rawtypes"})
38  public class FieldBinding {
39  
40    protected Field field;
41    protected ModelData model;
42    protected String property;
43    protected Store store;
44  
45    private Listener<FieldEvent> changeListener;
46    private ChangeListener modelListener;
47    private Converter converter;
48    private boolean updateOriginalValue = false;
49  
50    /**
51     * Creates a new binding instance.
52     * 
53     * @param field the bound field for the binding
54     */
55    public FieldBinding(Field field, String property) {
56      this.field = field;
57      this.property = property;
58  
59      changeListener = new Listener<FieldEvent>() {
60        public void handleEvent(FieldEvent be) {
61          onFieldChange(be);
62        }
63      };
64  
65      modelListener = new ChangeListener() {
66        public void modelChanged(ChangeEvent event) {
67          if (event.getType() == ChangeEventSource.Update) {
68            onModelChange((PropertyChangeEvent) event);
69          }
70        }
71      };
72    }
73  
74    /**
75     * Binds the model and field. This method also updates the fields original
76     * value which controls the dirty state of the field.
77     * 
78     * @param model the model to be bound
79     */
80    public void bind(ModelData model) {
81      if (this.model != null) {
82        unbind();
83      }
84      this.model = model;
85      field.addListener(Events.Change, changeListener);
86      if (model instanceof Model) {
87        ((Model) model).addChangeListener(modelListener);
88      }
89      updateField(updateOriginalValue);
90    }
91  
92    /**
93     * Returns the bindings converter.
94     * 
95     * @return the converter
96     */
97    public Converter getConverter() {
98      return converter;
99    }
100 
101   /**
102    * Returns the bound field.
103    * 
104    * @return the field
105    */
106   public Field<Object> getField() {
107     return field;
108   }
109 
110   /**
111    * Returns the bound model instance.
112    * 
113    * @return the model
114    */
115   public ModelData getModel() {
116     return model;
117   }
118 
119   /**
120    * Returns the model's bound property name.
121    * 
122    * @return the property name
123    */
124   public String getProperty() {
125     return property;
126   }
127 
128   /**
129    * Returns the binding's store.
130    * 
131    * @return the store or null
132    */
133   public Store getStore() {
134     return store;
135   }
136 
137   /**
138    * Returns true if the field's original value is updated when the field is
139    * bound.
140    * 
141    * @return true if original value is updated
142    */
143   public boolean isUpdateOriginalValue() {
144     return updateOriginalValue;
145   }
146 
147   /**
148    * Sets the converter which is used to translate data types when updating
149    * either the field or model.
150    * 
151    * @param converter the converter
152    */
153   public void setConverter(Converter converter) {
154     this.converter = converter;
155   }
156 
157   /**
158    * Sets the store for the binding. When a store is specified edits are done
159    * via Records instances obtained from the Store.
160    * 
161    * @param store the store
162    */
163   public void setStore(Store<? extends ModelData> store) {
164     this.store = store;
165   }
166 
167   /**
168    * True to update the field's original value when bound (defaults to false).
169    * 
170    * @param updateOriginalValue true to update the original value
171    */
172   public void setUpdateOriginalValue(boolean updateOriginalValue) {
173     this.updateOriginalValue = updateOriginalValue;
174   }
175 
176   /**
177    * Unbinds the model and field by removing all listeners.
178    */
179   public void unbind() {
180     if (model != null) {
181       if (model instanceof Model) {
182         ((Model) model).removeChangeListener(modelListener);
183       }
184       model = null;
185     }
186     field.removeListener(Events.Change, changeListener);
187 
188     if (updateOriginalValue) {
189       field.setOriginalValue(null);
190     }
191     field.clear();
192   }
193 
194   /**
195    * Updates the field's value with the model value.
196    */
197   public void updateField() {
198     updateField(false);
199   }
200 
201   /**
202    * Updates the field's value and original value with the model value. Updating
203    * the original value will reset the field to a non-dirty state.
204    * 
205    * @param updateOriginalValue true to update the original value
206    */
207   public void updateField(boolean updateOriginalValue) {
208     Object value = model.get(property);
209     Object val = onConvertModelValue(value);
210     /*begin laaglu*/
211     if (model instanceof SVGElementModel) {
212     	// Mark invalid fields
213     	SVGElementModel svgModel = (SVGElementModel)model;
214     	IMetadata metadata = svgModel.getMetaModel().getMetadata(property);
215     	ValidationError error = metadata.validate(svgModel.getElement(), value);
216     	if (error != null) {
217     		field.markInvalid(error.getMessage());
218     	} else {
219     		field.clearInvalid();
220     	}
221     }
222     /*end laaglu*/
223 
224     if (updateOriginalValue) {
225       field.setOriginalValue(val);
226     }
227 
228     field.setValue(val);
229   }
230 
231   /**
232    * Updates the model's value with the field value.
233    */
234   public void updateModel() {
235     Object val = onConvertFieldValue(field.getValue());
236     if (store != null) {
237       /*begin laaglu*/
238       ICommandFactory factory = null;
239       if (model instanceof SVGElementModel) {
240     	IFactoryInstantiator<?> instantiator = ((SVGElementModel)model).getMetaModel().getMetadata(property).getCommandFactory();
241     	if (instantiator != null && !SvgrealApp.getApp().getCommandFactorySelector().isSuspended()) {
242     	  factory = instantiator.create();
243     	  factory.start(this);
244     	}
245       }
246       /*end laaglu*/
247       Record r = store.getRecord(model);
248       if (r != null) {
249         r.setValid(property, field.isValid());
250         r.set(property, val);
251       }
252       /*begin laaglu*/
253       if (factory != null) {
254     	  r.commit(false);
255     	  factory.stop();
256       }
257       /*end laaglu*/
258     } else {
259       model.set(property, val);
260     }
261 
262   }
263 
264   protected Object onConvertFieldValue(Object value) {
265     if (converter != null) {
266       return converter.convertFieldValue(value);
267     }
268     return value;
269   }
270 
271   protected Object onConvertModelValue(Object value) {
272     if (converter != null) {
273       return converter.convertModelValue(value);
274     }
275     return value;
276   }
277 
278   protected void onFieldChange(FieldEvent e) {
279     updateModel();
280   }
281 
282   protected void onModelChange(PropertyChangeEvent event) {
283     if (event.getName().equals(property)) {
284       updateField();
285     }
286   }
287 
288 }