source: josm/trunk/src/org/openstreetmap/josm/gui/widgets/FileChooserManager.java

Last change on this file was 18208, checked in by Don-vip, 3 years ago

global use of Utils.isEmpty/isBlank

  • Property svn:eol-style set to native
File size: 15.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.widgets;
3
4import java.awt.Component;
5import java.io.File;
6import java.util.Collection;
7import java.util.Collections;
8import java.util.function.Predicate;
9
10import javax.swing.Action;
11import javax.swing.JFileChooser;
12import javax.swing.filechooser.FileFilter;
13
14import org.openstreetmap.josm.actions.DiskAccessAction;
15import org.openstreetmap.josm.actions.ExtensionFileFilter;
16import org.openstreetmap.josm.actions.SaveActionBase;
17import org.openstreetmap.josm.data.preferences.BooleanProperty;
18import org.openstreetmap.josm.gui.MainApplication;
19import org.openstreetmap.josm.spi.preferences.Config;
20import org.openstreetmap.josm.tools.PlatformManager;
21import org.openstreetmap.josm.tools.Utils;
22
23/**
24 * A chained utility class used to create and open {@link AbstractFileChooser} dialogs.<br>
25 * Use only this class if you need to control specifically your AbstractFileChooser dialog.<br>
26 * <p>
27 * A simpler usage is to call the {@link DiskAccessAction#createAndOpenFileChooser} methods.
28 *
29 * @since 5438 (creation)
30 * @since 7578 (rename)
31 */
32public class FileChooserManager {
33
34 /**
35 * Property to enable use of native file dialogs.
36 */
37 public static final BooleanProperty PROP_USE_NATIVE_FILE_DIALOG = new BooleanProperty("use.native.file.dialog",
38 // Native dialogs do not support file filters, so do not set them as default, except for OS X where they never worked
39 PlatformManager.isPlatformOsx());
40
41 /**
42 * Property to use the details view in file dialogs.
43 */
44 public static final BooleanProperty PROP_USE_DETAILS_VIEW_FILE_DIALOG = new BooleanProperty("use.details.view.file.dialog", false);
45
46 private final boolean open;
47 private final String lastDirProperty;
48 private final String curDir;
49
50 private boolean multiple;
51 private String title;
52 private Collection<? extends FileFilter> filters;
53 private FileFilter defaultFilter;
54 private int selectionMode = JFileChooser.FILES_ONLY;
55 private String extension;
56 private Predicate<ExtensionFileFilter> additionalTypes = ignore -> false;
57 private File file;
58
59 private AbstractFileChooser fc;
60
61 /**
62 * Creates a new {@code FileChooserManager} with default values.
63 * @see #createFileChooser
64 */
65 public FileChooserManager() {
66 this(false, null, null);
67 }
68
69 /**
70 * Creates a new {@code FileChooserManager}.
71 * @param open If true, "Open File" dialogs will be created. If false, "Save File" dialogs will be created.
72 * @see #createFileChooser
73 */
74 public FileChooserManager(boolean open) {
75 this(open, null);
76 }
77
78 // CHECKSTYLE.OFF: LineLength
79
80 /**
81 * Creates a new {@code FileChooserManager}.
82 * @param open If true, "Open File" dialogs will be created. If false, "Save File" dialogs will be created.
83 * @param lastDirProperty The name of the property used to get the last directory. This directory is used to initialize the AbstractFileChooser.
84 * Then, if the user effectively chooses a file or a directory, this property will be updated to the directory path.
85 * @see #createFileChooser
86 */
87 public FileChooserManager(boolean open, String lastDirProperty) {
88 this(open, lastDirProperty, null);
89 }
90
91 /**
92 * Creates a new {@code FileChooserManager}.
93 * @param open If true, "Open File" dialogs will be created. If false, "Save File" dialogs will be created.
94 * @param lastDirProperty The name of the property used to get the last directory. This directory is used to initialize the AbstractFileChooser.
95 * Then, if the user effectively chooses a file or a directory, this property will be updated to the directory path.
96 * @param defaultDir The default directory used to initialize the AbstractFileChooser if the {@code lastDirProperty} property value is missing.
97 * @see #createFileChooser
98 */
99 public FileChooserManager(boolean open, String lastDirProperty, String defaultDir) {
100 this.open = open;
101 this.lastDirProperty = Utils.isEmpty(lastDirProperty) ? "lastDirectory" : lastDirProperty;
102 this.curDir = Config.getPref().get(this.lastDirProperty).isEmpty() ?
103 Utils.isEmpty(defaultDir) ? "." : defaultDir
104 : Config.getPref().get(this.lastDirProperty);
105 }
106
107 // CHECKSTYLE.ON: LineLength
108
109 /**
110 * Replies the {@code AbstractFileChooser} that has been previously created.
111 * @return The {@code AbstractFileChooser} that has been previously created, or {@code null} if it has not been created yet.
112 * @see #createFileChooser
113 */
114 public final AbstractFileChooser getFileChooser() {
115 return fc;
116 }
117
118 /**
119 * Replies the initial directory used to construct the {@code AbstractFileChooser}.
120 * @return The initial directory used to construct the {@code AbstractFileChooser}.
121 */
122 public final String getInitialDirectory() {
123 return curDir;
124 }
125
126 /**
127 * Creates a new {@link AbstractFileChooser} with default settings. All files will be accepted.
128 * @return this
129 */
130 public final FileChooserManager createFileChooser() {
131 return doCreateFileChooser();
132 }
133
134 /**
135 * Creates a new {@link AbstractFileChooser} with given settings for a single {@code FileFilter}.
136 *
137 * @param multiple If true, makes the dialog allow multiple file selections
138 * @param title The string that goes in the dialog window's title bar
139 * @param filter The only file filter that will be proposed by the dialog
140 * @param selectionMode The selection mode that allows the user to:<br><ul>
141 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li>
142 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li>
143 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li></ul>
144 * @return this
145 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
146 */
147 public final FileChooserManager createFileChooser(boolean multiple, String title, FileFilter filter, int selectionMode) {
148 multiple(multiple);
149 title(title);
150 filters(Collections.singleton(filter));
151 defaultFilter(filter);
152 selectionMode(selectionMode);
153
154 doCreateFileChooser();
155 fc.setAcceptAllFileFilterUsed(false);
156 return this;
157 }
158
159 /**
160 * Creates a new {@link AbstractFileChooser} with given settings for a collection of {@code FileFilter}s.
161 *
162 * @param multiple If true, makes the dialog allow multiple file selections
163 * @param title The string that goes in the dialog window's title bar
164 * @param filters The file filters that will be proposed by the dialog
165 * @param defaultFilter The file filter that will be selected by default
166 * @param selectionMode The selection mode that allows the user to:<br><ul>
167 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li>
168 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li>
169 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li></ul>
170 * @return this
171 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, Collection, FileFilter, int, String)
172 */
173 public final FileChooserManager createFileChooser(boolean multiple, String title, Collection<? extends FileFilter> filters,
174 FileFilter defaultFilter, int selectionMode) {
175 multiple(multiple);
176 title(title);
177 filters(filters);
178 defaultFilter(defaultFilter);
179 selectionMode(selectionMode);
180 return doCreateFileChooser();
181 }
182
183 /**
184 * Creates a new {@link AbstractFileChooser} with given settings for a file extension.
185 *
186 * @param multiple If true, makes the dialog allow multiple file selections
187 * @param title The string that goes in the dialog window's title bar
188 * @param extension The file extension that will be selected as the default file filter
189 * @param allTypes If true, all the files types known by JOSM will be proposed in the "file type" combobox.
190 * If false, only the file filters that include {@code extension} will be proposed
191 * @param selectionMode The selection mode that allows the user to:<br><ul>
192 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li>
193 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li>
194 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li></ul>
195 * @return this
196 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
197 */
198 public final FileChooserManager createFileChooser(boolean multiple, String title, String extension, boolean allTypes, int selectionMode) {
199 multiple(multiple);
200 title(title);
201 extension(extension);
202 allTypes(allTypes);
203 selectionMode(selectionMode);
204 return doCreateFileChooser();
205 }
206
207 /**
208 * Builder method to set {@code multiple} property.
209 * @param value If true, makes the dialog allow multiple file selections
210 * @return this
211 */
212 public FileChooserManager multiple(boolean value) {
213 multiple = value;
214 return this;
215 }
216
217 /**
218 * Builder method to set {@code title} property.
219 * @param value The string that goes in the dialog window's title bar
220 * @return this
221 */
222 public FileChooserManager title(String value) {
223 title = value;
224 return this;
225 }
226
227 /**
228 * Builder method to set {@code filters} property.
229 * @param value The file filters that will be proposed by the dialog
230 * @return this
231 */
232 public FileChooserManager filters(Collection<? extends FileFilter> value) {
233 filters = value;
234 return this;
235 }
236
237 /**
238 * Builder method to set {@code defaultFilter} property.
239 * @param value The file filter that will be selected by default
240 * @return this
241 */
242 public FileChooserManager defaultFilter(FileFilter value) {
243 defaultFilter = value;
244 return this;
245 }
246
247 /**
248 * Builder method to set {@code selectionMode} property.
249 * @param value The selection mode that allows the user to:<br><ul>
250 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li>
251 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li>
252 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li></ul>
253 * @return this
254 */
255 public FileChooserManager selectionMode(int value) {
256 selectionMode = value;
257 return this;
258 }
259
260 /**
261 * Builder method to set {@code extension} property.
262 * @param value The file extension that will be selected as the default file filter
263 * @return this
264 */
265 public FileChooserManager extension(String value) {
266 extension = value;
267 return this;
268 }
269
270 /**
271 * Builder method to set {@code additionalTypes} property.
272 * @param value matching types will additionally be added to the "file type" combobox.
273 * @return this
274 */
275 public FileChooserManager additionalTypes(Predicate<ExtensionFileFilter> value) {
276 additionalTypes = value;
277 return this;
278 }
279
280 /**
281 * Builder method to set {@code allTypes} property.
282 * @param value If true, all the files types known by JOSM will be proposed in the "file type" combobox.
283 * If false, only the file filters that include {@code extension} will be proposed
284 * @return this
285 */
286 public FileChooserManager allTypes(boolean value) {
287 additionalTypes = ignore -> value;
288 return this;
289 }
290
291 /**
292 * Builder method to set {@code file} property.
293 * @param value {@link File} object with default filename
294 * @return this
295 */
296 public FileChooserManager file(File value) {
297 file = value;
298 return this;
299 }
300
301 /**
302 * Builds {@code FileChooserManager} object using properties set by builder methods or default values.
303 * @return this
304 */
305 public FileChooserManager doCreateFileChooser() {
306 File f = new File(curDir);
307 // Use native dialog is preference is set, unless an unsupported selection mode is specifically wanted
308 if (PROP_USE_NATIVE_FILE_DIALOG.get() && NativeFileChooser.supportsSelectionMode(selectionMode)) {
309 fc = new NativeFileChooser(f);
310 } else {
311 fc = new SwingFileChooser(f);
312 if (PROP_USE_DETAILS_VIEW_FILE_DIALOG.get()) {
313 // See sun.swing.FilePane.ACTION_VIEW_DETAILS
314 Action details = fc.getActionMap().get("viewTypeDetails");
315 if (details != null) {
316 details.actionPerformed(null);
317 }
318 }
319 }
320
321 if (title != null) {
322 fc.setDialogTitle(title);
323 }
324
325 fc.setFileSelectionMode(selectionMode);
326 fc.setMultiSelectionEnabled(multiple);
327 fc.setAcceptAllFileFilterUsed(false);
328 fc.setSelectedFile(this.file);
329
330 if (filters != null) {
331 for (FileFilter filter : filters) {
332 fc.addChoosableFileFilter(filter);
333 }
334 if (defaultFilter != null) {
335 fc.setFileFilter(defaultFilter);
336 }
337 } else if (open) {
338 ExtensionFileFilter.applyChoosableImportFileFilters(fc, extension, additionalTypes);
339 } else {
340 ExtensionFileFilter.applyChoosableExportFileFilters(fc, extension, additionalTypes);
341 }
342 return this;
343 }
344
345 /**
346 * Opens the {@code AbstractFileChooser} that has been created.
347 * @return the {@code AbstractFileChooser} if the user effectively chooses a file or directory.
348 * {@code null} if the user cancelled the dialog.
349 */
350 public final AbstractFileChooser openFileChooser() {
351 return openFileChooser(null);
352 }
353
354 /**
355 * Opens the {@code AbstractFileChooser} that has been created and waits for the user to choose a file/directory,
356 * or cancel the dialog.<br>
357 * When the user chooses a file or directory, the {@code lastDirProperty} is updated to the chosen directory path.
358 *
359 * @param parent The Component used as the parent of the AbstractFileChooser. If null,
360 * uses {@code MainApplication.getMainFrame()}.
361 * @return the {@code AbstractFileChooser} if the user effectively chooses
362 * a file or directory.{@code null} if the user cancelled the dialog.
363 */
364 public AbstractFileChooser openFileChooser(Component parent) {
365 if (fc == null)
366 doCreateFileChooser();
367
368 if (parent == null) {
369 parent = MainApplication.getMainFrame();
370 }
371
372 int answer = open ? fc.showOpenDialog(parent) : fc.showSaveDialog(parent);
373 if (answer != JFileChooser.APPROVE_OPTION) {
374 return null;
375 }
376
377 if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
378 Config.getPref().put(lastDirProperty, fc.getCurrentDirectory().getAbsolutePath());
379 }
380
381 if (!open && !FileChooserManager.PROP_USE_NATIVE_FILE_DIALOG.get() &&
382 !SaveActionBase.confirmOverwrite(fc.getSelectedFile())) {
383 return null;
384 }
385 return fc;
386 }
387
388 /**
389 * Opens the file chooser dialog, then checks if filename has the given extension.
390 * If not, adds the extension and asks for overwrite if filename exists.
391 *
392 * @return the {@code File} or {@code null} if the user cancelled the dialog.
393 */
394 public File getFileForSave() {
395 return SaveActionBase.checkFileAndConfirmOverWrite(openFileChooser(), extension);
396 }
397}
Note: See TracBrowser for help on using the repository browser.