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