package be.nikiroo.utils.ui; import java.awt.Component; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.JList; import javax.swing.JPopupMenu; import javax.swing.ListCellRenderer; import be.nikiroo.utils.compat.DefaultListModel6; import be.nikiroo.utils.compat.JList6; import be.nikiroo.utils.compat.ListCellRenderer6; /** * A {@link javax.swing.ListModel} that can maintain 2 lists; one with the * actual data (the elements), and a second one with the items that are * currently displayed (the items). *
* It also offers filter options, supports hovered changes and some more utility
* functions.
*
* @author niki
*
* @param
* Note that you must take care of passing a {@link JList} that only handles
* elements of the type of this {@link ListModel} -- you can also use
* {@link ListModel#ListModel(JList6)} instead.
*
* @param list
* the {@link JList} we will handle the data of (cannot be NULL,
* must only contain elements of the type of this
* {@link ListModel})
*/
@SuppressWarnings("rawtypes") // JList> not compatible Java 1.6
public ListModel(JList list) {
this(list, null);
}
/**
* Create a new {@link ListModel}.
*
* Note that you must take care of passing a {@link JList} that only handles
* elements of the type of this {@link ListModel} -- you can also use
* {@link ListModel#ListModel(JList6, JPopupMenu)} instead.
*
* @param list
* the {@link JList} we will handle the data of (cannot be NULL,
* must only contain elements of the type of this
* {@link ListModel})
* @param popup
* the popup to use and keep track of (can be NULL)
*/
@SuppressWarnings({ "unchecked", "rawtypes" }) // JList> not in Java 1.6
public ListModel(final JList list, final JPopupMenu popup) {
this.list = list;
list.setModel(this);
list.addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent me) {
if (popup != null && popup.isShowing())
return;
Point p = new Point(me.getX(), me.getY());
int index = list.locationToIndex(p);
if (index != hoveredIndex) {
int oldIndex = hoveredIndex;
hoveredIndex = index;
fireElementChanged(oldIndex);
fireElementChanged(index);
}
}
});
list.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
check(e);
}
@Override
public void mouseReleased(MouseEvent e) {
check(e);
}
@Override
public void mouseExited(MouseEvent e) {
if (popup != null && popup.isShowing())
return;
if (hoveredIndex > -1) {
int oldIndex = hoveredIndex;
hoveredIndex = -1;
fireElementChanged(oldIndex);
}
}
private void check(MouseEvent e) {
if (popup == null) {
return;
}
if (e.isPopupTrigger()) {
if (list.getSelectedIndices().length <= 1) {
list.setSelectedIndex(
list.locationToIndex(e.getPoint()));
}
popup.show(list, e.getX(), e.getY());
}
}
});
}
/**
* (Try and) keep the elements that were selected when filtering.
*
* This will use toString on the elements to identify them, and can be a bit
* resource intensive.
*
* @return TRUE if we do
*/
public boolean isKeepSelection() {
return keepSelection;
}
/**
* (Try and) keep the elements that were selected when filtering.
*
* This will use toString on the elements to identify them, and can be a bit
* resource intensive.
*
* @param keepSelection
* TRUE to try and keep them selected
*/
public void setKeepSelection(boolean keepSelection) {
this.keepSelection = keepSelection;
}
/**
* Check if this element is currently under the mouse.
*
* @param element
* the element to check
*
* @return TRUE if it is
*/
public boolean isHovered(T element) {
return indexOf(element) == hoveredIndex;
}
/**
* Check if this element is currently under the mouse.
*
* @param index
* the index of the element to check
*
* @return TRUE if it is
*/
public boolean isHovered(int index) {
return index == hoveredIndex;
}
/**
* Add an item to the model.
*
* @param item
* the new item to add
*/
public void addItem(T item) {
items.add(item);
}
/**
* Add items to the model.
*
* @param items
* the new items to add
*/
public void addAllItems(Collection
* This method will clear all the elements then look into all the items:
* those that pass the given filter will be copied as elements.
*
* @param filter
* the filter to select which elements to keep; an item that pass
* the filter will be copied as an element (can be NULL, in that
* case all items will be copied as elements)
*/
@SuppressWarnings("unchecked") // JList> not compatible Java 1.6
public void filter(Predicate