// Copyright 2004, FreeHEP. package org.freehep.swing.table; import java.awt.Component; import java.awt.Graphics; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.Icon; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.table.JTableHeader; import javax.swing.table.TableModel; import org.freehep.swing.table.TableColumnHeaderListener; import org.freehep.swing.table.TableHeaderCellRenderer; /** * Utility to add a sorter for columns to a JTable which has a SortableTableModel. * <p> * Example of use: * <pre> * TableModel model = ... * DefaultSortableTableModel sm = new DefaultSortableTableModel(model); * JTable table = new JTable(sm); * TableSorter sorter = new TableSorter(table); * </pre> * @author Mark Donszelmann * @author Tony Johnson * @version $Id: TableSorter.java 10766 2007-06-02 17:29:04Z tonyj $ * @see org.freehep.swing.table.SortableTableModel */ public class TableSorter { private static Icon downTriangle = new Triangle(false); private static Icon upTriangle = new Triangle(true); private SortableTableModel model; private JTableHeader header; /** * Create a TableSorter. The table will initially be unsorted. * @param table The table to be sorted */ public TableSorter(JTable table) { table.addPropertyChangeListener("model",new ModelChangeListener()); modelChanged(table.getModel()); header = table.getTableHeader(); header.addMouseListener(new HeaderListener()); header.setDefaultRenderer(new HeaderRenderer()); } /** * Create a TableSorter. The table will initially be sorted in ascending order by the given column. * @param table The table to be sorted. * @param column The column on which to sort, or <CODE>SortableTableModel.UNSORTED</CODE> */ public TableSorter(JTable table, int column) { this(table, column, true); } /** * Create a TableSorter specifiying initial sorting parameters. * @param table The table to be sorted. * @param column The column on which to sort, or <CODE>SortableTableModel.UNSORTED</CODE> * @param ascending <CODE>true</CODE> for ascending order, <CODE>false</CODE> for descending order */ public TableSorter(JTable table, int column, boolean ascending) { this(table); sort(column,ascending); } /** * Find the current sort column. * @return The current sort column, or <CODE>SortableTableModel.UNSORTED</CODE> */ public int getSortOnColumn() { return model == null ? SortableTableModel.UNSORTED : model.getSortOnColumn(); } /** * Set the sort column. * @param column The column on which to sort, or <CODE>SortableTableModel.UNSORTED</CODE> */ public void setSortOnColumn(int column) { if (model != null) model.sort(column,true); } /** * Get the current sort order. * @return <CODE>true</CODE> if ascending order, <CODE>false</CODE> for descending order. */ public boolean isSortAscending() { return model == null ? true : model.isSortAscending(); } /** * Set the current sort order. * @param ascending <CODE>true</CODE> for ascending order, <CODE>false</CODE> for descending order */ public void setSortAscending(boolean ascending) { if (model != null) model.sort(model.getSortOnColumn(),ascending); } private void sort(int sortOnColumn, boolean sortAscending) { if (model != null) { model.sort(sortOnColumn, sortAscending); header.resizeAndRepaint(); } } private void modelChanged(TableModel model) { this.model = model instanceof SortableTableModel ? (SortableTableModel) model : null; } private class ModelChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { modelChanged((TableModel) evt.getNewValue()); } } private class HeaderListener extends TableColumnHeaderListener { public void headerClicked(JTable table, int col) { if (model != null) { if (col != model.getSortOnColumn()) { sort(col, true); } else { sort(model.getSortOnColumn(), !model.isSortAscending()); } } } } private class HeaderRenderer extends TableHeaderCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col); if (model != null && table.convertColumnIndexToModel(col) == model.getSortOnColumn()) { label.setIcon(model.isSortAscending() ? downTriangle : upTriangle); } else { label.setIcon(null); } return label; } } private static class Triangle implements Icon { private boolean up; private static final int size = 16; private static final int[] xxdown = { 3 , 12, 7 }; private static final int[] yydown = { 5 , 5, 10 }; private static final int[] xxup = { 2 , 12, 7 }; private static final int[] yyup = { 10 , 10, 4 }; Triangle(boolean up) { this.up = up; } public int getIconHeight() { return size; } public int getIconWidth() { return size; } public void paintIcon(Component c, Graphics g, int x, int y) { int[] xp = new int[3]; int[] yp = new int[3]; for (int i=0; i<3; i++) { xp[i] = x + (up ? xxup[i] : xxdown[i]); yp[i] = y + (up ? yyup[i] : yydown[i]); } g.setColor(c.getForeground()); g.fillPolygon(xp,yp,3); } } }