📄 tablesorter.java
字号:
package org.hsqldb.util;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 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 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. * <p/> * 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. * <p/> * 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: * <ul> * <li> * 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). * <li> * 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}. * <li> * 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. * </ul> * <p/> * 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_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { if (o1 == o2) { return 0; } if (o1 == null) { if (o2 == null) { return 0; } return -1; } if (o2 == null) { return 1; } 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 TableSorter() { this.mouseListener = new MouseHandler(); this.tableModelListener = new TableModelHandler(); } public TableSorter(TableModel tableModel) { this(); 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_COMPARATOR; } return LEXICAL_COMPARATOR; } private Row[] getViewToModel() { if (viewToModel == null) { int tableModelRowCount = tableModel.getRowCount(); viewToModel = new Row[tableModelRowCount]; for (int row = 0; row < tableModelRowCount; row++) { viewToModel[row] = new Row(row); } if (isSorting()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -