All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lyonesgamer.propertygrid.properties.ChoiceProperty Maven / Gradle / Ivy

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;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy