package dk.itu.oop.lecture11; import java.awt.*; import javax.swing.*; import javax.swing.event.*; import java.util.*; /** Selecting list is a GUI component with two parts, a filter and a list. * Only elements that contain the filter will be shown in the list. * The selecting list has a raw list, which are the elements which * are filtered. **/ public class SelectingList extends JPanel{ private final JList jlist; private final SelectingListModel listModel; JTextField selText; public SelectingList(Object[] elements){ // set up the list listModel = new SelectingListModel( elements ); jlist = new JList( listModel ); jlist.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); // and the text field selText = new JTextField( 12 ); // layout this.setLayout( new BorderLayout() ); this.add( selText,"North" ); this.add( new JScrollPane( jlist ) ,"Center" ); // add the internal listeners selText.addCaretListener( new CaretListener(){ public void caretUpdate(CaretEvent e){ listModel.updateFilter( selText.getText() ); if ( listModel.getSize() == 1 ) jlist.setSelectedIndex(0); else jlist.clearSelection(); } }); jlist.addListSelectionListener(new ListSelectionListener(){ public void valueChanged(ListSelectionEvent e){ if (! e.getValueIsAdjusting() ) if ( jlist.isSelectionEmpty() ) notifyListeners( null ); else notifyListeners(listModel .getElementAt( jlist.getMinSelectionIndex() ) ); } }); } /** The listener interface used to listen for new selections from this list. * new selections occur when an element is selected from the list, or when * the filter become so specific that only one element remains in the list. */ public static interface Listener { /* The Event object contains a source which says what list the selection * was made in, and an object which is the selection made. */ public static class Event extends EventObject{ private Object selection; // private constructor - we make these objects internally private Event(SelectingList sl, Object sel){ super(sl); selection=sel; } /** return the selection made in the list. * return null if an element is deselected */ public Object getSelection(){ return selection; } } void selectionChanged(Event e); } private ArrayList listeners = new ArrayList(); private void notifyListeners(Object selection){ Listener.Event ev = new Listener.Event(this, selection); Iterator itr = listeners.iterator(); while ( itr.hasNext() ){ Listener l = (Listener)itr.next(); l.selectionChanged(ev); } } /** Add a Listener to this SelectingList */ public void addListener(Listener l){ listeners.add(l); } /** Remove the Listener from this SelectionList */ public void removeListener(Listener l){ listeners.remove(l); } /* SelectingListModel is used internally. It is not intended to bee seen * from the outside */ private static class SelectingListModel extends AbstractListModel implements Observer{ // The rawData is the list of all elements, no filtering is done private final Object[] rawData; // the filteredData is a list which only contains those elements // which matches the filter private java.util.List filteredData = new ArrayList(); // the current filter private String filter; SelectingListModel(Object[] raw){ rawData = raw; updateFilter(""); } /* this method returns true if the argument matches the filter. * a match occurs if the filter is a substring of o.toString * the match is case-insensitive */ private boolean checkAgainstFilter(Object o){ String data = o.toString().toLowerCase(); String filter = this.filter.toLowerCase(); return data.indexOf(filter) >=0; } /* update the filter and the filtered list */ void updateFilter(String newFilter){ filter = newFilter; Iterator itr = filteredData.iterator(); while (itr.hasNext()){ Object o = itr.next(); if (o instanceof Observable) ( (Observable) o).deleteObserver(this); } filteredData.clear(); for (int i = 0; i