X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FJalviewFileChooser.java;h=acd0e183f0048644813c069630e14bfce3b30aea;hb=d9f0a24d9662a0b530fd79b51108dd074d03d6e0;hp=8fc5ddd844673249b042082c8138d34ba427848f;hpb=bebc8c1502441eee34996343ecd785788f5b1def;p=jalview.git diff --git a/src/jalview/io/JalviewFileChooser.java b/src/jalview/io/JalviewFileChooser.java index 8fc5ddd..acd0e18 100755 --- a/src/jalview/io/JalviewFileChooser.java +++ b/src/jalview/io/JalviewFileChooser.java @@ -25,6 +25,7 @@ import jalview.bin.Cache; import jalview.gui.JvOptionPane; import jalview.util.MessageManager; import jalview.util.Platform; +import jalview.util.dialogrunner.DialogRunnerI; import java.awt.Component; import java.awt.Dimension; @@ -34,9 +35,13 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.StringTokenizer; import java.util.Vector; @@ -60,8 +65,15 @@ import javax.swing.plaf.basic.BasicFileChooserUI; * @author AMW * */ -public class JalviewFileChooser extends JFileChooser +public class JalviewFileChooser extends JFileChooser implements DialogRunnerI, + PropertyChangeListener { + private static final long serialVersionUID = 1L; + + private Map callbacks = new HashMap<>(); + + File selectedFile = null; + /** * backupfilesCheckBox = "Include backup files" checkbox includeBackupfiles = * flag set by checkbox @@ -81,6 +93,12 @@ public class JalviewFileChooser extends JFileChooser public static JalviewFileChooser forRead(String directory, String selected) { + return JalviewFileChooser.forRead(directory, selected, false); + } + + public static JalviewFileChooser forRead(String directory, + String selected, boolean allowBackupFiles) + { List extensions = new ArrayList<>(); List descs = new ArrayList<>(); for (FileFormatI format : FileFormats.getInstance().getFormats()) @@ -91,9 +109,11 @@ public class JalviewFileChooser extends JFileChooser descs.add(format.getName()); } } + return new JalviewFileChooser(directory, extensions.toArray(new String[extensions.size()]), - descs.toArray(new String[descs.size()]), selected, true); + descs.toArray(new String[descs.size()]), selected, true, + allowBackupFiles); } /** @@ -150,13 +170,13 @@ public class JalviewFileChooser extends JFileChooser } JalviewFileChooser(String dir, String[] extensions, String[] descs, - String selected, boolean allFiles) + String selected, boolean acceptAny) { - this(dir, extensions, descs, selected, allFiles, false); + this(dir, extensions, descs, selected, acceptAny, false); } public JalviewFileChooser(String dir, String[] extensions, String[] descs, - String selected, boolean allFiles, boolean allowBackupFiles) + String selected, boolean acceptAny, boolean allowBackupFiles) { super(safePath(dir)); if (extensions.length == descs.length) @@ -166,7 +186,7 @@ public class JalviewFileChooser extends JFileChooser { formats.add(new String[] { extensions[i], descs[i] }); } - init(formats, selected, allFiles, allowBackupFiles); + init(formats, selected, acceptAny, allowBackupFiles); } else { @@ -191,19 +211,45 @@ public class JalviewFileChooser extends JFileChooser } /** + * Overridden for JalviewJS compatibility: only one thread in Javascript, + * so we can't wait for user choice in another thread and then perform the + * desired action + */ + @Override + public int showOpenDialog(Component parent) + { + int value = super.showOpenDialog(this); + + if (!Platform.isJS()) + /** + * Java only + * + * @j2sNative + */ + { + /* + * code here is not run in JalviewJS, instead + * propertyChange() is called for dialog action + */ + handleResponse(value); + } + return value; + } + + /** * * @param formats * a list of {extensions, description} for each file format * @param selected - * @param allFiles + * @param acceptAny * if true, 'any format' option is included */ - void init(List formats, String selected, boolean allFiles) + void init(List formats, String selected, boolean acceptAny) { - init(formats, selected, allFiles, false); + init(formats, selected, acceptAny, false); } - void init(List formats, String selected, boolean allFiles, + void init(List formats, String selected, boolean acceptAny, boolean allowBackupFiles) { @@ -211,7 +257,7 @@ public class JalviewFileChooser extends JFileChooser // SelectAllFilter needs to be set first before adding further // file filters to fix bug on Mac OSX - setAcceptAllFileFilterUsed(allFiles); + setAcceptAllFileFilterUsed(acceptAny); for (String[] format : formats) { @@ -259,62 +305,19 @@ public class JalviewFileChooser extends JFileChooser Cache.setProperty(BackupFiles.NS + "_FC_INCLUDE", String.valueOf(includeBackupFiles)); - if (Platform.isAMac()) + FileFilter f = jfc.getFileFilter(); + // deselect the selected file if it's no longer choosable + File selectedFile = jfc.getSelectedFile(); + if (selectedFile != null && !f.accept(selectedFile)) { - // This is a kludge. Cannot find out how to get the file list to - // refresh on its own! This works the best out of a number of - // different attempts! - FileFilter ff = jfc.getFileFilter(); - jfc.setFileFilter(jfc.getAcceptAllFileFilter()); - jfc.setFileFilter(ff); - - /* - jfc.setFileHidingEnabled(!jfc.isFileHidingEnabled()); - jfc.setFileHidingEnabled(!jfc.isFileHidingEnabled()); - */ - - /* - jfc.getRootPane() - .paintImmediately(jfc.getRootPane().getBounds()); - jfc.paintImmediately(jfc.getBounds()); - */ - - /* - Object o = jfc.getClientProperty( - CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY); - jfc.firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, - o, o); - */ - - /* - File f = jfc.getSelectedFile(); jfc.setSelectedFile(null); - if (f != null) - { - jfc.setSelectedFile(f); - } - */ - - /* - Graphics g = jfc.getGraphics(); - jfc.update(g); - jfc.paintAll(g); - */ - - /* - jfc.setFileHidingEnabled(!jfc.isFileHidingEnabled()); - jfc.setFileHidingEnabled(!jfc.isFileHidingEnabled()); - */ - /* - jfc.invalidate(); - Component[] c = jfc.getComponents(); - for (int i = 0; i < c.length; i++) - { - c[i].invalidate(); - System.out.println("INVALIDATING " + c[i].getName()); - } - */ } + // fake the OK button changing (to force it to upate) + String s = jfc.getApproveButtonText(); + jfc.firePropertyChange( + APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, null, s); + // fake the file filter changing (its behaviour actually has) + jfc.firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, null, f); jfc.rescanCurrentDirectory(); jfc.revalidate(); @@ -407,31 +410,42 @@ public class JalviewFileChooser extends JFileChooser return null; } - File ourselectedFile = null; - @Override public File getSelectedFile() { - File selfile = super.getSelectedFile(); - if (selfile == null && ourselectedFile != null) - { - return ourselectedFile; - } - return selfile; + File f = super.getSelectedFile(); + return f == null ? selectedFile : f; } @Override public int showSaveDialog(Component parent) throws HeadlessException { this.setAccessory(null); + // Java 9,10,11 on OSX - clear selected file so name isn't auto populated + this.setSelectedFile(null); - setDialogType(SAVE_DIALOG); + return super.showSaveDialog(parent); + } - this.setSelectedFile(null); - int ret = showDialog(parent, MessageManager.getString("action.save")); - ourselectedFile = getSelectedFile(); + /** + * If doing a Save, and an existing file is chosen or entered, prompt for + * confirmation of overwrite. Proceed if Yes, else leave the file chooser + * open. + * + * @see https://stackoverflow.com/questions/8581215/jfilechooser-and-checking-for-overwrite + */ + @Override + public void approveSelection() + { + if (getDialogType() != SAVE_DIALOG) + { + super.approveSelection(); + return; + } + + selectedFile = getSelectedFile(); - if (getSelectedFile() == null) + if (selectedFile == null) { // Workaround for Java 9,10 on OSX - no selected file, but there is a // filename typed in @@ -440,7 +454,7 @@ public class JalviewFileChooser extends JFileChooser String filename = ((BasicFileChooserUI) getUI()).getFileName(); if (filename != null && filename.length() > 0) { - ourselectedFile = new File(getCurrentDirectory(), filename); + selectedFile = new File(getCurrentDirectory(), filename); } } catch (Throwable x) { @@ -448,44 +462,43 @@ public class JalviewFileChooser extends JFileChooser "Unexpected exception when trying to get filename."); x.printStackTrace(); } + // TODO: ENSURE THAT FILES SAVED WITH A ':' IN THE NAME ARE REFUSED AND + // THE + // USER PROMPTED FOR A NEW FILENAME } - if (ourselectedFile == null) + + if (selectedFile == null) { - return JalviewFileChooser.CANCEL_OPTION; + return; } + if (getFileFilter() instanceof JalviewFileFilter) { JalviewFileFilter jvf = (JalviewFileFilter) getFileFilter(); - if (!jvf.accept(ourselectedFile)) + if (!jvf.accept(selectedFile)) { String withExtension = getSelectedFile().getName() + "." + jvf.getAcceptableExtension(); - ourselectedFile = (new File(getCurrentDirectory(), withExtension)); - setSelectedFile(ourselectedFile); + selectedFile = (new File(getCurrentDirectory(), withExtension)); + setSelectedFile(selectedFile); } } - // TODO: ENSURE THAT FILES SAVED WITH A ':' IN THE NAME ARE REFUSED AND THE - // USER PROMPTED FOR A NEW FILENAME. - // DO NOT need to confirm file overwrite if using backup files (the files - // aren't being overwritten!) - if ((ret == JalviewFileChooser.APPROVE_OPTION) - && ourselectedFile.exists() && (!BackupFiles.getEnabled())) + if (selectedFile.exists()) { - int confirm = JvOptionPane.showConfirmDialog(parent, + int confirm = JvOptionPane.showConfirmDialog(this, 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; } - } - return ret; + super.approveSelection(); } void recentListSelectionChanged(Object selection) @@ -510,14 +523,15 @@ public class JalviewFileChooser extends JFileChooser class RecentlyOpened extends JPanel { - JList list; + private static final long serialVersionUID = 1L; + JList list; - public RecentlyOpened() + RecentlyOpened() { - - String historyItems = jalview.bin.Cache.getProperty("RECENT_FILE"); + setPreferredSize(new Dimension(300,100)); + String historyItems = Cache.getProperty("RECENT_FILE"); StringTokenizer st; - Vector recent = new Vector(); + Vector recent = new Vector<>(); if (historyItems != null) { @@ -525,12 +539,12 @@ public class JalviewFileChooser extends JFileChooser while (st.hasMoreTokens()) { - recent.addElement(st.nextElement()); + recent.addElement(st.nextToken()); } } - list = new JList(recent); - + list = new JList<>(recent); + DefaultListCellRenderer dlcr = new DefaultListCellRenderer(); dlcr.setHorizontalAlignment(DefaultListCellRenderer.RIGHT); list.setCellRenderer(dlcr); @@ -555,13 +569,13 @@ public class JalviewFileChooser extends JFileChooser layout.putConstraint(SpringLayout.NORTH, scroller, 5, SpringLayout.NORTH, this); - if (new Platform().isAMac()) + if (Platform.isAMacAndNotJS()) { scroller.setPreferredSize(new Dimension(500, 100)); } else { - scroller.setPreferredSize(new Dimension(130, 200)); + scroller.setPreferredSize(new Dimension(530, 200)); } this.add(scroller); @@ -579,4 +593,50 @@ public class JalviewFileChooser extends JFileChooser } } + + @Override + public DialogRunnerI setResponseHandler(Object response, Runnable action) + { + callbacks.put(response, action); + return this; + } + + @Override + public void handleResponse(Object response) + { + /* + * this test is for NaN in Chrome + */ + if (response != null && !response.equals(response)) + { + return; + } + Runnable action = callbacks.get(response); + if (action != null) + { + action.run(); + } + } + + /** + * JalviewJS signals file selection by a property change event + * for property "SelectedFile". This methods responds to that by + * running the response action for 'OK' in the dialog. + * + * @param evt + */ + @Override + public void propertyChange(PropertyChangeEvent evt) + { + // TODO other properties need runners... + switch (evt.getPropertyName()) + { + /* + * property name here matches that used in JFileChooser.js + */ + case "SelectedFile": + handleResponse(APPROVE_OPTION); + break; + } + } }