mirror of
https://github.com/mitb-archive/filebot
synced 2025-03-09 13:59:49 -04:00
Make sure to not lock on Swing / AWT Window object
@see https://www.filebot.net/forums/viewtopic.php?f=11&t=5259&p=29747#p35519
This commit is contained in:
parent
b9572f4501
commit
9d15ac34b4
@ -25,6 +25,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -231,7 +232,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// show selection dialog on EDT
|
// show selection dialog on EDT
|
||||||
RunnableFuture<SearchResult> showSelectDialog = new FutureTask<SearchResult>(() -> {
|
Callable<SearchResult> showSelectDialog = () -> {
|
||||||
JLabel header = new JLabel(getQueryInputMessage("Failed to identify some of the following files:", null, getFilesForQuery(files, query)));
|
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)));
|
header.setBorder(createCompoundBorder(createTitledBorder(""), createEmptyBorder(3, 3, 3, 3)));
|
||||||
|
|
||||||
@ -261,7 +262,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||||||
|
|
||||||
// selected value or null if the dialog was canceled by the user
|
// selected value or null if the dialog was canceled by the user
|
||||||
return selectDialog.getSelectedValue();
|
return selectDialog.getSelectedValue();
|
||||||
});
|
};
|
||||||
|
|
||||||
synchronized (selectionMemory) {
|
synchronized (selectionMemory) {
|
||||||
if (selectionMemory.containsKey(query)) {
|
if (selectionMemory.containsKey(query)) {
|
||||||
@ -277,16 +278,13 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allow only one select dialog at a time
|
// allow only one select dialog at a time
|
||||||
synchronized (INPUT_DIALOG_LOCK) {
|
SearchResult userSelection = showInputDialog(showSelectDialog);
|
||||||
SwingUtilities.invokeAndWait(showSelectDialog);
|
|
||||||
SearchResult userSelection = showSelectDialog.get();
|
|
||||||
|
|
||||||
// remember selected value
|
// remember selected value
|
||||||
selectionMemory.put(query, userSelection);
|
selectionMemory.put(query, userSelection);
|
||||||
return userSelection;
|
return userSelection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected Collection<File> getFilesForQuery(Collection<File> files, String query) {
|
protected Collection<File> getFilesForQuery(Collection<File> files, String query) {
|
||||||
Pattern pattern = Pattern.compile(query.isEmpty() ? ".+" : normalizePunctuation(query).replaceAll("\\W+", ".+"), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CHARACTER_CLASS);
|
Pattern pattern = Pattern.compile(query.isEmpty() ? ".+" : normalizePunctuation(query).replaceAll("\\W+", ".+"), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CHARACTER_CLASS);
|
||||||
|
@ -29,18 +29,16 @@ import java.util.Set;
|
|||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.FutureTask;
|
|
||||||
import java.util.concurrent.RunnableFuture;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
import net.filebot.similarity.Match;
|
import net.filebot.similarity.Match;
|
||||||
import net.filebot.similarity.NameSimilarityMetric;
|
import net.filebot.similarity.NameSimilarityMetric;
|
||||||
@ -340,7 +338,7 @@ class MovieMatcher implements AutoCompleteMatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// show selection dialog on EDT
|
// show selection dialog on EDT
|
||||||
RunnableFuture<Movie> showSelectDialog = new FutureTask<Movie>(() -> {
|
Callable<Movie> showSelectDialog = () -> {
|
||||||
String query = fileQuery.length() >= 2 || folderQuery.length() <= 2 ? fileQuery : folderQuery;
|
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));
|
JLabel header = new JLabel(getQueryInputMessage("Failed to identify some of the following files:", null, movieFile));
|
||||||
header.setBorder(createCompoundBorder(createTitledBorder(""), createEmptyBorder(3, 3, 3, 3)));
|
header.setBorder(createCompoundBorder(createTitledBorder(""), createEmptyBorder(3, 3, 3, 3)));
|
||||||
@ -372,7 +370,7 @@ class MovieMatcher implements AutoCompleteMatcher {
|
|||||||
|
|
||||||
// selected value or null if the dialog was canceled by the user
|
// selected value or null if the dialog was canceled by the user
|
||||||
return selectDialog.getSelectedValue();
|
return selectDialog.getSelectedValue();
|
||||||
});
|
};
|
||||||
|
|
||||||
// allow only one select dialog at a time
|
// allow only one select dialog at a time
|
||||||
synchronized (selectionMemory) {
|
synchronized (selectionMemory) {
|
||||||
@ -389,13 +387,12 @@ class MovieMatcher implements AutoCompleteMatcher {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (INPUT_DIALOG_LOCK) {
|
// allow only one select dialog at a time
|
||||||
SwingUtilities.invokeAndWait(showSelectDialog);
|
Movie userSelection = showInputDialog(showSelectDialog);
|
||||||
|
|
||||||
// cache selected value
|
// cache selected value
|
||||||
selectionMemory.put(selectionKey, showSelectDialog.get());
|
selectionMemory.put(selectionKey, userSelection);
|
||||||
return showSelectDialog.get();
|
return userSelection;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,9 @@ import java.net.URI;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -226,7 +228,39 @@ public final class SwingUI {
|
|||||||
return (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
|
return (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> showMultiValueInputDialog(Object message, String initialValue, String title, Component parent) {
|
private static final ReentrantLock INPUT_DIALOG_LOCK = new ReentrantLock(true); // use fair lock to display dialogs in FIFO order
|
||||||
|
|
||||||
|
public static <T> T showInputDialog(Callable<T> callable) throws Exception {
|
||||||
|
Object[] value = { null };
|
||||||
|
|
||||||
|
// display only one dialog at a time, one after another, in the correct sequence
|
||||||
|
INPUT_DIALOG_LOCK.lock();
|
||||||
|
try {
|
||||||
|
if (SwingUtilities.isEventDispatchThread()) {
|
||||||
|
value[0] = callable.call();
|
||||||
|
} else {
|
||||||
|
SwingUtilities.invokeAndWait(() -> {
|
||||||
|
try {
|
||||||
|
value[0] = callable.call();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
INPUT_DIALOG_LOCK.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T) value[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String showInputDialog(Object message, String initialValue, String title, Component parent) throws Exception {
|
||||||
|
return showInputDialog(() -> {
|
||||||
|
return (String) JOptionPane.showInputDialog(parent, message, title, PLAIN_MESSAGE, null, null, initialValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> showMultiValueInputDialog(Object message, String initialValue, String title, Component parent) throws Exception {
|
||||||
String input = showInputDialog(message, initialValue, title, parent);
|
String input = showInputDialog(message, initialValue, title, parent);
|
||||||
if (input == null || input.isEmpty()) {
|
if (input == null || input.isEmpty()) {
|
||||||
return emptyList();
|
return emptyList();
|
||||||
@ -252,23 +286,6 @@ public final class SwingUI {
|
|||||||
return singletonList(input);
|
return singletonList(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Object INPUT_DIALOG_LOCK = new Object();
|
|
||||||
|
|
||||||
public static String showInputDialog(Object message, String initialValue, String title, Component parent) {
|
|
||||||
StringBuilder buffer = new StringBuilder();
|
|
||||||
|
|
||||||
synchronized (INPUT_DIALOG_LOCK) {
|
|
||||||
runOnEventDispatchThread(() -> {
|
|
||||||
Object value = JOptionPane.showInputDialog(parent, message, title, PLAIN_MESSAGE, null, null, initialValue);
|
|
||||||
if (value != null) {
|
|
||||||
buffer.append(value.toString().trim());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer.length() == 0 ? null : buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Window getWindow(Object component) {
|
public static Window getWindow(Object component) {
|
||||||
if (component instanceof Window)
|
if (component instanceof Window)
|
||||||
return (Window) component;
|
return (Window) component;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user