1
0
mirror of https://github.com/mitb-archive/filebot synced 2024-11-18 07:15:07 -05:00

* play with new convenience methods for Swing using lambdas

This commit is contained in:
Reinhard Pointner 2016-02-06 14:03:56 +00:00
parent fde21946dc
commit 15dc273d7f
2 changed files with 183 additions and 133 deletions

View File

@ -1,6 +1,7 @@
package net.filebot.ui.subtitle.upload; package net.filebot.ui.subtitle.upload;
import static net.filebot.media.MediaDetection.*; import static net.filebot.media.MediaDetection.*;
import static net.filebot.util.ui.SwingUI.*;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
@ -21,14 +22,10 @@ import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.SwingWorker;
import net.filebot.Language; import net.filebot.Language;
import net.filebot.ResourceManager; import net.filebot.ResourceManager;
@ -64,8 +61,8 @@ public class SubtitleUploadDialog extends JDialog {
content.add(new JScrollPane(subtitleMappingTable), "grow, wrap"); content.add(new JScrollPane(subtitleMappingTable), "grow, wrap");
content.add(new JButton(uploadAction), "tag ok"); content.add(newButton("Upload", ResourceManager.getIcon("dialog.continue"), this::doUpload), "tag ok");
content.add(new JButton(finishAction), "tag cancel"); content.add(newButton("Close", ResourceManager.getIcon("dialog.cancel"), this::doClose), "tag cancel");
} }
protected JTable createTable() { protected JTable createTable() {
@ -108,10 +105,9 @@ public class SubtitleUploadDialog extends JDialog {
} }
public void startChecking() { public void startChecking() {
SubtitleMapping[] data = ((SubtitleMappingTableModel) subtitleMappingTable.getModel()).getData(); for (SubtitleMapping mapping : ((SubtitleMappingTableModel) subtitleMappingTable.getModel()).getData()) {
for (SubtitleMapping it : data) { if (mapping.isCheckReady()) {
if (it.isCheckReady()) { checkExecutorService.submit(() -> runCheck(mapping));
checkExecutorService.submit(new CheckTask(it));
} }
} }
} }
@ -135,153 +131,121 @@ public class SubtitleUploadDialog extends JDialog {
}).toList(); }).toList();
} }
private final Action uploadAction = new AbstractAction("Upload", ResourceManager.getIcon("dialog.continue")) { private void runCheck(SubtitleMapping mapping) {
try {
@Override if (mapping.getIdentity() == null && mapping.getVideo() != null) {
public void actionPerformed(ActionEvent evt) { mapping.setState(Status.Checking);
// disable any active cell editor
if (subtitleMappingTable.getCellEditor() != null) {
subtitleMappingTable.getCellEditor().stopCellEditing();
}
// don't allow restart of upload as long as there are still unfinished download tasks CheckResult checkResult = database.checkSubtitle(mapping.getVideo(), mapping.getSubtitle());
if (uploadExecutorService != null && !uploadExecutorService.isTerminated()) {
return;
}
uploadExecutorService = Executors.newSingleThreadExecutor(); // force upload all subtitles regardless of what TryUploadSubtitles returns (because other programs often submit crap)
if (checkResult.exists) {
SubtitleMapping[] table = ((SubtitleMappingTableModel) subtitleMappingTable.getModel()).getData(); mapping.setLanguage(Language.getLanguage(checkResult.language)); // trust language hint only if upload not required
for (SubtitleGroup it : groupRunsByCD(table)) {
if (it.isUploadReady()) {
uploadExecutorService.submit(new UploadTask(it));
} }
} }
// terminate after all uploads have been completed if (mapping.getLanguage() == null) {
uploadExecutorService.shutdown(); mapping.setState(Status.Identifying);
} try {
}; Locale locale = database.detectLanguage(FileUtilities.readFile(mapping.getSubtitle()));
mapping.setLanguage(Language.getLanguage(locale));
private final Action finishAction = new AbstractAction("Close", ResourceManager.getIcon("dialog.cancel")) { } catch (Exception e) {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to auto-detect language: " + e.getMessage());
@Override }
public void actionPerformed(ActionEvent evt) {
if (checkExecutorService != null) {
checkExecutorService.shutdownNow();
}
if (uploadExecutorService != null) {
uploadExecutorService.shutdownNow();
} }
setVisible(false); if (mapping.getIdentity() == null && mapping.getVideo() != null) {
dispose(); mapping.setState(Status.Identifying);
} try {
}; if (MediaDetection.isEpisode(mapping.getVideo().getPath(), true)) {
List<String> seriesNames = MediaDetection.detectSeriesNames(Collections.singleton(mapping.getVideo()), true, false, Locale.ENGLISH);
private class CheckTask extends SwingWorker<Object, Void> { NAMES: for (String name : seriesNames) {
List<SearchResult> options = WebServices.TheTVDB.search(name, Locale.ENGLISH);
private final SubtitleMapping mapping; for (SearchResult entry : options) {
TheTVDBSeriesInfo seriesInfo = (TheTVDBSeriesInfo) WebServices.TheTVDB.getSeriesInfo(entry, Locale.ENGLISH);
public CheckTask(SubtitleMapping mapping) { if (seriesInfo.getImdbId() != null) {
this.mapping = mapping; int imdbId = grepImdbId(seriesInfo.getImdbId()).iterator().next();
} mapping.setIdentity(WebServices.OpenSubtitles.getMovieDescriptor(new Movie(null, 0, imdbId, -1), Locale.ENGLISH));
break NAMES;
@Override
protected Object doInBackground() throws Exception {
try {
if (mapping.getIdentity() == null && mapping.getVideo() != null) {
mapping.setState(Status.Checking);
CheckResult checkResult = database.checkSubtitle(mapping.getVideo(), mapping.getSubtitle());
// force upload all subtitles regardless of what TryUploadSubtitles returns (because other programs often submit crap)
if (checkResult.exists) {
mapping.setLanguage(Language.getLanguage(checkResult.language)); // trust language hint only if upload not required
}
}
if (mapping.getLanguage() == null) {
mapping.setState(Status.Identifying);
try {
Locale locale = database.detectLanguage(FileUtilities.readFile(mapping.getSubtitle()));
mapping.setLanguage(Language.getLanguage(locale));
} catch (Exception e) {
Logger.getLogger(CheckTask.class.getClass().getName()).log(Level.WARNING, "Failed to auto-detect language: " + e.getMessage());
}
}
if (mapping.getIdentity() == null && mapping.getVideo() != null) {
mapping.setState(Status.Identifying);
try {
if (MediaDetection.isEpisode(mapping.getVideo().getPath(), true)) {
List<String> seriesNames = MediaDetection.detectSeriesNames(Collections.singleton(mapping.getVideo()), true, false, Locale.ENGLISH);
NAMES: for (String name : seriesNames) {
List<SearchResult> options = WebServices.TheTVDB.search(name, Locale.ENGLISH);
for (SearchResult entry : options) {
TheTVDBSeriesInfo seriesInfo = (TheTVDBSeriesInfo) WebServices.TheTVDB.getSeriesInfo(entry, Locale.ENGLISH);
if (seriesInfo.getImdbId() != null) {
int imdbId = grepImdbId(seriesInfo.getImdbId()).iterator().next();
mapping.setIdentity(WebServices.OpenSubtitles.getMovieDescriptor(new Movie(null, 0, imdbId, -1), Locale.ENGLISH));
break NAMES;
}
}
}
} else {
Collection<Movie> identity = MediaDetection.detectMovie(mapping.getVideo(), database, Locale.ENGLISH, true);
for (Movie it : identity) {
if (it.getImdbId() <= 0 && it.getTmdbId() > 0) {
it = WebServices.TheMovieDB.getMovieDescriptor(it, Locale.ENGLISH);
}
if (it != null && it.getImdbId() > 0) {
mapping.setIdentity(it);
break;
} }
} }
} }
} catch (Exception e) { } else {
Logger.getLogger(CheckTask.class.getClass().getName()).log(Level.WARNING, "Failed to auto-detect movie: " + e.getMessage()); Collection<Movie> identity = MediaDetection.detectMovie(mapping.getVideo(), database, Locale.ENGLISH, true);
for (Movie it : identity) {
if (it.getImdbId() <= 0 && it.getTmdbId() > 0) {
it = WebServices.TheMovieDB.getMovieDescriptor(it, Locale.ENGLISH);
}
if (it != null && it.getImdbId() > 0) {
mapping.setIdentity(it);
break;
}
}
} }
} catch (Exception e) {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to auto-detect movie: " + e.getMessage());
} }
if (mapping.getVideo() == null) {
mapping.setState(Status.IllegalInput);
} else if (mapping.getIdentity() == null || mapping.getLanguage() == null) {
mapping.setState(Status.IdentificationRequired);
} else {
mapping.setState(Status.UploadReady);
}
} catch (Exception e) {
Logger.getLogger(CheckTask.class.getClass().getName()).log(Level.SEVERE, e.getMessage(), e);
mapping.setState(Status.CheckFailed);
} }
return null;
if (mapping.getVideo() == null) {
mapping.setState(Status.IllegalInput);
} else if (mapping.getIdentity() == null || mapping.getLanguage() == null) {
mapping.setState(Status.IdentificationRequired);
} else {
mapping.setState(Status.UploadReady);
}
} catch (Exception e) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, e.getMessage(), e);
mapping.setState(Status.CheckFailed);
} }
} }
private class UploadTask extends SwingWorker<Object, Void> { private void runUpload(SubtitleGroup group) {
try {
group.setState(Status.Uploading);
database.uploadSubtitle(group.getIdentity(), group.getLanguage().getLocale(), group.getVideoFiles(), group.getSubtitleFiles());
group.setState(Status.UploadComplete);
} catch (Exception e) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, e.getMessage(), e);
group.setState(Status.UploadFailed);
}
}
private final SubtitleGroup uploadGroup; public void doUpload(ActionEvent evt) {
// disable any active cell editor
public UploadTask(SubtitleGroup uploadGroup) { if (subtitleMappingTable.getCellEditor() != null) {
this.uploadGroup = uploadGroup; subtitleMappingTable.getCellEditor().stopCellEditing();
} }
@Override // don't allow restart of upload as long as there are still unfinished download tasks
protected Object doInBackground() { if (uploadExecutorService != null && !uploadExecutorService.isTerminated()) {
try { return;
uploadGroup.setState(Status.Uploading); }
database.uploadSubtitle(uploadGroup.getIdentity(), uploadGroup.getLanguage().getLocale(), uploadGroup.getVideoFiles(), uploadGroup.getSubtitleFiles()); uploadExecutorService = Executors.newSingleThreadExecutor();
uploadGroup.setState(Status.UploadComplete); SubtitleMapping[] table = ((SubtitleMappingTableModel) subtitleMappingTable.getModel()).getData();
} catch (Exception e) { for (SubtitleGroup group : groupRunsByCD(table)) {
Logger.getLogger(UploadTask.class.getClass().getName()).log(Level.SEVERE, e.getMessage(), e); if (group.isUploadReady()) {
uploadGroup.setState(Status.UploadFailed); uploadExecutorService.submit(() -> runUpload(group));
} }
return null;
} }
// terminate after all uploads have been completed
uploadExecutorService.shutdown();
}
public void doClose(ActionEvent evt) {
if (checkExecutorService != null) {
checkExecutorService.shutdownNow();
}
if (uploadExecutorService != null) {
uploadExecutorService.shutdownNow();
}
setVisible(false);
dispose();
} }
} }

View File

@ -20,6 +20,8 @@ import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
@ -33,6 +35,7 @@ import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer; import javax.swing.Timer;
import javax.swing.event.MouseInputListener; import javax.swing.event.MouseInputListener;
import javax.swing.plaf.basic.BasicTableUI; import javax.swing.plaf.basic.BasicTableUI;
@ -266,6 +269,89 @@ public final class SwingUI {
return timer; return timer;
} }
public static JButton newButton(String name, Icon icon, Consumer<ActionEvent> action) {
return new JButton(new LambdaAction(name, icon, action));
}
public static Action newAction(String name, Icon icon, Consumer<ActionEvent> action) {
return new LambdaAction(name, icon, action);
}
private static class LambdaAction extends AbstractAction {
private Consumer<ActionEvent> action;
public LambdaAction(String name, Icon icon, Consumer<ActionEvent> action) {
super(name, icon);
this.action = action;
}
@Override
public void actionPerformed(ActionEvent e) {
action.accept(e);
}
}
public static SwingWorker<Void, Void> newSwingWorker(BackgroundRunnable doInBackground) {
return new SwingRunnable(doInBackground);
}
public static <T> SwingWorker<T, Void> newSwingWorker(BackgroundSupplier<T> doInBackground, Consumer<T> done, Consumer<Exception> error) {
return new SwingLambda<T, Void>(doInBackground, done, error);
}
private static class SwingRunnable extends SwingWorker<Void, Void> {
private BackgroundRunnable doInBackground;
public SwingRunnable(BackgroundRunnable doInBackground) {
this.doInBackground = doInBackground;
}
@Override
protected Void doInBackground() throws Exception {
doInBackground.run();
return null;
}
}
@FunctionalInterface
public static interface BackgroundRunnable {
void run() throws Exception;
}
@FunctionalInterface
public static interface BackgroundSupplier<T> {
T get() throws Exception;
}
private static class SwingLambda<T, V> extends SwingWorker<T, V> {
private BackgroundSupplier<T> doInBackground;
private Consumer<T> done;
private Consumer<Exception> error;
public SwingLambda(BackgroundSupplier<T> doInBackground, Consumer<T> done, Consumer<Exception> error) {
this.doInBackground = doInBackground;
this.done = done;
this.error = error;
}
@Override
protected T doInBackground() throws Exception {
return doInBackground.get();
}
@Override
protected void done() {
try {
done.accept(get());
} catch (InterruptedException | ExecutionException e) {
error.accept(e);
}
}
}
/** /**
* When trying to drag a row of a multi-select JTable, it will start selecting rows instead of initiating a drag. This TableUI will give the JTable proper dnd behaviour. * When trying to drag a row of a multi-select JTable, it will start selecting rows instead of initiating a drag. This TableUI will give the JTable proper dnd behaviour.
*/ */