From 1495881e93e8095ee99ae6fa45afdff8a7ed7480 Mon Sep 17 00:00:00 2001 From: Jan Eglinger Date: Fri, 30 Jun 2017 12:20:43 +0200 Subject: [PATCH 1/3] Add method signatures and preprocessor to select multiple files --- .../java/org/scijava/ui/DefaultUIService.java | 13 ++++ .../org/scijava/ui/FileListPreprocessor.java | 64 +++++++++++++++++++ src/main/java/org/scijava/ui/UIService.java | 24 ++++++- .../java/org/scijava/ui/UserInterface.java | 29 ++++++++- .../org/scijava/widget/FileListWidget.java | 7 ++ 5 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/scijava/ui/FileListPreprocessor.java create mode 100644 src/main/java/org/scijava/widget/FileListWidget.java diff --git a/src/main/java/org/scijava/ui/DefaultUIService.java b/src/main/java/org/scijava/ui/DefaultUIService.java index 687d59dd1..76aae7e50 100644 --- a/src/main/java/org/scijava/ui/DefaultUIService.java +++ b/src/main/java/org/scijava/ui/DefaultUIService.java @@ -33,6 +33,7 @@ package org.scijava.ui; import java.io.File; +import java.io.FileFilter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -319,6 +320,18 @@ public File chooseFile(final File file, final String style) { return ui == null ? null : ui.chooseFile(title, file, style); } + @Override + public File[] chooseFiles(File[] files, FileFilter filter) { + final UserInterface ui = getDefaultUI(); + return ui == null ? null : ui.chooseFiles(files, filter); + } + + @Override + public List chooseFiles(List fileList, FileFilter filter) { + final UserInterface ui = getDefaultUI(); + return ui == null ? null : ui.chooseFiles(fileList, filter); + } + @Override public void showContextMenu(final String menuRoot, final Display display, final int x, final int y) diff --git a/src/main/java/org/scijava/ui/FileListPreprocessor.java b/src/main/java/org/scijava/ui/FileListPreprocessor.java new file mode 100644 index 000000000..3da89f95f --- /dev/null +++ b/src/main/java/org/scijava/ui/FileListPreprocessor.java @@ -0,0 +1,64 @@ +package org.scijava.ui; + +import java.io.File; + +import org.scijava.module.Module; +import org.scijava.module.ModuleItem; +import org.scijava.module.process.AbstractPreprocessorPlugin; +import org.scijava.module.process.PreprocessorPlugin; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.widget.InputHarvester; + +@Plugin(type = PreprocessorPlugin.class, priority = InputHarvester.PRIORITY + 1.0) +public class FileListPreprocessor extends AbstractPreprocessorPlugin { + + @Parameter(required = false) + private UIService uiService; + + @Override + public void process(final Module module) { + if (uiService == null) return; + final ModuleItem fileInput = getFilesInput(module); + if (fileInput == null) return; + + final File[] files = fileInput.getValue(module); + + // show file chooser dialog box + final File[] result = uiService.chooseFiles(files, null); + if (result == null) { + cancel(""); + return; + } + + fileInput.setValue(module, result); + module.resolveInput(fileInput.getName()); + } + + // -- Helper methods -- + + /** + * Gets the single unresolved {@link File} input parameter. If there is not + * exactly one unresolved {@link File} input parameter, or if there are other + * types of unresolved parameters, this method returns null. + */ + private ModuleItem getFilesInput(final Module module) { + ModuleItem result = null; + for (final ModuleItem input : module.getInfo().inputs()) { + if (module.isInputResolved(input.getName())) continue; + final Class type = input.getType(); + if (!File[].class.isAssignableFrom(type)) { + // not a File[] parameter; abort + return null; + } + if (result != null) { + // second File parameter; abort + return null; + } + @SuppressWarnings("unchecked") + final ModuleItem fileInput = (ModuleItem) input; + result = fileInput; + } + return result; + } +} diff --git a/src/main/java/org/scijava/ui/UIService.java b/src/main/java/org/scijava/ui/UIService.java index c23006b0e..7191679dd 100644 --- a/src/main/java/org/scijava/ui/UIService.java +++ b/src/main/java/org/scijava/ui/UIService.java @@ -33,6 +33,7 @@ package org.scijava.ui; import java.io.File; +import java.io.FileFilter; import java.util.List; import org.scijava.app.StatusService; @@ -294,6 +295,28 @@ DialogPrompt.Result showDialog(String message, String title, */ File chooseFile(String title, File file, String style); + /** + * Prompts the user to select one or multiple files. + *

+ * The prompt is displayed in the default user interface. + *

+ * + * @param files The initial value displayed in the file chooser prompt. + * @param filter A filter allowing to restrict the choice of files + */ + File[] chooseFiles(File[] files, FileFilter filter); + + /** + * Prompts the user to select one or multiple files. + *

+ * The prompt is displayed in the default user interface. + *

+ * + * @param fileList The initial value displayed in the file chooser prompt. + * @param filter A filter allowing to restrict the choice of files + */ + List chooseFiles(List fileList, FileFilter filter); + /** * Displays a popup context menu for the given display at the specified * position. @@ -309,5 +332,4 @@ DialogPrompt.Result showDialog(String message, String title, * @see StatusService#getStatusMessage(String, StatusEvent) */ String getStatusMessage(StatusEvent statusEvent); - } diff --git a/src/main/java/org/scijava/ui/UserInterface.java b/src/main/java/org/scijava/ui/UserInterface.java index 84fd2210b..857090e3a 100644 --- a/src/main/java/org/scijava/ui/UserInterface.java +++ b/src/main/java/org/scijava/ui/UserInterface.java @@ -33,6 +33,9 @@ package org.scijava.ui; import java.io.File; +import java.io.FileFilter; +import java.util.Arrays; +import java.util.List; import org.scijava.Disposable; import org.scijava.display.Display; @@ -185,6 +188,31 @@ default File chooseFile(String title, File file, String style) { throw new UnsupportedOperationException(); } + /** + * Prompts the user to choose a list of files. + * + * @param files The initial value displayed in the file chooser prompt. + * @param filter A filter allowing to restrict file choice. + * @return The selected {@link File}s chosen by the user, or null if prompt is not + * available + */ + default File[] chooseFiles(File[] files, FileFilter filter) { + throw new UnsupportedOperationException(); + } + + /** + * Prompts the user to choose a list of files. + * + * @param fileList The initial value displayed in the file chooser prompt. + * @param filter A filter allowing to restrict file choice. + * @return The selected {@link File}s chosen by the user, or null if prompt is not + * available + */ + default List chooseFiles(List fileList, FileFilter filter) { + File[] files = fileList.toArray(new File[fileList.size()]); + return Arrays.asList(chooseFiles(files, filter)); + } + /** * Displays a popup context menu for the given display at the specified * position. @@ -199,5 +227,4 @@ default File chooseFile(String title, File file, String style) { /** Returns true if this UI requires the EDT. */ boolean requiresEDT(); - } diff --git a/src/main/java/org/scijava/widget/FileListWidget.java b/src/main/java/org/scijava/widget/FileListWidget.java new file mode 100644 index 000000000..c52097c0d --- /dev/null +++ b/src/main/java/org/scijava/widget/FileListWidget.java @@ -0,0 +1,7 @@ +package org.scijava.widget; + +import java.io.File; + +public interface FileListWidget extends InputWidget { + // NB: No changes to interface. +} From de98dcf722c347419b3322b06ae329be755862c5 Mon Sep 17 00:00:00 2001 From: Curtis Rueden Date: Wed, 19 Jul 2017 10:14:17 +0200 Subject: [PATCH 2/3] Fix NullPointerException when chooseFiles returns null --- src/main/java/org/scijava/ui/UserInterface.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/scijava/ui/UserInterface.java b/src/main/java/org/scijava/ui/UserInterface.java index 857090e3a..544991cd5 100644 --- a/src/main/java/org/scijava/ui/UserInterface.java +++ b/src/main/java/org/scijava/ui/UserInterface.java @@ -193,8 +193,8 @@ default File chooseFile(String title, File file, String style) { * * @param files The initial value displayed in the file chooser prompt. * @param filter A filter allowing to restrict file choice. - * @return The selected {@link File}s chosen by the user, or null if prompt is not - * available + * @return The selected {@link File}s chosen by the user, or null if the + * user cancels the prompt. */ default File[] chooseFiles(File[] files, FileFilter filter) { throw new UnsupportedOperationException(); @@ -205,12 +205,13 @@ default File[] chooseFiles(File[] files, FileFilter filter) { * * @param fileList The initial value displayed in the file chooser prompt. * @param filter A filter allowing to restrict file choice. - * @return The selected {@link File}s chosen by the user, or null if prompt is not - * available + * @return The selected {@link File}s chosen by the user, or null if the + * user cancels the prompt. */ default List chooseFiles(List fileList, FileFilter filter) { - File[] files = fileList.toArray(new File[fileList.size()]); - return Arrays.asList(chooseFiles(files, filter)); + final File[] initialFiles = fileList.toArray(new File[fileList.size()]); + final File[] chosenFiles = chooseFiles(initialFiles, filter); + return chosenFiles == null ? null : Arrays.asList(chosenFiles); } /** From baaaa55e3524ca99d18d0dd09d176a0db1dbbebc Mon Sep 17 00:00:00 2001 From: Curtis Rueden Date: Wed, 19 Jul 2017 10:17:10 +0200 Subject: [PATCH 3/3] Add note about storing persisted values for list and array inputs --- src/main/java/org/scijava/module/DefaultModuleService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/scijava/module/DefaultModuleService.java b/src/main/java/org/scijava/module/DefaultModuleService.java index ec3c1e0dd..2bcf13d24 100644 --- a/src/main/java/org/scijava/module/DefaultModuleService.java +++ b/src/main/java/org/scijava/module/DefaultModuleService.java @@ -297,6 +297,8 @@ public void save(final ModuleItem item, final T value) { return; } + // FIXME: Convert to string, instead of just calling toString. + // Otherwise many things (e.g. File[]) are persisted improperly. final String sValue = value == null ? "" : value.toString(); // do not persist if object cannot be converted back from a string