/** * Copyright (C) 2015 Valkyrie RCP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.valkyriercp.form.binding.swing; import org.valkyriercp.binding.form.FormModel; import org.valkyriercp.list.AbstractFilteredListModel; import javax.swing.*; import javax.swing.event.ListDataEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; /** * TODO: support for filters * * @author Oliver Hutchison */ public class ComboBoxBinding extends AbstractListBinding { private Object emptySelectionValue; private BoundComboBoxModel boundModel; public ComboBoxBinding(FormModel formModel, String formPropertyPath) { this(new JComboBox(), formModel, formPropertyPath, null); } public ComboBoxBinding(JComboBox comboBox, FormModel formModel, String formPropertyPath) { this(comboBox, formModel, formPropertyPath, null); } public ComboBoxBinding(JComboBox comboBox, FormModel formModel, String formPropertyPath, Class requiredSourceClass) { super(comboBox, formModel, formPropertyPath, requiredSourceClass); } protected void doBindControl(ListModel bindingModel) { boundModel = new BoundComboBoxModel(bindingModel); getComboBox().setModel(boundModel); } protected ListModel getDefaultModel() { return getComboBox().getModel(); } public ListCellRenderer getRenderer() { return getComboBox().getRenderer(); } public JComboBox getComboBox() { return (JComboBox) getComponent(); } public void setRenderer(ListCellRenderer renderer) { getComboBox().setRenderer(renderer); } public void setEditor(ComboBoxEditor comboBoxEditor) { getComboBox().setEditor(comboBoxEditor); } public ComboBoxEditor getEditor() { return getComboBox().getEditor(); } private class BoundComboBoxModel extends AbstractFilteredListModel implements ComboBoxModel, PropertyChangeListener { public BoundComboBoxModel(ListModel listModel) { super(listModel); getValueModel().addValueChangeListener(this); } public int getSize() { if (emptySelectionValue != null) { return super.getSize() + 1; } return super.getSize(); } public Object getElementAt(int index) { if (emptySelectionValue != null) { if (index == 0) return emptySelectionValue; return super.getElementAt(index - 1); } return super.getElementAt(index); } private boolean updateSelectedItem() { Object selectedItem = getSelectedItem(); if (selectedItem != null) { boolean found = false; for (int i = 0, size = getSize(); i < size && !found; i++) { found = selectedItem.equals(getElementAt(i)); } if (!found) { setSelectedItem(null); return true; } } return false; } public void contentsChanged(ListDataEvent e) { if (updateSelectedItem()) { fireContentsChanged(this, -1, -1); } else { super.contentsChanged(e); } } public void intervalRemoved(ListDataEvent e) { if (updateSelectedItem()) { fireContentsChanged(this, -1, -1); } else { super.intervalRemoved(e); } } public void setSelectedItem(Object selectedItem) { if (selectedItem == emptySelectionValue) { selectedItem = null; } getValueModel().setValueSilently(selectedItem, this); fireContentsChanged(this, -1, -1); } public Object getSelectedItem() { Object value = getValue(); if(emptySelectionValue != null && value == null) { return emptySelectionValue; } return value; } public void propertyChange(PropertyChangeEvent evt) { fireContentsChanged(this, -1, -1); } public void emptySelectionValueChanged() { fireContentsChanged(this, -1, -1); } } /** * @param value */ public void setEmptySelectionValue(Object value) { if (value != emptySelectionValue && boundModel != null) { emptySelectionValue = value; boundModel.emptySelectionValueChanged(); } else { emptySelectionValue = value; } } public Object getEmptySelectionValue() { return emptySelectionValue; } }