
package uk.co.wingpath.gui;

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import uk.co.wingpath.util.*;
import uk.co.wingpath.event.*;

/**
* This class implements {@link WComponent} using a {@link JComboBox} with
* a {@link SelectionVariable} as the model.
*/
public class WSelector<T>
    extends WAbstractComponent<T>
{
    private SelectionVariable<T> model;
    private final JComboBox comboBox;
    private boolean setting;
    private final ValueListener valueListener;
    private ToolTips toolTips;
    private ListCellRenderer renderer;

    /**
    * Constructs a <code>WSelector</code> using the specified list model and
    * variable.
    * @param label text for the associated label, or <code>null</code> if
    * there is no associated label.
    * @param model the selection variable.
    */
    public WSelector (String label, SelectionVariable<T> model)
    {
        if (model == null)
            model = new SelectionVariable<T> ();
        this.model = model;
        ListModel listModel = model.getListModel ();
        if (listModel instanceof ToolTips)
            toolTips = (ToolTips) listModel;
        else
            toolTips = null;

        comboBox = new JComboBox ();
        comboBox.setModel (model);
        renderer = comboBox.getRenderer ();
        comboBox.setRenderer (
            new ListCellRenderer ()
            {
                public Component getListCellRendererComponent (JList list,
                    Object value, int index, boolean isSelected,
                    boolean cellHasFocus)
                {
                    JComponent comp =
                        (JComponent) renderer.getListCellRendererComponent (
                            list, value, index, isSelected, cellHasFocus);
                    if (toolTips != null)
                        comp.setToolTipText (toolTips.getToolTip (index));
                    return comp;
                }
            });

        initialize (comboBox, label);
        setAlignment (SwingConstants.LEFT);
        setting = false;

        valueListener =
            new ValueListener ()
            {
                public void valueChanged (ValueEvent e)
                {
                    if (!setting)
                        listeners.fireValueChanged (e);
                }
            };

        model.addValueListener (valueListener);
    }

    /**
    * Constructs a <code>WSelector</code> using the specified list model and
    * a private variable.
    * @param label text for the associated label, or <code>null</code> if
    * there is no associated label.
    * @param listModel the list model.
    * @param autoSelect if {@code true} a new selection will be made if the
    * current selection is removed from the list. If {@code false}, the
    * selection will be set to {@code null}.
    */
    @SuppressWarnings ("unchecked")
    public WSelector (String label, ListModel listModel, boolean autoSelect)
    {
        this (label, new SelectionVariable<T> (listModel, autoSelect));
    }

    public void setModel (SelectionVariable<T> model)
    {
        if (model == this.model)
            return;
        if (model == null)
            model = new SelectionVariable<T> ();
        this.model.removeValueListener (valueListener);
        this.model = model;
        comboBox.setModel (model);
        ListModel listModel = model.getListModel ();
        if (listModel instanceof ToolTips)
            toolTips = (ToolTips) listModel;
        else
            toolTips = null;
        model.addValueListener (valueListener);
    }

    public void setToolTips (ToolTips toolTips)
    {
        this.toolTips = toolTips;
    }

    public void setValue (T value)
    {
        setting = true;
        model.setValue (value);
        setting = false;
    }

    public T getValue ()
    {
        return model.getValue ();
    }

    /*
    * Sets the maximum number of rows to be displayed.
    * If the number of items is greater than the maximum number of rows,
    * a scrollbar is used.
    * Scrolling may be inhibited by passing 0 for the number of rows.
    * @param rows the maximum number of rows, or 0 to inhibit scrolling.
    */
    public void setMaximumRowCount (int rows)
    {
        if (rows == 0)
            rows = model.getSize ();
        comboBox.setMaximumRowCount (rows);
    }

    /**
     * Sets the horizontal alignment of the selection text.
     * Valid parameter values are:
     * <ul>
     * <li><code>SwingConstants.LEFT</code>
     * <li><code>SwingConstants.CENTER</code>
     * <li><code>SwingConstants.RIGHT</code>
     * <li><code>SwingConstants.LEADING</code>
     * <li><code>SwingConstants.TRAILING</code>
     * </ul>
     * @param alignment the required alignment
     */
    @Override
    public void setAlignment (int alignment)
    {
        ListCellRenderer renderer = comboBox.getRenderer ();
        if (renderer instanceof JLabel)
            ((JLabel) renderer).setHorizontalAlignment (alignment);
    }
}

