1
0
mirror of https://github.com/mitb-archive/filebot synced 2024-08-13 17:03:45 -04:00

Make Episode/Movie selection dialog more pretty

This commit is contained in:
Reinhard Pointner 2016-04-09 20:58:37 +00:00
parent 5fc3a90159
commit 2fac737052
6 changed files with 56 additions and 37 deletions

View File

@ -31,17 +31,17 @@ import net.miginfocom.swing.MigLayout;
public class SelectDialog<T> extends JDialog {
private JLabel headerLabel = new JLabel();
private JLabel messageLabel = new JLabel();
private JCheckBox autoRepeatCheckBox = new JCheckBox();
private JList<T> list;
private String command = null;
public SelectDialog(Component parent, Collection<? extends T> options) {
this(parent, options, false, false);
this(parent, options, false, false, null);
}
public SelectDialog(Component parent, Collection<? extends T> options, boolean autoRepeatEnabled, boolean autoRepeatSelected) {
public SelectDialog(Component parent, Collection<? extends T> options, boolean autoRepeatEnabled, boolean autoRepeatSelected, JComponent header) {
super(getWindow(parent), "Select", ModalityType.DOCUMENT_MODAL);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
@ -69,9 +69,12 @@ public class SelectDialog<T> extends JDialog {
list.addMouseListener(mouseListener);
JComponent c = (JComponent) getContentPane();
c.setLayout(new MigLayout("insets 1.5mm 1.5mm 2.7mm 1.5mm, nogrid, fill", "", "[pref!][fill][pref!]"));
c.setLayout(new MigLayout("insets 1.5mm 1.5mm 2.7mm 1.5mm, nogrid, fill", "", header == null ? "[pref!][fill][pref!]" : "[pref!][pref!][fill][pref!]"));
c.add(headerLabel, "wmin 150px, growx, wrap");
if (header != null) {
c.add(header, "wmin 150px, growx, wrap");
}
c.add(messageLabel, "wmin 150px, growx, wrap");
c.add(new JScrollPane(list), "wmin 150px, hmin 150px, grow, wrap 2mm");
c.add(new JButton(selectAction), "align center, id select");
@ -122,8 +125,8 @@ public class SelectDialog<T> extends JDialog {
return html.toString();
}
public JLabel getHeaderLabel() {
return headerLabel;
public JLabel getMessageLabel() {
return messageLabel;
}
public JCheckBox getAutoRepeatCheckBox() {

View File

@ -224,7 +224,7 @@ public class EpisodeListPanel extends AbstractSearchPanel<EpisodeListProvider, E
@Override
protected void configureSelectDialog(SelectDialog<SearchResult> selectDialog) {
super.configureSelectDialog(selectDialog);
selectDialog.getHeaderLabel().setText("Select a Show:");
selectDialog.getMessageLabel().setText("Select a Show:");
}
}

View File

@ -3,6 +3,7 @@ package net.filebot.ui.rename;
import static java.util.Collections.*;
import static java.util.Comparator.*;
import static java.util.stream.Collectors.*;
import static javax.swing.BorderFactory.*;
import static net.filebot.MediaTypes.*;
import static net.filebot.Settings.*;
import static net.filebot.WebServices.*;
@ -35,6 +36,7 @@ import java.util.prefs.Preferences;
import java.util.regex.Pattern;
import javax.swing.Action;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import net.filebot.Cache;
@ -62,13 +64,13 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
return Cache.getCache("selection_" + provider.getName(), CacheType.Persistent).cast(SearchResult.class);
}
protected SearchResult selectSearchResult(List<File> files, String query, List<SearchResult> searchResults, Map<String, SearchResult> selectionMemory, boolean autodetection, Component parent) throws Exception {
if (searchResults.size() == 1) {
return searchResults.get(0);
protected SearchResult selectSearchResult(List<File> files, String query, List<SearchResult> options, Map<String, SearchResult> selectionMemory, boolean autodetection, Component parent) throws Exception {
if (options.size() == 1) {
return options.get(0);
}
// auto-select most probable search result
List<SearchResult> probableMatches = getProbableMatches(query, searchResults, true, true);
List<SearchResult> probableMatches = getProbableMatches(query, options, true, true);
// auto-select first and only probable search result
if (probableMatches.size() == 1) {
@ -77,11 +79,14 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
// show selection dialog on EDT
RunnableFuture<SearchResult> showSelectDialog = new FutureTask<SearchResult>(() -> {
JLabel header = new JLabel(getQueryInputMessage("Failed to identify some of the following files:", null, getFilesForQuery(files, query)));
header.setBorder(createCompoundBorder(createTitledBorder(""), createEmptyBorder(3, 3, 3, 3)));
// multiple results have been found, user must select one
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(parent, searchResults, true, false);
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(parent, options, true, false, header);
selectDialog.setTitle(provider.getName());
selectDialog.getHeaderLabel().setText(getQueryInputMessage(String.format("Select best match for \"<b>%s</b>\":", query), getFilesForQuery(files, query)));
selectDialog.getCancelAction().putValue(Action.NAME, "Ignore");
selectDialog.getMessageLabel().setText("<html>Select best match for \"<b>" + query + "</b>\":</html>");
selectDialog.getCancelAction().putValue(Action.NAME, "Skip");
selectDialog.pack();
// show dialog
@ -137,9 +142,10 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
List<Future<List<Episode>>> tasks = querySet.stream().map(q -> {
return requestThreadPool.submit(() -> {
// select search result
List<SearchResult> results = provider.search(q, locale);
if (results.size() > 0) {
SearchResult selectedSearchResult = selectSearchResult(files, q, results, selectionMemory, autodetection, parent);
List<SearchResult> options = provider.search(q, locale);
if (options.size() > 0) {
SearchResult selectedSearchResult = selectSearchResult(files, q, options, selectionMemory, autodetection, parent);
if (selectedSearchResult != null) {
return provider.getEpisodeList(selectedSearchResult, sortOrder, locale);
}
@ -237,7 +243,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
}
public List<Match<File, ?>> matchEpisodeSet(List<File> files, Collection<String> queries, SortOrder sortOrder, boolean strict, Locale locale, boolean autodetection, Map<String, SearchResult> selectionMemory, Map<String, List<String>> inputMemory, Component parent) throws Exception {
Set<Episode> episodes = emptySet();
Collection<Episode> episodes = emptySet();
// detect series name and fetch episode list
if (autodetection) {
@ -250,13 +256,12 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
// require user input if auto-detection has failed or has been disabled
if (episodes.isEmpty() && !strict) {
List<String> detectedSeriesNames = detectSeriesNames(files, anime, locale);
String parentPathHint = normalizePathSeparators(getRelativePathTail(files.get(0).getParentFile(), 2).getPath());
String suggestion = detectedSeriesNames.size() > 0 ? join(detectedSeriesNames, "; ") : normalizePunctuation(getName(files.get(0)));
synchronized (inputMemory) {
List<String> input = inputMemory.get(suggestion);
if (input == null || suggestion == null || suggestion.isEmpty()) {
input = showMultiValueInputDialog(getQueryInputMessage("Enter series name:", files), suggestion, parentPathHint, parent);
input = showMultiValueInputDialog(getQueryInputMessage("Please identify the following files:", "Enter series name:", files), suggestion, provider.getName(), parent);
inputMemory.put(suggestion, input);
}
@ -292,14 +297,15 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
return selection.size() > 0 ? selection : files;
}
protected String getQueryInputMessage(String message, Collection<File> files) throws Exception {
protected String getQueryInputMessage(String header, String message, Collection<File> files) throws Exception {
List<File> selection = files.stream().sorted(comparing(File::length).reversed()).limit(5).collect(toList());
StringBuilder html = new StringBuilder(512);
html.append("<html>");
if (selection.size() > 0) {
html.append("Failed to identify some of the following files:").append("<br>");
if (header != null) {
html.append(header).append("<br>");
}
for (File file : sortByUniquePath(selection)) {
html.append("<nobr>");
html.append("");
@ -313,14 +319,14 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
html.append("</nobr>");
html.append("<br>");
}
if (selection.size() < files.size()) {
html.append("").append("").append("<br>");
}
html.append("<br>");
}
html.append(message);
if (message != null) {
html.append(message);
}
html.append("</html>");
return html.toString();
}
@ -331,7 +337,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
List<Match<File, ?>> matches = new ArrayList<Match<File, ?>>();
if (input.size() > 0) {
Set<Episode> episodes = fetchEpisodeSet(emptyList(), input, sortOrder, locale, new HashMap<String, SearchResult>(), false, parent);
Collection<Episode> episodes = fetchEpisodeSet(emptyList(), input, sortOrder, locale, new HashMap<String, SearchResult>(), false, parent);
for (Episode it : episodes) {
matches.add(new Match<File, Episode>(null, it));
}

View File

@ -3,6 +3,7 @@ package net.filebot.ui.rename;
import static java.util.Collections.*;
import static java.util.Comparator.*;
import static java.util.stream.Collectors.*;
import static javax.swing.BorderFactory.*;
import static net.filebot.Logging.*;
import static net.filebot.MediaTypes.*;
import static net.filebot.Settings.*;
@ -38,6 +39,7 @@ import java.util.logging.Level;
import java.util.prefs.Preferences;
import javax.swing.Action;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import net.filebot.similarity.Match;
@ -229,7 +231,7 @@ class MovieMatcher implements AutoCompleteMatcher {
if (input == null || suggestion == null || suggestion.isEmpty()) {
File movieFolder = guessMovieFolder(movieFile);
input = showInputDialog(getQueryInputMessage("Enter movie name:", movieFile), suggestion != null && suggestion.length() > 0 ? suggestion : getName(movieFile), movieFolder == null ? movieFile.getName() : String.join(" / ", movieFolder.getName(), movieFile.getName()), parent);
input = showInputDialog(getQueryInputMessage("Please identify the following files:", "Enter movie name:", movieFile), suggestion != null && suggestion.length() > 0 ? suggestion : getName(movieFile), movieFolder == null ? movieFile.getName() : String.join(" / ", movieFolder.getName(), movieFile.getName()), parent);
inputMemory.put(suggestion, input);
}
@ -245,10 +247,12 @@ class MovieMatcher implements AutoCompleteMatcher {
return options.isEmpty() ? null : selectMovie(movieFile, strict, null, options, autoSelectionMode, selectionMemory, parent);
}
protected String getQueryInputMessage(String message, File file) throws Exception {
protected String getQueryInputMessage(String header, String message, File file) throws Exception {
StringBuilder html = new StringBuilder(512);
html.append("<html>");
html.append("Failed to identify some of the following files:").append("<br>");
if (header != null) {
html.append(header).append("<br>");
}
html.append("<nobr>");
html.append("");
@ -263,7 +267,9 @@ class MovieMatcher implements AutoCompleteMatcher {
html.append("<br>");
html.append("<br>");
html.append(message);
if (message != null) {
html.append(message);
}
html.append("</html>");
return html.toString();
}
@ -342,12 +348,16 @@ class MovieMatcher implements AutoCompleteMatcher {
// show selection dialog on EDT
RunnableFuture<Movie> showSelectDialog = new FutureTask<Movie>(() -> {
String query = fileQuery.length() >= 2 || folderQuery.length() <= 2 ? fileQuery : folderQuery;
JLabel header = new JLabel(getQueryInputMessage("Failed to identify some of the following files:", null, movieFile));
header.setBorder(createCompoundBorder(createTitledBorder(""), createEmptyBorder(3, 3, 3, 3)));
// multiple results have been found, user must select one
SelectDialog<Movie> selectDialog = new SelectDialog<Movie>(parent, options, true, false);
SelectDialog<Movie> selectDialog = new SelectDialog<Movie>(parent, options, true, false, header);
selectDialog.setTitle(service.getName());
selectDialog.getHeaderLabel().setText(getQueryInputMessage(String.format("Select best match for \"<b>%s</b>\":", fileQuery.length() >= 2 || folderQuery.length() <= 2 ? fileQuery : folderQuery), movieFile));
selectDialog.getCancelAction().putValue(Action.NAME, AutoSelection.Skip.toString());
selectDialog.getMessageLabel().setText("<html>Select best match for \"<b>" + query + "</b>\":</html>");
selectDialog.getCancelAction().putValue(Action.NAME, "Skip");
selectDialog.pack();
// show dialog

View File

@ -278,7 +278,7 @@ public class SfvPanel extends JComponent {
}
};
selectDialog.getHeaderLabel().setText("Select checksum column:");
selectDialog.getMessageLabel().setText("Select checksum column:");
selectDialog.pack();
selectDialog.setLocationRelativeTo(SfvPanel.this);
selectDialog.setVisible(true);

View File

@ -329,7 +329,7 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleProvider, Subtitl
@Override
protected void configureSelectDialog(SelectDialog<SearchResult> selectDialog) {
super.configureSelectDialog(selectDialog);
selectDialog.getHeaderLabel().setText("Select a Show / Movie:");
selectDialog.getMessageLabel().setText("Select a Show / Movie:");
}
}