Formatting
[jalview.git] / src / jalview / util / TableSorter.java
index c03e804..469bd7f 100755 (executable)
@@ -1,6 +1,6 @@
 /*\r
  * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
+ * Copyright (C) 2007 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
  */\r
 package jalview.util;\r
 \r
-import java.awt.*;\r
-import java.awt.event.*;\r
 import java.util.*;\r
 import java.util.List;\r
 \r
+import java.awt.*;\r
+import java.awt.event.*;\r
 import javax.swing.*;\r
-import javax.swing.event.TableModelEvent;\r
-import javax.swing.event.TableModelListener;\r
+import javax.swing.event.*;\r
 import javax.swing.table.*;\r
 \r
 /**\r
@@ -80,422 +79,519 @@ import javax.swing.table.*;
  * @version 2.0 02/27/04\r
  */\r
 \r
-public class TableSorter extends AbstractTableModel {\r
-    protected TableModel tableModel;\r
-\r
-    public static final int DESCENDING = -1;\r
-    public static final int NOT_SORTED = 0;\r
-    public static final int ASCENDING = 1;\r
-\r
-    private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);\r
-\r
-    public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() {\r
-        public int compare(Object o1, Object o2) {\r
-            return ((Comparable) o1).compareTo(o2);\r
+public class TableSorter\r
+    extends AbstractTableModel\r
+{\r
+  protected TableModel tableModel;\r
+\r
+  public static final int DESCENDING = -1;\r
+  public static final int NOT_SORTED = 0;\r
+  public static final int ASCENDING = 1;\r
+\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
+    }\r
+  };\r
+  public static final Comparator LEXICAL_COMPARATOR = new Comparator()\r
+  {\r
+    public int compare(Object o1, Object o2)\r
+    {\r
+      return o1.toString().compareTo(o2.toString());\r
+    }\r
+  };\r
+\r
+  private Row[] viewToModel;\r
+  private int[] modelToView;\r
+\r
+  private JTableHeader tableHeader;\r
+  private MouseListener mouseListener;\r
+  private TableModelListener tableModelListener;\r
+  private Map columnComparators = new HashMap();\r
+  private List sortingColumns = new ArrayList();\r
+\r
+  public TableSorter()\r
+  {\r
+    this.mouseListener = new MouseHandler();\r
+    this.tableModelListener = new TableModelHandler();\r
+  }\r
+\r
+  public TableSorter(TableModel tableModel)\r
+  {\r
+    this();\r
+    setTableModel(tableModel);\r
+  }\r
+\r
+  public TableSorter(TableModel tableModel, JTableHeader tableHeader)\r
+  {\r
+    this();\r
+    setTableHeader(tableHeader);\r
+    setTableModel(tableModel);\r
+  }\r
+\r
+  private void clearSortingState()\r
+  {\r
+    viewToModel = null;\r
+    modelToView = null;\r
+  }\r
+\r
+  public TableModel getTableModel()\r
+  {\r
+    return tableModel;\r
+  }\r
+\r
+  public void setTableModel(TableModel tableModel)\r
+  {\r
+    if (this.tableModel != null)\r
+    {\r
+      this.tableModel.removeTableModelListener(tableModelListener);\r
+    }\r
+\r
+    this.tableModel = tableModel;\r
+    if (this.tableModel != null)\r
+    {\r
+      this.tableModel.addTableModelListener(tableModelListener);\r
+    }\r
+\r
+    clearSortingState();\r
+    fireTableStructureChanged();\r
+  }\r
+\r
+  public JTableHeader getTableHeader()\r
+  {\r
+    return tableHeader;\r
+  }\r
+\r
+  public void setTableHeader(JTableHeader tableHeader)\r
+  {\r
+    if (this.tableHeader != null)\r
+    {\r
+      this.tableHeader.removeMouseListener(mouseListener);\r
+      TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();\r
+      if (defaultRenderer instanceof SortableHeaderRenderer)\r
+      {\r
+        this.tableHeader.setDefaultRenderer( ( (SortableHeaderRenderer)\r
+                                              defaultRenderer).\r
+                                            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
+    }\r
+  }\r
+\r
+  public boolean isSorting()\r
+  {\r
+    return sortingColumns.size() != 0;\r
+  }\r
+\r
+  private Directive getDirective(int column)\r
+  {\r
+    for (int i = 0; i < sortingColumns.size(); i++)\r
+    {\r
+      Directive directive = (Directive) sortingColumns.get(i);\r
+      if (directive.column == column)\r
+      {\r
+        return directive;\r
+      }\r
+    }\r
+    return EMPTY_DIRECTIVE;\r
+  }\r
+\r
+  public int getSortingStatus(int column)\r
+  {\r
+    return getDirective(column).direction;\r
+  }\r
+\r
+  private void sortingStatusChanged()\r
+  {\r
+    clearSortingState();\r
+    fireTableDataChanged();\r
+    if (tableHeader != null)\r
+    {\r
+      tableHeader.repaint();\r
+    }\r
+  }\r
+\r
+  public void setSortingStatus(int column, int status)\r
+  {\r
+    Directive directive = getDirective(column);\r
+    if (directive != EMPTY_DIRECTIVE)\r
+    {\r
+      sortingColumns.remove(directive);\r
+    }\r
+    if (status != NOT_SORTED)\r
+    {\r
+      sortingColumns.add(new Directive(column, status));\r
+    }\r
+    sortingStatusChanged();\r
+  }\r
+\r
+  protected Icon getHeaderRendererIcon(int column, int size)\r
+  {\r
+    Directive directive = getDirective(column);\r
+    if (directive == EMPTY_DIRECTIVE)\r
+    {\r
+      return null;\r
+    }\r
+    return new Arrow(directive.direction == DESCENDING, size,\r
+                     sortingColumns.indexOf(directive));\r
+  }\r
+\r
+  private void cancelSorting()\r
+  {\r
+    sortingColumns.clear();\r
+    sortingStatusChanged();\r
+  }\r
+\r
+  public void setColumnComparator(Class type, Comparator comparator)\r
+  {\r
+    if (comparator == null)\r
+    {\r
+      columnComparators.remove(type);\r
+    }\r
+    else\r
+    {\r
+      columnComparators.put(type, comparator);\r
+    }\r
+  }\r
+\r
+  protected Comparator getComparator(int column)\r
+  {\r
+    Class columnType = tableModel.getColumnClass(column);\r
+    Comparator comparator = (Comparator) columnComparators.get(columnType);\r
+    if (comparator != null)\r
+    {\r
+      return comparator;\r
+    }\r
+    if (Comparable.class.isAssignableFrom(columnType))\r
+    {\r
+      return COMPARABLE_COMAPRATOR;\r
+    }\r
+    return LEXICAL_COMPARATOR;\r
+  }\r
+\r
+  private Row[] getViewToModel()\r
+  {\r
+    if (viewToModel == null)\r
+    {\r
+      int tableModelRowCount = tableModel.getRowCount();\r
+      viewToModel = new Row[tableModelRowCount];\r
+      for (int row = 0; row < tableModelRowCount; row++)\r
+      {\r
+        viewToModel[row] = new Row(row);\r
+      }\r
+\r
+      if (isSorting())\r
+      {\r
+        Arrays.sort(viewToModel);\r
+      }\r
+    }\r
+    return viewToModel;\r
+  }\r
+\r
+  public int modelIndex(int viewIndex)\r
+  {\r
+    return getViewToModel()[viewIndex].modelIndex;\r
+  }\r
+\r
+  private int[] getModelToView()\r
+  {\r
+    if (modelToView == null)\r
+    {\r
+      int n = getViewToModel().length;\r
+      modelToView = new int[n];\r
+      for (int i = 0; i < n; i++)\r
+      {\r
+        modelToView[modelIndex(i)] = i;\r
+      }\r
+    }\r
+    return modelToView;\r
+  }\r
+\r
+  // TableModel interface methods\r
+\r
+  public int getRowCount()\r
+  {\r
+    return (tableModel == null) ? 0 : tableModel.getRowCount();\r
+  }\r
+\r
+  public int getColumnCount()\r
+  {\r
+    return (tableModel == null) ? 0 : tableModel.getColumnCount();\r
+  }\r
+\r
+  public String getColumnName(int column)\r
+  {\r
+    return tableModel.getColumnName(column);\r
+  }\r
+\r
+  public Class getColumnClass(int column)\r
+  {\r
+    return tableModel.getColumnClass(column);\r
+  }\r
+\r
+  public boolean isCellEditable(int row, int column)\r
+  {\r
+    return tableModel.isCellEditable(modelIndex(row), column);\r
+  }\r
+\r
+  public Object getValueAt(int row, int column)\r
+  {\r
+    return tableModel.getValueAt(modelIndex(row), column);\r
+  }\r
+\r
+  public void setValueAt(Object aValue, int row, int column)\r
+  {\r
+    tableModel.setValueAt(aValue, modelIndex(row), column);\r
+  }\r
+\r
+  // Helper classes\r
+\r
+  private class Row\r
+      implements Comparable\r
+  {\r
+    private int modelIndex;\r
+\r
+    public Row(int index)\r
+    {\r
+      this.modelIndex = index;\r
+    }\r
+\r
+    public int compareTo(Object o)\r
+    {\r
+      int row1 = modelIndex;\r
+      int row2 = ( (Row) o).modelIndex;\r
+\r
+      for (Iterator it = sortingColumns.iterator(); it.hasNext(); )\r
+      {\r
+        Directive directive = (Directive) it.next();\r
+        int column = directive.column;\r
+        Object o1 = tableModel.getValueAt(row1, column);\r
+        Object o2 = tableModel.getValueAt(row2, column);\r
+\r
+        int comparison = 0;\r
+        // Define null less than everything, except null.\r
+        if (o1 == null && o2 == null)\r
+        {\r
+          comparison = 0;\r
         }\r
-    };\r
-    public static final Comparator LEXICAL_COMPARATOR = new Comparator() {\r
-        public int compare(Object o1, Object o2) {\r
-            return o1.toString().compareTo(o2.toString());\r
-        }\r
-    };\r
-\r
-    private Row[] viewToModel;\r
-    private int[] modelToView;\r
-\r
-    private JTableHeader tableHeader;\r
-    private MouseListener mouseListener;\r
-    private TableModelListener tableModelListener;\r
-    private Map columnComparators = new HashMap();\r
-    private List sortingColumns = new ArrayList();\r
-\r
-    public TableSorter() {\r
-        this.mouseListener = new MouseHandler();\r
-        this.tableModelListener = new TableModelHandler();\r
-    }\r
-\r
-    public TableSorter(TableModel tableModel) {\r
-        this();\r
-        setTableModel(tableModel);\r
-    }\r
-\r
-    public TableSorter(TableModel tableModel, JTableHeader tableHeader) {\r
-        this();\r
-        setTableHeader(tableHeader);\r
-        setTableModel(tableModel);\r
-    }\r
-\r
-    private void clearSortingState() {\r
-        viewToModel = null;\r
-        modelToView = null;\r
-    }\r
-\r
-    public TableModel getTableModel() {\r
-        return tableModel;\r
-    }\r
-\r
-    public void setTableModel(TableModel tableModel) {\r
-        if (this.tableModel != null) {\r
-            this.tableModel.removeTableModelListener(tableModelListener);\r
+        else if (o1 == null)\r
+        {\r
+          comparison = -1;\r
         }\r
-\r
-        this.tableModel = tableModel;\r
-        if (this.tableModel != null) {\r
-            this.tableModel.addTableModelListener(tableModelListener);\r
+        else if (o2 == null)\r
+        {\r
+          comparison = 1;\r
         }\r
-\r
-        clearSortingState();\r
-        fireTableStructureChanged();\r
-    }\r
-\r
-    public JTableHeader getTableHeader() {\r
-        return tableHeader;\r
-    }\r
-\r
-    public void setTableHeader(JTableHeader tableHeader) {\r
-        if (this.tableHeader != null) {\r
-            this.tableHeader.removeMouseListener(mouseListener);\r
-            TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();\r
-            if (defaultRenderer instanceof SortableHeaderRenderer) {\r
-                this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);\r
-            }\r
+        else\r
+        {\r
+          comparison = getComparator(column).compare(o1, o2);\r
         }\r
-        this.tableHeader = tableHeader;\r
-        if (this.tableHeader != null) {\r
-            this.tableHeader.addMouseListener(mouseListener);\r
-            this.tableHeader.setDefaultRenderer(\r
-                    new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));\r
+        if (comparison != 0)\r
+        {\r
+          return directive.direction == DESCENDING ? -comparison : comparison;\r
         }\r
-    }\r
-\r
-    public boolean isSorting() {\r
-        return sortingColumns.size() != 0;\r
-    }\r
-\r
-    private Directive getDirective(int column) {\r
-        for (int i = 0; i < sortingColumns.size(); i++) {\r
-            Directive directive = (Directive)sortingColumns.get(i);\r
-            if (directive.column == column) {\r
-                return directive;\r
-            }\r
-        }\r
-        return EMPTY_DIRECTIVE;\r
-    }\r
-\r
-    public int getSortingStatus(int column) {\r
-        return getDirective(column).direction;\r
-    }\r
-\r
-    private void sortingStatusChanged() {\r
+      }\r
+      return 0;\r
+    }\r
+  }\r
+\r
+  private class TableModelHandler\r
+      implements TableModelListener\r
+  {\r
+    public void tableChanged(TableModelEvent e)\r
+    {\r
+      // If we're not sorting by anything, just pass the event along.\r
+      if (!isSorting())\r
+      {\r
         clearSortingState();\r
-        fireTableDataChanged();\r
-        if (tableHeader != null) {\r
-            tableHeader.repaint();\r
-        }\r
-    }\r
-\r
-    public void setSortingStatus(int column, int status) {\r
-        Directive directive = getDirective(column);\r
-        if (directive != EMPTY_DIRECTIVE) {\r
-            sortingColumns.remove(directive);\r
-        }\r
-        if (status != NOT_SORTED) {\r
-            sortingColumns.add(new Directive(column, status));\r
-        }\r
-        sortingStatusChanged();\r
-    }\r
-\r
-    protected Icon getHeaderRendererIcon(int column, int size) {\r
-        Directive directive = getDirective(column);\r
-        if (directive == EMPTY_DIRECTIVE) {\r
-            return null;\r
-        }\r
-        return new Arrow(directive.direction == DESCENDING, size, sortingColumns.indexOf(directive));\r
-    }\r
-\r
-    private void cancelSorting() {\r
-        sortingColumns.clear();\r
-        sortingStatusChanged();\r
-    }\r
-\r
-    public void setColumnComparator(Class type, Comparator comparator) {\r
-        if (comparator == null) {\r
-            columnComparators.remove(type);\r
-        } else {\r
-            columnComparators.put(type, comparator);\r
-        }\r
-    }\r
-\r
-    protected Comparator getComparator(int column) {\r
-        Class columnType = tableModel.getColumnClass(column);\r
-        Comparator comparator = (Comparator) columnComparators.get(columnType);\r
-        if (comparator != null) {\r
-            return comparator;\r
-        }\r
-        if (Comparable.class.isAssignableFrom(columnType)) {\r
-            return COMPARABLE_COMAPRATOR;\r
-        }\r
-        return LEXICAL_COMPARATOR;\r
-    }\r
-\r
-    private Row[] getViewToModel() {\r
-        if (viewToModel == null) {\r
-            int tableModelRowCount = tableModel.getRowCount();\r
-            viewToModel = new Row[tableModelRowCount];\r
-            for (int row = 0; row < tableModelRowCount; row++) {\r
-                viewToModel[row] = new Row(row);\r
-            }\r
-\r
-            if (isSorting()) {\r
-                Arrays.sort(viewToModel);\r
-            }\r
-        }\r
-        return viewToModel;\r
-    }\r
-\r
-    public int modelIndex(int viewIndex) {\r
-        return getViewToModel()[viewIndex].modelIndex;\r
-    }\r
-\r
-    private int[] getModelToView() {\r
-        if (modelToView == null) {\r
-            int n = getViewToModel().length;\r
-            modelToView = new int[n];\r
-            for (int i = 0; i < n; i++) {\r
-                modelToView[modelIndex(i)] = i;\r
-            }\r
-        }\r
-        return modelToView;\r
-    }\r
-\r
-    // TableModel interface methods\r
-\r
-    public int getRowCount() {\r
-        return (tableModel == null) ? 0 : tableModel.getRowCount();\r
-    }\r
-\r
-    public int getColumnCount() {\r
-        return (tableModel == null) ? 0 : tableModel.getColumnCount();\r
-    }\r
-\r
-    public String getColumnName(int column) {\r
-        return tableModel.getColumnName(column);\r
-    }\r
-\r
-    public Class getColumnClass(int column) {\r
-        return tableModel.getColumnClass(column);\r
-    }\r
-\r
-    public boolean isCellEditable(int row, int column) {\r
-        return tableModel.isCellEditable(modelIndex(row), column);\r
-    }\r
-\r
-    public Object getValueAt(int row, int column) {\r
-        return tableModel.getValueAt(modelIndex(row), column);\r
-    }\r
-\r
-    public void setValueAt(Object aValue, int row, int column) {\r
-        tableModel.setValueAt(aValue, modelIndex(row), column);\r
-    }\r
-\r
-    // Helper classes\r
-\r
-    private class Row implements Comparable {\r
-        private int modelIndex;\r
-\r
-        public Row(int index) {\r
-            this.modelIndex = index;\r
-        }\r
-\r
-        public int compareTo(Object o) {\r
-            int row1 = modelIndex;\r
-            int row2 = ((Row) o).modelIndex;\r
-\r
-            for (Iterator it = sortingColumns.iterator(); it.hasNext();) {\r
-                Directive directive = (Directive) it.next();\r
-                int column = directive.column;\r
-                Object o1 = tableModel.getValueAt(row1, column);\r
-                Object o2 = tableModel.getValueAt(row2, column);\r
-\r
-                int comparison = 0;\r
-                // Define null less than everything, except null.\r
-                if (o1 == null && o2 == null) {\r
-                    comparison = 0;\r
-                } else if (o1 == null) {\r
-                    comparison = -1;\r
-                } else if (o2 == null) {\r
-                    comparison = 1;\r
-                } else {\r
-                    comparison = getComparator(column).compare(o1, o2);\r
-                }\r
-                if (comparison != 0) {\r
-                    return directive.direction == DESCENDING ? -comparison : comparison;\r
-                }\r
-            }\r
-            return 0;\r
+        fireTableChanged(e);\r
+        return;\r
+      }\r
+\r
+      // If the table structure has changed, cancel the sorting; the\r
+      // sorting columns may have been either moved or deleted from\r
+      // the model.\r
+      if (e.getFirstRow() == TableModelEvent.HEADER_ROW)\r
+      {\r
+        cancelSorting();\r
+        fireTableChanged(e);\r
+        return;\r
+      }\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
+      // 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
+      //\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
+      // a performance bottleneck for applications where cells\r
+      // change rapidly in different parts of the table. If cells\r
+      // change alternately in the sorting column and then outside of\r
+      // it this class can end up re-sorting on alternate cell updates -\r
+      // which can be a performance problem for large tables. The last\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
+      {\r
+        int viewIndex = getModelToView()[e.getFirstRow()];\r
+        fireTableChanged(new TableModelEvent(TableSorter.this,\r
+                                             viewIndex, viewIndex,\r
+                                             column, e.getType()));\r
+        return;\r
+      }\r
+\r
+      // Something has happened to the data that may have invalidated the row order.\r
+      clearSortingState();\r
+      fireTableDataChanged();\r
+      return;\r
+    }\r
+  }\r
+\r
+  private class MouseHandler\r
+      extends MouseAdapter\r
+  {\r
+    public void mouseClicked(MouseEvent e)\r
+    {\r
+      JTableHeader h = (JTableHeader) e.getSource();\r
+      TableColumnModel columnModel = h.getColumnModel();\r
+      int viewColumn = columnModel.getColumnIndexAtX(e.getX());\r
+      int column = columnModel.getColumn(viewColumn).getModelIndex();\r
+      if (column != -1)\r
+      {\r
+        int status = getSortingStatus(column);\r
+        if (!e.isControlDown())\r
+        {\r
+          cancelSorting();\r
         }\r
-    }\r
-\r
-    private class TableModelHandler implements TableModelListener {\r
-        public void tableChanged(TableModelEvent e) {\r
-            // If we're not sorting by anything, just pass the event along.\r
-            if (!isSorting()) {\r
-                clearSortingState();\r
-                fireTableChanged(e);\r
-                return;\r
-            }\r
-\r
-            // If the table structure has changed, cancel the sorting; the\r
-            // sorting columns may have been either moved or deleted from\r
-            // the model.\r
-            if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {\r
-                cancelSorting();\r
-                fireTableChanged(e);\r
-                return;\r
-            }\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
-            // 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
-            //\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
-            // a performance bottleneck for applications where cells\r
-            // change rapidly in different parts of the table. If cells\r
-            // change alternately in the sorting column and then outside of\r
-            // it this class can end up re-sorting on alternate cell updates -\r
-            // which can be a performance problem for large tables. The last\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
-                int viewIndex = getModelToView()[e.getFirstRow()];\r
-                fireTableChanged(new TableModelEvent(TableSorter.this,\r
-                                                     viewIndex, viewIndex,\r
-                                                     column, e.getType()));\r
-                return;\r
-            }\r
-\r
-            // Something has happened to the data that may have invalidated the row order.\r
-            clearSortingState();\r
-            fireTableDataChanged();\r
-            return;\r
-        }\r
-    }\r
-\r
-    private class MouseHandler extends MouseAdapter {\r
-        public void mouseClicked(MouseEvent e) {\r
-            JTableHeader h = (JTableHeader) e.getSource();\r
-            TableColumnModel columnModel = h.getColumnModel();\r
-            int viewColumn = columnModel.getColumnIndexAtX(e.getX());\r
-            int column = columnModel.getColumn(viewColumn).getModelIndex();\r
-            if (column != -1) {\r
-                int status = getSortingStatus(column);\r
-                if (!e.isControlDown()) {\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
-                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
-\r
-    private static class Arrow implements Icon {\r
-        private boolean descending;\r
-        private int size;\r
-        private int priority;\r
-\r
-        public Arrow(boolean descending, int size, int priority) {\r
-            this.descending = descending;\r
-            this.size = size;\r
-            this.priority = priority;\r
-        }\r
-\r
-        public void paintIcon(Component c, Graphics g, int x, int y) {\r
-            Color color = c == null ? Color.GRAY : c.getBackground();\r
-            // In a compound sort, make each succesive triangle 20%\r
-            // smaller than the previous one.\r
-            int dx = (int)(size/2*Math.pow(0.8, priority));\r
-            int dy = descending ? dx : -dx;\r
-            // Align icon (roughly) with font baseline.\r
-            y = y + 5*size/6 + (descending ? -dy : 0);\r
-            int shift = descending ? 1 : -1;\r
-            g.translate(x, y);\r
-\r
-            // Right diagonal.\r
-            g.setColor(color.darker());\r
-            g.drawLine(dx / 2, dy, 0, 0);\r
-            g.drawLine(dx / 2, dy + shift, 0, shift);\r
-\r
-            // Left diagonal.\r
-            g.setColor(color.brighter());\r
-            g.drawLine(dx / 2, dy, dx, 0);\r
-            g.drawLine(dx / 2, dy + shift, dx, shift);\r
-\r
-            // Horizontal line.\r
-            if (descending) {\r
-                g.setColor(color.darker().darker());\r
-            } else {\r
-                g.setColor(color.brighter().brighter());\r
-            }\r
-            g.drawLine(dx, 0, 0, 0);\r
-\r
-            g.setColor(color);\r
-            g.translate(-x, -y);\r
-        }\r
-\r
-        public int getIconWidth() {\r
-            return size;\r
-        }\r
-\r
-        public int getIconHeight() {\r
-            return size;\r
-        }\r
-    }\r
-\r
-    private class SortableHeaderRenderer implements TableCellRenderer {\r
-        private TableCellRenderer tableCellRenderer;\r
-\r
-        public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {\r
-            this.tableCellRenderer = tableCellRenderer;\r
-        }\r
-\r
-        public Component getTableCellRendererComponent(JTable table,\r
-                                                       Object value,\r
-                                                       boolean isSelected,\r
-                                                       boolean hasFocus,\r
-                                                       int row,\r
-                                                       int column) {\r
-            Component c = tableCellRenderer.getTableCellRendererComponent(table,\r
-                    value, isSelected, hasFocus, row, column);\r
-            if (c instanceof JLabel) {\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
-            }\r
-            return c;\r
-        }\r
-    }\r
-\r
-    private static class Directive {\r
-        private int column;\r
-        private int direction;\r
-\r
-        public Directive(int column, int direction) {\r
-            this.column = column;\r
-            this.direction = direction;\r
-        }\r
-    }\r
+        // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or\r
+        // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is 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
+\r
+  private static class Arrow\r
+      implements Icon\r
+  {\r
+    private boolean descending;\r
+    private int size;\r
+    private int priority;\r
+\r
+    public Arrow(boolean descending, int size, int priority)\r
+    {\r
+      this.descending = descending;\r
+      this.size = size;\r
+      this.priority = priority;\r
+    }\r
+\r
+    public void paintIcon(Component c, Graphics g, int x, int y)\r
+    {\r
+      Color color = c == null ? Color.GRAY : c.getBackground();\r
+      // In a compound sort, make each succesive triangle 20%\r
+      // smaller than the previous one.\r
+      int dx = (int) (size / 2 * Math.pow(0.8, priority));\r
+      int dy = descending ? dx : -dx;\r
+      // Align icon (roughly) with font baseline.\r
+      y = y + 5 * size / 6 + (descending ? -dy : 0);\r
+      int shift = descending ? 1 : -1;\r
+      g.translate(x, y);\r
+\r
+      // Right diagonal.\r
+      g.setColor(color.darker());\r
+      g.drawLine(dx / 2, dy, 0, 0);\r
+      g.drawLine(dx / 2, dy + shift, 0, shift);\r
+\r
+      // Left diagonal.\r
+      g.setColor(color.brighter());\r
+      g.drawLine(dx / 2, dy, dx, 0);\r
+      g.drawLine(dx / 2, dy + shift, dx, shift);\r
+\r
+      // Horizontal line.\r
+      if (descending)\r
+      {\r
+        g.setColor(color.darker().darker());\r
+      }\r
+      else\r
+      {\r
+        g.setColor(color.brighter().brighter());\r
+      }\r
+      g.drawLine(dx, 0, 0, 0);\r
+\r
+      g.setColor(color);\r
+      g.translate( -x, -y);\r
+    }\r
+\r
+    public int getIconWidth()\r
+    {\r
+      return size;\r
+    }\r
+\r
+    public int getIconHeight()\r
+    {\r
+      return size;\r
+    }\r
+  }\r
+\r
+  private class SortableHeaderRenderer\r
+      implements TableCellRenderer\r
+  {\r
+    private TableCellRenderer tableCellRenderer;\r
+\r
+    public SortableHeaderRenderer(TableCellRenderer tableCellRenderer)\r
+    {\r
+      this.tableCellRenderer = tableCellRenderer;\r
+    }\r
+\r
+    public Component getTableCellRendererComponent(JTable table,\r
+        Object value,\r
+        boolean isSelected,\r
+        boolean hasFocus,\r
+        int row,\r
+        int column)\r
+    {\r
+      Component c = tableCellRenderer.getTableCellRendererComponent(table,\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
+      }\r
+      return c;\r
+    }\r
+  }\r
+\r
+  private static class Directive\r
+  {\r
+    private int column;\r
+    private int direction;\r
+\r
+    public Directive(int column, int direction)\r
+    {\r
+      this.column = column;\r
+      this.direction = direction;\r
+    }\r
+  }\r
 }\r