com.lyonesgamer.propertygrid.properties.ChoiceProperty Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of JPropertyGrid Show documentation
Show all versions of JPropertyGrid Show documentation
A property editor component for Swing.
The newest version!
package com.lyonesgamer.propertygrid.properties;
import com.lyonesgamer.propertygrid.PGProperty;
import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
/**
* Allows a user to choose a value from a list of options.
*
* The difference between `names` and `values` is comparable to HTML's <select> and <option> elements,
* in which a tag like <option value='0'>Example<option> displays the text Example to the user and sends
* the value 0 to the server.
*
* The sizes of the two arrays are not checked. The size of the displayed list is the minimum of the two sizes. Values of
* either list exceeding this minimum are unused.
*
* @param The type of values contained in the values list.
* @author Tristan Patch
* @since 1.0
*/
public class ChoiceProperty extends PGProperty {
/**
* The numeric index of the current value, within the `values` list.
*/
protected int index;
/**
* The names of the possible values, displayed in the list to the user.
*/
protected List names;
/**
* The values that are returned when the value is set.
*/
protected List values;
/**
* The editor to use for this property.
*/
protected ChoiceEditor editor = new ChoiceEditor();
/**
* The renderer to use for this property.
*/
protected ChoiceRenderer renderer = new ChoiceRenderer();
/**
* Creates the property.
*
* @param name The displayed name of the property.
* @param names The list of names of possible values.
* @param values The list of values that can be selected.
* @param initial The value that is initially selected. If the value is not in the list, defaults to the first value.
* @param The type of values contained in the list.
*/
public ChoiceProperty(String name, List names, List values, T initial) {
super(name);
this.names = names;
this.values = values;
this.index = getIndexForValue(initial);
}
/**
* Creates the property.
*
* @param name The displayed name of the property.
* @param names The list of names of possible values.
* @param values The list of values that can be selected.
* @param index The value that is initially selected. If it is negative or too large, it is clamped.
* @param The type of values contained in the list.
*/
public ChoiceProperty(String name, List names, List values, int index) {
super(name);
this.names = names;
this.values = values;
if (index < 0)
this.index = 0;
else if (index > Math.min(names.size(), values.size()))
this.index = Math.min(names.size(), values.size());
else
this.index = index;
}
@Override
protected void doAfterAdded() {}
/**
* Validates the given value. Determines if the value exists in the list of values.
*
* @param value The value to be validated.
* @return If the list of values contains this value.
*/
@Override
public boolean onValidateValue(E value) {
return values.contains(value);
}
@Override
public void onSetValue(E value) {
if (parent != null)
parent.firePropertyChangeEvent(this, value);
this.index = values.indexOf(value);
}
/**
* Gets the index in the list of values of the given value.
*
* @param value The value to find.
* @param The type of the value.
* @return The index of the value within the values list.
*/
public int getIndexForValue(T value) {
return values.indexOf(value);
}
/**
* Finds the index of a given name of a value. If the name is found in the names list, returns the index of the name.
* If the name is a parseable integer and is a valid index of the values list, returns the index.
* @param name The name to search for.
* @return The index of the name if a name, the index passed if the name is an index, or -1 otherwise.
*/
public int getIndexForName(String name) {
for (int i = 0; i < Math.min(names.size(), values.size()); i++) {
if (names.get(i).equalsIgnoreCase(name))
return i;
}
int index = Integer.parseInt(name);
if (values.size() > index)
return index;
return -1;
}
/**
* Sets the index of the current value to the index of the name passed by value, or value itself if it is a parseable int.
*
* @param value The string to attempt to set from.
*/
@Override
public void setValueFromString(String value) {
index = getIndexForName(value);
}
/**
* Sets the index of the current value to the passed value.
*
* @param value The int to set this value from.
*/
@Override
public void setValueFromLong(long value) {
if (values.size() > value)
index = (int)value;
}
@Override
public E getValue() {
return values.get(index);
}
@Override
public E stringToValue(String value) {
for (int i = 0; i < Math.min(names.size(), values.size()); i++) {
if (names.get(i).equalsIgnoreCase(value))
return values.get(i);
}
try {
int index = Integer.parseInt(value);
if (values.size() > index && index >= 0)
return values.get(index);
else
return null;
} catch (NumberFormatException e) {
return null;
}
}
@Override
public E longToValue(long value) {
if (values.size() > value && value >= 0)
return values.get(index);
else
return null;
}
/**
* If the value is in the values list, returns the name at its index.
*
* @param value The value to convert.
* @return The name at this value's index, or an empty string otherwise.
*/
@Override
public String valueToString(E value) {
int index = values.indexOf(value);
if (index > 0 && index < names.size())
return names.get(Math.min(index, names.size()));
return "";
}
@Override
public PGCellRenderer getRenderer() {
return renderer;
}
@Override
public PGCellEditor getEditor() {
return editor;
}
protected class ChoiceEditor extends JComboBox implements PGCellEditor, ActionListener {
//No need to use an EventListenerList if we only have one listener type
protected final List listeners = new ArrayList<>();
protected final Set listenersToRemove = new HashSet<>();
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
for (int i = 0; i < Math.min(values.size(), names.size()); i++) {
this.addItem(names.get(i));
}
this.addActionListener(this);
return this;
}
@Override
public void actionPerformed(ActionEvent e) {
parent.firePropertyChangeEvent(ChoiceProperty.this, values.get(this.getSelectedIndex()));
index = this.getSelectedIndex();
}
@Override
public Object getCellEditorValue() {
return index <= names.size() && index > 0 ? names.get(index) : "";
}
@Override
public boolean isCellEditable(EventObject anEvent) {
return !disabled;
}
@Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
@Override
public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
@Override
public void cancelCellEditing() {
fireEditingCancelled();
}
public void fireEditingCancelled() {
ChangeEvent event = new ChangeEvent(this);
for (CellEditorListener l : listeners)
l.editingCanceled(event);
doClearListeners();
}
public void fireEditingStopped() {
ChangeEvent event = new ChangeEvent(this);
for (CellEditorListener l : listeners)
l.editingStopped(event);
doClearListeners();
}
@Override
public void addCellEditorListener(CellEditorListener l) {
listeners.add(l);
}
@Override
public void removeCellEditorListener(CellEditorListener l) {
listenersToRemove.add(l);
}
protected void doClearListeners() {
listeners.removeAll(listenersToRemove);
listenersToRemove.clear();
}
}
protected class ChoiceRenderer extends JLabel implements PGCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
setText((index > names.size()) ? "" : names.get(index));
setToolTipText(helpString);
return this;
}
}
}