package net.sf.openrocket.gui.adaptors;
import java.util.ArrayList;
import java.util.EventObject;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.MutableComboBoxModel;
import org.jfree.util.Log;
import net.sf.openrocket.util.ChangeSource;
import net.sf.openrocket.util.Reflection;
import net.sf.openrocket.util.StateChangeListener;
public class EnumModel<T extends Enum<T>> extends AbstractListModel
implements ComboBoxModel, MutableComboBoxModel, StateChangeListener {
private final ChangeSource source;
private final String valueName;
private final String nullText;
private final Enum<T>[] values;
private Enum<T> currentValue = null;
ArrayList<Enum<T>> displayedValues = new ArrayList<Enum<T>>();
private final Reflection.Method getMethod;
private final Reflection.Method setMethod;
public EnumModel(ChangeSource source, String valueName) {
this(source,valueName,null,null);
}
public EnumModel(ChangeSource source, String valueName, Enum<T>[] values) {
this(source, valueName, values, null);
}
@SuppressWarnings("unchecked")
public EnumModel(ChangeSource source, String valueName, Enum<T>[] values, String nullText) {
Class<? extends Enum<T>> enumClass;
this.source = source;
this.valueName = valueName;
try {
java.lang.reflect.Method getM = source.getClass().getMethod("get" + valueName);
enumClass = (Class<? extends Enum<T>>) getM.getReturnType();
if (!enumClass.isEnum()) {
throw new IllegalArgumentException("Return type of get" + valueName +
" not an enum type");
}
getMethod = new Reflection.Method(getM);
setMethod = new Reflection.Method(source.getClass().getMethod("set" + valueName,
enumClass));
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("get/is methods for enum '"+valueName+
"' not present in class "+source.getClass().getCanonicalName());
}
if (values != null)
this.values = values;
else
this.values = enumClass.getEnumConstants();
for (Enum<T> e : this.values){
this.displayedValues.add( e );
}
this.nullText = nullText;
stateChanged(null); // Update current value
source.addChangeListener(this);
}
@Override
public Object getSelectedItem() {
if (currentValue==null)
return nullText;
return currentValue;
}
@Override
public void setSelectedItem(Object item) {
if (item == null) {
// Clear selection - huh?
return;
}
if (item instanceof String) {
if (currentValue != null)
setMethod.invoke(source, (Object)null);
return;
}
if (!(item instanceof Enum<?>)) {
throw new IllegalArgumentException("Not String or Enum, item="+item);
}
// Comparison with == ok, since both are enums
if (currentValue == item)
return;
setMethod.invoke(source, item);
}
@Override
public Object getElementAt(int index) {
if( ( index < 0 ) || ( index >= this.displayedValues.size())){
return nullText; // bad parameter
}
if (values[index] == null)
return nullText;
return displayedValues.get( index);
}
@Override
public int getSize() {
return displayedValues.size();
}
@SuppressWarnings("unchecked")
@Override
public void stateChanged(EventObject e) {
Enum<T> value = (Enum<T>) getMethod.invoke(source);
if (value != currentValue) {
currentValue = value;
this.fireContentsChanged(this, 0, values.length);
}
}
@Override
public String toString() {
return "EnumModel["+source.getClass().getCanonicalName()+":"+valueName+"]";
}
@Override
public void addElement(Object item) {
// Not actually allowed. The model starts out with all the enums, and only allows hiding some.
}
@Override
public void removeElement(Object obj) {
if( null == obj ){
return;
}
this.displayedValues.remove( obj );
}
@Override
public void insertElementAt(Object item, int index) {
// Not actually allowed. The model starts out with all the enums, and only allows hiding some.
}
@Override
public void removeElementAt(int index) {
if( ( index < 0 ) || ( index >= this.displayedValues.size())){
return; // bad parameter
}
this.displayedValues.remove( index );
}
}