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 }