New class, allows sorting
authoramwaterhouse <Andrew Waterhouse>
Wed, 16 Mar 2005 14:49:17 +0000 (14:49 +0000)
committeramwaterhouse <Andrew Waterhouse>
Wed, 16 Mar 2005 14:49:17 +0000 (14:49 +0000)
src/jalview/io/JalviewFileChooser.java [new file with mode: 0755]

diff --git a/src/jalview/io/JalviewFileChooser.java b/src/jalview/io/JalviewFileChooser.java
new file mode 100755 (executable)
index 0000000..7e6bd1b
--- /dev/null
@@ -0,0 +1,296 @@
+package jalview.io;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+import javax.swing.plaf.metal.*;
+import javax.swing.table.*;
+
+public class JalviewFileChooser extends JFileChooser
+{
+
+  private static final int COLUMN_FILENAME = 0;
+  private static final int COLUMN_FILESIZE = 1;
+  private static final int COLUMN_FILETYPE = 2;
+  private static final int COLUMN_FILEDATE = 3;
+  private static final int COLUMN_FILEATTR = 4;
+  private static final int COLUMN_COLCOUNT = 5;
+  private static String[] COLUMNS = null;
+
+  public JalviewFileChooser(String dir)
+  {
+    super(dir);
+    if (COLUMNS == null)
+    {
+      Locale l = getLocale();
+      COLUMNS = new String[]{
+        UIManager.getString("FileChooser.fileNameHeaderText",l),
+        UIManager.getString("FileChooser.fileSizeHeaderText",l),
+        UIManager.getString("FileChooser.fileTypeHeaderText",l),
+        UIManager.getString("FileChooser.fileDateHeaderText",l),
+        UIManager.getString("FileChooser.fileAttrHeaderText",l)
+      };
+    }
+
+  }
+
+  public JalviewFileChooser()
+  {
+    if (COLUMNS == null)
+    {
+      Locale l = getLocale();
+      COLUMNS = new String[]{
+        UIManager.getString("FileChooser.fileNameHeaderText",l),
+        UIManager.getString("FileChooser.fileSizeHeaderText",l),
+        UIManager.getString("FileChooser.fileTypeHeaderText",l),
+        UIManager.getString("FileChooser.fileDateHeaderText",l),
+        UIManager.getString("FileChooser.fileAttrHeaderText",l)
+      };
+    }
+  }
+
+
+  /**************************************************************************
+   * Always create the local UI
+   * @param comp
+   *************************************************************************/
+  public final void setUI(ComponentUI comp)
+  {
+    super.setUI(new UI(this));
+  }
+
+   /**************************************************************************
+    * Internal implementation of Metal LookAndFeel to create the table sorting
+    * ability.
+    *************************************************************************/
+   private final static class UI extends MetalFileChooserUI
+   {
+     private DirectoryModel model;
+
+     /**************************************************************************
+      * Must be overridden to extend
+      * @param e
+      *************************************************************************/
+     public UI(JFileChooser e)
+     {
+       super(e);
+     }
+
+     /**************************************************************************
+      * Overridden to create our own model
+      *************************************************************************/
+     protected final void createModel()
+     {
+       model = new DirectoryModel(getFileChooser());
+     }
+
+     /**************************************************************************
+      * Overridden to get our own model
+      * @return
+      *************************************************************************/
+     public final BasicDirectoryModel getModel() {       return model;     }
+
+     /**************************************************************************
+      * Calls the default method then adds a MouseListener to the JTable
+      * @param chooser
+      * @return
+      *************************************************************************/
+     protected final JPanel createDetailsView(JFileChooser chooser)
+     {
+       final JPanel panel = super.createDetailsView(chooser);
+
+       //Since we can't access MetalFileChooserUI's private member detailsTable
+       //directly, we have to find it in the JPanel
+       final JTable tbl = findJTable(panel.getComponents());
+       if (tbl != null)
+       {
+         //Fix the columns so they can't be rearranged, if we don't do this
+         //we would need to keep track when each column is moved
+         tbl.getTableHeader().setReorderingAllowed(false);
+
+         //Add a mouselistener to listen for clicks on column headers
+         tbl.getTableHeader().addMouseListener(new MouseAdapter(){
+           public void mouseClicked(MouseEvent e)
+           {
+             //Only process single clicks
+             if (e.getClickCount() > 1) return;
+             e.consume();
+             final int col = tbl.getTableHeader().columnAtPoint(e.getPoint());
+             if (col == COLUMN_FILENAME || col == COLUMN_FILESIZE ||
+                 col == COLUMN_FILEDATE)
+               model.sort(col,tbl);
+           }
+         });
+       }
+       return panel;
+     }
+
+     /**************************************************************************
+      * Finds the JTable in the panel so we can add MouseListener
+      * @param comp
+      * @return
+      *************************************************************************/
+     private final static JTable findJTable(Component[] comp)
+     {
+       for (int i=0;i<comp.length;i++)
+       {
+         if (comp[i] instanceof JTable)
+         {
+           return (JTable)comp[i];
+         }
+         if (comp[i] instanceof Container)
+         {
+           JTable tbl = findJTable(((Container)comp[i]).getComponents());
+           if (tbl != null) return tbl;
+         }
+       }
+       return null;
+     }
+   }
+
+  /***************************************************************************
+   * Implementation of BasicDirectoryModel that sorts the Files by column
+   **************************************************************************/
+  private final static class DirectoryModel extends BasicDirectoryModel
+   {
+     int col = 0;
+     boolean ascending;
+
+     /**************************************************************************
+      * Must be overridden to extend BasicDirectoryModel
+      * @param chooser
+      *************************************************************************/
+     DirectoryModel(JFileChooser chooser)
+     {
+       super(chooser);
+     }
+
+
+     /**************************************************************************
+      * Supposedly this is not used anymore, hopefully not.  We implemented
+      * some basic attempt at sorting just in case
+      * @param a
+      * @param b
+      * @return
+      *************************************************************************/
+     protected final boolean lt(File a, File b)
+     {
+       System.out.println("LT called?");
+       boolean less = false;
+       switch (col)
+       {
+         case COLUMN_FILEDATE:
+           less = a.lastModified() > b.lastModified();
+           break;
+         case COLUMN_FILESIZE:
+           less = a.length() > b.length();
+           break;
+         default:
+           less = a.getName().compareToIgnoreCase(b.getName()) > 0;
+         break;
+       }
+       if (ascending) return less = !less;
+       return less;
+     }
+
+     /**************************************************************************
+      * Resorts the JFileChooser table based on new column
+      * @param c
+      *************************************************************************/
+     protected final void sort(int c, JTable tbl)
+     {
+       //Set column and order
+       col = c;
+       ascending = !ascending;
+       String indicator = " (^)";
+       if (ascending)
+         indicator = " (v)";
+
+       final JTableHeader th = tbl.getTableHeader();
+       final TableColumnModel tcm = th.getColumnModel();
+
+       for (int i=0;i<JalviewFileChooser.COLUMN_COLCOUNT;i++)
+       {
+         final TableColumn tc = tcm.getColumn( i ); // the column to change
+         tc.setHeaderValue( COLUMNS[i] );
+       }
+
+       final TableColumn tc = tcm.getColumn( col ); // the column to change
+       tc.setHeaderValue( COLUMNS[col] + indicator );
+
+       th.repaint();
+
+       //Requery the file listing
+       validateFileCache();
+     }
+
+     /**************************************************************************
+      * Sorts the data based on current column setting
+      * @param data
+      *************************************************************************/
+     protected final void sort(Vector data)
+     {
+       switch (col)
+       {
+         case COLUMN_FILEDATE:
+           Collections.sort(data,new Comparator(){
+             public int compare(Object o1,Object o2)
+             {
+               int ret = 1;
+               final File a = (File)o1;
+               final File b = (File)o2;
+               if (a.lastModified() > b.lastModified())
+                 ret = -1;
+               else if (a.lastModified() == b.lastModified())
+                 ret = 0;
+
+               if (ascending)
+                 ret *= -1;
+               return ret;
+             }
+
+           });
+           break;
+         case COLUMN_FILESIZE:
+           Collections.sort(data,new Comparator(){
+             public int compare(Object o1,Object o2)
+             {
+               int ret = 1;
+               final File a = (File)o1;
+               final File b = (File)o2;
+               if (a.length() > b.length())
+                 ret = -1;
+               else if (a.length() == b.length())
+                 ret = 0;
+
+               if (ascending)
+                 ret *= -1;
+               return ret;
+             }
+
+           });
+           break;
+         case COLUMN_FILENAME:
+           Collections.sort(data,new Comparator(){
+             public int compare(Object o1,Object o2)
+             {
+               final File a = (File)o1;
+               final File b = (File)o2;
+               if (ascending)
+                 return a.getName().compareToIgnoreCase(b.getName());
+               else
+                 return -1 * a.getName().compareToIgnoreCase(b.getName());
+             }
+
+           });
+           break;
+       }
+     }
+  }
+}
+