From ec8e228e801ba80940531d136c4395820463d352 Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Sun, 27 Nov 2016 04:47:12 +0800 Subject: [PATCH] Refactor CmdlineOperationsTextUI --- .gitignore | 1 + .../filebot/cli/CmdlineOperationsTextUI.java | 131 ++++++++++-------- .../net/filebot/cli/ScriptShellBaseClass.java | 26 ++++ 3 files changed, 101 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 8220c0c9..8bc1f124 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ website/data/ *.sh *.cmd +*.groovy *.cer *.pfx diff --git a/source/net/filebot/cli/CmdlineOperationsTextUI.java b/source/net/filebot/cli/CmdlineOperationsTextUI.java index d390b439..93bdc815 100644 --- a/source/net/filebot/cli/CmdlineOperationsTextUI.java +++ b/source/net/filebot/cli/CmdlineOperationsTextUI.java @@ -2,13 +2,18 @@ package net.filebot.cli; import static java.util.Arrays.*; import static java.util.Collections.*; +import static java.util.stream.Collectors.*; import static net.filebot.media.MediaDetection.*; import java.io.File; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; import com.googlecode.lanterna.TextColor; @@ -71,14 +76,22 @@ public class CmdlineOperationsTextUI extends CmdlineOperations { } // manually confirm each file mapping - Map selection = onScreen(() -> confirmRenameMap(renameMap, renameAction, conflictAction)); + String title = String.format("%s / %s", renameAction, conflictAction); + + // Alias.1x01.mp4 => Alias - 1x01 - Pilot.mp4 + int columnSize = renameMap.keySet().stream().mapToInt(f -> f.getName().length()).max().orElse(0); + + Function, String> renderer = m -> String.format("%-" + columnSize + "s\t=>\t%s", m.getKey().getName(), m.getValue().getName()); + Predicate> checked = m -> m.getKey().exists() && !m.getValue().exists(); + + List> selection = showInputDialog(renameMap.entrySet(), renderer, checked, title); // no selection, do nothing and return successfully - if (selection.isEmpty()) { + if (selection == null || selection.isEmpty()) { return emptyList(); } - return super.renameAll(selection, renameAction, conflictAction, matches); + return super.renameAll(selection.stream().collect(toMap(Entry::getKey, Entry::getValue, (a, b) -> a, LinkedHashMap::new)), renameAction, conflictAction, matches); } @Override @@ -89,19 +102,9 @@ public class CmdlineOperationsTextUI extends CmdlineOperations { return matches; } - return onScreen(() -> confirmSearchResult(query, matches)); // manually select option if there is more than one - } + // manually select option if there is more than one + SearchResult selection = showInputDialog(matches, "Multiple Options", String.format("Select best match for \"%s\"", query)); - protected List confirmSearchResult(String query, List options) { - ListSelectDialogBuilder dialog = new ListSelectDialogBuilder(); - dialog.setTitle("Multiple Options"); - dialog.setDescription(String.format("Select best match for \"%s\"", query)); - dialog.setExtraWindowHints(singleton(Hint.CENTERED)); - - options.forEach(dialog::addListItem); - - // show UI - SearchResult selection = dialog.build().showDialog(ui); if (selection == null) { return emptyList(); } @@ -109,57 +112,71 @@ public class CmdlineOperationsTextUI extends CmdlineOperations { return singletonList(selection); } - protected Map confirmRenameMap(Map renameMap, RenameAction renameAction, ConflictAction conflictAction) { - Map selection = new LinkedHashMap(); + public T showInputDialog(Collection options, String title, String message) throws Exception { + return onScreen(() -> { + ListSelectDialogBuilder dialog = new ListSelectDialogBuilder(); + dialog.setExtraWindowHints(singleton(Hint.CENTERED)); - BasicWindow dialog = new BasicWindow(); - dialog.setTitle(String.format("%s / %s", renameAction, conflictAction)); - dialog.setHints(asList(Hint.MODAL, Hint.CENTERED)); + dialog.setTitle(title); + dialog.setDescription(message); + options.forEach(dialog::addListItem); - CheckBoxList checkBoxList = new CheckBoxList(); - - int columnSize = renameMap.keySet().stream().mapToInt(f -> f.getName().length()).max().orElse(0); - String labelFormat = "%-" + columnSize + "s\t=>\t%s"; - - renameMap.forEach((k, v) -> { - checkBoxList.addItem(new CheckBoxListItem(String.format(labelFormat, k.getName(), v.getName()), k, v), true); + return dialog.build().showDialog(ui); }); - - Button okButton = new Button(LocalizedString.OK.toString(), () -> { - checkBoxList.getCheckedItems().forEach(it -> selection.put(it.key, it.value)); - dialog.close(); - }); - - Button cancelButton = new Button(LocalizedString.Cancel.toString(), () -> { - selection.clear(); - dialog.close(); - }); - - Panel contentPane = new Panel(); - contentPane.setLayoutManager(new GridLayout(1)); - - contentPane.addComponent(checkBoxList.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.BEGINNING, GridLayout.Alignment.BEGINNING, true, true, 1, 1))); - contentPane.addComponent(new Separator(Direction.HORIZONTAL).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.FILL, GridLayout.Alignment.CENTER, true, false, 1, 1))); - contentPane.addComponent(Panels.grid(2, okButton, cancelButton).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER, false, false, 1, 1))); - - dialog.setComponent(contentPane); - - ui.addWindowAndWait(dialog); - - return selection; } - protected static class CheckBoxListItem { + public List showInputDialog(Collection options, Function renderer, Predicate checked, String title) throws Exception { + return onScreen(() -> { + List selection = new ArrayList(options.size()); - public final String label; + BasicWindow dialog = new BasicWindow(); + dialog.setTitle(title); + dialog.setHints(asList(Hint.MODAL, Hint.CENTERED)); - public final File key; - public final File value; + CheckBoxList checkBoxList = new CheckBoxList(); - public CheckBoxListItem(String label, File key, File value) { - this.label = label; - this.key = key; + for (T option : options) { + checkBoxList.addItem(new CheckBoxListItem(option, renderer.apply(option)), checked.test(option)); + } + + Button okButton = new Button(LocalizedString.OK.toString(), () -> { + for (CheckBoxListItem it : checkBoxList.getCheckedItems()) { + selection.add(it.getValue()); + } + dialog.close(); + }); + + Button cancelButton = new Button(LocalizedString.Cancel.toString(), () -> { + dialog.close(); + }); + + Panel contentPane = new Panel(); + contentPane.setLayoutManager(new GridLayout(1)); + + contentPane.addComponent(checkBoxList.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.BEGINNING, GridLayout.Alignment.BEGINNING, true, true, 1, 1))); + contentPane.addComponent(new Separator(Direction.HORIZONTAL).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.FILL, GridLayout.Alignment.CENTER, true, false, 1, 1))); + contentPane.addComponent(Panels.grid(2, okButton, cancelButton).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER, false, false, 1, 1))); + + dialog.setComponent(contentPane); + + ui.addWindowAndWait(dialog); + + return selection; + }); + } + + protected static class CheckBoxListItem { + + private final T value; + private final String label; + + public CheckBoxListItem(T value, String label) { this.value = value; + this.label = label; + } + + public T getValue() { + return value; } @Override diff --git a/source/net/filebot/cli/ScriptShellBaseClass.java b/source/net/filebot/cli/ScriptShellBaseClass.java index 9460a8a2..c46861cb 100644 --- a/source/net/filebot/cli/ScriptShellBaseClass.java +++ b/source/net/filebot/cli/ScriptShellBaseClass.java @@ -16,6 +16,7 @@ import java.io.PrintStream; import java.io.StringWriter; import java.net.Socket; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.EnumMap; import java.util.EnumSet; @@ -563,4 +564,29 @@ public abstract class ScriptShellBaseClass extends Script { return (RenameAction) DefaultTypeTransformation.castToType(obj, RenameAction.class); } + public T getUserChoice(Collection options, String title, String message) throws Exception { + if (options.isEmpty()) { + return null; + } + + // use Text UI in interactive mode + if (getCLI() instanceof CmdlineOperationsTextUI) { + CmdlineOperationsTextUI cli = (CmdlineOperationsTextUI) getCLI(); + return cli.showInputDialog(options, title, message); + } + + // use Swing dialog non-headless environments + if (!java.awt.GraphicsEnvironment.isHeadless()) { + List selection = new ArrayList(1); + javax.swing.SwingUtilities.invokeAndWait(() -> { + T value = (T) javax.swing.JOptionPane.showInputDialog(null, message, title, javax.swing.JOptionPane.QUESTION_MESSAGE, null, options.toArray(), options.iterator().next()); + selection.add(0, value); + }); + return selection.get(0); + } + + // just pick the first option if we can't ask the user + return options.iterator().next(); + } + }