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

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

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

import java.util.List;

import net.sf.cuf.model.DelegateAccess;
import net.sf.cuf.model.SelectionInList;

import javax.swing.DefaultListSelectionModel;
import javax.swing.JList;
import javax.swing.ListSelectionModel;
import javax.swing.JComboBox;
import javax.swing.ComboBoxModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionListener;

/**
 * A ListModelAdapter connects a model of a JList or a JComboBox to a SelectionInList
 * ValueModel, the index for the selected list item is the index in the list/combobox.
 * The data in the list/combobox is taken from the SelectionInList, too, and a
 * DelegateAccess object may be used to convert from the "raw" object to a display object.
 * Whenever either the selection of the list or the index of the 
 * ValueModel changes, the other model is adjusted accordingly.
 * A ListModelAdapter is not a ValueModel itself, but connects a
 * SelectionInList ValueModel to a ListSelectionModel and a ListModel/ComboBoxModel.
 */
public class ListModelAdapter implements ComboBoxModel, ListSelectionModel
{
    /** list of listeners for our Swing ListModel, never null */
    private   EventListenerList   mListenerList;
    /** our delegate handling the Swing ListSelectionModel, never null */
    private   ListSelectionModel  mListSelectionModel;
    /** marker if we are inside a selection change, we then ignore selection
      * changes from the "other" model */
    private   boolean             mInSelectionChange; 
    /** value model holding the list, never null */
    protected SelectionInList  mSelectionInList;
    /** ValueModel to get the attribute, may be null */
    private DelegateAccess        mAccessValueModel;

    /**
     * Creates a new adapter between a SelectionInList ValueModel
     * and a JList.
     * @param pList the list for which we adapt to
     * @param pListValueModel the value model (SelectionInList) that drives the list
     *        (data, selection) and gets updated by the list (selection only)
     * @param pAccessValueModel null or the converter we use to map between the
     *                          SelectionInList list objects and the display objects
     * @throws IllegalArgumentException if pList or pValueModel is null
     */
    public ListModelAdapter(final JList pList, final SelectionInList pListValueModel,
                            final DelegateAccess pAccessValueModel)
    {
        if (pList==null)
            throw new IllegalArgumentException("list must not be null");
        if (pListValueModel==null)
            throw new IllegalArgumentException("list value model must not be null");

        mListSelectionModel= pList.getSelectionModel();
        if (mListSelectionModel==null)
        {
            throw new IllegalArgumentException("list selection model must not be null");
        }
        mListSelectionModel.setSelectionMode(SINGLE_SELECTION);

        mSelectionInList  = pListValueModel;
        mAccessValueModel = pAccessValueModel;
        mListenerList     = new EventListenerList();
        mInSelectionChange= false;

        mSelectionInList.onChangeSend                  (this, "vmDataChanged");
        mSelectionInList.selectionHolder().onChangeSend(this, "vmSelectionChanged");
        pList.setModel         (this);
        pList.setSelectionModel(this);
    }

    /**
     * Creates a new adapter between a SelectionInList ValueModel
     * and a JComboBox.
     * @param pComboBox the combobox for which we adapt to
     * @param pListValueModel the value model (SelectionInList) that drives the combobox
     *        (data, selection) and gets updated by the combobox (selection only)
     * @param pAccessValueModel null or the converter we use to map between the
     *                          SelectionInList list objects and the display objects
     * @throws IllegalArgumentException if pComboBox or pValueModel is null
     */
    public ListModelAdapter(final JComboBox pComboBox, final SelectionInList pListValueModel, final DelegateAccess pAccessValueModel)
    {
        if (pComboBox==null)
            throw new IllegalArgumentException("combobox must not be null");
        if (pListValueModel==null)
            throw new IllegalArgumentException("list value model must not be null");

        mSelectionInList  = pListValueModel;
        mAccessValueModel = pAccessValueModel;
        mListenerList     = new EventListenerList();
        mInSelectionChange= false;
        mListSelectionModel = new DefaultListSelectionModel();
        mListSelectionModel.setSelectionMode(SINGLE_SELECTION);

        mSelectionInList.onChangeSend                  (this, "vmDataChanged");
        mSelectionInList.selectionHolder().onChangeSend(this, "vmSelectionChanged");
        pComboBox.setModel(this);
    }

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

    /**
     * Callback from our VM
     * @param pEvent not used
     */
    @SuppressWarnings({"UnusedDeclaration"})
    public void vmDataChanged(final ChangeEvent pEvent)
    {
        // notify the list to re-read the data, this will clear the selection,
        // so we re-set the selection afterwards
        int index = mSelectionInList.selectionHolder().intValue();

        mInSelectionChange = true;
        try
        {
            List data= mSelectionInList.getValue();
            int     size= (data==null? 0: data.size());
            ListDataEvent e = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, size);
            fireListChanged(e);
            if (index<0 || index>=size)
                mListSelectionModel.clearSelection();
            else
                mListSelectionModel.setSelectionInterval(index, index);
        }
        finally
        {
            mInSelectionChange= false;
        }
    }

    /**
     * Callback from our VM
     * @param pEvent not used
     */
    @SuppressWarnings({"UnusedDeclaration"})
    public void vmSelectionChanged(final ChangeEvent pEvent)
    {
        // ignore the changes we triggered
        if (mInSelectionChange)
        {
            return;
        }

        mInSelectionChange= true;
        try
        {
            // re-adjust the selection in our JList/JComboBox
            int index= mSelectionInList.selectionHolder().intValue();
            if (index==-1)
                mListSelectionModel.clearSelection();
            else
                mListSelectionModel.setSelectionInterval(index, index);
            ListDataEvent e = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index);
            fireListChanged(e);
        }
        finally
        {
            mInSelectionChange= false;
        }
    }
    
    /**
     * Common Swing ComboBoxModel callback code
     */
    private void handleListSelection()
    {
        // ignore the changes we triggered
        if (mInSelectionChange)
        {
            return;
        }
        // ignore changes when the ListSelectionModel is adjusting
        if (mListSelectionModel.getValueIsAdjusting())
        {
            return;
        }

        mInSelectionChange= true;
        try
        {
            mSelectionInList.selectionHolder().setValue(mListSelectionModel.getMinSelectionIndex());
        }
        finally
        {
            mInSelectionChange= false;
        }
    }

    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)
    {
        if (pIndex == -1)
        {
            return false;
        }

        return mListSelectionModel.isSelectedIndex(pIndex);
    }

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

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

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

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

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

    public void setValueIsAdjusting(final boolean pValueIsAdjusting)
    {
        if (pValueIsAdjusting!=mListSelectionModel.getValueIsAdjusting())
        {
            mListSelectionModel.setValueIsAdjusting(pValueIsAdjusting);
            handleListSelection();
        }
    }

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

    public Object getSelectedItem()
    {
        int index= mSelectionInList.getIndex();
        return getElementAt(index);
    }

    public void setSelectedItem(final Object pItem)
    {
        int index= getIndexByObject(pItem);
        setSelectionInterval(index, index);
    }

	/*
	 * Implementations of ListModel-Interface
	 */
	public Object getElementAt(final int pIndex)
    {
        if (pIndex==-1)
        {
            return null;
        }
        List list = mSelectionInList.getValue();
        Object  value= list.get(pIndex);
        if (mAccessValueModel != null)
        {
            value= mAccessValueModel.getValue(value);
        }
        return value;
	}

    public int getSize() 
    {   
        if (mSelectionInList.getValue() != null)
        {
            return mSelectionInList.getValue().size();
        }      
        return 0;
	}

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

    public void removeListDataListener(final ListDataListener pListener)
    {
        mListenerList.remove(ListDataListener.class, pListener);
    }
    
    /*
     * Additional methods for our ListModel
     */

    /**
     * Add the item to the list.
     * @see SelectionInList#addItem(Object)
     *
     * @param   pObj   the component to be added
     */
    public void addElement(final Object pObj)
    {
        // i don't understand generics, but the cast helps to make the compiler happy, so ...
        ((SelectionInList)mSelectionInList).addItem(pObj);
    }

    /**
     * Removes the item from the list.
     * @see SelectionInList#removeItem(int)
     *
     * @param   pObj   the component to be removed
     */
    public void removeElement(final Object pObj)
    {
        int index = getIndexByObject(pObj);

        if (index >= 0)
        {
            mSelectionInList.removeItem(index);
        }
    }

    /**
     * Small helper to find a item in our list.
     * The item may be of a different type than the entries in our list, if
     * a DelegateAccess object is used for display conversion.
     * @param pItem the (display) object we are searching
     * @return -1 or the index of the item
     */
    public int getIndexByObject(final Object pItem)
    {
        List list = mSelectionInList.getValue();
        if (list==null)
        {
        	return -1;
        }
        int index = -1;
        if(mAccessValueModel != null)
        {
            for (int i = 0, n = list.size(); i < n; i++)
            {
                Object item = mAccessValueModel.getValue(list.get(i));
                // if the items are equal (including null==null);
                //noinspection ObjectEquality
                if (pItem==item || (pItem != null && pItem.equals(item)))
                {
                    index= i;
                    break;
                }
            }
        }
        else
        {
            index = list.indexOf(pItem);
        }
        return index;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy