package org.esa.snap.ui.util;
import javax.swing.AbstractListModel;
import javax.swing.ListModel;
import javax.swing.SwingWorker;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import java.util.ArrayList;
// found at http://stackoverflow.com/questions/14758313/filtering-jlist-based-on-jtextfield
public class FilteredListModel<T> extends AbstractListModel {
public static interface Filter<T> {
boolean accept(T element);
}
private final ListModel<T> sourceModel;
private Filter<T> filter;
private final ArrayList<Integer> indices = new ArrayList<>();
public FilteredListModel(ListModel<T> source) {
if (source == null) {
throw new IllegalArgumentException("Source is null");
}
sourceModel = source;
sourceModel.addListDataListener(new ListDataListener() {
public void intervalRemoved(ListDataEvent e) {
doFilter();
}
public void intervalAdded(ListDataEvent e) {
doFilter();
}
public void contentsChanged(ListDataEvent e) {
doFilter();
}
});
}
public void setFilter(Filter<T> f) {
filter = f;
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
doFilter();
return null;
}
@Override
protected void done() {
fireContentsChanged(this, 0, getSize() - 1);
}
};
worker.execute();
}
private void doFilter() {
indices.clear();
Filter<T> f = filter;
if (f != null) {
int count = sourceModel.getSize();
for (int i = 0; i < count; i++) {
T element = sourceModel.getElementAt(i);
if (f.accept(element)) {
indices.add(i);
}
}
}
}
@Override
public int getSize() {
return (filter != null) ? indices.size() : sourceModel.getSize();
}
@Override
public T getElementAt(int index) {
return (filter != null) ? sourceModel.getElementAt(indices.get(index)) : sourceModel.getElementAt(index);
}
}