JAL-1503 update version in GPL header
[jalview.git] / src / jalview / io / JalviewFileChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 //////////////////////////////////////////////////////////////////
20 package jalview.io;
21
22 import jalview.util.MessageManager;
23
24 import java.io.*;
25 import java.util.*;
26
27 import java.awt.*;
28 import java.awt.event.*;
29 import javax.swing.*;
30
31 /**
32  * Enhanced file chooser dialog box.
33  * 
34  * NOTE: bug on Windows systems when filechooser opened on directory to view
35  * files with colons in title.
36  * 
37  * @author AMW
38  * 
39  */
40 public class JalviewFileChooser extends JFileChooser
41 {
42   public JalviewFileChooser(String dir)
43   {
44     super(safePath(dir));
45     setAccessory(new RecentlyOpened());
46   }
47
48   private static File safePath(String dir)
49   {
50     if (dir == null)
51     {
52       return null;
53     }
54
55     File f = new File(dir);
56     if (f.getName().indexOf(':') > -1)
57     {
58       return null;
59     }
60     return f;
61   }
62
63   public JalviewFileChooser(String dir, String[] suffix, String[] desc,
64           String selected, boolean selectAll)
65   {
66     super(safePath(dir));
67     init(suffix, desc, selected, selectAll);
68   }
69
70   public JalviewFileChooser(String dir, String[] suffix, String[] desc,
71           String selected)
72   {
73     super(safePath(dir));
74     init(suffix, desc, selected, true);
75   }
76
77   void init(String[] suffix, String[] desc, String selected,
78           boolean selectAll)
79   {
80
81     JalviewFileFilter chosen = null;
82
83     // SelectAllFilter needs to be set first before adding further
84     // file filters to fix bug on Mac OSX
85     setAcceptAllFileFilterUsed(selectAll);
86
87     for (int i = 0; i < suffix.length; i++)
88     {
89       JalviewFileFilter jvf = new JalviewFileFilter(suffix[i], desc[i]);
90       addChoosableFileFilter(jvf);
91       if ((selected != null) && selected.equalsIgnoreCase(desc[i]))
92       {
93         chosen = jvf;
94       }
95     }
96
97     if (chosen != null)
98     {
99       setFileFilter(chosen);
100     }
101
102     setAccessory(new RecentlyOpened());
103   }
104
105   public void setFileFilter(javax.swing.filechooser.FileFilter filter)
106   {
107     super.setFileFilter(filter);
108
109     try
110     {
111       if (getUI() instanceof javax.swing.plaf.basic.BasicFileChooserUI)
112       {
113         final javax.swing.plaf.basic.BasicFileChooserUI ui = (javax.swing.plaf.basic.BasicFileChooserUI) getUI();
114         final String name = ui.getFileName().trim();
115
116         if ((name == null) || (name.length() == 0))
117         {
118           return;
119         }
120
121         EventQueue.invokeLater(new Thread()
122         {
123           public void run()
124           {
125             String currentName = ui.getFileName();
126             if ((currentName == null) || (currentName.length() == 0))
127             {
128               ui.setFileName(name);
129             }
130           }
131         });
132       }
133     } catch (Exception ex)
134     {
135       ex.printStackTrace();
136       // Some platforms do not have BasicFileChooserUI
137     }
138   }
139
140   public String getSelectedFormat()
141   {
142     if (getFileFilter() == null)
143     {
144       return null;
145     }
146
147     String format = getFileFilter().getDescription();
148
149     if (format.toUpperCase().startsWith("JALVIEW"))
150     {
151       format = "Jalview";
152     }
153     else if (format.toUpperCase().startsWith("FASTA"))
154     {
155       format = "FASTA";
156     }
157     else if (format.toUpperCase().startsWith("MSF"))
158     {
159       format = "MSF";
160     }
161     else if (format.toUpperCase().startsWith("CLUSTAL"))
162     {
163       format = "CLUSTAL";
164     }
165     else if (format.toUpperCase().startsWith("BLC"))
166     {
167       format = "BLC";
168     }
169     else if (format.toUpperCase().startsWith("PIR"))
170     {
171       format = "PIR";
172     }
173     else if (format.toUpperCase().startsWith("PFAM"))
174     {
175       format = "PFAM";
176     }
177
178     return format;
179   }
180
181   public int showSaveDialog(Component parent) throws HeadlessException
182   {
183     this.setAccessory(null);
184
185     setDialogType(SAVE_DIALOG);
186
187     int ret = showDialog(parent, MessageManager.getString("action.save"));
188
189     if (getFileFilter() instanceof JalviewFileFilter)
190     {
191       JalviewFileFilter jvf = (JalviewFileFilter) getFileFilter();
192
193       if (!jvf.accept(getSelectedFile()))
194       {
195         String withExtension = getSelectedFile() + "."
196                 + jvf.getAcceptableExtension();
197         setSelectedFile(new File(withExtension));
198       }
199     }
200     // TODO: ENSURE THAT FILES SAVED WITH A ':' IN THE NAME ARE REFUSED AND THE
201     // USER PROMPTED FOR A NEW FILENAME
202     if ((ret == JalviewFileChooser.APPROVE_OPTION)
203             && getSelectedFile().exists())
204     {
205       int confirm = JOptionPane.showConfirmDialog(parent,
206               "Overwrite existing file?", "File exists",
207               JOptionPane.YES_NO_OPTION);
208
209       if (confirm != JOptionPane.YES_OPTION)
210       {
211         ret = JalviewFileChooser.CANCEL_OPTION;
212       }
213     }
214
215     return ret;
216   }
217
218   void recentListSelectionChanged(Object selection)
219   {
220     setSelectedFile(null);
221     if (selection != null)
222     {
223       File file = new File((String) selection);
224       if (getFileFilter() instanceof JalviewFileFilter)
225       {
226         JalviewFileFilter jvf = (JalviewFileFilter) this.getFileFilter();
227
228         if (!jvf.accept(file))
229         {
230           setFileFilter(getChoosableFileFilters()[0]);
231         }
232       }
233
234       setSelectedFile(file);
235     }
236   }
237
238   class RecentlyOpened extends JPanel
239   {
240     JList list;
241
242     public RecentlyOpened()
243     {
244       String historyItems = jalview.bin.Cache.getProperty("RECENT_FILE");
245       StringTokenizer st;
246       Vector recent = new Vector();
247
248       if (historyItems != null)
249       {
250         st = new StringTokenizer(historyItems, "\t");
251
252         while (st.hasMoreTokens())
253         {
254           recent.addElement(st.nextElement());
255         }
256       }
257
258       list = new JList(recent);
259
260       DefaultListCellRenderer dlcr = new DefaultListCellRenderer();
261       dlcr.setHorizontalAlignment(DefaultListCellRenderer.RIGHT);
262       list.setCellRenderer(dlcr);
263
264       list.addMouseListener(new MouseAdapter()
265       {
266         public void mousePressed(MouseEvent evt)
267         {
268           recentListSelectionChanged(list.getSelectedValue());
269         }
270       });
271
272       this.setBorder(new javax.swing.border.TitledBorder("Recently Opened"));
273
274       final JScrollPane scroller = new JScrollPane(list);
275       scroller.setPreferredSize(new Dimension(130, 200));
276       this.add(scroller);
277
278       javax.swing.SwingUtilities.invokeLater(new Runnable()
279       {
280         public void run()
281         {
282           scroller.getHorizontalScrollBar().setValue(
283                   scroller.getHorizontalScrollBar().getMaximum());
284         }
285       });
286
287     }
288
289   }
290 }