GPL license added
[jalview.git] / src / jalview / io / JalviewFileChooser.java
1 /*\r
2 * Jalview - A Sequence Alignment Editor and Viewer\r
3 * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4 *\r
5 * This program is free software; you can redistribute it and/or\r
6 * modify it under the terms of the GNU General Public License\r
7 * as published by the Free Software Foundation; either version 2\r
8 * of the License, or (at your option) any later version.\r
9 *\r
10 * This program is distributed in the hope that it will be useful,\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 * GNU General Public License for more details.\r
14 *\r
15 * You should have received a copy of the GNU General Public License\r
16 * along with this program; if not, write to the Free Software\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18 */\r
19 \r
20 \r
21 /*///////////////////////////////////////////////////////////////////\r
22 // This file was taken from java forum\r
23 // Re: JFileChooser functioning like normal Windows Apps FileChooser\r
24 // Author: ddanimal\r
25 // http://forum.java.sun.com/thread.jspa?forumID=57&threadID=327712\r
26 *///////////////////////////////////////////////////////////////////\r
27 \r
28 package jalview.io;\r
29 \r
30 import java.awt.*;\r
31 import java.awt.event.*;\r
32 import java.io.*;\r
33 import java.util.*;\r
34 \r
35 import javax.swing.*;\r
36 import javax.swing.plaf.*;\r
37 import javax.swing.plaf.basic.*;\r
38 import javax.swing.plaf.metal.*;\r
39 import javax.swing.table.*;\r
40 \r
41 public class JalviewFileChooser extends JFileChooser\r
42 {\r
43 \r
44   private static final int COLUMN_FILENAME = 0;\r
45   private static final int COLUMN_FILESIZE = 1;\r
46   private static final int COLUMN_FILETYPE = 2;\r
47   private static final int COLUMN_FILEDATE = 3;\r
48   private static final int COLUMN_FILEATTR = 4;\r
49   private static final int COLUMN_COLCOUNT = 5;\r
50   private static String[] COLUMNS = null;\r
51 \r
52 \r
53   public JalviewFileChooser(String dir, String [] suffix, String [] desc, String selected)\r
54   {\r
55     super(dir);\r
56 \r
57     JalviewFileFilter chosen = null;\r
58     for(int i=0; i<suffix.length; i++)\r
59     {\r
60       JalviewFileFilter jvf = new JalviewFileFilter(suffix[i], desc[i]);\r
61       addChoosableFileFilter(jvf);\r
62       if(selected!=null && selected.equalsIgnoreCase(desc[i]))\r
63         chosen = jvf;\r
64     }\r
65     if(chosen!=null)\r
66       setFileFilter(chosen);\r
67     initColumns();\r
68   }\r
69 \r
70   public String getSelectedFormat()\r
71   {\r
72 \r
73     String format = getFileFilter().getDescription();\r
74 \r
75     if (format.toUpperCase().startsWith("JALVIEW"))\r
76       format = "Jalview";\r
77     else if (format.toUpperCase().startsWith("FASTA"))\r
78       format = "FASTA";\r
79     else if (format.toUpperCase().startsWith("MSF"))\r
80       format = "MSF";\r
81     else if (format.toUpperCase().startsWith("CLUSTAL"))\r
82       format = "CLUSTAL";\r
83     else if (format.toUpperCase().startsWith("BLC"))\r
84       format = "BLC";\r
85     else if (format.toUpperCase().startsWith("PIR"))\r
86       format = "PIR";\r
87     else if (format.toUpperCase().startsWith("PFAM"))\r
88       format = "PFAM";\r
89 \r
90     return format;\r
91   }\r
92   public JalviewFileChooser(String dir)\r
93   {\r
94     super(dir);\r
95     initColumns();\r
96   }\r
97 \r
98   public int showSaveDialog(Component parent) throws HeadlessException {\r
99       setDialogType(SAVE_DIALOG);\r
100       int ret = showDialog(parent, null);\r
101 \r
102       if(getFileFilter() instanceof JalviewFileFilter)\r
103       {\r
104         JalviewFileFilter jvf = (JalviewFileFilter) getFileFilter();\r
105         if (!jvf.accept(getSelectedFile()))\r
106         {\r
107           String withExtension = getSelectedFile() + "." + jvf.getAcceptableExtension();\r
108           setSelectedFile(new File(withExtension));\r
109         }\r
110       }\r
111 \r
112       if(ret == JalviewFileChooser.APPROVE_OPTION  &&  getSelectedFile().exists() )\r
113       {\r
114        int confirm =  JOptionPane.showConfirmDialog(parent,\r
115                                       "Overwrite existing file?",\r
116                                       "File exists",\r
117                                       JOptionPane.YES_NO_OPTION);\r
118        if(confirm!=JOptionPane.YES_OPTION)\r
119          ret = this.CANCEL_OPTION;\r
120       }\r
121       return ret;\r
122   }\r
123 \r
124 \r
125   void initColumns()\r
126   {\r
127     if (COLUMNS == null)\r
128     {\r
129         Locale l = getLocale();\r
130         COLUMNS = new String[]{\r
131         UIManager.getString("FileChooser.fileNameHeaderText",l),\r
132         UIManager.getString("FileChooser.fileSizeHeaderText",l),\r
133         UIManager.getString("FileChooser.fileTypeHeaderText",l),\r
134         UIManager.getString("FileChooser.fileDateHeaderText",l),\r
135         UIManager.getString("FileChooser.fileAttrHeaderText",l)\r
136       };\r
137     }\r
138   }\r
139 \r
140   /**************************************************************************\r
141    * Always create the local UI\r
142    * @param comp\r
143    *************************************************************************/\r
144   public final void setUI(ComponentUI comp)\r
145   {\r
146     super.setUI(new UI(this));\r
147   }\r
148 \r
149    /**************************************************************************\r
150     * Internal implementation of Metal LookAndFeel to create the table sorting\r
151     * ability.\r
152     *************************************************************************/\r
153    private final static class UI extends MetalFileChooserUI\r
154    {\r
155      private DirectoryModel model;\r
156 \r
157      /**************************************************************************\r
158       * Must be overridden to extend\r
159       * @param e\r
160       *************************************************************************/\r
161      public UI(JFileChooser e)\r
162      {\r
163        super(e);\r
164      }\r
165 \r
166      /**************************************************************************\r
167       * Overridden to create our own model\r
168       *************************************************************************/\r
169      protected final void createModel()\r
170      {\r
171        model = new DirectoryModel(getFileChooser());\r
172      }\r
173 \r
174      /**************************************************************************\r
175       * Overridden to get our own model\r
176       * @return\r
177       *************************************************************************/\r
178      public final BasicDirectoryModel getModel() {       return model;     }\r
179 \r
180      /**************************************************************************\r
181       * Calls the default method then adds a MouseListener to the JTable\r
182       * @param chooser\r
183       * @return\r
184       *************************************************************************/\r
185      protected final JPanel createDetailsView(JFileChooser chooser)\r
186      {\r
187        final JPanel panel = super.createDetailsView(chooser);\r
188 \r
189        //Since we can't access MetalFileChooserUI's private member detailsTable\r
190        //directly, we have to find it in the JPanel\r
191        final JTable tbl = findJTable(panel.getComponents());\r
192        if (tbl != null)\r
193        {\r
194          //Fix the columns so they can't be rearranged, if we don't do this\r
195          //we would need to keep track when each column is moved\r
196          tbl.getTableHeader().setReorderingAllowed(false);\r
197 \r
198          //Add a mouselistener to listen for clicks on column headers\r
199          tbl.getTableHeader().addMouseListener(new MouseAdapter(){\r
200            public void mouseClicked(MouseEvent e)\r
201            {\r
202              //Only process single clicks\r
203              if (e.getClickCount() > 1) return;\r
204              e.consume();\r
205              final int col = tbl.getTableHeader().columnAtPoint(e.getPoint());\r
206              if (col == COLUMN_FILENAME || col == COLUMN_FILESIZE ||\r
207                  col == COLUMN_FILEDATE)\r
208                model.sort(col,tbl);\r
209            }\r
210          });\r
211        }\r
212        return panel;\r
213      }\r
214 \r
215      /**************************************************************************\r
216       * Finds the JTable in the panel so we can add MouseListener\r
217       * @param comp\r
218       * @return\r
219       *************************************************************************/\r
220      private final static JTable findJTable(Component[] comp)\r
221      {\r
222        for (int i=0;i<comp.length;i++)\r
223        {\r
224          if (comp[i] instanceof JTable)\r
225          {\r
226            return (JTable)comp[i];\r
227          }\r
228          if (comp[i] instanceof Container)\r
229          {\r
230            JTable tbl = findJTable(((Container)comp[i]).getComponents());\r
231            if (tbl != null) return tbl;\r
232          }\r
233        }\r
234        return null;\r
235      }\r
236    }\r
237 \r
238   /***************************************************************************\r
239    * Implementation of BasicDirectoryModel that sorts the Files by column\r
240    **************************************************************************/\r
241   private final static class DirectoryModel extends BasicDirectoryModel\r
242    {\r
243      int col = 0;\r
244      boolean ascending;\r
245 \r
246      /**************************************************************************\r
247       * Must be overridden to extend BasicDirectoryModel\r
248       * @param chooser\r
249       *************************************************************************/\r
250      DirectoryModel(JFileChooser chooser)\r
251      {\r
252        super(chooser);\r
253      }\r
254 \r
255 \r
256      /**************************************************************************\r
257       * Supposedly this is not used anymore, hopefully not.  We implemented\r
258       * some basic attempt at sorting just in case\r
259       * @param a\r
260       * @param b\r
261       * @return\r
262       *************************************************************************/\r
263      protected final boolean lt(File a, File b)\r
264      {\r
265        System.out.println("DEBUG:LT called?");\r
266        boolean less = false;\r
267        switch (col)\r
268        {\r
269          case COLUMN_FILEDATE:\r
270            less = a.lastModified() > b.lastModified();\r
271            break;\r
272          case COLUMN_FILESIZE:\r
273            less = a.length() > b.length();\r
274            break;\r
275          default:\r
276            less = a.getName().compareToIgnoreCase(b.getName()) > 0;\r
277          break;\r
278        }\r
279        if (ascending) return less = !less;\r
280        return less;\r
281      }\r
282 \r
283      /**************************************************************************\r
284       * Resorts the JFileChooser table based on new column\r
285       * @param c\r
286       *************************************************************************/\r
287      protected final void sort(int c, JTable tbl)\r
288      {\r
289        //Set column and order\r
290        col = c;\r
291        ascending = !ascending;\r
292        String indicator = " (^)";\r
293        if (ascending)\r
294          indicator = " (v)";\r
295 \r
296        final JTableHeader th = tbl.getTableHeader();\r
297        final TableColumnModel tcm = th.getColumnModel();\r
298 \r
299        for (int i=0;i<JalviewFileChooser.COLUMN_COLCOUNT;i++)\r
300        {\r
301          final TableColumn tc = tcm.getColumn( i ); // the column to change\r
302          tc.setHeaderValue( COLUMNS[i] );\r
303        }\r
304 \r
305        final TableColumn tc = tcm.getColumn( col ); // the column to change\r
306        tc.setHeaderValue( COLUMNS[col] + indicator );\r
307 \r
308        th.repaint();\r
309 \r
310        //Requery the file listing\r
311        validateFileCache();\r
312      }\r
313 \r
314      /**************************************************************************\r
315       * Sorts the data based on current column setting\r
316       * @param data\r
317       *************************************************************************/\r
318      protected final void sort(Vector data)\r
319      {\r
320        switch (col)\r
321        {\r
322          case COLUMN_FILEDATE:\r
323            Collections.sort(data,new Comparator(){\r
324              public int compare(Object o1,Object o2)\r
325              {\r
326                int ret = 1;\r
327                final File a = (File)o1;\r
328                final File b = (File)o2;\r
329                if (a.lastModified() > b.lastModified())\r
330                  ret = -1;\r
331                else if (a.lastModified() == b.lastModified())\r
332                  ret = 0;\r
333 \r
334                if (ascending)\r
335                  ret *= -1;\r
336                return ret;\r
337              }\r
338 \r
339            });\r
340            break;\r
341          case COLUMN_FILESIZE:\r
342            Collections.sort(data,new Comparator(){\r
343              public int compare(Object o1,Object o2)\r
344              {\r
345                int ret = 1;\r
346                final File a = (File)o1;\r
347                final File b = (File)o2;\r
348                if (a.length() > b.length())\r
349                  ret = -1;\r
350                else if (a.length() == b.length())\r
351                  ret = 0;\r
352 \r
353                if (ascending)\r
354                  ret *= -1;\r
355                return ret;\r
356              }\r
357 \r
358            });\r
359            break;\r
360          case COLUMN_FILENAME:\r
361            Collections.sort(data,new Comparator(){\r
362              public int compare(Object o1,Object o2)\r
363              {\r
364                final File a = (File)o1;\r
365                final File b = (File)o2;\r
366                if (ascending)\r
367                  return a.getName().compareToIgnoreCase(b.getName());\r
368                else\r
369                  return -1 * a.getName().compareToIgnoreCase(b.getName());\r
370              }\r
371 \r
372            });\r
373            break;\r
374        }\r
375      }\r
376   }\r
377 }\r
378 \r