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

Last change on this file since 7578 was 7578, checked in by Don-vip, 10 years ago

fix #10024 - Add an option in Preferences/Look-and-Feel to use native file-choosing dialogs.
They look nicer but they do not support file filters, so we cannot use them (yet) as default.
Based on patch by Lesath and code review by simon04.
The native dialogs are not used if selection mode is not supported ("files and directories" on all platforms, "directories" on systems other than OS X)

File size: 11.1 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;
8
9import javax.swing.JFileChooser;
10import javax.swing.filechooser.FileFilter;
11
12import org.openstreetmap.josm.Main;
13import org.openstreetmap.josm.actions.DiskAccessAction;
14import org.openstreetmap.josm.actions.ExtensionFileFilter;
15import org.openstreetmap.josm.actions.SaveActionBase;
16import org.openstreetmap.josm.data.preferences.BooleanProperty;
17
18/**
19 * A chained utility class used to create and open {@link AbstractFileChooser} dialogs.<br>
20 * Use only this class if you need to control specifically your AbstractFileChooser dialog.<br>
21 * <p>
22 * A simpler usage is to call the {@link DiskAccessAction#createAndOpenFileChooser} methods.
23 *
24 * @since 5438 (creation)
25 * @since 7578 (rename)
26 */
27public class FileChooserManager {
28
29 /**
30 * Property to enable use of native file dialogs.
31 */
32 public static final BooleanProperty PROP_USE_NATIVE_FILE_DIALOG = new BooleanProperty("use.native.file.dialog", false);
33
34 private final boolean open;
35 private final String lastDirProperty;
36 private final String curDir;
37
38 private AbstractFileChooser fc;
39
40 /**
41 * Creates a new {@code FileChooserManager}.
42 * @param open If true, "Open File" dialogs will be created. If false, "Save File" dialogs will be created.
43 * @see #createFileChooser
44 */
45 public FileChooserManager(boolean open) {
46 this(open, null);
47 }
48
49 /**
50 * Creates a new {@code FileChooserManager}.
51 * @param open If true, "Open File" dialogs will be created. If false, "Save File" dialogs will be created.
52 * @param lastDirProperty The name of the property used to get the last directory. This directory is used to initialize the AbstractFileChooser.
53 * Then, if the user effectively chooses a file or a directory, this property will be updated to the directory path.
54 * @see #createFileChooser
55 */
56 public FileChooserManager(boolean open, String lastDirProperty) {
57 this(open, lastDirProperty, null);
58 }
59
60 /**
61 * Creates a new {@code FileChooserManager}.
62 * @param open If true, "Open File" dialogs will be created. If false, "Save File" dialogs will be created.
63 * @param lastDirProperty The name of the property used to get the last directory. This directory is used to initialize the AbstractFileChooser.
64 * Then, if the user effectively chooses a file or a directory, this property will be updated to the directory path.
65 * @param defaultDir The default directory used to initialize the AbstractFileChooser if the {@code lastDirProperty} property value is missing.
66 * @see #createFileChooser
67 */
68 public FileChooserManager(boolean open, String lastDirProperty, String defaultDir) {
69 this.open = open;
70 this.lastDirProperty = lastDirProperty == null || lastDirProperty.isEmpty() ? "lastDirectory" : lastDirProperty;
71 this.curDir = Main.pref.get(this.lastDirProperty).isEmpty() ?
72 (defaultDir == null || defaultDir.isEmpty() ? "." : defaultDir)
73 : Main.pref.get(this.lastDirProperty);
74 }
75
76 /**
77 * Replies the {@code AbstractFileChooser} that has been previously created.
78 * @return The {@code AbstractFileChooser} that has been previously created, or {@code null} if it has not been created yet.
79 * @see #createFileChooser
80 */
81 public final AbstractFileChooser getFileChooser() {
82 return fc;
83 }
84
85 /**
86 * Replies the initial directory used to construct the {@code AbstractFileChooser}.
87 * @return The initial directory used to construct the {@code AbstractFileChooser}.
88 */
89 public final String getInitialDirectory() {
90 return curDir;
91 }
92
93 /**
94 * Creates a new {@link AbstractFileChooser} with default settings. All files will be accepted.
95 * @return this
96 */
97 public final FileChooserManager createFileChooser() {
98 return doCreateFileChooser(false, null, null, null, null, JFileChooser.FILES_ONLY, false);
99 }
100
101 /**
102 * Creates a new {@link AbstractFileChooser} with given settings for a single {@code FileFilter}.
103 *
104 * @param multiple If true, makes the dialog allow multiple file selections
105 * @param title The string that goes in the dialog window's title bar
106 * @param filter The only file filter that will be proposed by the dialog
107 * @param selectionMode The selection mode that allows the user to:<br><ul>
108 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li>
109 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li>
110 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li></ul>
111 * @return this
112 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
113 */
114 public final FileChooserManager createFileChooser(boolean multiple, String title, FileFilter filter, int selectionMode) {
115 doCreateFileChooser(multiple, title, Collections.singleton(filter), filter, null, selectionMode, false);
116 getFileChooser().setAcceptAllFileFilterUsed(false);
117 return this;
118 }
119
120 /**
121 * Creates a new {@link AbstractFileChooser} with given settings for a collection of {@code FileFilter}s.
122 *
123 * @param multiple If true, makes the dialog allow multiple file selections
124 * @param title The string that goes in the dialog window's title bar
125 * @param filters The file filters that will be proposed by the dialog
126 * @param defaultFilter The file filter that will be selected by default
127 * @param selectionMode The selection mode that allows the user to:<br><ul>
128 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li>
129 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li>
130 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li></ul>
131 * @return this
132 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, Collection, FileFilter, int, String)
133 */
134 public final FileChooserManager createFileChooser(boolean multiple, String title, Collection<? extends FileFilter> filters,
135 FileFilter defaultFilter, int selectionMode) {
136 return doCreateFileChooser(multiple, title, filters, defaultFilter, null, selectionMode, false);
137 }
138
139 /**
140 * Creates a new {@link AbstractFileChooser} with given settings for a file extension.
141 *
142 * @param multiple If true, makes the dialog allow multiple file selections
143 * @param title The string that goes in the dialog window's title bar
144 * @param extension The file extension that will be selected as the default file filter
145 * @param allTypes If true, all the files types known by JOSM will be proposed in the "file type" combobox.
146 * If false, only the file filters that include {@code extension} will be proposed
147 * @param selectionMode The selection mode that allows the user to:<br><ul>
148 * <li>just select files ({@code JFileChooser.FILES_ONLY})</li>
149 * <li>just select directories ({@code JFileChooser.DIRECTORIES_ONLY})</li>
150 * <li>select both files and directories ({@code JFileChooser.FILES_AND_DIRECTORIES})</li></ul>
151 * @return this
152 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
153 */
154 public final FileChooserManager createFileChooser(boolean multiple, String title, String extension, boolean allTypes, int selectionMode) {
155 return doCreateFileChooser(multiple, title, null, null, extension, selectionMode, allTypes);
156 }
157
158 private final FileChooserManager doCreateFileChooser(boolean multiple, String title, Collection<? extends FileFilter> filters,
159 FileFilter defaultFilter, String extension, int selectionMode, boolean allTypes) {
160 File file = new File(curDir);
161 // Use native dialog is preference is set, unless an unsupported selection mode is specifically wanted
162 if (PROP_USE_NATIVE_FILE_DIALOG.get() && NativeFileChooser.supportsSelectionMode(selectionMode)) {
163 fc = new NativeFileChooser(file);
164 } else {
165 fc = new SwingFileChooser(file);
166 }
167
168 if (title != null) {
169 fc.setDialogTitle(title);
170 }
171
172 fc.setFileSelectionMode(selectionMode);
173 fc.setMultiSelectionEnabled(multiple);
174 fc.setAcceptAllFileFilterUsed(false);
175
176 if (filters != null) {
177 for (FileFilter filter : filters) {
178 fc.addChoosableFileFilter(filter);
179 }
180 if (defaultFilter != null) {
181 fc.setFileFilter(defaultFilter);
182 }
183 } else if (open) {
184 ExtensionFileFilter.applyChoosableImportFileFilters(fc, extension, allTypes);
185 } else {
186 ExtensionFileFilter.applyChoosableExportFileFilters(fc, extension, allTypes);
187 }
188 return this;
189 }
190
191 /**
192 * Opens the {@code AbstractFileChooser} that has been created. Nothing happens if it has not been created yet.
193 * @return the {@code AbstractFileChooser} if the user effectively choses a file or directory. {@code null} if the user cancelled the dialog.
194 */
195 public final AbstractFileChooser openFileChooser() {
196 return openFileChooser(null);
197 }
198
199 /**
200 * Opens the {@code AbstractFileChooser} that has been created and waits for the user to choose a file/directory, or cancel the dialog.<br>
201 * Nothing happens if the dialog has not been created yet.<br>
202 * When the user choses a file or directory, the {@code lastDirProperty} is updated to the chosen directory path.
203 *
204 * @param parent The Component used as the parent of the AbstractFileChooser. If null, uses {@code Main.parent}.
205 * @return the {@code AbstractFileChooser} if the user effectively choses a file or directory. {@code null} if the user cancelled the dialog.
206 */
207 public AbstractFileChooser openFileChooser(Component parent) {
208 if (fc != null) {
209 if (parent == null) {
210 parent = Main.parent;
211 }
212
213 int answer = open ? fc.showOpenDialog(parent) : fc.showSaveDialog(parent);
214 if (answer != JFileChooser.APPROVE_OPTION) {
215 return null;
216 }
217
218 if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
219 Main.pref.put(lastDirProperty, fc.getCurrentDirectory().getAbsolutePath());
220 }
221
222 if (!open) {
223 File file = fc.getSelectedFile();
224 if (!SaveActionBase.confirmOverwrite(file)) {
225 return null;
226 }
227 }
228 }
229 return fc;
230 }
231}
Note: See TracBrowser for help on using the repository browser.