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