mirror of
https://github.com/mitb-archive/filebot
synced 2024-12-23 08:18:52 -05:00
Make Episode/Movie selection dialog more pretty
This commit is contained in:
parent
5fc3a90159
commit
2fac737052
@ -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() {
|
||||
|
@ -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:");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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:");
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user