/** 类,编译就可以用 */
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
/**
* TableSorter is a decorator for TableModels; adding sorting functionality to a
* supplied TableModel. TableSorter does not store or copy the data in its
* TableModel; instead it maintains a map from the row indexes of the view to
* the row indexes of the model. As requests are made of the sorter (like
* getValueAt(row, col)) they are passed to the underlying model after the row
* numbers have been translated via the internal mapping array. This way, the
* TableSorter appears to hold another copy of the table with the rows in a
* different order.
*
* TableSorter registers itself as a listener to the underlying model, just as
* the JTable itself would. Events recieved from the model are examined,
* sometimes manipulated (typically widened), and then passed on to the
* TableSorter's listeners (typically the JTable). If a change to the model has
* invalidated the order of TableSorter's rows, a note of this is made and the
* sorter will resort the rows the next time a value is requested.
*
* When the tableHeader property is set, either by using the setTableHeader()
* method or the two argument constructor, the table header may be used as a
* complete UI for TableSorter. The default renderer of the tableHeader is
* decorated with a renderer that indicates the sorting status of each column.
* In addition, a mouse listener is installed with the following behavior:
*
* Mouse-click: Clears the sorting status of all other columns and advances the
* sorting status of that column through three values: {NOT_SORTED, ASCENDING,
* DESCENDING} (then back to NOT_SORTED again).
*
* SHIFT-mouse-click: Clears the sorting status of all other columns and cycles
* the sorting status of the column through the same three values, in the
* opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.
*
* CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except that the
* changes to the column do not cancel the statuses of columns that are already
* sorting - giving a way to initiate a compound sort.
*
* This is a long overdue rewrite of a class of the same name that first
* appeared in the swing table demos in 1997.
*
* @author Philip Milne
* @author Brendon McLean
* @author Dan van Enckevort
* @author Parwinder Sekhon
* @version 2.0 02/27/04
*/
public class TableSorter extends AbstractTableModel {
protected TableModel tableModel;
public static final int DESCENDING = -1;
public static final int NOT_SORTED = 0;
public static final int ASCENDING = 1;
private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() {
public int compare(Object o1, Object o2) {
return ((Comparable) o1).compareTo(o2);
}
};
public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
public int compare(Object o1, Object o2) {
return o1.toString().compareTo(o2.toString());
}
};
private Row[] viewToModel;
private int[] modelToView;
private JTableHeader tableHeader;
private MouseListener mouseListener;
private TableModelListener tableModelListener;
private Map columnComparators = new HashMap();
private List sortingColumns = new ArrayList();
public void setSortingColumns(List sortingColumns)
{
this.sortingColumns = sortingColumns;
}
public TableSorter() {
this.mouseListener = new MouseHandler();
this.tableModelListener = new TableModelHandler();
}
public TableSorter(TableModel tableModel) {
this();
sortingColumns.add(new TableSorter.Directive(0,1));
sortingColumns.add(new TableSorter.Directive(1,1));
setTableModel(tableModel);
}
public TableSorter(TableModel tableModel, JTableHeader tableHeader) {
this();
setTableHeader(tableHeader);
setTableModel(tableModel);
}
private void clearSortingState() {
viewToModel = null;
modelToView = null;
}
public TableModel getTableModel() {
return tableModel;
}
public void setTableModel(TableModel tableModel) {
if (this.tableModel != null) {
this.tableModel.removeTableModelListener(tableModelListener);
}
this.tableModel = tableModel;
if (this.tableModel != null) {
this.tableModel.addTableModelListener(tableModelListener);
}
clearSortingState();
fireTableStructureChanged();
}
public JTableHeader getTableHeader() {
return tableHeader;
}
public void setTableHeader(JTableHeader tableHeader) {
if (this.tableHeader != null) {
this.tableHeader.removeMouseListener(mouseListener);
TableCellRenderer defaultRenderer = this.tableHeader
.getDefaultRenderer();
if (defaultRenderer instanceof SortableHeaderRenderer) {
this.tableHeader
.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
}
}
this.tableHeader = tableHeader;
if (this.tableHeader != null) {
this.tableHeader.addMouseListener(mouseListener);
this.tableHeader.setDefaultRenderer(new SortableHeaderRenderer(
this.tableHeader.getDefaultRenderer()));
}
}
public boolean isSorting() {
return sortingColumns.size() != 0;
}
private Directive getDirective(int column) {
for (int i = 0; i < sortingColumns.size(); i++) {
Directive directive = (Directive) sortingColumns.get(i);
if (directive.column == column) {
return directive;
}
}
return EMPTY_DIRECTIVE;
}
public int getSortingStatus(int column) {
return getDirective(column).direction;
}
private void sortingStatusChanged() {
clearSortingState();
fireTableDataChanged();
if (tableHeader != null) {
tableHeader.repaint();
}
}
public void setSortingStatus(int column, int status) {
Directive directive = getDirective(column);
if (directive != EMPTY_DIRECTIVE) {
sortingColumns.remove(directive);
}
if (status != NOT_SORTED) {
sortingColumns.add(new Directive(column, status));
}
sortingStatusChanged();
}
protected Icon getHeaderRendererIcon(int column, int size) {
Directive directive = getDirective(column);
if (directive == EMPTY_DIRECTIVE) {
return null;
}
return new Arrow(directive.direction == DESCENDING, size,
sortingColumns.indexOf(directive));
}
private void cancelSorting() {
sortingColumns.clear();
sortingStatusChanged();
}
public void setColumnComparator(Class type, Comparator comparator) {
if (comparator == null) {
columnComparators.remove(type);
} else {
columnComparators.put(type, comparator);
}
}
protected Comparator getComparator(int column) {
Class columnType = tableModel.getColumnClass(column);
Comparator comparator = (Comparator) columnComparators.get(columnType);
if (comparator != null) {
return comparator;
}
if (Comparable.class.isAssignableFrom(columnType)) {
return COMPARABLE_COMAPRATOR;
}
return LEXICAL_COMPARATOR;
}
private Row[] getViewToModel() {
if (viewToModel == null) {
int tableModelRowCount = tableModel.getRowCount();
viewToModel = new Row[tableModelRowCount];
for (int row = 0; row < tableModelRowCount; row++) {