/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * CheckBoxList.java * Copyright (C) 2006 University of Waikato, Hamilton, New Zealand */ package weka.gui; import java.awt.Component; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Vector; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JList; import javax.swing.ListCellRenderer; import javax.swing.ListModel; /** * An extended JList that contains CheckBoxes. If necessary a CheckBoxListItem * wrapper is added around the displayed object in any of the Model methods, * e.g., addElement. For methods returning objects the opposite takes place, * the wrapper is removed and only the payload object is returned. * * @author fracpete (fracpete at waikato dot ac dot nz) * @version $Revision: 1.3 $ */ public class CheckBoxList extends JList { /** for serialization */ private static final long serialVersionUID = -4359573373359270258L; /** * represents an item in the CheckBoxListModel * * @author fracpete (fracpete at waikato dot ac dot nz) * @version $Revision: 1.3 $ */ protected class CheckBoxListItem { /** whether item is checked or not */ private boolean m_Checked = false; /** the actual object */ private Object m_Content = null; /** * initializes the item with the given object and initially unchecked * * @param o the content object */ public CheckBoxListItem(Object o) { this(o, false); } /** * initializes the item with the given object and whether it's checked * initially * * @param o the content object * @param checked whether the item should be checked initially */ public CheckBoxListItem(Object o, boolean checked) { m_Checked = checked; m_Content = o; } /** * returns the content object */ public Object getContent() { return m_Content; } /** * sets the checked state of the item */ public void setChecked(boolean value) { m_Checked = value; } /** * returns the checked state of the item */ public boolean getChecked() { return m_Checked; } /** * returns the string representation of the content object */ public String toString() { return m_Content.toString(); } /** * returns true if the "payload" objects of the current and the given * CheckBoxListItem are the same. * * @param o the CheckBoxListItem to check * @throws IllegalArgumentException if the provided object is not a CheckBoxListItem */ public boolean equals(Object o) { if (!(o instanceof CheckBoxListItem)) throw new IllegalArgumentException("Must be a CheckBoxListItem!"); return getContent().equals(((CheckBoxListItem) o).getContent()); } } /** * A specialized model. * * @author fracpete (fracpete at waikato dot ac dot nz) * @version $Revision: 1.3 $ */ public class CheckBoxListModel extends DefaultListModel { /** for serialization */ private static final long serialVersionUID = 7772455499540273507L; /** * initializes the model with no data. */ public CheckBoxListModel() { super(); } /** * Constructs a CheckBoxListModel from an array of objects and then applies * setModel to it. * * @param listData the data to use */ public CheckBoxListModel(Object[] listData) { for (int i = 0; i < listData.length; i++) addElement(listData[i]); } /** * Constructs a CheckBoxListModel from a Vector and then applies setModel * to it. */ public CheckBoxListModel(Vector listData) { for (int i = 0; i < listData.size(); i++) addElement(listData.get(i)); } /** * Inserts the specified element at the specified position in this list. * * @param index index at which the specified element is to be inserted * @param element element to be inserted */ public void add(int index, Object element) { if (!(element instanceof CheckBoxListItem)) super.add(index, new CheckBoxListItem(element)); else super.add(index, element); } /** * Adds the specified component to the end of this list. * * @param obj the component to be added */ public void addElement(Object obj) { if (!(obj instanceof CheckBoxListItem)) super.addElement(new CheckBoxListItem(obj)); else super.addElement(obj); } /** * Tests whether the specified object is a component in this list. * * @param elem the element to check * @return true if the element is in the list */ public boolean contains(Object elem) { if (!(elem instanceof CheckBoxListItem)) return super.contains(new CheckBoxListItem(elem)); else return super.contains(elem); } /** * Copies the components of this list into the specified array. * * @param anArray the array into which the components get copied * @throws IndexOutOfBoundsException if the array is not big enough */ public void copyInto(Object[] anArray) { if (anArray.length < getSize()) throw new IndexOutOfBoundsException("Array not big enough!"); for (int i = 0; i < getSize(); i++) anArray[i] = ((CheckBoxListItem) getElementAt(i)).getContent(); } /** * Returns the component at the specified index. Throws an * ArrayIndexOutOfBoundsException if the index is negative or not less * than the size of the list. * * @param index an index into this list * @return the component at the specified index * @throws ArrayIndexOutOfBoundsException */ public Object elementAt(int index) { return ((CheckBoxListItem) super.elementAt(index)).getContent(); } /** * Returns the first component of this list. Throws a * NoSuchElementException if this vector has no components. * * @return the first component of this list * @throws NoSuchElementException */ public Object firstElement() { return ((CheckBoxListItem) super.firstElement()).getContent(); } /** * Returns the element at the specified position in this list. * * @param index of element to return * @throws ArrayIndexOutOfBoundsException */ public Object get(int index) { return ((CheckBoxListItem) super.get(index)).getContent(); } /** * Returns the component at the specified index. * * @param index an index into this list * @return the component at the specified index * @throws ArrayIndexOutOfBoundsException */ public Object getElementAt(int index) { return ((CheckBoxListItem) super.getElementAt(index)).getContent(); } /** * Searches for the first occurrence of elem. * * @param elem an object * @return the index of the first occurrence of the argument in this list; * returns -1 if the object is not found */ public int indexOf(Object elem) { if (!(elem instanceof CheckBoxListItem)) return super.indexOf(new CheckBoxListItem(elem)); else return super.indexOf(elem); } /** * Searches for the first occurrence of elem, beginning the search at index. * * @param elem the desired component * @param index the index from which to begin searching * @return the index where the first occurrence of elem is found after index; * returns -1 if the elem is not found in the list */ public int indexOf(Object elem, int index) { if (!(elem instanceof CheckBoxListItem)) return super.indexOf(new CheckBoxListItem(elem), index); else return super.indexOf(elem, index); } /** * Inserts the specified object as a component in this list at the * specified index. * * @param obj the component to insert * @param index where to insert the new component * @throws ArrayIndexOutOfBoundsException */ public void insertElementAt(Object obj, int index) { if (!(obj instanceof CheckBoxListItem)) super.insertElementAt(new CheckBoxListItem(obj), index); else super.insertElementAt(obj, index); } /** * Returns the last component of the list. Throws a NoSuchElementException * if this vector has no components. * * @return the last component of the list * @throws NoSuchElementException */ public Object lastElement() { return ((CheckBoxListItem) super.lastElement()).getContent(); } /** * Returns the index of the last occurrence of elem. * * @param elem the desired component * @return the index of the last occurrence of elem in the list; * returns -1 if the object is not found */ public int lastIndexOf(Object elem) { if (!(elem instanceof CheckBoxListItem)) return super.lastIndexOf(new CheckBoxListItem(elem)); else return super.lastIndexOf(elem); } /** * Searches backwards for elem, starting from the specified index, * and returns an index to it. * * @param elem the desired component * @param index the index to start searching from * @return the index of the last occurrence of the elem in this * list at position less than index; returns -1 if the * object is not found */ public int lastIndexOf(Object elem, int index) { if (!(elem instanceof CheckBoxListItem)) return super.lastIndexOf(new CheckBoxListItem(elem), index); else return super.lastIndexOf(elem, index); } /** * Removes the element at the specified position in this list. Returns the * element that was removed from the list. * * @param index the index of the element to removed * @throws ArrayIndexOutOfBoundsException */ public Object remove(int index) { return ((CheckBoxListItem) super.remove(index)).getContent(); } /** * Removes the first (lowest-indexed) occurrence of the argument from this * list. * * @param obj the component to be removed * @return true if the argument was a component of this list; * false otherwise */ public boolean removeElement(Object obj) { if (!(obj instanceof CheckBoxListItem)) return super.removeElement(new CheckBoxListItem(obj)); else return super.removeElement(obj); } /** * Replaces the element at the specified position in this list with the * specified element. * * @param index index of element to replace * @param element element to be stored at the specified position * @throws ArrayIndexOutOfBoundsException */ public Object set(int index, Object element) { if (!(element instanceof CheckBoxListItem)) return ((CheckBoxListItem) super.set(index, new CheckBoxListItem(element))).getContent(); else return ((CheckBoxListItem) super.set(index, element)).getContent(); } /** * Sets the component at the specified index of this list to be the * specified object. The previous component at that position is discarded. * * @param obj what the component is to be set to * @param index the specified index * @throws ArrayIndexOutOfBoundsException */ public void setElementAt(Object obj, int index) { if (!(obj instanceof CheckBoxListItem)) super.setElementAt(new CheckBoxListItem(obj), index); else super.setElementAt(obj, index); } /** * Returns an array containing all of the elements in this list in the * correct order. * * @return an array containing the elements of the list */ public Object[] toArray() { Object[] result; Object[] internal; int i; internal = super.toArray(); result = new Object[internal.length]; for (i = 0; i < internal.length; i++) result[i] = ((CheckBoxListItem) internal[i]).getContent(); return result; } /** * returns the checked state of the element at the given index * * @param index the index of the element to return the checked state for * @return the checked state of the specifed element */ public boolean getChecked(int index) { return ((CheckBoxListItem) super.getElementAt(index)).getChecked(); } /** * sets the checked state of the element at the given index * * @param index the index of the element to set the checked state for * @param checked the new checked state */ public void setChecked(int index, boolean checked) { ((CheckBoxListItem) super.getElementAt(index)).setChecked(checked); } } /** * A specialized CellRenderer for the CheckBoxList * * @author fracpete (fracpete at waikato dot ac dot nz) * @version $Revision: 1.3 $ * @see CheckBoxList */ public class CheckBoxListRenderer extends JCheckBox implements ListCellRenderer { /** for serialization */ private static final long serialVersionUID = 1059591605858524586L; /** * Return a component that has been configured to display the specified * value. * * @param list The JList we're painting. * @param value The value returned by list.getModel().getElementAt(index). * @param index The cells index. * @param isSelected True if the specified cell was selected. * @param cellHasFocus True if the specified cell has the focus. * @return A component whose paint() method will render the * specified value. */ public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { setText(value.toString()); setSelected(((CheckBoxList) list).getChecked(index)); setBackground(isSelected ? list.getSelectionBackground() : list.getBackground()); setForeground(isSelected ? list.getSelectionForeground() : list.getForeground()); setFocusPainted(false); return this; } } /** * initializes the list with an empty CheckBoxListModel */ public CheckBoxList() { this(null); } /** * initializes the list with the given CheckBoxListModel * * @param model the model to initialize with */ public CheckBoxList(CheckBoxListModel model) { super(); if (model == null) model = this.new CheckBoxListModel(); setModel(model); setCellRenderer(new CheckBoxListRenderer()); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { int index = locationToIndex(e.getPoint()); if (index != -1) { setChecked(index, !getChecked(index)); repaint(); } } }); addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { if ( (e.getKeyChar() == ' ') && (e.getModifiers() == 0) ) { int index = getSelectedIndex(); setChecked(index, !getChecked(index)); e.consume(); repaint(); } } }); } /** * sets the model - must be an instance of CheckBoxListModel * * @param model the model to use * @throws IllegalArgumentException if the model is not an instance of * CheckBoxListModel * @see CheckBoxListModel */ public void setModel(ListModel model) { if (!(model instanceof CheckBoxListModel)) throw new IllegalArgumentException("Model must be an instance of CheckBoxListModel!"); super.setModel(model); } /** * Constructs a CheckBoxListModel from an array of objects and then applies * setModel to it. * * @param listData the data to use */ public void setListData(Object[] listData) { setModel(new CheckBoxListModel(listData)); } /** * Constructs a CheckBoxListModel from a Vector and then applies setModel * to it. */ public void setListData(Vector listData) { setModel(new CheckBoxListModel(listData)); } /** * returns the checked state of the element at the given index * * @param index the index of the element to return the checked state for * @return the checked state of the specifed element */ public boolean getChecked(int index) { return ((CheckBoxListModel) getModel()).getChecked(index); } /** * sets the checked state of the element at the given index * * @param index the index of the element to set the checked state for * @param checked the new checked state */ public void setChecked(int index, boolean checked) { ((CheckBoxListModel) getModel()).setChecked(index, checked); } /** * returns an array with the indices of all checked items * * @return the indices of all items that are currently checked */ public int[] getCheckedIndices() { Vector list; int[] result; int i; // traverse over model list = new Vector(); for (i = 0; i < getModel().getSize(); i++) { if (getChecked(i)) list.add(new Integer(i)); } // generate result array result = new int[list.size()]; for (i = 0; i < list.size(); i++) { result[i] = ((Integer) list.get(i)).intValue(); } return result; } }