merge from 2_4_Release branch
[jalview.git] / src / jalview / util / TableSorter.java
index 469bd7f..a6ead15 100755 (executable)
@@ -1,17 +1,17 @@
 /*\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
@@ -28,50 +28,39 @@ import javax.swing.event.*;
 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
@@ -79,24 +68,26 @@ import javax.swing.table.*;
  * @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
@@ -106,12 +97,17 @@ public class TableSorter
   };\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
@@ -171,20 +167,20 @@ public class TableSorter
     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
@@ -243,7 +239,7 @@ public class TableSorter
       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
@@ -356,8 +352,7 @@ public class TableSorter
 \r
   // Helper classes\r
 \r
-  private class Row\r
-      implements Comparable\r
+  private class Row implements Comparable\r
   {\r
     private int modelIndex;\r
 \r
@@ -369,9 +364,9 @@ public class TableSorter
     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
@@ -398,15 +393,15 @@ public class TableSorter
         }\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
@@ -431,12 +426,16 @@ public class TableSorter
       // 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
@@ -448,26 +447,25 @@ public class TableSorter
       // 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
@@ -482,8 +480,10 @@ public class TableSorter
         {\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
@@ -491,11 +491,12 @@ public class TableSorter
     }\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
@@ -539,7 +540,7 @@ public class TableSorter
       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
@@ -553,8 +554,7 @@ public class TableSorter
     }\r
   }\r
 \r
-  private class SortableHeaderRenderer\r
-      implements TableCellRenderer\r
+  private class SortableHeaderRenderer implements TableCellRenderer\r
   {\r
     private TableCellRenderer tableCellRenderer;\r
 \r
@@ -564,20 +564,19 @@ public class TableSorter
     }\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
@@ -586,6 +585,7 @@ public class TableSorter
   private static class Directive\r
   {\r
     private int column;\r
+\r
     private int direction;\r
 \r
     public Directive(int column, int direction)\r