mirror of
https://github.com/mitb-archive/filebot
synced 2025-03-09 05:51:31 -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.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -231,7 +232,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
||||
}
|
||||
|
||||
// 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)));
|
||||
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
|
||||
return selectDialog.getSelectedValue();
|
||||
});
|
||||
};
|
||||
|
||||
synchronized (selectionMemory) {
|
||||
if (selectionMemory.containsKey(query)) {
|
||||
@ -277,14 +278,11 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
||||
}
|
||||
|
||||
// allow only one select dialog at a time
|
||||
synchronized (INPUT_DIALOG_LOCK) {
|
||||
SwingUtilities.invokeAndWait(showSelectDialog);
|
||||
SearchResult userSelection = showSelectDialog.get();
|
||||
SearchResult userSelection = showInputDialog(showSelectDialog);
|
||||
|
||||
// remember selected value
|
||||
selectionMemory.put(query, userSelection);
|
||||
return userSelection;
|
||||
}
|
||||
// remember selected value
|
||||
selectionMemory.put(query, userSelection);
|
||||
return userSelection;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,18 +29,16 @@ import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
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;
|
||||
import net.filebot.similarity.NameSimilarityMetric;
|
||||
@ -340,7 +338,7 @@ class MovieMatcher implements AutoCompleteMatcher {
|
||||
}
|
||||
|
||||
// show selection dialog on EDT
|
||||
RunnableFuture<Movie> showSelectDialog = new FutureTask<Movie>(() -> {
|
||||
Callable<Movie> showSelectDialog = () -> {
|
||||
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)));
|
||||
@ -372,7 +370,7 @@ class MovieMatcher implements AutoCompleteMatcher {
|
||||
|
||||
// selected value or null if the dialog was canceled by the user
|
||||
return selectDialog.getSelectedValue();
|
||||
});
|
||||
};
|
||||
|
||||
// allow only one select dialog at a time
|
||||
synchronized (selectionMemory) {
|
||||
@ -389,13 +387,12 @@ class MovieMatcher implements AutoCompleteMatcher {
|
||||
return null;
|
||||
}
|
||||
|
||||
synchronized (INPUT_DIALOG_LOCK) {
|
||||
SwingUtilities.invokeAndWait(showSelectDialog);
|
||||
// allow only one select dialog at a time
|
||||
Movie userSelection = showInputDialog(showSelectDialog);
|
||||
|
||||
// cache selected value
|
||||
selectionMemory.put(selectionKey, showSelectDialog.get());
|
||||
return showSelectDialog.get();
|
||||
}
|
||||
// cache selected value
|
||||
selectionMemory.put(selectionKey, userSelection);
|
||||
return userSelection;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,9 @@ import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
@ -226,7 +228,39 @@ public final class SwingUI {
|
||||
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);
|
||||
if (input == null || input.isEmpty()) {
|
||||
return emptyList();
|
||||
@ -252,23 +286,6 @@ public final class SwingUI {
|
||||
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) {
|
||||
if (component instanceof Window)
|
||||
return (Window) component;
|
||||
|
Loading…
x
Reference in New Issue
Block a user