KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sapia > gumby > view > View


1 package org.sapia.gumby.view;
2
3 import java.util.ArrayList JavaDoc;
4 import java.util.HashMap JavaDoc;
5 import java.util.List JavaDoc;
6 import java.util.Map JavaDoc;
7
8 import org.sapia.gumby.RenderContext;
9 import org.sapia.gumby.Scope;
10
11 /**
12  * A <code>View</code> (the V of MVC) is a kind of <code>Scope</code> that
13  * allows associating user interface components to a model (the M of MVC). Such
14  * associations are materialized by <code>Binding</code> instances. The whole
15  * process goes as follows:
16  * <p>
17  * Components are registered with the view at creation time (this can be done
18  * through XML configuration, by using <code>gumby:Register</code> tags).
19  * <p>
20  * Then, <code>Binding</code> instances are mapped to these components
21  * (through their ID) - this can also be done through XML configuration. A
22  * <code>Binding</code> is meant to bind part(s) of the model to a given UI
23  * components, and vice-versa - the <code>Binding</code> interface specifies
24  * callbacks corresponding to the different use-cases.
25  * <p>
26  * Once bindings have been set up, the model (which is an arbitrary,
27  * application-specific object) is assigned to the view. When this is done for
28  * the first time, the view calls the <code>onBind()</code> method of all its
29  * bindings.
30  * <p>
31  * It is up to applications to trigger the different operations corresponding to
32  * a given MVC lifecycle; more precisely, applications are in charge of
33  * implementing the C in MVC.
34  * <p>
35  * The following situations can arise:
36  * <ol>
37  * <li>The user performs input and then clicks a button to indicate that input
38  * has completed. An application-specific listener is registered with the button
39  * and is notified of the input completion. The listener calls the
40  * <code>fireUpateModel()</code> on the <code>View</code>. This internally
41  * calls the <code>updateModel()</code> method of all <code>Binding</code> s
42  * registered with the view (typically, the bindings assign the input data to
43  * the model). Then the listener is in charge of actually handling the newly
44  * updated model (for example by performing an SQL update with the model's new
45  * data.
46  * <li>The application changes the model by calling <code>setModel()</code>
47  * on the <code>View</code>. Then, internally, the <code>onChanged()</code>
48  * method of all bindings is called; the bindings should then update their
49  * corresponding UI components accordingly.
50  * <li>The model instance remains the same, but its state as somehow been
51  * changed. The application should then notify the view that this has occurred
52  * by calling <code>fireUpdate()</code> on it. The view then calls
53  * <code>onUpdated</code> on all the <code>Binding</code> s that it holds.
54  * </ol>
55  * <p>
56  * Note that developpers are responsible for performant event-handling code:
57  * long-running operations can freeze the user interface, a characteristic that
58  * is often blamed on Swing, but is in fact the result of poor code.
59  *
60  * @see org.sapia.gumby.view.Binding
61  *
62  * @author Yanick Duchesne
63  *
64  * <dl>
65  * <dt><b>Copyright: </b>
66  * <dd>Copyright &#169; 2002-2005 <a HREF="http://www.sapia-oss.org">Sapia Open
67  * Source Software </a>. All Rights Reserved.</dd>
68  * </dt>
69  * <dt><b>License: </b>
70  * <dd>Read the license.txt file of the jar or visit the <a
71  * HREF="http://www.sapia-oss.org/license.html">license page </a> at the Sapia
72  * OSS web site</dd>
73  * </dt>
74  * </dl>
75  */

76 public class View implements Scope {
77
78   private Map JavaDoc _items = new HashMap JavaDoc();
79   private Map JavaDoc _bindingMap = new HashMap JavaDoc();
80   private List JavaDoc _bindingList = new ArrayList JavaDoc();
81   private boolean _created;
82
83   private Object JavaDoc _model;
84   private RenderContext _context;
85
86   public View(RenderContext context) {
87     _context = context;
88   }
89
90   /**
91    * @return this instance's <code>RenderContext</code>.
92    */

93   public RenderContext getContext() {
94     return _context;
95   }
96
97   /**
98    * Returns the object that is mapped to the given name.
99    *
100    * @param name
101    * a name.
102    * @return an <code>Object</code>.
103    * @throws IllegalArgumentException
104    * if no such object could be found.
105    */

106   public synchronized Object JavaDoc acquire(String JavaDoc name)
107       throws IllegalArgumentException JavaDoc {
108     Object JavaDoc toReturn = _items.get(name);
109     if(toReturn == null) {
110       throw new IllegalArgumentException JavaDoc("No item found for: " + name);
111     }
112     return toReturn;
113   }
114
115   /**
116    * @see org.sapia.gumby.Scope#get(java.lang.String)
117    */

118   public synchronized Object JavaDoc get(String JavaDoc name) {
119     return _items.get(name);
120   }
121
122   /**
123    * @see org.sapia.gumby.Scope#put(java.lang.String, java.lang.Object)
124    */

125   public synchronized void put(String JavaDoc name, Object JavaDoc o) {
126     _items.put(name, o);
127   }
128
129   /**
130    * @param model
131    * an arbitratry <code>Object</code>.
132    */

133   public synchronized void setModel(Object JavaDoc model) {
134     if(_model == null) {
135       _model = model;
136       fireBind();
137     } else {
138       _model = model;
139       fireChanged();
140     }
141   }
142
143   /**
144    * @return this instance's model.
145    */

146   public synchronized Object JavaDoc getModel() {
147     return _model;
148   }
149
150   /**
151    * @param binding
152    * a <code>Binding</code>.
153    */

154   public synchronized void addBinding(Binding binding) {
155     if(binding.getId() == null) {
156       throw new IllegalArgumentException JavaDoc("Binding does not have an ID");
157     }
158     if(_bindingMap.containsKey(binding.getId())) {
159       throw new IllegalArgumentException JavaDoc("Binding already exists for: "
160           + binding.getId());
161     }
162     _bindingMap.put(binding.getId(), binding);
163     _bindingList.add(binding);
164     if(_model != null) {
165       binding.onBound(this, _model);
166     }
167   }
168
169   /**
170    * Removes the <code>Binding</code> corresponding to the given identifier
171    * from ths instance.
172    *
173    * @param id
174    * an binding identifier.
175    */

176   public synchronized void removeBinding(String JavaDoc id) {
177     Binding b = (Binding) _bindingMap.remove(id);
178     if(b != null)
179       _bindingList.remove(b);
180   }
181
182   /**
183    * Internally calls the <code>onUpdated()</code> method of the binding
184    * corresponding to the given identifier.
185    *
186    * @see Binding#onUpdated(View, Object)
187    *
188    * @param id
189    * the identifier of a <code>Binding</code> held within this
190    * instance.
191    */

192   public synchronized void fireUpdated(String JavaDoc id) {
193     Binding b = (Binding) _bindingMap.get(id);
194     if(b != null && _model != null) {
195       b.onUpdated(this, _model);
196     }
197   }
198
199   /**
200    * Internally calls the <code>onUpdate()</code> method of all bindings held
201    * by this instance.
202    *
203    * @see Binding#onUpdated(View, Object)
204    */

205   public synchronized void fireUpdated() {
206     if(_model != null) {
207       for(int i = 0; i < _bindingList.size(); i++) {
208         ((Binding) _bindingList.get(i)).onUpdated(this, _model);
209       }
210     }
211   }
212
213   /**
214    * Internally calls the <code>updateModel()</code> method of the binding
215    * corresponding to the given identifier.
216    *
217    * @see Binding#updateModel(View, Object)
218    *
219    * @param id
220    * the identifier of a <code>Binding</code> held within this
221    * instance.
222    */

223   public synchronized void fireUpdateModel(String JavaDoc id) {
224     Binding b = (Binding) _bindingMap.get(id);
225     if(b != null && _model != null) {
226       b.updateModel(this, _model);
227     }
228   }
229
230   /**
231    * Internally calls the <code>updateModel()</code> method of all bindings
232    * held by this instance.
233    *
234    * @see Binding#updateModel(View, Object)
235    */

236   public synchronized void fireUpdateModel() {
237     if(_model != null) {
238       for(int i = 0; i < _bindingList.size(); i++) {
239         ((Binding) _bindingList.get(i)).updateModel(this, _model);
240       }
241     }
242   }
243
244   private synchronized void fireChanged() {
245     if(_model != null) {
246       for(int i = 0; i < _bindingList.size(); i++) {
247         ((Binding) _bindingList.get(i)).onChanged(this, _model);
248       }
249     }
250   }
251
252   private synchronized void fireBind() {
253     if(_model != null) {
254       for(int i = 0; i < _bindingList.size(); i++) {
255         ((Binding) _bindingList.get(i)).onBound(this, _model);
256       }
257     }
258   }
259
260 }
261
Popular Tags