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 effectively chooses 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 effectively chooses 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 }