001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.widgets; 003 004import java.awt.Component; 005import java.awt.FileDialog; 006import java.awt.Frame; 007import java.io.File; 008import java.io.FilenameFilter; 009import java.util.ArrayList; 010import java.util.List; 011 012import javax.swing.JFileChooser; 013import javax.swing.filechooser.FileFilter; 014 015import org.openstreetmap.josm.Main; 016import org.openstreetmap.josm.tools.Utils; 017 018/** 019 * File chooser based on the AWT's {@link FileDialog} implementation, 020 * which looks like more a native file chooser than the Swing implementation. 021 * @since 7578 022 */ 023public class NativeFileChooser extends AbstractFileChooser { 024 025 /** The instance of the fileDialog */ 026 private final FileDialog fileDialog; 027 private FileFilter fileFilter; 028 private final List<FileFilter> fileFilters = new ArrayList<>(); 029 private int selectionMode; 030 031 /** 032 * Constructs a new {@code NativeFileChooser}. 033 * @param file the current file/directory to point to 034 */ 035 public NativeFileChooser(File file) { 036 fileDialog = new FileDialog((Frame) Main.parent); 037 if (file != null) { 038 fileDialog.setDirectory(file.getAbsolutePath()); 039 if (file.isFile()) { 040 fileDialog.setFile(file.toString()); 041 } 042 } 043 } 044 045 @Override 046 public void addChoosableFileFilter(FileFilter filter) { 047 // TODO implement this after Oracle fixes JDK-4811090 / JDK-6192906 048 // https://bugs.openjdk.java.net/browse/JDK-4811090 : Extend awt filedialog 049 // https://bugs.openjdk.java.net/browse/JDK-6192906 : Add more features to java.awt.FileDialog 050 fileFilters.add(filter); 051 } 052 053 @Override 054 public FileFilter[] getChoosableFileFilters() { 055 // TODO implement this after Oracle fixes JDK-4811090 / JDK-6192906 056 // https://bugs.openjdk.java.net/browse/JDK-4811090 : Extend awt filedialog 057 // https://bugs.openjdk.java.net/browse/JDK-6192906 : Add more features to java.awt.FileDialog 058 return fileFilters.toArray(new FileFilter[0]); 059 } 060 061 @Override 062 public File getCurrentDirectory() { 063 return new File(fileDialog.getDirectory()); 064 } 065 066 @Override 067 public FileFilter getFileFilter() { 068 return fileFilter; 069 } 070 071 @Override 072 public File getSelectedFile() { 073 return new File(fileDialog.getDirectory() + fileDialog.getFile()); 074 } 075 076 @Override 077 public File[] getSelectedFiles() { 078 return fileDialog.getFiles(); 079 } 080 081 @Override 082 public boolean isMultiSelectionEnabled() { 083 return fileDialog.isMultipleMode(); 084 } 085 086 @Override 087 public void setAcceptAllFileFilterUsed(boolean b) { 088 // TODO implement this after Oracle fixes JDK-4811090 / JDK-6192906 089 // https://bugs.openjdk.java.net/browse/JDK-4811090 : Extend awt filedialog 090 // https://bugs.openjdk.java.net/browse/JDK-6192906 : Add more features to java.awt.FileDialog 091 } 092 093 @Override 094 public void setCurrentDirectory(File f) { 095 fileDialog.setDirectory(f.toString()); 096 } 097 098 @Override 099 public void setDialogTitle(String title) { 100 fileDialog.setTitle(title); 101 } 102 103 @Override 104 public void setFileFilter(final FileFilter cff) { 105 FilenameFilter filter = (directory, fileName) -> cff.accept(new File(directory.getAbsolutePath() + fileName)); 106 fileDialog.setFilenameFilter(filter); 107 fileFilter = cff; 108 } 109 110 @Override 111 public void setFileSelectionMode(int selectionMode) { 112 // CHECKSTYLE.OFF: LineLength 113 // TODO implement this after Oracle fixes JDK-6192906 / JDK-6699863 / JDK-6927978 / JDK-7125172: 114 // https://bugs.openjdk.java.net/browse/JDK-6192906 : Add more features to java.awt.FileDialog 115 // https://bugs.openjdk.java.net/browse/JDK-6699863 : awt filedialog cannot select directories 116 // https://bugs.openjdk.java.net/browse/JDK-6927978 : Directory Selection standard dialog support 117 // https://bugs.openjdk.java.net/browse/JDK-7125172 : FileDialog objects don't allow directory AND files selection simultaneously 118 119 // There is however a basic support for directory selection on OS X, with Java >= 7u40: 120 // http://stackoverflow.com/questions/1224714/how-can-i-make-a-java-filedialog-accept-directories-as-its-filetype-in-os-x/1224744#1224744 121 // https://bugs.openjdk.java.net/browse/JDK-7161437 : [macosx] awt.FileDialog doesn't respond appropriately for mac when selecting folders 122 // CHECKSTYLE.ON: LineLength 123 this.selectionMode = selectionMode; 124 } 125 126 @Override 127 public void setMultiSelectionEnabled(boolean multiple) { 128 fileDialog.setMultipleMode(multiple); 129 } 130 131 @Override 132 public void setSelectedFile(File file) { 133 if (file == null) return; 134 fileDialog.setDirectory(file.getParent()); 135 fileDialog.setFile(file.getName()); 136 } 137 138 @Override 139 public int showOpenDialog(Component parent) { 140 boolean appleProperty = Main.isPlatformOsx() && selectionMode == JFileChooser.DIRECTORIES_ONLY; 141 if (appleProperty) { 142 Utils.updateSystemProperty("apple.awt.fileDialogForDirectories", "true"); 143 } 144 try { 145 fileDialog.setLocale(locale); 146 fileDialog.setMode(FileDialog.LOAD); 147 fileDialog.setVisible(true); 148 return fileDialog.getFile() == null ? JFileChooser.CANCEL_OPTION : JFileChooser.APPROVE_OPTION; 149 } finally { 150 if (appleProperty) { 151 Utils.updateSystemProperty("apple.awt.fileDialogForDirectories", "false"); 152 } 153 } 154 } 155 156 @Override 157 public int showSaveDialog(Component parent) { 158 fileDialog.setLocale(locale); 159 fileDialog.setMode(FileDialog.SAVE); 160 fileDialog.setVisible(true); 161 return fileDialog.getFile() == null ? JFileChooser.CANCEL_OPTION : JFileChooser.APPROVE_OPTION; 162 } 163 164 /** 165 * Determines if the selection mode is suuported by the native file chooser. 166 * @param selectionMode the selection mode 167 * @return {@code true} if the selection mode is supported, {@code false} otherwise 168 */ 169 public static boolean supportsSelectionMode(int selectionMode) { 170 switch (selectionMode) { 171 case JFileChooser.FILES_AND_DIRECTORIES: 172 // CHECKSTYLE.OFF: LineLength 173 // https://bugs.openjdk.java.net/browse/JDK-7125172 : FileDialog objects don't allow directory AND files selection simultaneously 174 return false; 175 case JFileChooser.DIRECTORIES_ONLY: 176 // http://stackoverflow.com/questions/1224714/how-can-i-make-a-java-filedialog-accept-directories-as-its-filetype-in-os-x/1224744#1224744 177 // CHECKSTYLE.ON: LineLength 178 return Main.isPlatformOsx(); 179 case JFileChooser.FILES_ONLY: 180 default: 181 return true; 182 } 183 } 184}