/* * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ ////////////////////////////////////////////////////////////////// package jalview.io; import jalview.bin.Cache; import jalview.gui.JvOptionPane; import jalview.util.MessageManager; import jalview.util.Platform; import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.HeadlessException; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import java.util.Vector; import javax.swing.DefaultListCellRenderer; import javax.swing.JFileChooser; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SpringLayout; import javax.swing.plaf.basic.BasicFileChooserUI; /** * Enhanced file chooser dialog box. * * NOTE: bug on Windows systems when filechooser opened on directory to view * files with colons in title. * * @author AMW * */ public class JalviewFileChooser extends JFileChooser { /** * Factory method to return a file chooser that offers readable alignment file * formats * * @param directory * @param selected * @return */ public static JalviewFileChooser forRead(String directory, String selected) { List extensions = new ArrayList(); List descs = new ArrayList(); for (FileFormatI format : FileFormats.getInstance().getFormats()) { if (format.isReadable()) { extensions.add(format.getExtensions()); descs.add(format.getName()); } } return new JalviewFileChooser(directory, extensions.toArray(new String[extensions.size()]), descs.toArray(new String[descs.size()]), selected, true); } /** * Factory method to return a file chooser that offers writable alignment file * formats * * @param directory * @param selected * @return */ public static JalviewFileChooser forWrite(String directory, String selected) { // TODO in Java 8, forRead and forWrite can be a single method // with a lambda expression parameter for isReadable/isWritable List extensions = new ArrayList(); List descs = new ArrayList(); for (FileFormatI format : FileFormats.getInstance().getFormats()) { if (format.isWritable()) { extensions.add(format.getExtensions()); descs.add(format.getName()); } } return new JalviewFileChooser(directory, extensions.toArray(new String[extensions.size()]), descs.toArray(new String[descs.size()]), selected, false); } public JalviewFileChooser(String dir) { super(safePath(dir)); setAccessory(new RecentlyOpened()); } public JalviewFileChooser(String dir, String[] suffix, String[] desc, String selected) { this(dir, suffix, desc, selected, true); } /** * Constructor for a single choice of file extension and description * * @param extension * @param desc */ public JalviewFileChooser(String extension, String desc) { this(Cache.getProperty("LAST_DIRECTORY"), new String[] { extension }, new String[] { desc }, desc, true); } JalviewFileChooser(String dir, String[] extensions, String[] descs, String selected, boolean allFiles) { super(safePath(dir)); if (extensions.length == descs.length) { List formats = new ArrayList(); for (int i = 0; i < extensions.length; i++) { formats.add(new String[] { extensions[i], descs[i] }); } init(formats, selected, allFiles); } else { System.err.println("JalviewFileChooser arguments mismatch: " + extensions + ", " + descs); } } private static File safePath(String dir) { if (dir == null) { return null; } File f = new File(dir); if (f.getName().indexOf(':') > -1) { return null; } return f; } /** * * @param formats * a list of {extensions, description} for each file format * @param selected * @param allFiles * if true, 'any format' option is included */ void init(List formats, String selected, boolean allFiles) { JalviewFileFilter chosen = null; // SelectAllFilter needs to be set first before adding further // file filters to fix bug on Mac OSX setAcceptAllFileFilterUsed(allFiles); for (String[] format : formats) { JalviewFileFilter jvf = new JalviewFileFilter(format[0], format[1]); addChoosableFileFilter(jvf); if ((selected != null) && selected.equalsIgnoreCase(format[1])) { chosen = jvf; } } if (chosen != null) { setFileFilter(chosen); } setAccessory(new RecentlyOpened()); } @Override public void setFileFilter(javax.swing.filechooser.FileFilter filter) { super.setFileFilter(filter); try { if (getUI() instanceof BasicFileChooserUI) { final BasicFileChooserUI fcui = (BasicFileChooserUI) getUI(); final String name = fcui.getFileName().trim(); if ((name == null) || (name.length() == 0)) { return; } EventQueue.invokeLater(new Thread() { @Override public void run() { String currentName = fcui.getFileName(); if ((currentName == null) || (currentName.length() == 0)) { fcui.setFileName(name); } } }); } } catch (Exception ex) { ex.printStackTrace(); // Some platforms do not have BasicFileChooserUI } } /** * Returns the selected file format, or null if none selected * * @return */ public FileFormatI getSelectedFormat() { if (getFileFilter() == null) { return null; } /* * logic here depends on option description being formatted as * formatName (extension, extension...) * or the 'no option selected' value * All Files * @see JalviewFileFilter.getDescription */ String format = getFileFilter().getDescription(); int parenPos = format.indexOf("("); if (parenPos > 0) { format = format.substring(0, parenPos).trim(); try { return FileFormats.getInstance().forName(format); } catch (IllegalArgumentException e) { System.err.println("Unexpected format: " + format); } } return null; } @Override public int showSaveDialog(Component parent) throws HeadlessException { this.setAccessory(null); setDialogType(SAVE_DIALOG); int ret = showDialog(parent, MessageManager.getString("action.save")); if (getFileFilter() instanceof JalviewFileFilter) { JalviewFileFilter jvf = (JalviewFileFilter) getFileFilter(); if (!jvf.accept(getSelectedFile())) { String withExtension = getSelectedFile() + "." + jvf.getAcceptableExtension(); setSelectedFile(new File(withExtension)); } } // TODO: ENSURE THAT FILES SAVED WITH A ':' IN THE NAME ARE REFUSED AND THE // USER PROMPTED FOR A NEW FILENAME if ((ret == JalviewFileChooser.APPROVE_OPTION) && getSelectedFile().exists()) { int confirm = JvOptionPane.showConfirmDialog(parent, MessageManager.getString("label.overwrite_existing_file"), MessageManager.getString("label.file_already_exists"), JvOptionPane.YES_NO_OPTION); if (confirm != JvOptionPane.YES_OPTION) { ret = JalviewFileChooser.CANCEL_OPTION; } } return ret; } void recentListSelectionChanged(Object selection) { setSelectedFile(null); if (selection != null) { File file = new File((String) selection); if (getFileFilter() instanceof JalviewFileFilter) { JalviewFileFilter jvf = (JalviewFileFilter) this.getFileFilter(); if (!jvf.accept(file)) { setFileFilter(getChoosableFileFilters()[0]); } } setSelectedFile(file); } } class RecentlyOpened extends JPanel { JList list; public RecentlyOpened() { String historyItems = jalview.bin.Cache.getProperty("RECENT_FILE"); StringTokenizer st; Vector recent = new Vector(); if (historyItems != null) { st = new StringTokenizer(historyItems, "\t"); while (st.hasMoreTokens()) { recent.addElement(st.nextElement()); } } list = new JList(recent); DefaultListCellRenderer dlcr = new DefaultListCellRenderer(); dlcr.setHorizontalAlignment(DefaultListCellRenderer.RIGHT); list.setCellRenderer(dlcr); list.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { recentListSelectionChanged(list.getSelectedValue()); } }); this.setBorder(new javax.swing.border.TitledBorder(MessageManager .getString("label.recently_opened"))); final JScrollPane scroller = new JScrollPane(list); SpringLayout layout = new SpringLayout(); layout.putConstraint(SpringLayout.WEST, scroller, 5, SpringLayout.WEST, this); layout.putConstraint(SpringLayout.NORTH, scroller, 5, SpringLayout.NORTH, this); if (new Platform().isAMac()) { scroller.setPreferredSize(new Dimension(500, 100)); } else { scroller.setPreferredSize(new Dimension(130, 200)); } this.add(scroller); javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { scroller.getHorizontalScrollBar().setValue( scroller.getHorizontalScrollBar().getMaximum()); } }); } } }