001 /*
002 * Copyright 2002-2004 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.springframework.richclient.form.binding.swing;
017
018 import java.beans.PropertyChangeEvent;
019 import java.beans.PropertyChangeListener;
020
021 import javax.swing.ComboBoxEditor;
022 import javax.swing.ComboBoxModel;
023 import javax.swing.JComboBox;
024 import javax.swing.ListCellRenderer;
025 import javax.swing.ListModel;
026 import javax.swing.event.ListDataEvent;
027
028 import org.springframework.binding.form.FormModel;
029 import org.springframework.richclient.list.AbstractFilteredListModel;
030
031 /**
032 * TODO: support for filters
033 *
034 * @author Oliver Hutchison
035 */
036 public class ComboBoxBinding extends AbstractListBinding {
037
038 private Object emptySelectionValue;
039
040 private BoundComboBoxModel boundModel;
041
042 public ComboBoxBinding(FormModel formModel, String formPropertyPath) {
043 this(new JComboBox(), formModel, formPropertyPath, null);
044 }
045
046 public ComboBoxBinding(JComboBox comboBox, FormModel formModel, String formPropertyPath) {
047 this(comboBox, formModel, formPropertyPath, null);
048 }
049
050 public ComboBoxBinding(JComboBox comboBox, FormModel formModel, String formPropertyPath, Class requiredSourceClass) {
051 super(comboBox, formModel, formPropertyPath, requiredSourceClass);
052 }
053
054 protected void doBindControl(ListModel bindingModel) {
055 boundModel = new BoundComboBoxModel(bindingModel);
056 getComboBox().setModel(boundModel);
057 }
058
059 protected ListModel getDefaultModel() {
060 return getComboBox().getModel();
061 }
062
063 public ListCellRenderer getRenderer() {
064 return getComboBox().getRenderer();
065 }
066
067 public JComboBox getComboBox() {
068 return (JComboBox) getComponent();
069 }
070
071 public void setRenderer(ListCellRenderer renderer) {
072 getComboBox().setRenderer(renderer);
073 }
074
075 public void setEditor(ComboBoxEditor comboBoxEditor) {
076 getComboBox().setEditor(comboBoxEditor);
077 }
078
079 public ComboBoxEditor getEditor() {
080 return getComboBox().getEditor();
081 }
082
083 private class BoundComboBoxModel extends AbstractFilteredListModel implements ComboBoxModel, PropertyChangeListener {
084
085 public BoundComboBoxModel(ListModel listModel) {
086 super(listModel);
087 getValueModel().addValueChangeListener(this);
088 }
089
090 public int getSize() {
091 if (emptySelectionValue != null) {
092 return super.getSize() + 1;
093 }
094 return super.getSize();
095 }
096
097 public Object getElementAt(int index) {
098 if (emptySelectionValue != null) {
099 if (index == 0)
100 return emptySelectionValue;
101 return super.getElementAt(index - 1);
102 }
103 return super.getElementAt(index);
104 }
105
106 private boolean updateSelectedItem() {
107 Object selectedItem = getSelectedItem();
108 if (selectedItem != null) {
109 boolean found = false;
110 for (int i = 0, size = getSize(); i < size && !found; i++) {
111 found = selectedItem.equals(getElementAt(i));
112 }
113 if (!found) {
114 setSelectedItem(null);
115 return true;
116 }
117 }
118 return false;
119 }
120
121 public void contentsChanged(ListDataEvent e) {
122 if (updateSelectedItem()) {
123 fireContentsChanged(this, -1, -1);
124 } else {
125 super.contentsChanged(e);
126 }
127 }
128
129 public void intervalRemoved(ListDataEvent e) {
130 if (updateSelectedItem()) {
131 fireContentsChanged(this, -1, -1);
132 } else {
133 super.intervalRemoved(e);
134 }
135 }
136
137 public void setSelectedItem(Object selectedItem) {
138 if (selectedItem == emptySelectionValue) {
139 selectedItem = null;
140 }
141 getValueModel().setValueSilently(selectedItem, this);
142 fireContentsChanged(this, -1, -1);
143 }
144
145 public Object getSelectedItem() {
146 Object value = getValue();
147 if(emptySelectionValue != null && value == null) {
148 return emptySelectionValue;
149 }
150 return value;
151 }
152
153 public void propertyChange(PropertyChangeEvent evt) {
154 fireContentsChanged(this, -1, -1);
155 }
156
157 public void emptySelectionValueChanged() {
158 fireContentsChanged(this, -1, -1);
159 }
160 }
161
162 /**
163 * @param value
164 */
165 public void setEmptySelectionValue(Object value) {
166 if (value != emptySelectionValue && boundModel != null) {
167 emptySelectionValue = value;
168 boundModel.emptySelectionValueChanged();
169 } else {
170 emptySelectionValue = value;
171 }
172 }
173
174 public Object getEmptySelectionValue() {
175 return emptySelectionValue;
176 }
177 }