X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Futil%2FTableSorter.java;h=a6ead1524b1fc6ede8ccca6d7252d8bc967c74f0;hb=506d60f0e188723ddc91c26824b41ac7034df3fe;hp=469bd7f594ef7045d20a79d8b7e8221a0e3017d5;hpb=60f2d6c034560415fd0139c8bc7df0c19cae1186;p=jalview.git diff --git a/src/jalview/util/TableSorter.java b/src/jalview/util/TableSorter.java index 469bd7f..a6ead15 100755 --- a/src/jalview/util/TableSorter.java +++ b/src/jalview/util/TableSorter.java @@ -1,17 +1,17 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer - * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle - * + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4) + * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle + * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA @@ -28,50 +28,39 @@ import javax.swing.event.*; import javax.swing.table.*; /** - * 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: + * 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: *

- *

- * This is a long overdue rewrite of a class of the same name that - * first appeared in the swing table demos in 1997. - * + *

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 @@ -79,24 +68,26 @@ import javax.swing.table.*; * @version 2.0 02/27/04 */ -public class TableSorter - extends AbstractTableModel +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); + 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); + return ((Comparable) o1).compareTo(o2); } }; + public static final Comparator LEXICAL_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) @@ -106,12 +97,17 @@ public class TableSorter }; 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() @@ -171,20 +167,20 @@ public class TableSorter if (this.tableHeader != null) { this.tableHeader.removeMouseListener(mouseListener); - TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer(); + TableCellRenderer defaultRenderer = this.tableHeader + .getDefaultRenderer(); if (defaultRenderer instanceof SortableHeaderRenderer) { - this.tableHeader.setDefaultRenderer( ( (SortableHeaderRenderer) - defaultRenderer). - tableCellRenderer); + 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())); + this.tableHeader.setDefaultRenderer(new SortableHeaderRenderer( + this.tableHeader.getDefaultRenderer())); } } @@ -243,7 +239,7 @@ public class TableSorter return null; } return new Arrow(directive.direction == DESCENDING, size, - sortingColumns.indexOf(directive)); + sortingColumns.indexOf(directive)); } private void cancelSorting() @@ -356,8 +352,7 @@ public class TableSorter // Helper classes - private class Row - implements Comparable + private class Row implements Comparable { private int modelIndex; @@ -369,9 +364,9 @@ public class TableSorter public int compareTo(Object o) { int row1 = modelIndex; - int row2 = ( (Row) o).modelIndex; + int row2 = ((Row) o).modelIndex; - for (Iterator it = sortingColumns.iterator(); it.hasNext(); ) + for (Iterator it = sortingColumns.iterator(); it.hasNext();) { Directive directive = (Directive) it.next(); int column = directive.column; @@ -398,15 +393,15 @@ public class TableSorter } if (comparison != 0) { - return directive.direction == DESCENDING ? -comparison : comparison; + return directive.direction == DESCENDING ? -comparison + : comparison; } } return 0; } } - private class TableModelHandler - implements TableModelListener + private class TableModelHandler implements TableModelListener { public void tableChanged(TableModelEvent e) { @@ -431,12 +426,16 @@ public class TableSorter // We can map a cell event through to the view without widening // when the following conditions apply: // - // a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and, - // b) all the changes are in one column (column != TableModelEvent.ALL_COLUMNS) and, - // c) we are not sorting on that column (getSortingStatus(column) == NOT_SORTED) and, + // a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) + // and, + // b) all the changes are in one column (column != + // TableModelEvent.ALL_COLUMNS) and, + // c) we are not sorting on that column (getSortingStatus(column) == + // NOT_SORTED) and, // d) a reverse lookup will not trigger a sort (modelToView != null) // - // Note: INSERT and DELETE events fail this test as they have column == ALL_COLUMNS. + // Note: INSERT and DELETE events fail this test as they have column == + // ALL_COLUMNS. // // The last check, for (modelToView != null) is to see if modelToView // is already allocated. If we don't do this check; sorting can become @@ -448,26 +447,25 @@ public class TableSorter // clause avoids this problem. int column = e.getColumn(); if (e.getFirstRow() == e.getLastRow() - && column != TableModelEvent.ALL_COLUMNS - && getSortingStatus(column) == NOT_SORTED - && modelToView != null) + && column != TableModelEvent.ALL_COLUMNS + && getSortingStatus(column) == NOT_SORTED + && modelToView != null) { int viewIndex = getModelToView()[e.getFirstRow()]; - fireTableChanged(new TableModelEvent(TableSorter.this, - viewIndex, viewIndex, - column, e.getType())); + fireTableChanged(new TableModelEvent(TableSorter.this, viewIndex, + viewIndex, column, e.getType())); return; } - // Something has happened to the data that may have invalidated the row order. + // Something has happened to the data that may have invalidated the row + // order. clearSortingState(); fireTableDataChanged(); return; } } - private class MouseHandler - extends MouseAdapter + private class MouseHandler extends MouseAdapter { public void mouseClicked(MouseEvent e) { @@ -482,8 +480,10 @@ public class TableSorter { cancelSorting(); } - // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or - // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed. + // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} + // or + // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is + // pressed. status = status + (e.isShiftDown() ? -1 : 1); status = (status + 4) % 3 - 1; // signed mod, returning {-1, 0, 1} setSortingStatus(column, status); @@ -491,11 +491,12 @@ public class TableSorter } } - private static class Arrow - implements Icon + private static class Arrow implements Icon { private boolean descending; + private int size; + private int priority; public Arrow(boolean descending, int size, int priority) @@ -539,7 +540,7 @@ public class TableSorter g.drawLine(dx, 0, 0, 0); g.setColor(color); - g.translate( -x, -y); + g.translate(-x, -y); } public int getIconWidth() @@ -553,8 +554,7 @@ public class TableSorter } } - private class SortableHeaderRenderer - implements TableCellRenderer + private class SortableHeaderRenderer implements TableCellRenderer { private TableCellRenderer tableCellRenderer; @@ -564,20 +564,19 @@ public class TableSorter } public Component getTableCellRendererComponent(JTable table, - Object value, - boolean isSelected, - boolean hasFocus, - int row, - int column) + Object value, boolean isSelected, boolean hasFocus, int row, + int column) { Component c = tableCellRenderer.getTableCellRendererComponent(table, - value, isSelected, hasFocus, row, column); + value, isSelected, hasFocus, row, column); if (c instanceof JLabel) { JLabel l = (JLabel) c; l.setHorizontalTextPosition(JLabel.LEFT); int modelColumn = table.convertColumnIndexToModel(column); - l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize())); + l + .setIcon(getHeaderRendererIcon(modelColumn, l.getFont() + .getSize())); } return c; } @@ -586,6 +585,7 @@ public class TableSorter private static class Directive { private int column; + private int direction; public Directive(int column, int direction)