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  
29  package net.sf.echobinding.controls;
30  
31  import java.beans.PropertyChangeEvent;
32  import java.beans.PropertyChangeListener;
33  import java.util.ArrayList;
34  import java.util.Collection;
35  
36  import net.sf.echobinding.BoundControl;
37  import net.sf.echobinding.binding.BindingContext;
38  import net.sf.echobinding.decorator.Decorator;
39  import net.sf.echobinding.validation.*;
40  import nextapp.echo2.app.event.*;
41  import nextapp.echo2.app.list.ListModel;
42  
43  /***
44   * 
45   */
46  public class SelectField extends nextapp.echo2.app.SelectField implements
47  		BoundControl, ActionListener, PropertyChangeListener {
48  
49  	private static final long serialVersionUID = -3593733868533261539L;
50  
51  	private BindingContext _ctx;
52  
53  	private String _id;
54  
55  	private String _itemsAdapterId;
56  
57  	private ArrayList<Object> _listItems;
58  
59  	private Collection<Object> _items;
60  
61  	private ValidationHandler _validationHandler;
62  
63  	/***
64  	 * creates a data bound select field
65  	 * 
66  	 * @param adapterId
67  	 * @param context
68  	 */
69  	public SelectField(String adapterId, Object[] items, BindingContext context) {
70  		super(items);
71  		_id = adapterId;
72  		setBindingConext(context);
73  		setActionCommand( adapterId );
74  	}
75  
76  	/***
77  	 * Creates a data bound select field
78  	 * 
79  	 * @param bindingId
80  	 * @param context
81  	 */
82  	public SelectField(String bindingId, ListModel model, BindingContext context) {
83  		super(model);
84  		_id = bindingId;
85  		_ctx = context;
86  	}
87  
88  	/***
89  	 * creates a data bound select field
90  	 * 
91  	 * @param adapterId
92  	 * @param itemsAdapterId
93  	 * @param context
94  	 */
95  	public SelectField(String adapterId, String itemsAdapterId,
96  			BindingContext context) {
97  		super();
98  		_id = adapterId;
99  		_itemsAdapterId = itemsAdapterId;
100 		setActionCommand( adapterId );
101 		addActionListener(this);
102 		addPropertyChangeListener(this);
103 		
104 		context.addPropertyChangeListener(SELECTION_CHANGED_PROPERTY, this);
105 		
106 		setBindingConext(context);
107 	}
108 
109 	/* (non-Javadoc)
110 	 * @see echobinding.BoundControl#setBindingConext(echobinding.BindingContext)
111 	 */
112 	public void setBindingConext(BindingContext context) {
113 		if(context == null)	return;
114 		if( _ctx != null) _ctx.removeControl(this);
115 		context.registerControl( _id, this);
116 		_ctx = context;
117 		update();
118 	}
119 
120 
121 	/*
122 	 * (non-Javadoc)
123 	 * 
124 	 * @see echobinding.BoundControl#setBindingId(java.lang.String)
125 	 */
126 	public void setAdapterId(String adapterId) {
127 		_id = adapterId;
128 	}
129 
130 	/*
131 	 * (non-Javadoc)
132 	 * 
133 	 * @see echobinding.BoundControl#loadValues()
134 	 */
135 	@SuppressWarnings("unchecked")
136 	public void update() {
137 		assert(_ctx != null);
138 		
139 		// load the selected value 
140 		Object value = _ctx.getValue(_id);
141 
142 		// load the items collection 
143 		_items = (Collection<Object>) _ctx
144 						.getValue(_itemsAdapterId);
145 		
146 		if (_items == null) { 
147 			// in case of list dependency, items may be null
148 			_items = new ArrayList<Object>();
149 		}
150 
151 		//_listItems = new ArrayList<Object>(_items);
152 		_listItems = new ArrayList<Object>();
153 		_listItems.add("");	// explicitly add an empty option (workaround for bug in Mozilla/FireFox) 
154 		_listItems.addAll(_items);
155 		
156 
157 		// get the selected item
158 		Object selectedItem = null;
159 		for (Object item : _listItems) {
160 			if (item.equals(value))
161 				selectedItem = item;
162 		}
163 		if (selectedItem != null) {
164 			int index = _listItems.indexOf(selectedItem);
165 			if( getSelectedIndex() != index )
166 				setSelectedIndex( index );
167 		}
168 
169 		final Decorator decorator = _ctx.getDecorator(_itemsAdapterId);
170 		
171 		ListModel model = new ListModel() {
172 
173 			private static final long serialVersionUID = -6693815714661801487L;
174 
175 			public void removeListDataListener(ListDataListener arg0) {
176 			}
177 
178 			public int size() {
179 				return _listItems.size();
180 			}
181 
182 			public Object get(int i) {
183 				return decorator.decorate(_listItems.get(i));
184 			}
185 
186 			public void addListDataListener(ListDataListener arg0) {
187 			}
188 
189 		};
190 
191 		setModel(model);
192 	}
193 
194 	/*
195 	 * (non-Javadoc)
196 	 * 
197 	 * @see echobinding.BoundControl#saveValues()
198 	 */
199 	public void save() {
200 		
201 		if(getSelectedIndex() == -1)
202 			_ctx.setValue(_id, null);
203 		else
204 			_ctx.setValue(_id, _listItems.get(getSelectedIndex()));
205 	}	
206 
207 	/*
208 	 * (non-Javadoc)
209 	 * 
210 	 * @see echobinding.BoundControl#isValid()
211 	 */
212 	public boolean isValid() {
213 		
214 		return createValidationReport().isValid();
215 	}
216 
217 	/*
218 	 * (non-Javadoc)
219 	 * 
220 	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
221 	 */
222 	public void propertyChange(PropertyChangeEvent event) {
223 		if (SELECTION_CHANGED_PROPERTY.equals(event.getPropertyName())) {
224 			Object value = _ctx.getValue( _itemsAdapterId );
225 			if( value != null && ! value.equals( _items ) ) {
226 				update();
227 			}
228 		}
229 	}
230 
231 	/*
232 	 * (non-Javadoc)
233 	 * 
234 	 * @see nextapp.echo2.app.event.ActionListener#actionPerformed(nextapp.echo2.app.event.ActionEvent)
235 	 */
236 	public void actionPerformed(ActionEvent event) {
237 		fireSelectionChange();
238 	}
239 
240 	/***
241 	 * 
242 	 */
243 	private void fireSelectionChange() {
244 		
245 		int selectedIndex = getSelectedIndex();
246 		int minListIndex = 1;	// due to bug in firefox/mozilla (added empty item on position 0)
247 		if (selectedIndex >= minListIndex) {
248 			PropertyChangeEvent selectionChangeEvent = new PropertyChangeEvent(
249 					this, SELECTION_CHANGED_PROPERTY, null, _listItems
250 							.get(selectedIndex));
251 			_ctx.propertyChange(selectionChangeEvent);
252 		}
253 	}
254 
255 	@Override
256 	public String toString() {
257 		return super.toString()+"#"+_id;
258 	}
259 
260 	@Override
261 	public void setSelectedIndex(int index) {
262 		super.setSelectedIndex(index);
263 		
264 		fireSelectionChange();
265 	}
266 
267 
268 	/* 
269 	 * Validates the control's input and invokes the validation handler.
270 	 * 
271 	 * @see echobinding.BoundControl#validateInput()
272 	 */
273 	public void validateInput() {
274 		
275 		ValidationReport validationReport = createValidationReport();
276 
277 		setToolTipText(validationReport.getMessage());
278 		
279 		invokeValidationHandler(validationReport);
280 		
281 	}
282 
283 	/***
284 	 * @return
285 	 */
286 	private ValidationReport createValidationReport() {
287 		ValidationReport validationReport;
288 		Object value = getSelectedIndex() == -1 ? null : _listItems.get(getSelectedIndex());
289 		validationReport = _ctx.validate(_id, value);
290 		return validationReport;
291 	}
292 
293 	/***
294 	 * @param validationReport
295 	 */
296 	private void invokeValidationHandler(ValidationReport validationReport) {
297 		initValidationHandler();
298 		
299 		if(validationReport.isValid())
300 			_validationHandler.markValid(this);
301 		else
302 			_validationHandler.markInvalid(this);
303 	}
304 
305 	/***
306 	 * Initializes the validation handler 
307 	 *
308 	 */
309 	private void initValidationHandler() {
310 		if( _validationHandler == null ) {
311 			_validationHandler = _ctx.getValidationHandler(_id);
312 			if( _validationHandler == null )
313 				_validationHandler = new DefaultValidationHandler(this);
314 		}
315 	}
316 
317 	/* (non-Javadoc)
318 	 * @see echobinding.BoundControl#isDirty()
319 	 */
320 	public boolean isDirty() {
321 		if(getSelectedIndex() == -1)
322 			return _ctx.isDirty(_id, null);
323 		else
324 			return _ctx.isDirty(_id, _listItems.get(getSelectedIndex()));
325 	}
326 
327 	/* (non-Javadoc)
328 	 * @see echobinding.BoundControl#getValue()
329 	 */
330 	public Object getValue() {
331 		if(getSelectedIndex() < 0)
332 			return null;
333 		return _listItems.get(getSelectedIndex());
334 	}
335 
336 	/* (non-Javadoc)
337 	 * @see echobinding.BoundControl#setValue(java.lang.Object)
338 	 */
339 	public void setValue(Object value) {
340 		if( value==null ) { 
341 			setSelectedIndex( 0 );
342 			return;
343 		}
344 		setSelectedIndex( _listItems.indexOf( value ) );
345 	}
346 }