// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.gui.widgets;
import java.awt.Component;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Predicate;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import org.openstreetmap.josm.actions.DiskAccessAction;
import org.openstreetmap.josm.actions.ExtensionFileFilter;
import org.openstreetmap.josm.actions.SaveActionBase;
import org.openstreetmap.josm.data.preferences.BooleanProperty;
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.spi.preferences.Config;
import org.openstreetmap.josm.tools.PlatformManager;
import org.openstreetmap.josm.tools.Utils;
/**
* A chained utility class used to create and open {@link AbstractFileChooser} dialogs.
* Use only this class if you need to control specifically your AbstractFileChooser dialog.
*
* A simpler usage is to call the {@link DiskAccessAction#createAndOpenFileChooser} methods.
*
* @since 5438 (creation)
* @since 7578 (rename)
*/
public class FileChooserManager {
/**
* Property to enable use of native file dialogs.
*/
public static final BooleanProperty PROP_USE_NATIVE_FILE_DIALOG = new BooleanProperty("use.native.file.dialog",
// Native dialogs do not support file filters, so do not set them as default, except for OS X where they never worked
PlatformManager.isPlatformOsx());
/**
* Property to use the details view in file dialogs.
*/
public static final BooleanProperty PROP_USE_DETAILS_VIEW_FILE_DIALOG = new BooleanProperty("use.details.view.file.dialog", false);
private final boolean open;
private final String lastDirProperty;
private final String curDir;
private boolean multiple;
private String title;
private Collection extends FileFilter> filters;
private FileFilter defaultFilter;
private int selectionMode = JFileChooser.FILES_ONLY;
private String extension;
private Predicate
*
* @return this
* @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
*/
public final FileChooserManager createFileChooser(boolean multiple, String title, FileFilter filter, int selectionMode) {
multiple(multiple);
title(title);
filters(Collections.singleton(filter));
defaultFilter(filter);
selectionMode(selectionMode);
doCreateFileChooser();
fc.setAcceptAllFileFilterUsed(false);
return this;
}
/**
* Creates a new {@link AbstractFileChooser} with given settings for a collection of {@code FileFilter}s.
*
* @param multiple If true, makes the dialog allow multiple file selections
* @param title The string that goes in the dialog window's title bar
* @param filters The file filters that will be proposed by the dialog
* @param defaultFilter The file filter that will be selected by default
* @param selectionMode The selection mode that allows the user to:
*
* @return this
* @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, Collection, FileFilter, int, String)
*/
public final FileChooserManager createFileChooser(boolean multiple, String title, Collection extends FileFilter> filters,
FileFilter defaultFilter, int selectionMode) {
multiple(multiple);
title(title);
filters(filters);
defaultFilter(defaultFilter);
selectionMode(selectionMode);
return doCreateFileChooser();
}
/**
* Creates a new {@link AbstractFileChooser} with given settings for a file extension.
*
* @param multiple If true, makes the dialog allow multiple file selections
* @param title The string that goes in the dialog window's title bar
* @param extension The file extension that will be selected as the default file filter
* @param allTypes If true, all the files types known by JOSM will be proposed in the "file type" combobox.
* If false, only the file filters that include {@code extension} will be proposed
* @param selectionMode The selection mode that allows the user to:
*
* @return this
* @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
*/
public final FileChooserManager createFileChooser(boolean multiple, String title, String extension, boolean allTypes, int selectionMode) {
multiple(multiple);
title(title);
extension(extension);
allTypes(allTypes);
selectionMode(selectionMode);
return doCreateFileChooser();
}
/**
* Builder method to set {@code multiple} property.
* @param value If true, makes the dialog allow multiple file selections
* @return this
*/
public FileChooserManager multiple(boolean value) {
multiple = value;
return this;
}
/**
* Builder method to set {@code title} property.
* @param value The string that goes in the dialog window's title bar
* @return this
*/
public FileChooserManager title(String value) {
title = value;
return this;
}
/**
* Builder method to set {@code filters} property.
* @param value The file filters that will be proposed by the dialog
* @return this
*/
public FileChooserManager filters(Collection extends FileFilter> value) {
filters = value;
return this;
}
/**
* Builder method to set {@code defaultFilter} property.
* @param value The file filter that will be selected by default
* @return this
*/
public FileChooserManager defaultFilter(FileFilter value) {
defaultFilter = value;
return this;
}
/**
* Builder method to set {@code selectionMode} property.
* @param value The selection mode that allows the user to:
*
* @return this
*/
public FileChooserManager selectionMode(int value) {
selectionMode = value;
return this;
}
/**
* Builder method to set {@code extension} property.
* @param value The file extension that will be selected as the default file filter
* @return this
*/
public FileChooserManager extension(String value) {
extension = value;
return this;
}
/**
* Builder method to set {@code additionalTypes} property.
* @param value matching types will additionally be added to the "file type" combobox.
* @return this
*/
public FileChooserManager additionalTypes(Predicate
* When the user chooses a file or directory, the {@code lastDirProperty} is updated to the chosen directory path.
*
* @param parent The Component used as the parent of the AbstractFileChooser. If null,
* uses {@code MainApplication.getMainFrame()}.
* @return the {@code AbstractFileChooser} if the user effectively chooses
* a file or directory.{@code null} if the user cancelled the dialog.
*/
public AbstractFileChooser openFileChooser(Component parent) {
if (fc == null)
doCreateFileChooser();
if (parent == null) {
parent = MainApplication.getMainFrame();
}
int answer = open ? fc.showOpenDialog(parent) : fc.showSaveDialog(parent);
if (answer != JFileChooser.APPROVE_OPTION) {
return null;
}
if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
Config.getPref().put(lastDirProperty, fc.getCurrentDirectory().getAbsolutePath());
}
if (!open && !FileChooserManager.PROP_USE_NATIVE_FILE_DIALOG.get() &&
!SaveActionBase.confirmOverwrite(fc.getSelectedFile())) {
return null;
}
return fc;
}
/**
* Opens the file chooser dialog, then checks if filename has the given extension.
* If not, adds the extension and asks for overwrite if filename exists.
*
* @return the {@code File} or {@code null} if the user cancelled the dialog.
*/
public File getFileForSave() {
return SaveActionBase.checkFileAndConfirmOverWrite(openFileChooser(), extension);
}
}