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: ActiveBoundModel.java,v 1.12 2002/09/13 17:11:29 ludovicc Exp $
37 */
38 package org.scopemvc.view.util;
39
40
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43 import org.scopemvc.core.ModelChangeEvent;
44 import org.scopemvc.core.ModelChangeEventSource;
45 import org.scopemvc.core.ModelChangeListener;
46 import org.scopemvc.core.ModelChangeTypes;
47 import org.scopemvc.core.PropertyManager;
48 import org.scopemvc.core.Selector;
49 import org.scopemvc.util.Debug;
50
51 /***
52 * <P>
53 *
54 * A {@link BoundModel} that handles ModelChangeEvents and provides full two-way
55 * data-binding between a View and its bound model property. The parent View
56 * needs to implement the {@link ModelBindable} interface to provide a generic
57 * interface used by this delegate. An ActiveBoundModel registers itself as a
58 * ModelChangeListener to the bound model object so that it can update its
59 * parent View. </P>
60 *
61 * @author <A HREF="mailto:smeyfroi@users.sourceforge.net">Steve Meyfroidt</A>
62 * @created 05 September 2002
63 * @version $Revision: 1.12 $ $Date: 2002/09/13 17:11:29 $
64 * @see org.scopemvc.view.swing.SwingBoundModel
65 */
66 public class ActiveBoundModel extends BoundModel implements ModelChangeListener {
67
68 private static final Log LOG = LogFactory.getLog(ActiveBoundModel.class);
69
70 /***
71 * The ModelBindable View that delegates bound Model handling to this
72 * helper.
73 */
74 protected ModelBindable view;
75
76 /***
77 * PropertyManager for the bound model.
78 */
79 protected PropertyManager manager;
80
81
82 /***
83 * Constructor for the ActiveBoundModel object
84 *
85 * @param inView The view to bind to the model
86 */
87 public ActiveBoundModel(ModelBindable inView) {
88 super();
89
90 if (inView == null) {
91 throw new IllegalArgumentException("Can't create for null View.");
92 }
93 view = inView;
94 }
95
96
97 /***
98 * Gets the property manager
99 *
100 * @return The propertyManager value
101 */
102 public PropertyManager getPropertyManager() {
103 return manager;
104 }
105
106
107 // --------------------- Model to View -----------------------
108
109 /***
110 * Returns true if the property in the bound model is read only
111 *
112 * @return true if the property in the bound model is read only
113 */
114 public boolean getPropertyReadOnly() {
115 boolean result = true;
116 if (boundModel != null) {
117 try {
118 if (Debug.ON) {
119 Debug.assertTrue(manager != null, "null manager");
120 }
121 result = manager.isReadOnly(boundModel, getSelector());
122 } catch (Exception e) {
123 // ignore and leave readOnly == true
124 }
125 }
126 return result;
127 }
128
129
130 /***
131 * Gets the value of the property in the bound model
132 *
133 * @return The value of the property in the bound model
134 */
135 public Object getPropertyValue() {
136 Object result = null;
137 if (boundModel != null) {
138 try {
139 if (Debug.ON) {
140 Debug.assertTrue(manager != null, "null manager");
141 }
142 result = manager.get(boundModel, getSelector());
143 } catch (Exception e) {
144 // ignore and leave result == null
145 }
146 }
147 return result;
148 }
149
150
151 /***
152 * Gets the class of the property in the bound model
153 *
154 * @return The class of the property in the bound model
155 */
156 public Class getPropertyClass() {
157 Class result = null;
158 if (boundModel != null) {
159 try {
160 if (Debug.ON) {
161 Debug.assertTrue(manager != null, "null manager");
162 }
163 result = manager.getPropertyClass(boundModel, getSelector());
164 } catch (Exception e) {
165 // ignore and leave result == null
166 }
167 }
168 return result;
169 }
170
171
172 /***
173 * Sets the bound model
174 *
175 * @param inModel The new boundModel value
176 */
177 public final void setBoundModel(Object inModel) {
178 if (LOG.isDebugEnabled()) {
179 LOG.debug("setBoundModel: " + inModel);
180 }
181
182 if (boundModel instanceof ModelChangeEventSource) {
183 ((ModelChangeEventSource) boundModel).removeModelChangeListener(this);
184 }
185
186 manager = null;
187 if (inModel instanceof ModelChangeEventSource) {
188 ((ModelChangeEventSource) inModel).addModelChangeListener(this);
189 }
190 if (inModel != null) {
191 manager = PropertyManager.getInstance(inModel);
192 }
193
194 boundModel = inModel;
195 updateFromModel(ModelChangeTypes.VALUE_CHANGED);
196 }
197
198
199 /***
200 * Sets the selector
201 *
202 * @param inSelector The new selector value
203 */
204 public final void setSelector(Selector inSelector) {
205 if (LOG.isDebugEnabled()) {
206 LOG.debug("setSelector: " + inSelector);
207 }
208
209 super.setSelector(inSelector);
210 updateFromModel(ModelChangeTypes.VALUE_CHANGED);
211 }
212
213
214 /***
215 * Update the parent View in response to the passed ModelChangeEvent, if the
216 * event reports that the property we are bound to has changed.
217 *
218 * @param inEvent The event describing the change in the model
219 */
220 public final void modelChanged(ModelChangeEvent inEvent) {
221 if (Debug.ON) {
222 Debug.assertTrue(boundModel instanceof ModelChangeEventSource, "boundModel not a Model");
223 }
224 if (LOG.isDebugEnabled()) {
225 LOG.debug("modelChanged: view: " + view + ", event: " + inEvent);
226 LOG.debug("modelChanged: property selector: " + getSelector() + ", event selector: " + inEvent.getSelector());
227 }
228
229 // Event affects us if a Model changes somewhere at or above us in the hierarchy.
230 if (inEvent.getModel() == boundModel && (getSelector() == null || getSelector().startsWith(inEvent.getSelector()))) {
231 if (LOG.isDebugEnabled()) {
232 LOG.debug("modelChanged: for me!");
233 }
234 updateFromModel(inEvent.getType());
235 view.validationSuccess();
236 }
237 }
238
239
240 // ---------------------- View to Model ----------------------
241
242 /***
243 * Put the current View contents into the bound model property. <br>
244 * Errors in getting the UI's new value into the model property are handled
245 * by calling back into the parent View's
246 * {org.scopemvc.view.util.ModelBindable#validationFailed} with the
247 * Exception. <br>
248 * On no errors, call the parent's {org.scopemvc.view.util.ModelBindable#validationSuccess}
249 */
250 public void updateModel() {
251 try {
252 // If boundModel==null then we're not hooked up.
253 // If selector==null then the view is hooked directly to a top-level model in a model tree,
254 // ...in which case there's no way we could be updating that model.
255 if (boundModel == null || getSelector() == null) {
256 LOG.warn("updateModel: not bound");
257 return;
258 }
259
260 Object currentValue = view.getViewValue();
261 if (LOG.isDebugEnabled()) {
262 LOG.debug("updateModel: view: " + view + ", currentValue: " + currentValue);
263 }
264
265 if (Debug.ON) {
266 Debug.assertTrue(manager != null, "null manager");
267 }
268 manager.set(boundModel, getSelector(), currentValue);
269 view.validationSuccess();
270 } catch (Exception e) {
271 LOG.warn("updateModel: " + view, e);
272 view.validationFailed(e);
273 }
274 }
275
276
277 /***
278 * Calls parent View's {org.scopemvc.view.util.ModelBindable#validationSuccess}
279 * to clear any previous validation failure.
280 *
281 * @param inEventType The type of the change event, one of the {@link
282 * org.scopemvc.core.ModelChangeTypes ModelChangeTypes} values
283 */
284 public void updateFromModel(int inEventType) {
285 // Find the new property value
286 Object property = getPropertyValue();
287 boolean readOnly = getPropertyReadOnly();
288 if (LOG.isDebugEnabled()) {
289 LOG.debug("updateFromModel: view: " + view + ", eventType: " + inEventType + ", property: " + property + ", readOnly: " + readOnly);
290 }
291
292 // for ACCESS_CHANGED and VALUE_CHANGED *****
293 view.updateFromProperty(property, readOnly);
294 }
295 }
This page was automatically generated by Maven