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

net.sf.cuf.model.ui.LOVAdapter Maven / Gradle / Ivy

The newest version!
package net.sf.cuf.model.ui;

import net.sf.cuf.model.ValueModel;

import javax.swing.ComboBoxModel;
import javax.swing.ListSelectionModel;
import javax.swing.JComboBox;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JList;
import javax.swing.ButtonGroup;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionListener;
import java.util.List;
import java.util.Collections;
import java.util.Enumeration;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

/**
 * A LOVAdapter connects a model of a JList, a JComboBox or a JRadioBox ButtonGroup
 * to various ValueModels holding the display, the data and the selection value(s).
 * The displayed data in the list/combobox is taken from a List of Objects,
 * this List may be inside a ValueModel. The "keys" or "ids" for the displayed
 * data is taken from an other List, again this list may be inside a value model.
 * The selected key/id is taken from another ValueModel. The value of that ValueModel
 * is kept in sync (both ways) with the selected list/combobox entry.
 * The mapping of "nothing selected" (aka -1) to a "magic" key/id is also supported.
 * TODO: provide a "inSync" ValueModel, that contains true if the index is valid (!=-1) and false if it the index is -1.
 * TODO: provide a "DelegateAccess" attribute, so that the mDisplayedItems are created on the fly from the mKeys
 */
public class LOVAdapter implements ListSelectionModel, ComboBoxModel, ActionListener
{
    /** the list of our displayed values, never null */
    private List             mDisplayedItems;
    /** null or the ValueModel the above list comes from */
    private ValueModel> mDisplayedItemsVM;
    /** the list of our matching keys/ids, never null */
    private List             mKeys;
    /** null or the ValueModel the above list comes from */
    private ValueModel> mKeysVM;
    /** the value model containing the key matching the selection, never null */
    private ValueModel       mSelectedKeyVM;
    /** the magic value for a "unselected" key, may be null */
    private Object              mUnselectedKey;
    /** marker if we are inside a selection change, we then ignore selection
      * changes from the "other" model */
    private boolean             mInSelectionChange;
    /** list of listeners for our Swing ListModel, never null */
    private EventListenerList   mListenerList;
    /** our delegate handling the Swing ListSelectionModel, never null */
    private ListSelectionModel  mListSelectionModel;
    /** the container of our radiobuttons, may be  null if we adapt to a combobox/list */
    private ButtonGroup         mButtonGroup;
    /** -1 or the currently selected index */
    private int                 mIndex;

    /**
     * Create a new adapter between the displayed itams and the keys.
     * @param pComboBox the combobox widget, must not be null
     * @param pDisplayedItemsVM the value model holding the displayed items, must not be null
     * @param pKeysVM the value model holding the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     */
    public LOVAdapter(final JComboBox pComboBox,
                      final ValueModel> pDisplayedItemsVM, final ValueModel> pKeysVM,
                      final ValueModel pSelectedKeyVM)
    {
        this(pComboBox, pDisplayedItemsVM, pKeysVM, pSelectedKeyVM, null);
    }

    /**
     * Create a new adapter between the displayed itams, the keys and a magic "null"
     * key value.
     * @param pComboBox the combobox widget, must not be null
     * @param pDisplayedItemsVM the value model holding the displayed items, must not be null
     * @param pKeysVM the value model holding the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     * @param pUnselectedKey the magic key, may be nulll
     */
    public LOVAdapter(final JComboBox pComboBox,
                      final ValueModel> pDisplayedItemsVM, final ValueModel> pKeysVM,
                      final ValueModel pSelectedKeyVM, final Object pUnselectedKey)
    {
        if (pComboBox==null) throw new IllegalArgumentException("ComboBox must not be null");
        if (pDisplayedItemsVM==null) throw new IllegalArgumentException("DisplayedItemsVM must not be null");
        if (pKeysVM==null) throw new IllegalArgumentException("KeysVM must not be null");
        if (pSelectedKeyVM==null) throw new IllegalArgumentException("SelectedKeyVM must not be null");

        List displayedItems = getDisplayedList(pDisplayedItemsVM);
        List keys           = getKeysList     (pKeysVM);

        DefaultListSelectionModel listSelectionModel= new DefaultListSelectionModel();
        init(displayedItems, pDisplayedItemsVM, keys, pKeysVM, pSelectedKeyVM, pUnselectedKey, listSelectionModel, null);
        pComboBox.setModel(this);
        // set the widget according to to the current key
        vmSelectedKeyChanged(null);
    }

    /**
     * Create a new adapter between the displayed itams and the keys.
     * @param pComboBox the combobox widget, must not be null
     * @param pDisplayedItems the list containing the displayed items, must not be null
     * @param pKeys the list containing the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     */
    public LOVAdapter(final JComboBox pComboBox,
                      final List pDisplayedItems, final List pKeys,
                      final ValueModel pSelectedKeyVM)
    {
        this(pComboBox, pDisplayedItems, pKeys, pSelectedKeyVM, null);
    }

    /**
     * Create a new adapter between the displayed itams, the keys and a magic "null"
     * key value.
     * @param pComboBox the combobox widget, must not be null
     * @param pDisplayedItems the list containing the displayed items, must not be null
     * @param pKeys the list containing the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     * @param pUnselectedKey the magic key, may be nulll
     */
    public LOVAdapter(final JComboBox pComboBox,
                      final List pDisplayedItems, final List pKeys,
                      final ValueModel pSelectedKeyVM, final Object pUnselectedKey)
    {
        if (pDisplayedItems==null) throw new IllegalArgumentException("DisplayedItems must not be null");
        if (pKeys==null) throw new IllegalArgumentException("Keys must not be null");
        if (pSelectedKeyVM==null) throw new IllegalArgumentException("SelectedKeyVM must not be null");

        DefaultListSelectionModel listSelectionModel= new DefaultListSelectionModel();
        init(pDisplayedItems, null, pKeys, null, pSelectedKeyVM, pUnselectedKey, listSelectionModel, null);
        pComboBox.setModel(this);

        // set the widget according to to the current key
        vmSelectedKeyChanged(null);
    }

    /**
     * Create a new adapter between the displayed itams and the keys.
     * @param pList the list widget, must not be null
     * @param pDisplayedItemsVM the value model holding the displayed items, must not be null
     * @param pKeysVM the value model holding the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     */
    public LOVAdapter(final JList pList,
                      final ValueModel> pDisplayedItemsVM, final ValueModel> pKeysVM,
                      final ValueModel pSelectedKeyVM)
    {
        this(pList, pDisplayedItemsVM, pKeysVM, pSelectedKeyVM, null);
    }

    /**
     * Create a new adapter between the displayed itams, the keys and a magic "null"
     * key value.
     * @param pList the list widget, must not be null
     * @param pDisplayedItemsVM the value model holding the displayed items, must not be null
     * @param pKeysVM the value model holding the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     * @param pUnselectedKey the magic key, may be nulll
     */
    public LOVAdapter(final JList pList,
                      final ValueModel> pDisplayedItemsVM, final ValueModel> pKeysVM,
                      final ValueModel pSelectedKeyVM, final Object pUnselectedKey)
    {
        if (pList==null) throw new IllegalArgumentException("List must not be null");
        if (pDisplayedItemsVM==null) throw new IllegalArgumentException("DisplayedItemsVM must not be null");
        if (pKeysVM==null) throw new IllegalArgumentException("KeysVM must not be null");
        if (pSelectedKeyVM==null) throw new IllegalArgumentException("SelectedKeyVM must not be null");

        List displayedItems= getDisplayedList(pDisplayedItemsVM);
        List keys          = getKeysList     (pKeysVM);

        ListSelectionModel listSelectionModel= pList.getSelectionModel();
        if (listSelectionModel==null)
        {
            listSelectionModel= new DefaultListSelectionModel();
        }
        listSelectionModel.setSelectionMode(SINGLE_SELECTION);
        init(displayedItems, pDisplayedItemsVM, keys,
             pKeysVM, pSelectedKeyVM, pUnselectedKey, listSelectionModel, null);
        pList.setModel         (this);
        pList.setSelectionModel(this);

        // set the widget according to to the current key
        vmSelectedKeyChanged(null);
    }

    /**
     * Create a new adapter between the displayed itams and the keys.
     * @param pList the list widget, must not be null
     * @param pDisplayedItems the list containing the displayed items, must not be null
     * @param pKeys the list containing the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     */
    public LOVAdapter(final JList pList,
                      final List pDisplayedItems, final List pKeys,
                      final ValueModel pSelectedKeyVM)
    {
        this(pList, pDisplayedItems, pKeys, pSelectedKeyVM, null);
    }

    /**
     * Create a new adapter between the displayed itams, the keys and a magic "null"
     * key value.
     * @param pList the list widget, must not be null
     * @param pDisplayedItems the list containing the displayed items, must not be null
     * @param pKeys the list containing the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     * @param pUnselectedKey the magic key, may be nulll
     */
    public LOVAdapter(final JList pList,
                      final List pDisplayedItems, final List pKeys,
                      final ValueModel pSelectedKeyVM, final Object pUnselectedKey)
    {
        if (pDisplayedItems==null) throw new IllegalArgumentException("DisplayedItems must not be null");
        if (pKeys==null) throw new IllegalArgumentException("Keys must not be null");
        if (pSelectedKeyVM==null) throw new IllegalArgumentException("SelectedKeyVM must not be null");

        ListSelectionModel listSelectionModel= pList.getSelectionModel();
        if (listSelectionModel==null)
        {
            listSelectionModel= new DefaultListSelectionModel();
        }
        init(pDisplayedItems, null, pKeys, null, pSelectedKeyVM, pUnselectedKey, listSelectionModel, null);
        pList.setModel         (this);
        pList.setSelectionModel(this);

        // set the widget according to to the current key
        vmSelectedKeyChanged(null);
    }

    /**
     * Create a new adapter between the buttong group, the keys and the selected key.
     * @param pButtonGroup the list widget, must not be null
     * @param pDisplayedItemsVM the value model holding the displayed items, must not be null
     * @param pKeysVM the value model holding the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     * @param pUnselectedKey the magic key, may be nulll
     */
    public LOVAdapter(final ButtonGroup pButtonGroup,
                      final ValueModel> pDisplayedItemsVM, final ValueModel> pKeysVM,
                      final ValueModel pSelectedKeyVM, final Object pUnselectedKey)
    {
        if (pButtonGroup==null) throw new IllegalArgumentException("ButtonGroup must not be null");
        if (pDisplayedItemsVM==null) throw new IllegalArgumentException("DisplayedItemsVM must not be null");
        if (pKeysVM==null) throw new IllegalArgumentException("KeysVM must not be null");
        if (pSelectedKeyVM==null) throw new IllegalArgumentException("SelectedKeyVM must not be null");

        List displayedItems= getDisplayedList(pDisplayedItemsVM);
        List keys          = getKeysList     (pKeysVM);

        initButtonGroup(pButtonGroup, displayedItems, pDisplayedItemsVM, keys,
                        pKeysVM, pSelectedKeyVM, pUnselectedKey);
    }

    /**
     * Create a new adapter between the buttong group, the keys and the selected key.
     * @param pButtonGroup the button group, must not be null
     * @param pDisplayedItems the list containing the displayed items, must not be null, but not really used
     * @param pKeys the list containing the matching keys, must not be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     * @param pUnselectedKey the magic key, may be nulll
     */
    public LOVAdapter(final ButtonGroup pButtonGroup,
                      final List pDisplayedItems, final List pKeys,
                      final ValueModel pSelectedKeyVM, final Object pUnselectedKey)
    {
        if (pButtonGroup==null) throw new IllegalArgumentException("ButtonGroup must not be null");
        if (pDisplayedItems==null) throw new IllegalArgumentException("DisplayedItems must not be null");
        if (pKeys==null) throw new IllegalArgumentException("Keys must not be null");
        if (pSelectedKeyVM==null) throw new IllegalArgumentException("SelectedKeyVM must not be null");

        initButtonGroup(pButtonGroup, pDisplayedItems, null, pKeys, null, pSelectedKeyVM, pUnselectedKey);
    }

    /**
     * Common ButtonGroup init code.
     * @param pButtonGroup the button group, must not be null
     * @param pDisplayedItems the list containing the displayed items, must not be null, but not really used
     * @param pDisplayedItemsVM the value model holding the displayed items, may be null
     * @param pKeys the list containing the matching keys, must not be null
     * @param pKeysVM the value model holding the matching keys, may be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     * @param pUnselectedKey the magic key, may be nulll
     */
    private void initButtonGroup(final ButtonGroup pButtonGroup,
                                 final List pDisplayedItems, final ValueModel> pDisplayedItemsVM,
                                 final List pKeys, final ValueModel> pKeysVM,
                                 final ValueModel pSelectedKeyVM, final Object pUnselectedKey)
    {
        ListSelectionModel listSelectionModel= new DefaultListSelectionModel();
        init(pDisplayedItems, pDisplayedItemsVM, pKeys, pKeysVM,
             pSelectedKeyVM, pUnselectedKey, listSelectionModel, pButtonGroup);

        Enumeration e= pButtonGroup.getElements();
        while (e.hasMoreElements())
        {
            AbstractButton button = e.nextElement();
            button.addActionListener(this);

        }
        // set the widget according to to the current key
        vmSelectedKeyChanged(null);

    }

    /**
     * Return the list in a VM, or a empty null if null is the current value.
     * @param pValueModel the ValueModel, must not be null
     * @throws IllegalArgumentException if the ValueModel contains no list
     * @return a list, never null
     */
    private List getDisplayedList(final ValueModel> pValueModel)
    {
        List list= pValueModel.getValue();
        return list == null ? Collections.emptyList() : list;
    }

    /**
     * Return the list in a VM, or a empty null if null is the current value.
     * @param pValueModel the ValueModel, must not be null
     * @throws IllegalArgumentException if the ValueModel contains no list
     * @return a list, never null
     */
    private List getKeysList(final ValueModel> pValueModel)
    {
        List list= pValueModel.getValue();
        if (list==null)
            return Collections.emptyList();
        else return list;
    }


    /**
     * Common init stuff.
     */
    /**
     * Common init stuff.
     * @param pDisplayedItems the list containing the displayed items, must not be null, but not really used
     * @param pDisplayedItemsVM the value model holding the displayed items, may be null
     * @param pKeys the list containing the matching keys, must not be null
     * @param pKeysVM the value model holding the matching keys, may be null
     * @param pSelectedKeyVM the value model holding the key matching the selection keys, must not be null
     * @param pUnselectedKey the magic key, may be nulll
     * @param pListSelectionModel the list selection model, must not be null
     * @param pButtonGroup the button group, must not be null
     */
    private void init(final List pDisplayedItems, final ValueModel> pDisplayedItemsVM,
                      final List pKeys, final ValueModel> pKeysVM,
                      final ValueModel pSelectedKeyVM, final Object pUnselectedKey,
                      final ListSelectionModel pListSelectionModel, final ButtonGroup pButtonGroup)
    {
        mDisplayedItems     = pDisplayedItems;
        mDisplayedItemsVM   = pDisplayedItemsVM;
        mKeys               = pKeys;
        mKeysVM             = pKeysVM;
        mSelectedKeyVM      = pSelectedKeyVM;
        mUnselectedKey      = pUnselectedKey;
        mInSelectionChange  = false;
        mListenerList       = new EventListenerList();
        mListSelectionModel = pListSelectionModel;
        mListSelectionModel.setSelectionMode(SINGLE_SELECTION);
        mButtonGroup        = pButtonGroup;
        mIndex              = -1;

        // register callbacks
        if (mDisplayedItemsVM!=null)
        {
            // don't change the order, we depend on it, because mDisplayedItemsVM
            // and mKeysVM might be the same VM's, so only one of the changeSend's
            // get's registerd
            mDisplayedItemsVM.onChangeSend(this, "vmItemsChanged");
            mKeysVM.          onChangeSend(this, "vmKeysChanged");
        }
        mSelectedKeyVM.onChangeSend(this, "vmSelectedKeyChanged");
    }

    /**
     * Helper method to notify all listeners that something changed in our list model.
     * @param pListDataEvent the list data event to dispatch
     */
    protected void fireListChanged(final ListDataEvent pListDataEvent)
    {
        Object[] listeners = mListenerList.getListenerList();
        for (int i= listeners.length-2; i>=0; i-=2)
        {
            if (listeners[i]== ListDataListener.class)
            {
                ((ListDataListener)listeners[i+1]).contentsChanged(pListDataEvent);
            }
        }
    }

    /**
     * Return the selected index or -1 if there is no valid selection.
     * @return -1 or the selected index
     */
    public int getSelectedIndex()
    {
        return mIndex;
    }

    /**
     * Small helper to find the index for a key in the key list.
     * @param pKey the key we are searching the index for
     * @return -1 or the index of the key
     */
    public int getIndexByKey(final Object pKey)
    {
        for (int i = 0, n = mKeys.size(); i < n; i++)
        {
            Object key = mKeys.get(i);
            if (key==null && pKey==null)
            {
                return i;
            }
            else if (key!=null && key.equals(pKey))
            {
                return i;
            }
        }
        return -1;
    }

    /*
     * ValueModel callbacks
     */

    /**
     * Callback from our ValueModel holding the displayed items.
     * @param pEvent not used
     */
    @SuppressWarnings({"UnusedDeclaration"})
    public void vmItemsChanged(final ChangeEvent pEvent)
    {
        // ignore the changes we triggered
        if (mInSelectionChange)
        {
            return;
        }

        // notify the list to re-read the data, this will clear the selection,
        // so we re-set the selection afterwards, but only if we don't get
        // out of range
        int index = mIndex;
        mDisplayedItems= getDisplayedList(mDisplayedItemsVM);
        if (index<0 || index>=mDisplayedItems.size())
        {
            index= -1;
        }

        propagateChange(index);
        handleListSelection();
    }

    /**
     * Callback from our ValueModel holding the selected key.
     * @param pEvent not used
     */
    @SuppressWarnings({"UnusedDeclaration"})
    public void vmSelectedKeyChanged(final ChangeEvent pEvent)
    {
        // ignore the changes we triggered
        if (mInSelectionChange)
        {
            return;
        }

        mIndex= getIndexByKey(mSelectedKeyVM.getValue());
        propagateChange(mIndex);
    }

    /**
     * Callback from our ValueModel holding the possible keys.
     * @param pEvent not used
     */
    public void vmKeysChanged(final ChangeEvent pEvent)
    {
        // ignore the changes we triggered
        if (mInSelectionChange)
        {
            return;
        }

        mKeys = getKeysList(mKeysVM);
        mIndex= getIndexByKey(mSelectedKeyVM.getValue());

        // this is tricky: when the VM of the keys is also the VM containing the
        // displayed items, we need to call vmItemsChanged ourself, because the VM
        // can store only one call back method
        //noinspection ObjectEquality,RedundantCast
        if ((Object)mDisplayedItemsVM==(Object)mKeysVM)
        {
            vmItemsChanged(pEvent);
        }
        else
        {
            propagateChange(mIndex);
            handleListSelection();
        }
    }

    /**
     * Small helper to propagate the changes to our UI.
     * @param pIndex the new index
     */
    private void propagateChange(int pIndex)
    {
        mInSelectionChange= true;
        try
        {
            if (pIndex==-1)
                mListSelectionModel.clearSelection();
            else
                mListSelectionModel.setSelectionInterval(pIndex, pIndex);
            ListDataEvent e = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, pIndex, pIndex);
            fireListChanged(e);

            if (mButtonGroup!=null)
            {
                Enumeration elements= mButtonGroup.getElements();
                if (pIndex==-1)
                {
                    for (int i= 0; i < mButtonGroup.getButtonCount(); i++)
                    {
                        AbstractButton button = elements.nextElement();
                        button.setSelected(false);
                    }
                }
                else
                {
                    while (pIndex-->0)
                    {
                        elements.nextElement();
                    }
                    AbstractButton toBeSelected= elements.nextElement();
                    toBeSelected.setSelected(true);
                }
            }
        }
        finally
        {
            mInSelectionChange= false;
        }
    }

    /*
     * Swing ListSelectionModel callbacks
     */

    public void setSelectionInterval(final int pIndex0, final int pIndex1)
    {
        mListSelectionModel.setSelectionInterval(pIndex0, pIndex1);
        handleListSelection();
    }

    public void addSelectionInterval(final int pIndex0, final int pIndex1)
    {
        mListSelectionModel.addSelectionInterval(pIndex0, pIndex1);
        handleListSelection();
    }

    public void removeSelectionInterval(final int pIndex0, final int pIndex1)
    {
        mListSelectionModel.removeSelectionInterval(pIndex0, pIndex1);
        handleListSelection();
    }

    public void insertIndexInterval(final int pIndex, final int pLength, final boolean pBefore)
    {
        mListSelectionModel.insertIndexInterval(pIndex, pLength, pBefore);
        handleListSelection();
    }

    public void removeIndexInterval(final int pIndex0, final int pIndex1)
    {
        mListSelectionModel.removeIndexInterval(pIndex0, pIndex1);
        handleListSelection();
    }

    public void clearSelection()
    {
        mListSelectionModel.clearSelection();
        handleListSelection();
    }

    public int getMinSelectionIndex()
    {
        return mListSelectionModel.getMinSelectionIndex();
    }

    public int getMaxSelectionIndex()
    {
        return mListSelectionModel.getMaxSelectionIndex();
    }

    public boolean isSelectedIndex(final int pIndex)
    {
        //noinspection SimplifiableIfStatement
        if (pIndex == -1)
            return false;
        else
            return mListSelectionModel.isSelectedIndex(pIndex);
    }

    public int getAnchorSelectionIndex()
    {
        return mListSelectionModel.getAnchorSelectionIndex();
    }

    public void setAnchorSelectionIndex(final int pIndex)
    {
        mListSelectionModel.setAnchorSelectionIndex(pIndex);
    }

    public int getLeadSelectionIndex()
    {
        return mListSelectionModel.getLeadSelectionIndex();
    }

    public void setLeadSelectionIndex(final int pIndex)
    {
        mListSelectionModel.setLeadSelectionIndex(pIndex);
    }

    public boolean isSelectionEmpty()
    {
        return mListSelectionModel.isSelectionEmpty();
    }

    public void setValueIsAdjusting(final boolean pValueIsAdjusting)
    {
        mListSelectionModel.setValueIsAdjusting(pValueIsAdjusting);
    }

    public boolean getValueIsAdjusting()
    {
        return mListSelectionModel.getValueIsAdjusting();
    }

    public void setSelectionMode(final int pSelectionMode)
    {
        if (pSelectionMode!= SINGLE_SELECTION)
        {
            throw new IllegalArgumentException("this selection model only supports single selection");
        }
        mListSelectionModel.setSelectionMode(pSelectionMode);
    }

    public int getSelectionMode()
    {
        return mListSelectionModel.getSelectionMode();
    }

    public void addListSelectionListener(final ListSelectionListener pListener)
    {
        mListSelectionModel.addListSelectionListener(pListener);
    }

    public void removeListSelectionListener(final ListSelectionListener pListener)
    {
        mListSelectionModel.removeListSelectionListener(pListener);
    }

    /**
     * Helper method to propagate index changes from the Swing list selection model
     * to the selection VM. If we adapt radio buttons, this method is allso called from
     * actionPerformed method.
     */
    private void handleListSelection()
    {
        // ignore the changes we triggered
        if (mInSelectionChange)
        {
            return;
        }

        mInSelectionChange= true;
        try
        {
            mIndex= mListSelectionModel.getMinSelectionIndex();
            Object selectedKey;
            if (mIndex>= 0 && mIndex< mKeys.size())
            {
                selectedKey= mKeys.get(mIndex);
            }
            else
            {
                // bad: if the index is not -1, the size of the displayed stuff is
                //      out of sync with the keys we hope that the VM holding the
                //      keys will change soon and invalidate the selected key
                selectedKey= mUnselectedKey;
            }
            mSelectedKeyVM.setObjectValue(selectedKey);
        }
        finally
        {
            mInSelectionChange= false;
        }
    }

    /*
     * Swing ComboBoxModel/ListModel callbacks
     */

    public Object getSelectedItem()
    {
        return getElementAt(mIndex);
    }

    public void setSelectedItem(final Object pItem)
    {
        int index= -1;
        for (int i = 0, n = mDisplayedItems.size(); i < n; i++)
        {
            Object item = mDisplayedItems.get(i);
            //noinspection ObjectEquality
            if (pItem==item || (pItem != null && pItem.equals(item)))
            {
                index= i;
                break;
            }
        }
        setSelectionInterval(index, index);
    }

    public int getSize()
    {
        return mDisplayedItems.size();
    }

    public Object getElementAt(final int pIndex)
    {
        if (pIndex <0 || pIndex >=mDisplayedItems.size())
        {
            return null;
        }
        return mDisplayedItems.get(pIndex);
    }

    public void addListDataListener(final ListDataListener pListDataListener)
    {
        mListenerList.add(ListDataListener.class, pListDataListener);
    }

    public void removeListDataListener(final ListDataListener pListDataListener)
    {
        mListenerList.remove(ListDataListener.class, pListDataListener);
    }

    /*
     * Swing Button callbacks
     */

    /*
     * Called when the radio buttons change.
     * @param pEvent not used
     */
    public void actionPerformed(final ActionEvent pEvent)
    {
        ButtonModel                 selectedModel= mButtonGroup.getSelection();
        Enumeration e            = mButtonGroup.getElements();
        int                         index        = -1;
        for (int i= 0; i < mButtonGroup.getButtonCount(); i++)
        {
            AbstractButton button = e.nextElement();
            //noinspection ObjectEquality
            if (button.getModel()==selectedModel)
            {
                index= i;
                break;
            }
        }

        if (index==-1)
            mListSelectionModel.clearSelection();
        else
            mListSelectionModel.setSelectionInterval(index, index);
        handleListSelection();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy