1   /*
2    * Copyright 2002-2004 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.springframework.richclient.form.binding.swing;
17  
18  import java.util.Arrays;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Observable;
24  
25  import javax.swing.ComboBoxModel;
26  import javax.swing.DefaultComboBoxModel;
27  import javax.swing.DefaultListModel;
28  import javax.swing.JComboBox;
29  import javax.swing.ListModel;
30  import javax.swing.event.ListDataEvent;
31  import javax.swing.event.ListDataListener;
32  
33  import org.springframework.binding.value.ValueModel;
34  import org.springframework.binding.value.support.ValueHolder;
35  import org.springframework.rules.constraint.Constraint;
36  import org.springframework.richclient.form.binding.Binding;
37  import org.springframework.util.comparator.ComparableComparator;
38  
39  public class ComboBoxBindingTests extends BindingAbstractTests {
40  
41      private static final String[] SELECTABLEITEMS = new String[] { "0", "1", "2", "3", "4" };
42  
43      private ValueModel sih;
44  
45      private ComboBoxBinding cbb;
46  
47      private JComboBox cb;
48  
49      private TestDataListener testListener;
50  
51      protected String setUpBinding() {
52          cbb = new ComboBoxBinding(fm, "simpleProperty");
53          cb = (JComboBox) cbb.getControl();
54          sih = new ValueHolder(SELECTABLEITEMS);
55          cbb.setSelectableItems(sih);
56          testListener = new TestDataListener();
57          cb.getModel().addListDataListener(testListener);
58          return "simpleProperty";
59      }
60  
61      public void testWithListModel() throws Exception {
62          DefaultListModel model = new DefaultListModel();
63          model.addElement("1");
64          model.addElement("2");
65          model.addElement("3");
66          model.addElement("4");
67          cbb.setSelectableItems(model);
68          cbb.doBindControl();
69          ComboBoxModel cbmodel = cb.getModel();
70          assertEquals(model.getSize(), cbmodel.getSize());
71          for (int i = 0, size = model.size(); i < size; i++) {
72              assertEquals(model.getElementAt(i), cbmodel.getElementAt(i));
73          }
74      }
75  
76      public void testWithList() throws Exception {
77          List model = Arrays.asList(SELECTABLEITEMS);
78          cbb.setSelectableItems(model);
79          cbb.doBindControl();
80          ComboBoxModel cbmodel = cb.getModel();
81          assertEquals(model.size(), cbmodel.getSize());
82          for (int i = 0, size = model.size(); i < size; i++) {
83              assertEquals(model.get(i), cbmodel.getElementAt(i));
84          }
85      }
86  
87      public void testWithArray() throws Exception {
88          Object[] model = SELECTABLEITEMS;
89          cbb.setSelectableItems(model);
90          cbb.doBindControl();
91          ComboBoxModel cbmodel = cb.getModel();
92          assertEquals(model.length, cbmodel.getSize());
93          for (int i = 0, size = model.length; i < size; i++) {
94              assertEquals(model[i], cbmodel.getElementAt(i));
95          }
96      }
97  
98      public void testValueModelUpdatesComponent() {
99          TestListDataListener tldl = new TestListDataListener();
100         cb.getModel().addListDataListener(tldl);
101 
102         assertEquals(null, cb.getSelectedItem());
103         assertEquals(-1, cb.getSelectedIndex());
104         tldl.assertCalls(0);
105 
106         vm.setValue("1");
107         assertEquals("1", cb.getSelectedItem());
108         assertEquals(1, cb.getSelectedIndex());
109         tldl.assertEvent(1, ListDataEvent.CONTENTS_CHANGED, -1, -1);
110 
111         vm.setValue("2");
112         assertEquals("2", cb.getSelectedItem());
113         assertEquals(2, cb.getSelectedIndex());
114         tldl.assertEvent(2, ListDataEvent.CONTENTS_CHANGED, -1, -1);
115 
116         vm.setValue(null);
117         assertEquals(null, cb.getSelectedItem());
118         assertEquals(-1, cb.getSelectedIndex());
119         tldl.assertEvent(3, ListDataEvent.CONTENTS_CHANGED, -1, -1);
120 
121         vm.setValue(null);
122         tldl.assertCalls(3);
123     }
124 
125     public void testComponentUpdatesValueModel() {
126         cb.setSelectedIndex(1);
127         assertEquals("1", vm.getValue());
128 
129         cb.setSelectedItem("2");
130         assertEquals("2", vm.getValue());
131 
132         cb.setSelectedIndex(-1);
133         assertEquals(null, vm.getValue());
134 
135         cb.setSelectedItem(null);
136         assertEquals(null, vm.getValue());
137     }
138 
139     public void testSelectableValueChangeUpdatesComboBoxModel() {
140         assertEquals("0", cb.getModel().getElementAt(0));
141 
142         sih.setValue(new Object[] { "1" });
143         assertEquals("1", cb.getModel().getElementAt(0));
144     }
145 
146     public void testComponentTracksEnabledChanges() {
147         assertTrue(cb.isEnabled());
148 
149         fm.getFieldMetadata("simpleProperty").setEnabled(false);
150         assertFalse(cb.isEnabled());
151 
152         fm.getFieldMetadata("simpleProperty").setEnabled(true);
153         assertTrue(cb.isEnabled());
154     }
155 
156     public void testComponentTracksReadOnlyChanges() {
157         assertTrue(cb.isEnabled());
158 
159         fm.getFieldMetadata("simpleProperty").setReadOnly(true);
160         assertFalse(cb.isEnabled());
161 
162         fm.getFieldMetadata("simpleProperty").setReadOnly(false);
163         assertTrue(cb.isEnabled());
164     }
165 
166     public void testSelectableItemHolderNullValue() {
167         ComboBoxBinding binding = new ComboBoxBinding(fm, "simpleProperty");
168         binding.getControl();
169         ValueHolder valueHolder = new ValueHolder();
170         try {
171             binding.setSelectableItems(valueHolder);
172             fail();
173         } catch (IllegalArgumentException e) {
174             // expected
175         }
176     }
177 
178     public void testExistingModel() {
179         JComboBox cb = new JComboBox(new DefaultComboBoxModel(new Object[] { "1", "2", "3" }));
180         ComboBoxBinder binder = new ComboBoxBinder();
181         Binding binding = binder.bind(cb, fm, "simpleProperty", Collections.EMPTY_MAP);
182         assertEquals(3, ((JComboBox) binding.getControl()).getModel().getSize());
183     }
184 
185     public void testFilter() {
186         setUpBinding();
187         ListModel model = cb.getModel();
188         cbb.setFilter(new Constraint() {
189             public boolean test(Object argument) {
190                 return "1".equals(argument) || "4".equals(argument);
191             }
192         });
193         assertEquals(2, model.getSize());
194         assertEquals("1", model.getElementAt(0));
195         assertEquals("4", model.getElementAt(1));
196     }
197 
198     public void testUpdatingFilter() {
199         setUpBinding();
200         ListModel model = cb.getModel();
201         TestConstraint testConstraint = new TestConstraint();
202         cbb.setFilter(testConstraint);
203         assertEquals(2, model.getSize());
204         assertEquals("1", model.getElementAt(0));
205         assertEquals("4", model.getElementAt(1));
206 
207         testConstraint.testCalled = 0;
208         testConstraint.setFilterValues(new Object[] { "2" });
209         // assertEquals(SELECTABLEITEMS.length, testConstraint.testCalled);
210         assertEquals(testConstraint.filterValues.length, model.getSize());
211         assertEquals("2", model.getElementAt(0));
212     }
213 
214     public void testFilterWithContext() {
215         ComboBoxBinder binder = new ComboBoxBinder();
216         binder.setSelectableItems(SELECTABLEITEMS);
217         Map context = new HashMap();
218         Constraint filter = new Constraint() {
219             public boolean test(Object argument) {
220                 return "1".equals(argument) || "4".equals(argument);
221             }
222         };
223         context.put(ComboBoxBinder.FILTER_KEY, filter);
224         ComboBoxBinding binding = (ComboBoxBinding) binder.bind(fm, "simpleProperty", context);
225         ListModel bindingModel = binding.getBindingModel();
226         assertEquals(filter, binding.getFilter());
227         assertEquals(2, bindingModel.getSize());
228         assertEquals("1", bindingModel.getElementAt(0));
229         assertEquals("4", bindingModel.getElementAt(1));
230     }
231 
232     public void testComparator() {
233         ComboBoxBinder binder = new ComboBoxBinder();
234         binder.setSelectableItems(new Object[] { "2", "4", "1", "2", "3" });
235         binder.setComparator(new ComparableComparator());
236         ComboBoxBinding binding = (ComboBoxBinding) binder.bind(fm, "simpleProperty", Collections.EMPTY_MAP);
237         ListModel bindingModel = binding.getBindingModel();
238         assertEquals(5, bindingModel.getSize());
239         assertEquals("1", bindingModel.getElementAt(0));
240         assertEquals("2", bindingModel.getElementAt(1));
241         assertEquals("2", bindingModel.getElementAt(2));
242         assertEquals("3", bindingModel.getElementAt(3));
243         assertEquals("4", bindingModel.getElementAt(4));
244     }
245 
246     public void testEmptySelectionValue() throws Exception {
247         ComboBoxModel model = cb.getModel();
248         int modelSize = model.getSize();
249         testListener.contentsChanged = null;
250         testListener.intervalAdded = null;
251         testListener.intervalRemoved = null;
252         String emptyValue = "select a Value";
253         cbb.setEmptySelectionValue(emptyValue);
254         assertEquals(modelSize + 1, model.getSize());
255         assertEquals(emptyValue, model.getElementAt(0));
256         assertNotNull(testListener.contentsChanged);
257         assertNull(testListener.intervalAdded);
258         assertNull(testListener.intervalRemoved);
259         cb.setSelectedItem(SELECTABLEITEMS[0]);
260         assertEquals(SELECTABLEITEMS[0], model.getSelectedItem());
261         assertEquals(SELECTABLEITEMS[0], vm.getValue());
262         cb.setSelectedItem(emptyValue);
263         assertEquals(emptyValue, model.getSelectedItem());
264         assertEquals(null, vm.getValue());
265         cb.setSelectedItem(null);
266         assertEquals(emptyValue, model.getSelectedItem());
267         assertEquals(null, vm.getValue());
268         
269         cb.setSelectedItem(emptyValue);
270         testListener.contentsChanged = null;
271         testListener.intervalAdded = null;
272         testListener.intervalRemoved = null;
273         cbb.setEmptySelectionValue(null);
274         assertNotNull(testListener.contentsChanged);
275         assertNull(testListener.intervalAdded);
276         assertNull(testListener.intervalRemoved);
277         assertEquals(modelSize, model.getSize());
278         assertEquals(SELECTABLEITEMS[0], model.getElementAt(0));
279         assertNull(vm.getValue());
280     }
281 
282     private static class TestConstraint extends Observable implements Constraint {
283         Object[] filterValues = new Object[] { "1", "4" };
284 
285         int testCalled = 0;
286 
287         public boolean test(Object argument) {
288             testCalled++;
289             for (int i = 0; i < filterValues.length; i++) {
290                 if (filterValues[i].equals(argument))
291                     return true;
292             }
293             return false;
294         }
295 
296         public void setFilterValues(Object[] objects) {
297             filterValues = objects;
298             setChanged();
299             notifyObservers();
300         }
301     }
302 
303     private class TestDataListener implements ListDataListener {
304 
305         private ListDataEvent contentsChanged;
306 
307         private ListDataEvent intervalAdded;
308 
309         private ListDataEvent intervalRemoved;
310 
311         public void contentsChanged(ListDataEvent e) {
312             contentsChanged = e;
313         }
314 
315         public void intervalAdded(ListDataEvent e) {
316             intervalAdded = e;
317         }
318 
319         public void intervalRemoved(ListDataEvent e) {
320             intervalRemoved = e;
321         }
322 
323     }
324 }