Refactor CmdlineOperationsTextUI

This commit is contained in:
Reinhard Pointner 2016-11-27 04:47:12 +08:00
parent b82fab09f7
commit ec8e228e80
3 changed files with 101 additions and 57 deletions

1
.gitignore vendored
View File

@ -11,6 +11,7 @@ website/data/
*.sh *.sh
*.cmd *.cmd
*.groovy
*.cer *.cer
*.pfx *.pfx

View File

@ -2,13 +2,18 @@ package net.filebot.cli;
import static java.util.Arrays.*; import static java.util.Arrays.*;
import static java.util.Collections.*; import static java.util.Collections.*;
import static java.util.stream.Collectors.*;
import static net.filebot.media.MediaDetection.*; import static net.filebot.media.MediaDetection.*;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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 java.util.function.Supplier;
import com.googlecode.lanterna.TextColor; import com.googlecode.lanterna.TextColor;
@ -71,14 +76,22 @@ public class CmdlineOperationsTextUI extends CmdlineOperations {
} }
// manually confirm each file mapping // manually confirm each file mapping
Map<File, File> 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<Entry<File, File>, String> renderer = m -> String.format("%-" + columnSize + "s\t=>\t%s", m.getKey().getName(), m.getValue().getName());
Predicate<Entry<File, File>> checked = m -> m.getKey().exists() && !m.getValue().exists();
List<Entry<File, File>> selection = showInputDialog(renameMap.entrySet(), renderer, checked, title);
// no selection, do nothing and return successfully // no selection, do nothing and return successfully
if (selection.isEmpty()) { if (selection == null || selection.isEmpty()) {
return emptyList(); 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 @Override
@ -89,19 +102,9 @@ public class CmdlineOperationsTextUI extends CmdlineOperations {
return matches; 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<SearchResult> confirmSearchResult(String query, List<SearchResult> options) {
ListSelectDialogBuilder<SearchResult> dialog = new ListSelectDialogBuilder<SearchResult>();
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) { if (selection == null) {
return emptyList(); return emptyList();
} }
@ -109,57 +112,71 @@ public class CmdlineOperationsTextUI extends CmdlineOperations {
return singletonList(selection); return singletonList(selection);
} }
protected Map<File, File> confirmRenameMap(Map<File, File> renameMap, RenameAction renameAction, ConflictAction conflictAction) { public <T> T showInputDialog(Collection<T> options, String title, String message) throws Exception {
Map<File, File> selection = new LinkedHashMap<File, File>(); return onScreen(() -> {
ListSelectDialogBuilder<T> dialog = new ListSelectDialogBuilder<T>();
dialog.setExtraWindowHints(singleton(Hint.CENTERED));
BasicWindow dialog = new BasicWindow(); dialog.setTitle(title);
dialog.setTitle(String.format("%s / %s", renameAction, conflictAction)); dialog.setDescription(message);
dialog.setHints(asList(Hint.MODAL, Hint.CENTERED)); options.forEach(dialog::addListItem);
CheckBoxList<CheckBoxListItem> checkBoxList = new CheckBoxList<CheckBoxListItem>(); return dialog.build().showDialog(ui);
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);
}); });
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 <T> List<T> showInputDialog(Collection<T> options, Function<T, String> renderer, Predicate<T> checked, String title) throws Exception {
return onScreen(() -> {
List<T> selection = new ArrayList<T>(options.size());
public final String label; BasicWindow dialog = new BasicWindow();
dialog.setTitle(title);
dialog.setHints(asList(Hint.MODAL, Hint.CENTERED));
public final File key; CheckBoxList<CheckBoxListItem> checkBoxList = new CheckBoxList<CheckBoxListItem>();
public final File value;
public CheckBoxListItem(String label, File key, File value) { for (T option : options) {
this.label = label; checkBoxList.addItem(new CheckBoxListItem<T>(option, renderer.apply(option)), checked.test(option));
this.key = key; }
Button okButton = new Button(LocalizedString.OK.toString(), () -> {
for (CheckBoxListItem<T> 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<T> {
private final T value;
private final String label;
public CheckBoxListItem(T value, String label) {
this.value = value; this.value = value;
this.label = label;
}
public T getValue() {
return value;
} }
@Override @Override

View File

@ -16,6 +16,7 @@ import java.io.PrintStream;
import java.io.StringWriter; import java.io.StringWriter;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.EnumSet; import java.util.EnumSet;
@ -563,4 +564,29 @@ public abstract class ScriptShellBaseClass extends Script {
return (RenameAction) DefaultTypeTransformation.castToType(obj, RenameAction.class); return (RenameAction) DefaultTypeTransformation.castToType(obj, RenameAction.class);
} }
public <T> T getUserChoice(Collection<T> 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<T> selection = new ArrayList<T>(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();
}
} }