org.nuiton.jaxx.runtime.swing.JAXXComboBox Maven / Gradle / Ivy
The newest version!
/*
* #%L
* JAXX :: Runtime
* %%
* Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.jaxx.runtime.swing;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.ListModel;
import java.awt.Component;
import java.awt.event.ItemEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class JAXXComboBox extends JComboBox {
private static final long serialVersionUID = 1L;
public class JAXXComboBoxModel extends AbstractListModel implements ComboBoxModel {
private final List- items;
private Object selectedItem;
private static final long serialVersionUID = -8940733376638766414L;
public JAXXComboBoxModel(List
- items) {
this.items = items;
PropertyChangeListener listener = e -> {
if (e.getPropertyName().equals(Item.SELECTED_PROPERTY)) {
Item item = (Item) e.getSource();
int itemIndex = JAXXComboBoxModel.this.items.indexOf(item);
// TODO: fix cut-and-pasting badness
int[] oldSelection = new int[]{getSelectedIndex()};
int[] newSelection;
int index = -1;
for (int i = 0; i < oldSelection.length; i++) {
if (oldSelection[i] == itemIndex) {
index = i;
break;
}
}
if (item.isSelected()) {
if (index != -1) // it was already selected
{
return;
}
newSelection = new int[oldSelection.length + 1];
System.arraycopy(oldSelection, 0, newSelection, 0, oldSelection.length);
newSelection[newSelection.length - 1] = itemIndex;
} else {
if (index == -1) // it already wasn't selected
{
return;
}
newSelection = new int[oldSelection.length - 1];
System.arraycopy(oldSelection, 0, newSelection, 0, index);
System.arraycopy(oldSelection, index + 1, newSelection, index, oldSelection.length - 1 - index);
}
if (newSelection.length > 0) {
setSelectedIndex(newSelection[0]);
}
} else {
// TODO: more cut-and-pasting badness
for (int i = 0; i < getSize(); i++) {
if (getElementAt(i) == ((Item) e.getSource()).getValue()) {
fireContentsChanged(JAXXComboBoxModel.this, i, i);
if (getSelectedIndex() == i) {
fireItemStateChanged(new ItemEvent(JAXXComboBox.this, ItemEvent.ITEM_STATE_CHANGED, getElementAt(i), ItemEvent.DESELECTED));
}
return;
}
}
}
};
for (Item item : items) {
item.addPropertyChangeListener(listener);
}
}
public List
- getItems() {
return items;
}
@Override
public Object getElementAt(int i) {
return items.get(i).getValue();
}
@Override
public int getSize() {
return items.size();
}
@Override
public Object getSelectedItem() {
return selectedItem;
}
@Override
public void setSelectedItem(Object selectedItem) {
if (this.selectedItem != null && !this.selectedItem.equals(selectedItem) ||
this.selectedItem == null && selectedItem != null) {
this.selectedItem = selectedItem;
fireContentsChanged(this, -1, -1);
}
}
}
public JAXXComboBox() {
setRenderer(new DefaultListCellRenderer() {
private static final long serialVersionUID = 1L;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
ListModel model = list.getModel();
if (model instanceof JAXXComboBoxModel) {
List/*
- */ items = ((JAXXComboBoxModel) model).items;
Item item = null;
if (index == -1) {
for (Object item1 : items) {
Item testItem = (Item) item1;
if (testItem.getValue() == value) {
item = testItem;
break;
}
}
} else {
item = (Item) items.get(index);
}
if (item != null) {
String label = item.getLabel();
if (label != null) {
value = label;
}
}
}
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
});
addItemListener(e -> {
ListModel model = getModel();
if (model instanceof JAXXComboBoxModel) {
List
- items = ((JAXXComboBoxModel) model).items;
for (int i = items.size() - 1; i >= 0; i--) {
boolean selected = getSelectedIndex() == i;
Item item = items.get(i);
if (selected != item.isSelected()) {
item.setSelected(selected);
}
}
}
});
}
/**
* Fill a combo box model with some datas, and select after all the given object
*
* @param data data ot inject in combo
* @param select the object to select in combo after reflling his model
* @param methodName method to invoke to display data's name
*/
public void fillComboBox(Collection> data, Object select, String methodName) {
// prepare method to use
Method m;
try {
m = select.getClass().getMethod(methodName);
m.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("could not find method " + methodName + " on " + select.getClass());
}
List
- items = new ArrayList<>();
for (Object o : data) {
boolean selected = o.equals(select);
try {
items.add(new Item(o.toString(), (String) m.invoke(o), o, selected));
} catch (IllegalAccessException | InvocationTargetException e) {
// shoudl never happen ?
throw new RuntimeException(e);
}
}
setItems(items);
}
// this way we can keep it marked protected and still allow code in this file to call it
@Override
protected void fireItemStateChanged(ItemEvent e) {
super.fireItemStateChanged(e);
}
public void setItems(List
- items) {
setModel(new JAXXComboBoxModel(items));
List
selectedIndexList = new ArrayList<>();
for (int i = 0; i < items.size(); i++) {
if (items.get(i).isSelected()) {
selectedIndexList.add(i);
}
}
int[] selectedIndices = new int[selectedIndexList.size()];
for (int i = 0; i < selectedIndexList.size(); i++) {
selectedIndices[i] = selectedIndexList.get(i);
}
if (selectedIndices.length > 0) {
setSelectedIndex(selectedIndices[0]);
}
}
public List- getItems() {
if (getModel() instanceof JAXXComboBoxModel) {
return ((JAXXComboBoxModel) getModel()).getItems();
}
return null;
}
public void setSelectedItem(Item item) {
//TC-20092004 Anomalie #73 fix npe when want to call with a null
// value
super.setSelectedItem(item == null ? null : item.getValue());
}
public Item getSelectedJaxxItem() {
Object selected = super.getSelectedItem();
return findItem(selected);
}
public Item findItem(Object value) {
List
- items = getItems();
if (items != null) {
for (Item i : items) {
if (i.getValue().equals(value)) {
return i;
}
}
}
return null;
}
public void addItem(Item item) {
List
- items = getItems();
if (items != null) {
items.add(item);
setItems(items);
}
}
public void addAllItems(Collection
- itemsToAdd) {
List
- items = getItems();
if (items != null) {
items.addAll(itemsToAdd);
setItems(items);
}
}
public void removeItem(Item item) {
List
- items = getItems();
if (items != null) {
items.remove(item);
setItems(items);
}
}
public void removeAllItems(Collection
- itemsToRemove) {
List
- items = getItems();
if (items != null) {
items.removeAll(itemsToRemove);
setItems(items);
}
}
}