View Javadoc

1   /***
2    * Copyright (C) 2006 Philipp Mpalampanis
3    *
4    * License: MPL 1.1/GPL 2.0/LGPL 2.1
5    *
6    * The contents of this file are subject to the Mozilla Public License Version
7    * 1.1 (the "License"); you may not use this file except in compliance with
8    * the License. You may obtain a copy of the License at
9    * http://www.mozilla.org/MPL/
10   *
11   * Software distributed under the License is distributed on an "AS IS" basis,
12   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13   * for the specific language governing rights and limitations under the
14   * License.
15   *
16   * Alternatively, the contents of this file may be used under the terms of
17   * either the GNU General Public License Version 2 or later (the "GPL"), or
18   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19   * in which case the provisions of the GPL or the LGPL are applicable instead
20   * of those above. If you wish to allow use of your version of this file only
21   * under the terms of either the GPL or the LGPL, and not to allow others to
22   * use your version of this file under the terms of the MPL, indicate your
23   * decision by deleting the provisions above and replace them with the notice
24   * and other provisions required by the GPL or the LGPL. If you do not delete
25   * the provisions above, a recipient may use your version of this file under
26   * the terms of any one of the MPL, the GPL or the LGPL.
27   */
28  package net.sf.echobinding.binding;
29  
30  import java.beans.*;
31  import java.io.Serializable;
32  import java.util.*;
33  
34  import net.sf.echobinding.BoundControl;
35  import net.sf.echobinding.decorator.Decorator;
36  import net.sf.echobinding.format.Format;
37  import net.sf.echobinding.model.PresentationModel;
38  
39  /***
40   *
41   */
42  public abstract class AbstractBindingContext implements BindingContext, Serializable {
43  
44  	private BindingContext _parent;
45  	private Set<BindingContext> _childs;
46  	protected HashMap<String, PropertyAdapter> _adapters = new HashMap<String, PropertyAdapter>();
47  	private HashMap<String, BoundControl> _controls;
48  	protected PropertyChangeSupport _changes = new PropertyChangeSupport(this);
49  
50  	private PresentationModel _presentationModel;
51  	
52  	/*
53  	 * (non-Javadoc)
54  	 * 
55  	 * @see echobinding.BindingContext#add(java.lang.String,
56  	 *      echobinding.Binding)
57  	 */
58  	public BindingContext add(String id, PropertyAdapter binding) {
59  		binding.setId(id);
60  		_adapters.put(id, binding);
61  		return this;
62  	}
63  	
64  	/*
65  	 * (non-Javadoc)
66  	 * 
67  	 * @see echobinding.BindingContext#remove(java.lang.String)
68  	 */
69  	public PropertyAdapter remove(String id) {
70  		return _adapters.remove(id);
71  	}
72  
73  	
74  	/***
75  	 * Adds a child to the set of child contexts.
76  	 * 
77  	 * @param child
78  	 */
79  	public void addChild(BindingContext child) {
80  		getChilds().add(child);
81  	}
82  
83  	/***
84  	 * @return Returns the childs.
85  	 */
86  	public Set<BindingContext> getChilds() {
87  		if( _childs == null)
88  			_childs = new HashSet<BindingContext>();
89  		return _childs;
90  	}
91  
92  	/***
93  	 * Sets the child contexts.
94  	 * 
95  	 * @param childs The childs to set.
96  	 */
97  	public void setChilds(Set<BindingContext> childs) {
98  		_childs = childs;
99  	}
100 
101 	/***
102 	 * @return Returns the parent binding context.
103 	 */
104 	public BindingContext getParent() {
105 		return _parent;
106 	}
107 
108 	/***
109 	 * Sets the parent binding context.
110 	 * 
111 	 * @param parent The parent binding context to set.
112 	 */
113 	public void setParent(BindingContext parent) {
114 		_parent = parent;
115 	}
116 
117 	public List<PropertyAdapter> getPropertyAdapters() {
118 		ArrayList<PropertyAdapter> list = new ArrayList<PropertyAdapter>();
119 		for (String bindingId : _adapters.keySet()) {
120 			list.add(_adapters.get(bindingId));
121 		}
122 		return list;
123 	}
124 
125 	public Decorator getDecorator(String id) {
126 		return getAdapter(id).getDecorator();
127 	}
128 
129 	public Format getFormat(String id) {
130 		return getAdapter(id).getFormat();
131 	}
132 
133 	/***
134 	 * Adds a control to the list of registered controls and registers the
135 	 * control as PropertyChangeListener at this context.
136 	 */
137 	public void registerControl(String id, BoundControl control) {
138 		if( _controls == null )
139 			_controls = new HashMap<String,BoundControl>();
140 		
141 		addPropertyChangeListener(id, control);
142 		
143 		_controls.put(id, control);
144 	}
145 	
146 	public void removeControl(BoundControl control) {
147 		if( _controls != null )
148 			_controls.remove(control);
149 	}
150 
151 
152 	public BoundControl getControl(String id) {
153 		if( _controls == null )
154 			return null;
155 		return _controls.get(id);
156 	}
157 
158 	public Set<BoundControl> getControls() {
159 		if(_controls == null)
160 			return new HashSet<BoundControl>(); 
161 		return new HashSet<BoundControl>( _controls.values() );
162 	}
163 
164 	
165 	
166 	/***
167 	 * 
168 	 * @param bindingId
169 	 * @param oldValue
170 	 * @param newValue
171 	 * @throws BindingException
172 	 */
173 	protected void firePropertyChange(String bindingId, Object oldValue, Object newValue) throws BindingException {
174 
175 		PropertyChangeEvent event = new PropertyChangeEvent(this, bindingId,
176 				getValue(bindingId), newValue);
177 
178 		
179 		firePropertyChange(event);
180 	}
181 
182 	protected void firePropertyChange(PropertyChangeEvent event) throws BindingException {
183 		
184 		notifyPropertyChangeListener(event);
185 		
186 		notifyParentContext( event );
187 		
188 		notifiyChildContexts( event );
189 	}
190 	
191 	
192 
193 	/***
194 	 * Sends a property change event to all child contexts.
195 	 * 
196 	 * @param event
197 	 */
198 	private void notifiyChildContexts(PropertyChangeEvent event) {
199 		Object source = event.getSource();
200 		
201 		PropertyChangeEvent newEvent = replaceSender( event );
202 		
203 		// notify all child contexts
204 		for( BindingContext child : getChilds() ) {
205 			if( ! (source==null || source.equals(child)))
206 				child.propertyChange(newEvent);
207 		}
208 	}
209 
210 	/***
211 	 * Sends a property change event to the parent context.
212 	 *  
213 	 * @param event
214 	 */
215 	private void notifyParentContext(PropertyChangeEvent event) {
216 		
217 		Object source = event.getSource();
218 		
219 		PropertyChangeEvent newEvent = replaceSender( event );
220 		
221 		// notify parent context
222 		if( ! ( getParent()==null || source.equals(getParent())) )
223 			getParent().propertyChange(newEvent);
224 	}
225 
226 	/***
227 	 * @param event
228 	 * @return
229 	 */
230 	private PropertyChangeEvent replaceSender(PropertyChangeEvent event) {
231 		if(event.getSource().equals(this))
232 			return event;
233 		PropertyChangeEvent newEvent = new PropertyChangeEvent(this, event.getPropertyName(), event.getOldValue(), event.getNewValue());
234 		return newEvent;
235 	}
236 
237 	
238 	/***
239 	 * 
240 	 */
241 	public void propertyChange(PropertyChangeEvent event) {
242 		
243 		notifyPropertyChangeListener( event );
244 		
245 		notifiyChildContexts(event);
246 		
247 		notifyParentContext(event);
248 	}
249 
250 	/***
251 	 *  
252 	 */
253 	private void notifyPropertyChangeListener(PropertyChangeEvent event) {
254 		PropertyChangeEvent newEvent = replaceSender(event);
255 		
256 		// TODO: refactor change notification
257 		for (PropertyChangeListener listener : _changes.getPropertyChangeListeners(event.getPropertyName()) ) {
258 			if (!listener.equals(event.getSource()))	// do not propagate events back to origin
259 				listener.propertyChange(newEvent);
260 		}
261 
262 		for (PropertyChangeListener listener : _changes.getPropertyChangeListeners() ) {
263 			if (!listener.equals(event.getSource()))	// do not propagate events back to origin
264 				listener.propertyChange(newEvent);
265 		}
266 		
267 		
268 	}
269 
270 
271 	
272 	/***
273 	 * 
274 	 */
275 	public void addPropertyChangeListener(PropertyChangeListener listener) {
276 		_changes.addPropertyChangeListener(listener);
277 	}
278 
279 	/***
280 	 * Add listener for the specified property name.
281 	 * 
282 	 * @param propertyName
283 	 * @param listener
284 	 */
285 	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
286 		_changes.addPropertyChangeListener(propertyName, listener);
287 	}
288 
289 	/***
290 	 * 
291 	 */
292 	public void removePropertyChangeListener(PropertyChangeListener listener) {
293 		_changes.removePropertyChangeListener(listener);
294 	}
295 
296 	/***
297 	 * Remove listeners for the given property name. 
298 	 * 
299 	 * @param propertyName
300 	 * @param listener
301 	 */
302 	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
303 		_changes.removePropertyChangeListener(propertyName, listener);
304 	}
305 
306 	/* (non-Javadoc)
307 	 * @see echobinding.binding.BindingContext#synchronize()
308 	 */
309 	public void synchronize() {
310 		// synchronize this context
311 		for(BoundControl widget: getControls()) {
312 			widget.save();
313 		}
314 		// .. and all its childs
315 		for(BindingContext child: getChilds()) {
316 			child.synchronize();
317 		}
318 	}
319 
320 	/* (non-Javadoc)
321 	 * @see echobinding.binding.BindingContext#isValid()
322 	 */
323 	public boolean isValid() {
324 		
325 		// check this context 
326 		for(BoundControl widget: getControls()) {
327 			if( ! widget.isValid() )
328 				return false;
329 		}
330 		// .. and all its childs
331 		for(BindingContext child: getChilds()) {
332 			if( ! child.isValid() )
333 				return false;
334 		}
335 		return true;
336 	}
337 	
338 	
339 	/* (non-Javadoc)
340 	 * @see echobinding.binding.BindingContext#isDirty()
341 	 */
342 	public boolean isDirty() {
343 		// check this context 
344 		for(BoundControl widget: getControls()) {
345 			if( widget.isDirty() )
346 				return true;
347 		}
348 		// .. and all its child contexts
349 		for(BindingContext child: getChilds()) {
350 			if( child.isDirty() )
351 				return true;
352 		}
353 		return false;
354 	}
355 	
356 	/* (non-Javadoc)
357 	 * @see echobinding.binding.BindingContext#reload()
358 	 */
359 	public void update() {
360 		// reset the widget's state 
361 		for(BoundControl widget: getControls()) {
362 			widget.update();
363 		}
364 		// .. reset child contexts
365 		for(BindingContext child: getChilds()) {
366 			child.update();
367 		}
368 	}
369 	
370 	
371 
372 	/* (non-Javadoc)
373 	 * @see echobinding.binding.BindingContext#validate()
374 	 */
375 	public void validate() {
376 		// validate this context 
377 		for(BoundControl widget: getControls()) {
378 			widget.validateInput();
379 		}
380 		// .. and all its childs
381 		for(BindingContext child: getChilds()) {
382 			child.validate();
383 		}
384 	}
385 
386 	public boolean removeChild(BindingContext context) {
387 		return _childs.remove(context);
388 	}
389 
390 	/***
391 	 * @return Returns the presentationModel.
392 	 */
393 	public PresentationModel getPresentationModel() {
394 		return _presentationModel;
395 	}
396 
397 	/***
398 	 * @param presentationModel The presentationModel to set.
399 	 */
400 	public void setPresentationModel(PresentationModel presentationModel) {
401 		_presentationModel = presentationModel;
402 		_presentationModel.setContext(this);
403 	}
404 
405 	
406 }