001 package org.openstreetmap.josm.gui.widgets; 002 003 import java.awt.Component; 004 import java.io.File; 005 import java.util.Collection; 006 import java.util.Collections; 007 008 import javax.swing.JFileChooser; 009 import javax.swing.filechooser.FileFilter; 010 011 import org.openstreetmap.josm.Main; 012 import org.openstreetmap.josm.actions.DiskAccessAction; 013 import org.openstreetmap.josm.actions.ExtensionFileFilter; 014 import org.openstreetmap.josm.actions.SaveActionBase; 015 016 /** 017 * A chained utility class used to create and open {@link JFileChooser} dialogs.<br/> 018 * Use only this class if you need to control specifically your JFileChooser dialog.<br/> 019 * <p> 020 * A simpler usage is to call the {@link DiskAccessAction#createAndOpenFileChooser} methods. 021 * 022 * @since 5438 023 */ 024 public class JFileChooserManager { 025 private final boolean open; 026 private final String lastDirProperty; 027 private final String curDir; 028 029 private JFileChooser fc; 030 031 /** 032 * Creates a new {@code JFileChooserManager}. 033 * @param open If true, "Open File" dialogs will be created. If false, "Save File" dialogs will be created. 034 * @see #createFileChooser 035 */ 036 public JFileChooserManager(boolean open) { 037 this(open, null); 038 } 039 040 /** 041 * Creates a new {@code JFileChooserManager}. 042 * @param open If true, "Open File" dialogs will be created. If false, "Save File" dialogs will be created. 043 * @param lastDirProperty The name of the property used to get the last directory. This directory is used to initialize the JFileChooser. 044 * Then, if the user effetively choses a file or a directory, this property will be updated to the directory path. 045 * @see #createFileChooser 046 */ 047 public JFileChooserManager(boolean open, String lastDirProperty) { 048 this(open, lastDirProperty, null); 049 } 050 051 /** 052 * Creates a new {@code JFileChooserManager}. 053 * @param open If true, "Open File" dialogs will be created. If false, "Save File" dialogs will be created. 054 * @param lastDirProperty The name of the property used to get the last directory. This directory is used to initialize the JFileChooser. 055 * Then, if the user effetively choses a file or a directory, this property will be updated to the directory path. 056 * @param defaultDir The default directory used to initialize the JFileChooser if the {@code lastDirProperty} property value is missing. 057 * @see #createFileChooser 058 */ 059 public JFileChooserManager(boolean open, String lastDirProperty, String defaultDir) { 060 this.open = open; 061 this.lastDirProperty = lastDirProperty == null || lastDirProperty.isEmpty() ? "lastDirectory" : lastDirProperty; 062 this.curDir = Main.pref.get(this.lastDirProperty).isEmpty() ? 063 (defaultDir == null || defaultDir.isEmpty() ? "." : defaultDir) 064 : Main.pref.get(this.lastDirProperty); 065 } 066 067 /** 068 * Replies the {@code JFileChooser} that has been previously created. 069 * @return The {@code JFileChooser} that has been previously created, or {@code null} if it has not been created yet. 070 * @see #createFileChooser 071 */ 072 public final JFileChooser getFileChooser() { 073 return fc; 074 } 075 076 /** 077 * Replies the initial directory used to construct the {@code JFileChooser}. 078 * @return The initial directory used to construct the {@code JFileChooser}. 079 */ 080 public final String getInitialDirectory() { 081 return curDir; 082 } 083 084 /** 085 * Creates a new {@link JFileChooser} with default settings. All files will be accepted. 086 * @return this 087 */ 088 public final JFileChooserManager createFileChooser() { 089 return doCreateFileChooser(false, null, null, null, null, JFileChooser.FILES_ONLY, false); 090 } 091 092 /** 093 * Creates a new {@link JFileChooser} with given settings for a single {@code FileFilter}. 094 * 095 * @param multiple If true, makes the dialog allow multiple file selections 096 * @param title The string that goes in the dialog window's title bar 097 * @param filter The only file filter that will be proposed by the dialog 098 * @param selectionMode The selection mode that allows the user to:<br/> 099 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li> 100 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li> 101 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li> 102 * @return this 103 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String) 104 */ 105 public final JFileChooserManager createFileChooser(boolean multiple, String title, FileFilter filter, int selectionMode) { 106 doCreateFileChooser(multiple, title, Collections.singleton(filter), filter, null, selectionMode, false); 107 getFileChooser().setAcceptAllFileFilterUsed(false); 108 return this; 109 } 110 111 /** 112 * Creates a new {@link JFileChooser} with given settings for a collection of {@code FileFilter}s. 113 * 114 * @param multiple If true, makes the dialog allow multiple file selections 115 * @param title The string that goes in the dialog window's title bar 116 * @param filters The file filters that will be proposed by the dialog 117 * @param defaultFilter The file filter that will be selected by default 118 * @param selectionMode The selection mode that allows the user to:<br/> 119 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li> 120 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li> 121 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li> 122 * @return this 123 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, Collection, FileFilter, int, String) 124 */ 125 public final JFileChooserManager createFileChooser(boolean multiple, String title, Collection<? extends FileFilter> filters, FileFilter defaultFilter, int selectionMode) { 126 return doCreateFileChooser(multiple, title, filters, defaultFilter, null, selectionMode, false); 127 } 128 129 /** 130 * Creates a new {@link JFileChooser} with given settings for a file extension. 131 * 132 * @param multiple If true, makes the dialog allow multiple file selections 133 * @param title The string that goes in the dialog window's title bar 134 * @param extension The file extension that will be selected as the default file filter 135 * @param allTypes If true, all the files types known by JOSM will be proposed in the "file type" combobox. 136 * If false, only the file filters that include {@code extension} will be proposed 137 * @param selectionMode The selection mode that allows the user to:<br/> 138 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li> 139 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li> 140 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li> 141 * @return this 142 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String) 143 */ 144 public final JFileChooserManager createFileChooser(boolean multiple, String title, String extension, boolean allTypes, int selectionMode) { 145 return doCreateFileChooser(multiple, title, null, null, extension, selectionMode, allTypes); 146 } 147 148 private final JFileChooserManager doCreateFileChooser(boolean multiple, String title, Collection<? extends FileFilter> filters, FileFilter defaultFilter, String extension, int selectionMode, boolean allTypes) { 149 fc = new JFileChooser(new File(curDir)); 150 if (title != null) { 151 fc.setDialogTitle(title); 152 } 153 154 fc.setFileSelectionMode(selectionMode); 155 fc.setMultiSelectionEnabled(multiple); 156 fc.setAcceptAllFileFilterUsed(false); 157 158 if (filters != null) { 159 for (FileFilter filter : filters) { 160 fc.addChoosableFileFilter(filter); 161 } 162 if (defaultFilter != null) { 163 fc.setFileFilter(defaultFilter); 164 } 165 } else if (open) { 166 ExtensionFileFilter.applyChoosableImportFileFilters(fc, extension, allTypes); 167 } else { 168 ExtensionFileFilter.applyChoosableExportFileFilters(fc, extension, allTypes); 169 } 170 return this; 171 } 172 173 /** 174 * Opens the {@code JFileChooser} that has been created. Nothing happens if it has not been created yet. 175 * @return the {@code JFileChooser} if the user effectively choses a file or directory. {@code null} if the user cancelled the dialog. 176 */ 177 public final JFileChooser openFileChooser() { 178 return openFileChooser(null); 179 } 180 181 /** 182 * Opens the {@code JFileChooser} that has been created and waits for the user to choose a file/directory, or cancel the dialog.<br/> 183 * Nothing happens if the dialog has not been created yet.<br/> 184 * When the user choses a file or directory, the {@code lastDirProperty} is updated to the chosen directory path. 185 * 186 * @param parent The Component used as the parent of the JFileChooser. If null, uses {@code Main.parent}. 187 * @return the {@code JFileChooser} if the user effectively choses a file or directory. {@code null} if the user cancelled the dialog. 188 */ 189 public JFileChooser openFileChooser(Component parent) { 190 if (fc != null) { 191 if (parent == null) { 192 parent = Main.parent; 193 } 194 195 int answer = open ? fc.showOpenDialog(parent) : fc.showSaveDialog(parent); 196 if (answer != JFileChooser.APPROVE_OPTION) { 197 return null; 198 } 199 200 if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) { 201 Main.pref.put(lastDirProperty, fc.getCurrentDirectory().getAbsolutePath()); 202 } 203 204 if (!open) { 205 File file = fc.getSelectedFile(); 206 if (!SaveActionBase.confirmOverwrite(file)) { 207 return null; 208 } 209 } 210 } 211 return fc; 212 } 213 }