/*\r
- * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
- *\r
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)\r
+ * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
+ * \r
* This program is free software; you can redistribute it and/or\r
* modify it under the terms of the GNU General Public License\r
* as published by the Free Software Foundation; either version 2\r
* of the License, or (at your option) any later version.\r
- *\r
+ * \r
* This program is distributed in the hope that it will be useful,\r
* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
* GNU General Public License for more details.\r
- *\r
+ * \r
* You should have received a copy of the GNU General Public License\r
* along with this program; if not, write to the Free Software\r
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\r
import javax.swing.table.*;\r
\r
/**\r
- * TableSorter is a decorator for TableModels; adding sorting\r
- * functionality to a supplied TableModel. TableSorter does\r
- * not store or copy the data in its TableModel; instead it maintains\r
- * a map from the row indexes of the view to the row indexes of the\r
- * model. As requests are made of the sorter (like getValueAt(row, col))\r
- * they are passed to the underlying model after the row numbers\r
- * have been translated via the internal mapping array. This way,\r
- * the TableSorter appears to hold another copy of the table\r
- * with the rows in a different order.\r
- * <p/>\r
- * TableSorter registers itself as a listener to the underlying model,\r
- * just as the JTable itself would. Events recieved from the model\r
- * are examined, sometimes manipulated (typically widened), and then\r
- * passed on to the TableSorter's listeners (typically the JTable).\r
- * If a change to the model has invalidated the order of TableSorter's\r
- * rows, a note of this is made and the sorter will resort the\r
- * rows the next time a value is requested.\r
- * <p/>\r
- * When the tableHeader property is set, either by using the\r
- * setTableHeader() method or the two argument constructor, the\r
- * table header may be used as a complete UI for TableSorter.\r
- * The default renderer of the tableHeader is decorated with a renderer\r
- * that indicates the sorting status of each column. In addition,\r
- * a mouse listener is installed with the following behavior:\r
+ * TableSorter is a decorator for TableModels; adding sorting functionality to a\r
+ * supplied TableModel. TableSorter does not store or copy the data in its\r
+ * TableModel; instead it maintains a map from the row indexes of the view to\r
+ * the row indexes of the model. As requests are made of the sorter (like\r
+ * getValueAt(row, col)) they are passed to the underlying model after the row\r
+ * numbers have been translated via the internal mapping array. This way, the\r
+ * TableSorter appears to hold another copy of the table with the rows in a\r
+ * different order. <p/> TableSorter registers itself as a listener to the\r
+ * underlying model, just as the JTable itself would. Events recieved from the\r
+ * model are examined, sometimes manipulated (typically widened), and then\r
+ * passed on to the TableSorter's listeners (typically the JTable). If a change\r
+ * to the model has invalidated the order of TableSorter's rows, a note of this\r
+ * is made and the sorter will resort the rows the next time a value is\r
+ * requested. <p/> When the tableHeader property is set, either by using the\r
+ * setTableHeader() method or the two argument constructor, the table header may\r
+ * be used as a complete UI for TableSorter. The default renderer of the\r
+ * tableHeader is decorated with a renderer that indicates the sorting status of\r
+ * each column. In addition, a mouse listener is installed with the following\r
+ * behavior:\r
* <ul>\r
- * <li>\r
- * Mouse-click: Clears the sorting status of all other columns\r
- * and advances the sorting status of that column through three\r
- * values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to\r
- * NOT_SORTED again).\r
- * <li>\r
- * SHIFT-mouse-click: Clears the sorting status of all other columns\r
- * and cycles the sorting status of the column through the same\r
- * three values, in the opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.\r
- * <li>\r
- * CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except\r
- * that the changes to the column do not cancel the statuses of columns\r
- * that are already sorting - giving a way to initiate a compound\r
- * sort.\r
+ * <li> Mouse-click: Clears the sorting status of all other columns and advances\r
+ * the sorting status of that column through three values: {NOT_SORTED,\r
+ * ASCENDING, DESCENDING} (then back to NOT_SORTED again).\r
+ * <li> SHIFT-mouse-click: Clears the sorting status of all other columns and\r
+ * cycles the sorting status of the column through the same three values, in the\r
+ * opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.\r
+ * <li> CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except that\r
+ * the changes to the column do not cancel the statuses of columns that are\r
+ * already sorting - giving a way to initiate a compound sort.\r
* </ul>\r
- * <p/>\r
- * This is a long overdue rewrite of a class of the same name that\r
- * first appeared in the swing table demos in 1997.\r
- *\r
+ * <p/> This is a long overdue rewrite of a class of the same name that first\r
+ * appeared in the swing table demos in 1997.\r
+ * \r
* @author Philip Milne\r
* @author Brendon McLean\r
* @author Dan van Enckevort\r
* @version 2.0 02/27/04\r
*/\r
\r
-public class TableSorter\r
- extends AbstractTableModel\r
+public class TableSorter extends AbstractTableModel\r
{\r
protected TableModel tableModel;\r
\r
public static final int DESCENDING = -1;\r
+\r
public static final int NOT_SORTED = 0;\r
+\r
public static final int ASCENDING = 1;\r
\r
- private static Directive EMPTY_DIRECTIVE = new Directive( -1, NOT_SORTED);\r
+ private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);\r
\r
public static final Comparator COMPARABLE_COMAPRATOR = new Comparator()\r
{\r
public int compare(Object o1, Object o2)\r
{\r
- return ( (Comparable) o1).compareTo(o2);\r
+ return ((Comparable) o1).compareTo(o2);\r
}\r
};\r
+\r
public static final Comparator LEXICAL_COMPARATOR = new Comparator()\r
{\r
public int compare(Object o1, Object o2)\r
};\r
\r
private Row[] viewToModel;\r
+\r
private int[] modelToView;\r
\r
private JTableHeader tableHeader;\r
+\r
private MouseListener mouseListener;\r
+\r
private TableModelListener tableModelListener;\r
+\r
private Map columnComparators = new HashMap();\r
+\r
private List sortingColumns = new ArrayList();\r
\r
public TableSorter()\r
if (this.tableHeader != null)\r
{\r
this.tableHeader.removeMouseListener(mouseListener);\r
- TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();\r
+ TableCellRenderer defaultRenderer = this.tableHeader\r
+ .getDefaultRenderer();\r
if (defaultRenderer instanceof SortableHeaderRenderer)\r
{\r
- this.tableHeader.setDefaultRenderer( ( (SortableHeaderRenderer)\r
- defaultRenderer).\r
- tableCellRenderer);\r
+ this.tableHeader\r
+ .setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);\r
}\r
}\r
this.tableHeader = tableHeader;\r
if (this.tableHeader != null)\r
{\r
this.tableHeader.addMouseListener(mouseListener);\r
- this.tableHeader.setDefaultRenderer(\r
- new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));\r
+ this.tableHeader.setDefaultRenderer(new SortableHeaderRenderer(\r
+ this.tableHeader.getDefaultRenderer()));\r
}\r
}\r
\r
return null;\r
}\r
return new Arrow(directive.direction == DESCENDING, size,\r
- sortingColumns.indexOf(directive));\r
+ sortingColumns.indexOf(directive));\r
}\r
\r
private void cancelSorting()\r
\r
// Helper classes\r
\r
- private class Row\r
- implements Comparable\r
+ private class Row implements Comparable\r
{\r
private int modelIndex;\r
\r
public int compareTo(Object o)\r
{\r
int row1 = modelIndex;\r
- int row2 = ( (Row) o).modelIndex;\r
+ int row2 = ((Row) o).modelIndex;\r
\r
- for (Iterator it = sortingColumns.iterator(); it.hasNext(); )\r
+ for (Iterator it = sortingColumns.iterator(); it.hasNext();)\r
{\r
Directive directive = (Directive) it.next();\r
int column = directive.column;\r
}\r
if (comparison != 0)\r
{\r
- return directive.direction == DESCENDING ? -comparison : comparison;\r
+ return directive.direction == DESCENDING ? -comparison\r
+ : comparison;\r
}\r
}\r
return 0;\r
}\r
}\r
\r
- private class TableModelHandler\r
- implements TableModelListener\r
+ private class TableModelHandler implements TableModelListener\r
{\r
public void tableChanged(TableModelEvent e)\r
{\r
// We can map a cell event through to the view without widening\r
// when the following conditions apply:\r
//\r
- // a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and,\r
- // b) all the changes are in one column (column != TableModelEvent.ALL_COLUMNS) and,\r
- // c) we are not sorting on that column (getSortingStatus(column) == NOT_SORTED) and,\r
+ // a) all the changes are on one row (e.getFirstRow() == e.getLastRow())\r
+ // and,\r
+ // b) all the changes are in one column (column !=\r
+ // TableModelEvent.ALL_COLUMNS) and,\r
+ // c) we are not sorting on that column (getSortingStatus(column) ==\r
+ // NOT_SORTED) and,\r
// d) a reverse lookup will not trigger a sort (modelToView != null)\r
//\r
- // Note: INSERT and DELETE events fail this test as they have column == ALL_COLUMNS.\r
+ // Note: INSERT and DELETE events fail this test as they have column ==\r
+ // ALL_COLUMNS.\r
//\r
// The last check, for (modelToView != null) is to see if modelToView\r
// is already allocated. If we don't do this check; sorting can become\r
// clause avoids this problem.\r
int column = e.getColumn();\r
if (e.getFirstRow() == e.getLastRow()\r
- && column != TableModelEvent.ALL_COLUMNS\r
- && getSortingStatus(column) == NOT_SORTED\r
- && modelToView != null)\r
+ && column != TableModelEvent.ALL_COLUMNS\r
+ && getSortingStatus(column) == NOT_SORTED\r
+ && modelToView != null)\r
{\r
int viewIndex = getModelToView()[e.getFirstRow()];\r
- fireTableChanged(new TableModelEvent(TableSorter.this,\r
- viewIndex, viewIndex,\r
- column, e.getType()));\r
+ fireTableChanged(new TableModelEvent(TableSorter.this, viewIndex,\r
+ viewIndex, column, e.getType()));\r
return;\r
}\r
\r
- // Something has happened to the data that may have invalidated the row order.\r
+ // Something has happened to the data that may have invalidated the row\r
+ // order.\r
clearSortingState();\r
fireTableDataChanged();\r
return;\r
}\r
}\r
\r
- private class MouseHandler\r
- extends MouseAdapter\r
+ private class MouseHandler extends MouseAdapter\r
{\r
public void mouseClicked(MouseEvent e)\r
{\r
{\r
cancelSorting();\r
}\r
- // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or\r
- // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed.\r
+ // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING}\r
+ // or\r
+ // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is\r
+ // pressed.\r
status = status + (e.isShiftDown() ? -1 : 1);\r
status = (status + 4) % 3 - 1; // signed mod, returning {-1, 0, 1}\r
setSortingStatus(column, status);\r
}\r
}\r
\r
- private static class Arrow\r
- implements Icon\r
+ private static class Arrow implements Icon\r
{\r
private boolean descending;\r
+\r
private int size;\r
+\r
private int priority;\r
\r
public Arrow(boolean descending, int size, int priority)\r
g.drawLine(dx, 0, 0, 0);\r
\r
g.setColor(color);\r
- g.translate( -x, -y);\r
+ g.translate(-x, -y);\r
}\r
\r
public int getIconWidth()\r
}\r
}\r
\r
- private class SortableHeaderRenderer\r
- implements TableCellRenderer\r
+ private class SortableHeaderRenderer implements TableCellRenderer\r
{\r
private TableCellRenderer tableCellRenderer;\r
\r
}\r
\r
public Component getTableCellRendererComponent(JTable table,\r
- Object value,\r
- boolean isSelected,\r
- boolean hasFocus,\r
- int row,\r
- int column)\r
+ Object value, boolean isSelected, boolean hasFocus, int row,\r
+ int column)\r
{\r
Component c = tableCellRenderer.getTableCellRendererComponent(table,\r
- value, isSelected, hasFocus, row, column);\r
+ value, isSelected, hasFocus, row, column);\r
if (c instanceof JLabel)\r
{\r
JLabel l = (JLabel) c;\r
l.setHorizontalTextPosition(JLabel.LEFT);\r
int modelColumn = table.convertColumnIndexToModel(column);\r
- l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize()));\r
+ l\r
+ .setIcon(getHeaderRendererIcon(modelColumn, l.getFont()\r
+ .getSize()));\r
}\r
return c;\r
}\r
private static class Directive\r
{\r
private int column;\r
+\r
private int direction;\r
\r
public Directive(int column, int direction)\r