package prefuse.data.query;
import java.util.ArrayList;
import javax.swing.DefaultListSelectionModel;
import javax.swing.MutableComboBoxModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import prefuse.util.collections.CopyOnWriteArrayList;
/**
* List data model supporting both data modeling and selection management.
* Though generally useful, this has been designed particularly to support
* dynamic queries.
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public class ListModel extends DefaultListSelectionModel
implements MutableComboBoxModel
{
private ArrayList m_items = new ArrayList();
private CopyOnWriteArrayList m_lstnrs = new CopyOnWriteArrayList();
/**
* Create an empty ListModel.
*/
public ListModel() {
// do nothing
}
/**
* Create a ListModel with the provided items.
* @param items the items for the data model.
*/
public ListModel(final Object[] items) {
for ( int i=0; i<items.length; ++i )
m_items.add(items[i]);
}
// --------------------------------------------------------------------
/**
* Indicates if the ListModel currently has multiple selections.
* @return true if there are multiple selections, false otherwise
*/
private boolean isMultipleSelection() {
return getMaxSelectionIndex()-getMinSelectionIndex() > 0;
}
/**
* @see javax.swing.ComboBoxModel#getSelectedItem()
*/
public Object getSelectedItem() {
int idx = getMinSelectionIndex();
return ( idx == -1 ? null : m_items.get(idx) );
}
/**
* @see javax.swing.ComboBoxModel#setSelectedItem(java.lang.Object)
*/
public void setSelectedItem(Object item) {
int idx = m_items.indexOf(item);
if ( idx < 0 ) return;
if ( !isMultipleSelection() && idx == getMinSelectionIndex() )
return;
super.setSelectionInterval(idx,idx);
fireDataEvent(this,ListDataEvent.CONTENTS_CHANGED,-1,-1);
}
/**
* @see javax.swing.ListModel#getSize()
*/
public int getSize() {
return m_items.size();
}
/**
* @see javax.swing.ListModel#getElementAt(int)
*/
public Object getElementAt(int idx) {
return m_items.get(idx);
}
/**
* @see javax.swing.MutableComboBoxModel#addElement(java.lang.Object)
*/
public void addElement(Object item) {
m_items.add(item);
int sz = m_items.size()-1;
fireDataEvent(this,ListDataEvent.INTERVAL_ADDED,sz,sz);
if ( sz >= 0 && isSelectionEmpty() && item != null )
setSelectedItem(item);
}
/**
* @see javax.swing.MutableComboBoxModel#insertElementAt(java.lang.Object, int)
*/
public void insertElementAt(Object item, int idx) {
m_items.add(idx, item);
fireDataEvent(this,ListDataEvent.INTERVAL_ADDED,idx,idx);
}
/**
* @see javax.swing.MutableComboBoxModel#removeElement(java.lang.Object)
*/
public void removeElement(Object item) {
int idx = m_items.indexOf(item);
if ( idx >= 0 )
removeElementAt(idx);
}
/**
* @see javax.swing.MutableComboBoxModel#removeElementAt(int)
*/
public void removeElementAt(int idx) {
if ( !isMultipleSelection() && idx == getMinSelectionIndex() ) {
int sidx = ( idx==0 ? getSize()==1 ? -1 : idx+1 : idx-1 );
Object sel = ( sidx == -1 ? null : m_items.get(sidx) );
setSelectedItem(sel);
}
m_items.remove(idx);
fireDataEvent(this,ListDataEvent.INTERVAL_REMOVED,idx,idx);
}
// --------------------------------------------------------------------
// List Data Listeners
/**
* @see javax.swing.ListModel#addListDataListener(javax.swing.event.ListDataListener)
*/
public void addListDataListener(ListDataListener l) {
if ( !m_lstnrs.contains(l) )
m_lstnrs.add(l);
}
/**
* @see javax.swing.ListModel#removeListDataListener(javax.swing.event.ListDataListener)
*/
public void removeListDataListener(ListDataListener l) {
m_lstnrs.remove(l);
}
/**
* Fires a change notification in response to changes in the ListModel.
*/
protected void fireDataEvent(Object src, int type, int idx0, int idx1) {
Object[] lstnrs = m_lstnrs.getArray();
if ( lstnrs.length > 0 ) {
ListDataEvent e = new ListDataEvent(src, type, idx0, idx1);
for ( int i=0; i<lstnrs.length; ++i ) {
((ListDataListener)lstnrs[i]).contentsChanged(e);
}
}
}
} // end of class ListModel