From 98ddfafe43bc8e2b9a55a31799ffa2cb5669615f Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Fri, 19 Jun 2009 22:35:39 +0000 Subject: [PATCH] * subtitle file view in download component * added ByteBufferTransferable and use it as superclass of TextFileTransferable * added ListView * lots of refactoring --- .../sourceforge/filebot/FileBotUtilities.java | 1 - .../net/sourceforge/filebot/MediaTypes.java | 4 +- source/net/sourceforge/filebot/media.types | 12 - .../filebot/resources/file.subtitle.png | Bin 0 -> 666 bytes .../filebot/resources/file.unknown.png | Bin 0 -> 630 bytes .../filebot/resources/status.archive.png | Bin 386 -> 0 bytes .../sourceforge/filebot/torrent/Torrent.java | 7 +- .../filebot/ui/EpisodeFormatDialog.java | 2 +- .../filebot/ui/panel/rename/MatchAction.java | 8 +- .../filebot/ui/panel/subtitle/Archive.java | 15 - .../ui/panel/subtitle/ArchiveType.java | 19 +- .../filebot/ui/panel/subtitle/MemoryFile.java | 42 +++ .../subtitle/MemoryFileListExportHandler.java | 75 ++++ .../filebot/ui/panel/subtitle/RarArchive.java | 30 +- .../subtitle/SubtitleDownloadComponent.java | 320 ++++++++++++++++++ .../panel/subtitle/SubtitleListComponent.java | 125 ------- .../ui/panel/subtitle/SubtitlePackage.java | 101 ++++-- ....java => SubtitlePackageCellRenderer.java} | 15 +- .../ui/panel/subtitle/SubtitlePanel.java | 8 +- .../filebot/ui/panel/subtitle/ZipArchive.java | 24 +- .../ui/transfer/ByteBufferTransferable.java | 104 ++++++ .../ui/transfer/LazyTextFileTransferable.java | 86 ----- .../ui/transfer/TextFileExportHandler.java | 7 +- .../ui/transfer/TextFileTransferable.java | 73 ++++ .../sourceforge/filebot/web/IMDbClient.java | 4 +- .../web/OpenSubtitlesSubtitleDescriptor.java | 13 +- .../filebot/web/SublightSubtitleClient.java | 2 +- .../web/SublightSubtitleDescriptor.java | 35 +- .../web/SubsceneSubtitleDescriptor.java | 13 +- .../filebot/web/SubtitleDescriptor.java | 5 +- .../web/SubtitleSourceSubtitleDescriptor.java | 13 +- .../net/sourceforge/tuned/FileUtilities.java | 11 +- .../ui/AbstractFancyListCellRenderer.java | 5 +- .../tuned/ui/IconViewCellRenderer.java | 245 -------------- .../sourceforge/tuned/ui/IconViewPanel.java | 135 -------- source/net/sourceforge/tuned/ui/ListView.java | 204 +++++++++++ .../filebot/web/IMDbClientTest.java | 7 - .../web/SublightSubtitleClientTest.java | 8 +- .../web/SubsceneSubtitleClientTest.java | 2 +- 39 files changed, 1008 insertions(+), 772 deletions(-) create mode 100644 source/net/sourceforge/filebot/resources/file.subtitle.png create mode 100644 source/net/sourceforge/filebot/resources/file.unknown.png delete mode 100644 source/net/sourceforge/filebot/resources/status.archive.png delete mode 100644 source/net/sourceforge/filebot/ui/panel/subtitle/Archive.java create mode 100644 source/net/sourceforge/filebot/ui/panel/subtitle/MemoryFile.java create mode 100644 source/net/sourceforge/filebot/ui/panel/subtitle/MemoryFileListExportHandler.java create mode 100644 source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleDownloadComponent.java delete mode 100644 source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleListComponent.java rename source/net/sourceforge/filebot/ui/panel/subtitle/{SubtitleListCellRenderer.java => SubtitlePackageCellRenderer.java} (79%) create mode 100644 source/net/sourceforge/filebot/ui/transfer/ByteBufferTransferable.java delete mode 100644 source/net/sourceforge/filebot/ui/transfer/LazyTextFileTransferable.java create mode 100644 source/net/sourceforge/filebot/ui/transfer/TextFileTransferable.java delete mode 100644 source/net/sourceforge/tuned/ui/IconViewCellRenderer.java delete mode 100644 source/net/sourceforge/tuned/ui/IconViewPanel.java create mode 100644 source/net/sourceforge/tuned/ui/ListView.java diff --git a/source/net/sourceforge/filebot/FileBotUtilities.java b/source/net/sourceforge/filebot/FileBotUtilities.java index 892230ab..a7823465 100644 --- a/source/net/sourceforge/filebot/FileBotUtilities.java +++ b/source/net/sourceforge/filebot/FileBotUtilities.java @@ -64,7 +64,6 @@ public final class FileBotUtilities { public static final ExtensionFileFilter LIST_FILES = MediaTypes.getDefault().filter("application/list"); public static final ExtensionFileFilter VIDEO_FILES = MediaTypes.getDefault().filter("video"); public static final ExtensionFileFilter SUBTITLE_FILES = MediaTypes.getDefault().filter("subtitle"); - public static final ExtensionFileFilter ARCHIVE_FILES = MediaTypes.getDefault().filter("archive"); public static final ExtensionFileFilter SFV_FILES = MediaTypes.getDefault().filter("verification/sfv"); diff --git a/source/net/sourceforge/filebot/MediaTypes.java b/source/net/sourceforge/filebot/MediaTypes.java index 91bf6ba1..63c8f354 100644 --- a/source/net/sourceforge/filebot/MediaTypes.java +++ b/source/net/sourceforge/filebot/MediaTypes.java @@ -58,7 +58,7 @@ public class MediaTypes { } - public String[] extensions(String name) { + public List extensions(String name) { List extensions = new ArrayList(); for (Type type : types) { @@ -67,7 +67,7 @@ public class MediaTypes { } } - return extensions.toArray(new String[0]); + return extensions; } } diff --git a/source/net/sourceforge/filebot/media.types b/source/net/sourceforge/filebot/media.types index 6774e175..5001a528 100644 --- a/source/net/sourceforge/filebot/media.types +++ b/source/net/sourceforge/filebot/media.types @@ -31,18 +31,6 @@ - - - zip - - - - rar - - - diff --git a/source/net/sourceforge/filebot/resources/file.subtitle.png b/source/net/sourceforge/filebot/resources/file.subtitle.png new file mode 100644 index 0000000000000000000000000000000000000000..0fb90d9e23b72d0790bdc4360d4a5aaee64796c7 GIT binary patch literal 666 zcmV;L0%iS)P)n@Z)YbI&7&ffT*~C}i#q28IDb0ii%@A(9CF1tV+$i0;z- z`3^x{Hz-11g|z>KP@ z*x%ph)yo&`?(XvL{RfVYk130?iwBSlAay1JS~zVOJ3Bkv-qjqPoYL?2DN@l&k2W2( z0$RXydTVX&LLnq^dUAq$&@@g_l+@MTLaBS8PC?maZV|0XwB9fn3|L>^WIP^ocJ_s` zx3cJk+HsdnRPwHA)@3oB-f?j734kIc)QuY9|EB;lxg&RG?)3Y8_V)G|4lgOnlJRK7 z`T2mRsX-!p#yu~MfJ_Jh3FG%Z}O6xj)PylYxf6d++{n9==(V0~i~_dJ}< zusRJP)jK~y-6m66YD6HySyKQo&&iD(fEZH4{-tsqGCP$)w2;7xC( z76Kl;^(uJr;=#NBfLE`@3c2^Dw<;1^Xd)D>7;NJYni$(8yZd%LWOt2CEjaLChWEao z`OZ8sGel$>nB)Iq)68}%)w8Uc5nZIa7) zJXxF`0BD+spsJ`U+qFa1w;QM`lOuT+uAJx1ho7kDrA-DM!~jo~)rYgpjGw_%MO3ML zIpY4pc&|=&^Dls^GCO$|jm10rZ90C$gIgEV&Zhz-h9sx-?i){+FEcWnJMl073?tIp zL!T27VecSd`Q}(^{rCteK>A(85B3{Ai}Rx=3I|3&1nFCnh;Xiu;r6u)hzQO(f*`;- z$I#G_4ep@NMRK06f9BF?o~8LQTCEoKdL31zTrR%_Du3^wPn^W->JQ$3JizyTYPA|u zQ&Uu{)lbD@aRsOXU}gYIUEjBMyKTPjTMz^mhM`4KWMLRuv)Qz*tt~5+O1s%?_68tk z*3%|{(79CToHOT~MNwqVIqP&f(c0SD25`M!Y-YVeL}ud4)1m@YE$*1aZ$WF;d*+Uz QLI3~&07*qoM6N<$f*}tUeE_QM!1S$Bhw4w+iRuFWf;tfR6D%SMJrb+tx zC9R6{2>Ou6#juIy6u(I?|;&Owi$sRB4^20apB5xE2 z#B9XekY66S6lzfCL!eEQRgo0LokTA55@Y#%_wN!T metrics; - + public MatchAction(RenameModel model) { super("Match", ResourceManager.getIcon("action.match")); @@ -71,7 +71,7 @@ class MatchAction extends AbstractAction { } }; - // 2. pass: match by season / episode numbers, or generic numeric similarity + // 2. pass: match by season / episode numbers metrics[1] = new SeasonEpisodeSimilarityMetric() { @Override @@ -177,12 +177,12 @@ class MatchAction extends AbstractAction { return progressDialog; } - + protected class BackgroundMatcher extends SwingWorker>, Void> implements Cancellable { private final Matcher matcher; - + public BackgroundMatcher(MatchModel model, Collection metrics) { // match names against files this.matcher = new Matcher(model.values(), model.candidates(), metrics); diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/Archive.java b/source/net/sourceforge/filebot/ui/panel/subtitle/Archive.java deleted file mode 100644 index 2b4eca2a..00000000 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/Archive.java +++ /dev/null @@ -1,15 +0,0 @@ - -package net.sourceforge.filebot.ui.panel.subtitle; - - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Map; - - -interface Archive { - - Map extract() throws IOException; - -} diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/ArchiveType.java b/source/net/sourceforge/filebot/ui/panel/subtitle/ArchiveType.java index f2198de6..38390f55 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/ArchiveType.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/ArchiveType.java @@ -2,18 +2,15 @@ package net.sourceforge.filebot.ui.panel.subtitle; -import java.io.File; -import java.io.IOException; import java.nio.ByteBuffer; import java.util.Collections; -import java.util.Map; enum ArchiveType { ZIP { @Override - public Archive fromData(ByteBuffer data) { + public Iterable fromData(ByteBuffer data) { return new ZipArchive(data); } }, @@ -21,7 +18,7 @@ enum ArchiveType { RAR { @Override - public Archive fromData(ByteBuffer data) { + public Iterable fromData(ByteBuffer data) { return new RarArchive(data); } }, @@ -29,15 +26,9 @@ enum ArchiveType { UNDEFINED { @Override - public Archive fromData(ByteBuffer data) { + public Iterable fromData(ByteBuffer data) { // cannot extract data, return empty archive - return new Archive() { - - @Override - public Map extract() throws IOException { - return Collections.emptyMap(); - } - }; + return Collections.emptySet(); } }; @@ -53,6 +44,6 @@ enum ArchiveType { } - public abstract Archive fromData(ByteBuffer data); + public abstract Iterable fromData(ByteBuffer data); } diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/MemoryFile.java b/source/net/sourceforge/filebot/ui/panel/subtitle/MemoryFile.java new file mode 100644 index 00000000..ca6d2a82 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/MemoryFile.java @@ -0,0 +1,42 @@ + +package net.sourceforge.filebot.ui.panel.subtitle; + + +import java.nio.ByteBuffer; + + +class MemoryFile { + + private final String path; + + private final ByteBuffer data; + + + public MemoryFile(String path, ByteBuffer data) { + // normalize folder separator + this.path = path.replace('\\', '/'); + this.data = data; + } + + + public String getName() { + return path.substring(path.lastIndexOf("/") + 1); + } + + + public String getPath() { + return path; + } + + + public ByteBuffer getData() { + return data.duplicate(); + } + + + @Override + public String toString() { + return path; + } + +} diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/MemoryFileListExportHandler.java b/source/net/sourceforge/filebot/ui/panel/subtitle/MemoryFileListExportHandler.java new file mode 100644 index 00000000..e7e41965 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/MemoryFileListExportHandler.java @@ -0,0 +1,75 @@ + +package net.sourceforge.filebot.ui.panel.subtitle; + + +import java.awt.datatransfer.Transferable; +import java.nio.ByteBuffer; +import java.util.AbstractList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.TransferHandler; + +import net.sourceforge.filebot.ui.transfer.ByteBufferTransferable; +import net.sourceforge.filebot.ui.transfer.TransferableExportHandler; + + +class MemoryFileListExportHandler implements TransferableExportHandler { + + public boolean canExport(JComponent component) { + JList list = (JList) component; + + // can't export anything, if nothing is selected + return !list.isSelectionEmpty(); + } + + + public List export(JComponent component) { + JList list = (JList) component; + + // get selected values + final Object[] selection = list.getSelectedValues(); + + // as file list + return new AbstractList() { + + @Override + public MemoryFile get(int index) { + return (MemoryFile) selection[index]; + } + + + @Override + public int size() { + return selection.length; + } + }; + } + + + @Override + public int getSourceActions(JComponent component) { + return canExport(component) ? TransferHandler.COPY_OR_MOVE : TransferHandler.NONE; + } + + + @Override + public Transferable createTransferable(JComponent component) { + Map vfs = new HashMap(); + + for (MemoryFile file : export(component)) { + vfs.put(file.getName(), file.getData()); + } + + return new ByteBufferTransferable(vfs); + } + + + @Override + public void exportDone(JComponent source, Transferable data, int action) { + + } +} diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/RarArchive.java b/source/net/sourceforge/filebot/ui/panel/subtitle/RarArchive.java index 402c83b0..bc01e5a6 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/RarArchive.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/RarArchive.java @@ -2,21 +2,22 @@ package net.sourceforge.filebot.ui.panel.subtitle; -import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import net.sourceforge.tuned.ByteBufferOutputStream; +import de.innosystec.unrar.Archive; import de.innosystec.unrar.exception.RarException; import de.innosystec.unrar.rarfile.FileHeader; -class RarArchive implements Archive { +class RarArchive implements Iterable { private final ByteBuffer data; @@ -26,11 +27,24 @@ class RarArchive implements Archive { } - public Map extract() throws IOException { - Map vfs = new LinkedHashMap(); + @Override + public Iterator iterator() { + try { + // extract rar archives one at a time, because of JUnRar memory problems + synchronized (RarArchive.class) { + return extract().iterator(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + public List extract() throws IOException { + List vfs = new ArrayList(); try { - de.innosystec.unrar.Archive rar = new de.innosystec.unrar.Archive(data.duplicate()); + Archive rar = new Archive(data.duplicate()); for (FileHeader header : rar.getFileHeaders()) { // ignore directory entries @@ -45,7 +59,7 @@ class RarArchive implements Archive { rar.extractFile(header, buffer); // add memory file - vfs.put(new File(header.getFileNameString()), buffer.getByteBuffer()); + vfs.add(new MemoryFile(header.getFileNameString(), buffer.getByteBuffer())); } catch (OutOfMemoryError e) { // ignore, there seems to be bug with JUnRar allocating lots of memory for no apparent reason // @see https://sourceforge.net/forum/forum.php?thread_id=2773018&forum_id=706772 diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleDownloadComponent.java b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleDownloadComponent.java new file mode 100644 index 00000000..d2f34277 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleDownloadComponent.java @@ -0,0 +1,320 @@ + +package net.sourceforge.filebot.ui.panel.subtitle; + + +import static net.sourceforge.filebot.FileBotUtilities.*; + +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.ListModel; +import javax.swing.SwingUtilities; +import javax.swing.border.LineBorder; + +import ca.odell.glazedlists.BasicEventList; +import ca.odell.glazedlists.EventList; +import ca.odell.glazedlists.FilterList; +import ca.odell.glazedlists.GlazedLists; +import ca.odell.glazedlists.ListSelection; +import ca.odell.glazedlists.ObservableElementList; +import ca.odell.glazedlists.TextFilterator; +import ca.odell.glazedlists.matchers.MatcherEditor; +import ca.odell.glazedlists.swing.EventListModel; +import ca.odell.glazedlists.swing.EventSelectionModel; +import ca.odell.glazedlists.swing.TextComponentMatcherEditor; + +import net.miginfocom.swing.MigLayout; +import net.sourceforge.filebot.ResourceManager; +import net.sourceforge.filebot.ui.panel.subtitle.SubtitlePackage.Download.Phase; +import net.sourceforge.filebot.ui.transfer.DefaultTransferHandler; +import net.sourceforge.tuned.ExceptionUtilities; +import net.sourceforge.tuned.ui.ListView; + + +public class SubtitleDownloadComponent extends JComponent { + + private EventList packages = new BasicEventList(); + + private EventList files = new BasicEventList(); + + private SubtitlePackageCellRenderer renderer = new SubtitlePackageCellRenderer(); + + private JTextField filterEditor = new JTextField(); + + + public SubtitleDownloadComponent() { + JList packageList = new JList(createPackageListModel()); + packageList.setFixedCellHeight(32); + packageList.setCellRenderer(renderer); + + // better selection behaviour + EventSelectionModel packageSelection = new EventSelectionModel(packages); + packageSelection.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); + packageList.setSelectionModel(packageSelection); + + // context menu and fetch on double click + packageList.addMouseListener(packageListMouseHandler); + + // file list view + JList fileList = new ListView(createFileListModel()) { + + @Override + protected Icon convertValueToIcon(Object value) { + if (SUBTITLE_FILES.accept(value.toString())) + return ResourceManager.getIcon("file.subtitle"); + + return ResourceManager.getIcon("file.unknown"); + } + }; + + fileList.setDragEnabled(true); + fileList.setTransferHandler(new DefaultTransferHandler(null, new MemoryFileListExportHandler())); + + JButton clearButton = new JButton(clearFilterAction); + clearButton.setOpaque(false); + + JButton exportButton = new JButton(exportToFolderAction); + exportButton.setOpaque(false); + + setLayout(new MigLayout("fill, nogrid", "[fill]", "[pref!][fill]")); + + add(new JLabel("Filter:"), "gap indent:push"); + add(filterEditor, "wmin 120px, gap rel"); + add(clearButton, "w 24px!, h 24px!"); + add(new JScrollPane(packageList), "newline"); + + JScrollPane scrollPane = new JScrollPane(fileList); + scrollPane.setViewportBorder(new LineBorder(fileList.getBackground())); + add(scrollPane, "newline"); + add(exportButton, "w pref!, h pref!"); + } + + + protected ListModel createPackageListModel() { + // allow filtering by language name and subtitle name + MatcherEditor matcherEditor = new TextComponentMatcherEditor(filterEditor, new TextFilterator() { + + @Override + public void getFilterStrings(List list, SubtitlePackage element) { + list.add(element.getLanguage().getName()); + list.add(element.getName()); + } + }); + + // source list + EventList source = getPackageModel(); + + // filter list + source = new FilterList(source, matcherEditor); + + // listen to changes (e.g. download progress) + source = new ObservableElementList(source, GlazedLists.beanConnector(SubtitlePackage.class)); + + // as list model + return new EventListModel(source); + } + + + protected ListModel createFileListModel() { + // as list model + return new EventListModel(getFileModel()); + } + + + public void reset() { + // cancel and reset download workers + for (SubtitlePackage subtitle : packages) { + subtitle.reset(); + } + + files.clear(); + } + + + public EventList getPackageModel() { + return packages; + } + + + public EventList getFileModel() { + return files; + } + + + public void setLanguageVisible(boolean visible) { + renderer.getLanguageLabel().setVisible(visible); + } + + + private void fetchAll(Object[] selection) { + for (Object value : selection) { + fetch((SubtitlePackage) value); + } + } + + + private void fetch(final SubtitlePackage subtitle) { + if (subtitle.getDownload().isStarted()) { + // download has been started already + return; + } + + // listen to download + subtitle.addPropertyChangeListener(new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getNewValue() == Phase.DONE) { + try { + files.addAll(subtitle.getDownload().get()); + } catch (CancellationException e) { + // ignore cancellation + } catch (Exception e) { + Logger.getLogger("ui").log(Level.WARNING, ExceptionUtilities.getRootCauseMessage(e), e); + + // reset download + subtitle.reset(); + } + + // listener no longer required + subtitle.removePropertyChangeListener(this); + } + } + }); + + // enqueue worker + subtitle.getDownload().start(); + } + + + private final Action clearFilterAction = new AbstractAction(null, ResourceManager.getIcon("edit.clear")) { + + @Override + public void actionPerformed(ActionEvent e) { + filterEditor.setText(""); + } + }; + + private final Action exportToFolderAction = new AbstractAction("Export") { + + @Override + public void actionPerformed(ActionEvent evt) { + JComponent source = (JComponent) evt.getSource(); + + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + if (fileChooser.showSaveDialog(source) == JFileChooser.APPROVE_OPTION) { + File folder = fileChooser.getSelectedFile(); + + for (MemoryFile file : files) { + try { + FileChannel fileChannel = new FileOutputStream(new File(folder, file.getName())).getChannel(); + + try { + fileChannel.write(file.getData()); + } finally { + fileChannel.close(); + } + } catch (IOException e) { + Logger.getLogger("ui").log(Level.SEVERE, e.getMessage(), e); + } + } + } + } + }; + + private final MouseListener packageListMouseHandler = new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + // fetch on double click + if (SwingUtilities.isLeftMouseButton(e) && (e.getClickCount() == 2)) { + JList list = (JList) e.getSource(); + + fetchAll(list.getSelectedValues()); + } + } + + + @Override + public void mousePressed(MouseEvent e) { + maybeShowPopup(e); + } + + + @Override + public void mouseReleased(MouseEvent e) { + maybeShowPopup(e); + } + + + private void maybeShowPopup(MouseEvent e) { + if (e.isPopupTrigger()) { + JList list = (JList) e.getSource(); + + int index = list.locationToIndex(e.getPoint()); + + if (index >= 0 && !list.isSelectedIndex(index)) { + // auto-select clicked element + list.setSelectedIndex(index); + } + + final Object[] selection = list.getSelectedValues(); + + Action downloadAction = new AbstractAction("Download", ResourceManager.getIcon("action.fetch")) { + + @Override + public void actionPerformed(ActionEvent e) { + fetchAll(selection); + } + }; + + downloadAction.setEnabled(isPending(selection)); + + JPopupMenu contextMenu = new JPopupMenu(); + contextMenu.add(downloadAction); + + contextMenu.show(e.getComponent(), e.getX(), e.getY()); + } + } + + + private boolean isPending(Object[] selection) { + for (Object value : selection) { + SubtitlePackage subtitle = (SubtitlePackage) value; + + if (!subtitle.getDownload().isStarted()) { + // pending download found + return true; + } + } + + return false; + } + }; + +} diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleListComponent.java b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleListComponent.java deleted file mode 100644 index ec74a2e7..00000000 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleListComponent.java +++ /dev/null @@ -1,125 +0,0 @@ - -package net.sourceforge.filebot.ui.panel.subtitle; - - -import java.awt.event.ActionEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.List; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JScrollPane; -import javax.swing.JTextField; -import javax.swing.ListModel; -import javax.swing.SwingUtilities; - -import ca.odell.glazedlists.BasicEventList; -import ca.odell.glazedlists.EventList; -import ca.odell.glazedlists.FilterList; -import ca.odell.glazedlists.GlazedLists; -import ca.odell.glazedlists.ListSelection; -import ca.odell.glazedlists.ObservableElementList; -import ca.odell.glazedlists.TextFilterator; -import ca.odell.glazedlists.matchers.MatcherEditor; -import ca.odell.glazedlists.swing.EventListModel; -import ca.odell.glazedlists.swing.EventSelectionModel; -import ca.odell.glazedlists.swing.TextComponentMatcherEditor; - -import net.miginfocom.swing.MigLayout; -import net.sourceforge.filebot.ResourceManager; - - -public class SubtitleListComponent extends JComponent { - - private EventList model = new BasicEventList(); - - private EventSelectionModel selectionModel = new EventSelectionModel(model); - - private SubtitleListCellRenderer renderer = new SubtitleListCellRenderer(); - - private JTextField filterEditor = new JTextField(); - - - public SubtitleListComponent() { - JList list = new JList(createListModel(model)); - list.setFixedCellHeight(32); - list.setCellRenderer(renderer); - list.addMouseListener(mouseListener); - - selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); - list.setSelectionModel(selectionModel); - - JButton clearButton = new JButton(clearFilterAction); - clearButton.setOpaque(false); - - setLayout(new MigLayout("fill, nogrid", "[fill]", "[pref!][fill]")); - - add(new JLabel("Filter:"), "gap indent:push"); - add(filterEditor, "wmin 120px, gap rel"); - add(clearButton, "w 24px!, h 24px!"); - add(new JScrollPane(list), "newline"); - } - - - protected ListModel createListModel(EventList source) { - // allow filtering by language name and subtitle name - MatcherEditor matcherEditor = new TextComponentMatcherEditor(filterEditor, new TextFilterator() { - - @Override - public void getFilterStrings(List list, SubtitlePackage element) { - list.add(element.getLanguage().getName()); - list.add(element.getName()); - } - }); - - // filter list - source = new FilterList(source, matcherEditor); - - // listen to changes (e.g. download progress) - source = new ObservableElementList(source, GlazedLists.beanConnector(SubtitlePackage.class)); - - // as list model - return new EventListModel(source); - } - - - public EventList getModel() { - return model; - } - - - public void setLanguageVisible(boolean visible) { - renderer.getLanguageLabel().setVisible(visible); - } - - - private final MouseAdapter mouseListener = new MouseAdapter() { - - @Override - public void mouseClicked(MouseEvent e) { - if (SwingUtilities.isLeftMouseButton(e) && (e.getClickCount() == 2)) { - JList list = (JList) e.getSource(); - - for (Object value : list.getSelectedValues()) { - final SubtitlePackage subtitle = (SubtitlePackage) value; - - subtitle.getDownload().execute(); - } - } - } - }; - - private final Action clearFilterAction = new AbstractAction(null, ResourceManager.getIcon("edit.clear")) { - - @Override - public void actionPerformed(ActionEvent e) { - filterEditor.setText(""); - } - }; - -} diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePackage.java b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePackage.java index 38650546..a88128cd 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePackage.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePackage.java @@ -2,21 +2,19 @@ package net.sourceforge.filebot.ui.panel.subtitle; -import static net.sourceforge.filebot.FileBotUtilities.*; +import static java.util.Collections.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; -import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedHashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; -import java.util.Map.Entry; -import java.util.concurrent.Callable; import javax.swing.SwingWorker; import javax.swing.event.SwingPropertyChangeSupport; @@ -27,20 +25,21 @@ import net.sourceforge.tuned.FileUtilities; public class SubtitlePackage { - private final String name; + private final SubtitleDescriptor subtitle; private final Language language; - private final ArchiveType archiveType; - private Download download; - public SubtitlePackage(SubtitleDescriptor descriptor) { - name = descriptor.getName(); - language = new Language(languageCodeByName.get(descriptor.getLanguageName()), descriptor.getLanguageName()); - archiveType = ArchiveType.forName(descriptor.getArchiveType()); - download = new Download(descriptor.getDownloadFunction(), archiveType); + public SubtitlePackage(SubtitleDescriptor subtitle) { + this.subtitle = subtitle; + + // resolve language name + this.language = new Language(languageCodeByName.get(subtitle.getLanguageName()), subtitle.getLanguageName()); + + // initialize download worker + download = new Download(subtitle); // forward phase events download.addPropertyChangeListener(new PropertyChangeListener() { @@ -56,7 +55,7 @@ public class SubtitlePackage { public String getName() { - return name; + return subtitle.getName(); } @@ -65,8 +64,8 @@ public class SubtitlePackage { } - public ArchiveType getArchiveType() { - return archiveType; + public String getType() { + return subtitle.getType(); } @@ -76,8 +75,12 @@ public class SubtitlePackage { public void reset() { + // cancel old download + download.cancel(false); + + // create new download Download old = download; - download = new Download(old.function, old.archiveType); + download = new Download(subtitle); // transfer listeners for (PropertyChangeListener listener : old.getPropertyChangeSupport().getPropertyChangeListeners()) { @@ -91,7 +94,7 @@ public class SubtitlePackage { @Override public String toString() { - return name; + return subtitle.getName(); } @@ -108,39 +111,57 @@ public class SubtitlePackage { } - public static class Download extends SwingWorker, Void> { + public static class Download extends SwingWorker, Void> { enum Phase { PENDING, + WAITING, DOWNLOADING, EXTRACTING, DONE } - private final Callable function; - private final ArchiveType archiveType; + private final SubtitleDescriptor subtitle; private Phase current = Phase.PENDING; - private Download(Callable function, ArchiveType archiveType) { - this.function = function; - this.archiveType = archiveType; + private Download(SubtitleDescriptor descriptor) { + this.subtitle = descriptor; + } + + + public void start() { + setPhase(Phase.WAITING); + + // enqueue worker + execute(); } @Override - protected Map doInBackground() throws Exception { + protected List doInBackground() throws Exception { setPhase(Phase.DOWNLOADING); // fetch archive - ByteBuffer data = function.call(); + ByteBuffer data = subtitle.fetch(); + + // abort if download has been cancelled + if (isCancelled()) + return null; setPhase(Phase.EXTRACTING); + ArchiveType archiveType = ArchiveType.forName(subtitle.getType()); + + if (archiveType == ArchiveType.UNDEFINED) { + // cannot extract files from archive + return singletonList(new MemoryFile(subtitle.getName() + '.' + subtitle.getType(), data)); + } + // extract contents of the archive - Map vfs = extract(archiveType, data); + List vfs = extract(archiveType, data); // if we can't extract files from a rar archive, it might actually be a zip file with the wrong extension if (vfs.isEmpty() && archiveType != ArchiveType.ZIP) { @@ -156,18 +177,19 @@ public class SubtitlePackage { } - private Map extract(ArchiveType archiveType, ByteBuffer data) throws IOException { - Map vfs = new LinkedHashMap(); + private List extract(ArchiveType archiveType, ByteBuffer data) throws IOException { + List vfs = new ArrayList(); - for (Entry entry : archiveType.fromData(data).extract().entrySet()) { - String filename = entry.getKey().getName(); + for (MemoryFile file : archiveType.fromData(data)) { + // check if file is a supported archive + ArchiveType type = ArchiveType.forName(FileUtilities.getExtension(file.getName())); - if (SUBTITLE_FILES.accept(filename)) { - // keep only subtitle files - vfs.put(entry.getKey(), entry.getValue()); - } else if (ARCHIVE_FILES.accept(filename)) { - // extract recursively if archive contains another archive - vfs.putAll(extract(ArchiveType.forName(FileUtilities.getExtension(filename)), entry.getValue())); + if (type == ArchiveType.UNDEFINED) { + // add subtitle file + vfs.add(file); + } else { + // extract nested archives recursively + vfs.addAll(extract(type, file.getData())); } } @@ -189,6 +211,11 @@ public class SubtitlePackage { } + public boolean isStarted() { + return current != Phase.PENDING; + } + + public Phase getPhase() { return current; } diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleListCellRenderer.java b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePackageCellRenderer.java similarity index 79% rename from source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleListCellRenderer.java rename to source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePackageCellRenderer.java index 39567451..241a23ff 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitleListCellRenderer.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePackageCellRenderer.java @@ -2,6 +2,8 @@ package net.sourceforge.filebot.ui.panel.subtitle; +import static net.sourceforge.filebot.FileBotUtilities.*; + import java.awt.Color; import java.awt.Insets; @@ -15,13 +17,13 @@ import net.sourceforge.filebot.ResourceManager; import net.sourceforge.tuned.ui.AbstractFancyListCellRenderer; -public class SubtitleListCellRenderer extends AbstractFancyListCellRenderer { +public class SubtitlePackageCellRenderer extends AbstractFancyListCellRenderer { private final JLabel titleLabel = new JLabel(); private final JLabel languageLabel = new JLabel(); - public SubtitleListCellRenderer() { + public SubtitlePackageCellRenderer() { super(new Insets(5, 5, 5, 5)); setHighlightingEnabled(false); @@ -59,7 +61,14 @@ public class SubtitleListCellRenderer extends AbstractFancyListCellRenderer { private Icon getIcon(SubtitlePackage subtitle) { switch (subtitle.getDownload().getPhase()) { case PENDING: - return ResourceManager.getIcon(subtitle.getArchiveType() != ArchiveType.UNDEFINED ? "bullet.green" : "bullet.yellow"); + if (ArchiveType.forName(subtitle.getType()) != ArchiveType.UNDEFINED || SUBTITLE_FILES.extensions().contains(subtitle.getType())) { + return ResourceManager.getIcon("bullet.green"); + } + + // unsupported archive or unknown subtitle type + return ResourceManager.getIcon("bullet.yellow"); + case WAITING: + return ResourceManager.getIcon("worker.pending"); case DOWNLOADING: return ResourceManager.getIcon("package.fetch"); case EXTRACTING: diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java index 9da771e0..bfe8c029 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java @@ -141,7 +141,7 @@ public class SubtitlePanel extends AbstractSearchPanel { public SubtitleRequestProcessor(SubtitleRequest request) { - super(request, new SubtitleListComponent()); + super(request, new SubtitleDownloadComponent()); } @@ -172,13 +172,13 @@ public class SubtitlePanel extends AbstractSearchPanel subtitles) { getComponent().setLanguageVisible(request.getLanguageName() == null); - getComponent().getModel().addAll(subtitles); + getComponent().getPackageModel().addAll(subtitles); } @Override - public SubtitleListComponent getComponent() { - return (SubtitleListComponent) super.getComponent(); + public SubtitleDownloadComponent getComponent() { + return (SubtitleDownloadComponent) super.getComponent(); } diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/ZipArchive.java b/source/net/sourceforge/filebot/ui/panel/subtitle/ZipArchive.java index 95b622ce..d32af77b 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/ZipArchive.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/ZipArchive.java @@ -2,11 +2,11 @@ package net.sourceforge.filebot.ui.panel.subtitle; -import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -14,7 +14,7 @@ import net.sourceforge.tuned.ByteBufferInputStream; import net.sourceforge.tuned.ByteBufferOutputStream; -class ZipArchive implements Archive { +class ZipArchive implements Iterable { private final ByteBuffer data; @@ -24,8 +24,18 @@ class ZipArchive implements Archive { } - public Map extract() throws IOException { - Map vfs = new LinkedHashMap(); + @Override + public Iterator iterator() { + try { + return extract().iterator(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + public List extract() throws IOException { + List vfs = new ArrayList(); // read first zip entry ZipInputStream zipInputStream = new ZipInputStream(new ByteBufferInputStream(data.duplicate())); @@ -44,7 +54,7 @@ class ZipArchive implements Archive { buffer.transferFully(zipInputStream); // add memory file - vfs.put(new File(zipEntry.getName()), buffer.getByteBuffer()); + vfs.add(new MemoryFile(zipEntry.getName(), buffer.getByteBuffer())); } } finally { zipInputStream.close(); diff --git a/source/net/sourceforge/filebot/ui/transfer/ByteBufferTransferable.java b/source/net/sourceforge/filebot/ui/transfer/ByteBufferTransferable.java new file mode 100644 index 00000000..b8ce1d63 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/transfer/ByteBufferTransferable.java @@ -0,0 +1,104 @@ + +package net.sourceforge.filebot.ui.transfer; + + +import static net.sourceforge.filebot.FileBotUtilities.*; +import static net.sourceforge.filebot.Settings.*; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import net.sourceforge.tuned.TemporaryFolder; + + +public class ByteBufferTransferable implements Transferable { + + protected final Map vfs; + + private FileTransferable transferable; + + + public ByteBufferTransferable(Map vfs) { + this.vfs = vfs; + } + + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { + if (FileTransferable.isFileListFlavor(flavor)) { + try { + // create file for transfer on demand + if (transferable == null) { + transferable = createFileTransferable(); + } + + return transferable.getTransferData(flavor); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + throw new UnsupportedFlavorException(flavor); + } + + + protected FileTransferable createFileTransferable() throws IOException { + // remove invalid characters from file name + List files = new ArrayList(); + + for (Entry entry : vfs.entrySet()) { + String name = entry.getKey(); + ByteBuffer data = entry.getValue().duplicate(); + + // write temporary file + files.add(createTemporaryFile(name, data)); + } + + return new FileTransferable(files); + } + + + protected File createTemporaryFile(String name, ByteBuffer data) throws IOException { + // remove invalid characters from file name + String validFileName = validateFileName(name); + + // create new temporary file in TEMP/APP_NAME [UUID]/dnd + File temporaryFile = TemporaryFolder.getFolder(getApplicationName()).subFolder("dnd").createFile(validFileName); + + // write data to file + FileChannel fileChannel = new FileOutputStream(temporaryFile).getChannel(); + + try { + fileChannel.write(data); + } finally { + fileChannel.close(); + } + + return temporaryFile; + } + + + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { + DataFlavor.javaFileListFlavor, FileTransferable.uriListFlavor + }; + } + + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return FileTransferable.isFileListFlavor(flavor); + } + +} diff --git a/source/net/sourceforge/filebot/ui/transfer/LazyTextFileTransferable.java b/source/net/sourceforge/filebot/ui/transfer/LazyTextFileTransferable.java deleted file mode 100644 index b55e1f9f..00000000 --- a/source/net/sourceforge/filebot/ui/transfer/LazyTextFileTransferable.java +++ /dev/null @@ -1,86 +0,0 @@ - -package net.sourceforge.filebot.ui.transfer; - - -import static net.sourceforge.filebot.FileBotUtilities.*; -import static net.sourceforge.filebot.Settings.*; - -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.Transferable; -import java.awt.datatransfer.UnsupportedFlavorException; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; -import java.nio.charset.Charset; - -import net.sourceforge.tuned.TemporaryFolder; - - -public class LazyTextFileTransferable implements Transferable { - - private final String text; - private final String defaultFileName; - - private FileTransferable fileTransferable = null; - - - public LazyTextFileTransferable(String text, String defaultFileName) { - this.text = text; - this.defaultFileName = defaultFileName; - } - - - @Override - public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { - if (flavor.isFlavorTextType()) { - return text; - } else if (FileTransferable.isFileListFlavor(flavor)) { - try { - // create text file for transfer on demand - if (fileTransferable == null) { - fileTransferable = createFileTransferable(); - } - - return fileTransferable.getTransferData(flavor); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - throw new UnsupportedFlavorException(flavor); - } - - - private FileTransferable createFileTransferable() throws IOException { - // remove invalid characters from file name - String validFileName = validateFileName(defaultFileName); - - // create new temporary file in TEMP/APP_NAME [UUID]/dnd - File temporaryFile = TemporaryFolder.getFolder(getApplicationName()).subFolder("dnd").createFile(validFileName); - - // write text to file - FileChannel fileChannel = new FileOutputStream(temporaryFile).getChannel(); - - try { - fileChannel.write(Charset.forName("UTF-8").encode(text)); - } finally { - fileChannel.close(); - } - - return new FileTransferable(temporaryFile); - } - - - @Override - public DataFlavor[] getTransferDataFlavors() { - return new DataFlavor[] { DataFlavor.stringFlavor, DataFlavor.javaFileListFlavor, FileTransferable.uriListFlavor }; - } - - - @Override - public boolean isDataFlavorSupported(DataFlavor flavor) { - return flavor.isFlavorTextType() || FileTransferable.isFileListFlavor(flavor); - } - -} diff --git a/source/net/sourceforge/filebot/ui/transfer/TextFileExportHandler.java b/source/net/sourceforge/filebot/ui/transfer/TextFileExportHandler.java index 7a21a2b9..3f720871 100644 --- a/source/net/sourceforge/filebot/ui/transfer/TextFileExportHandler.java +++ b/source/net/sourceforge/filebot/ui/transfer/TextFileExportHandler.java @@ -37,10 +37,7 @@ public abstract class TextFileExportHandler implements TransferableExportHandler @Override public int getSourceActions(JComponent c) { - if (!canExport()) - return TransferHandler.NONE; - - return TransferHandler.MOVE | TransferHandler.COPY; + return canExport() ? TransferHandler.COPY_OR_MOVE : TransferHandler.NONE; } @@ -50,7 +47,7 @@ public abstract class TextFileExportHandler implements TransferableExportHandler StringWriter buffer = new StringWriter(); export(new PrintWriter(buffer)); - return new LazyTextFileTransferable(buffer.toString(), getDefaultFileName()); + return new TextFileTransferable(getDefaultFileName(), buffer.toString()); } diff --git a/source/net/sourceforge/filebot/ui/transfer/TextFileTransferable.java b/source/net/sourceforge/filebot/ui/transfer/TextFileTransferable.java new file mode 100644 index 00000000..61a701c0 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/transfer/TextFileTransferable.java @@ -0,0 +1,73 @@ + +package net.sourceforge.filebot.ui.transfer; + + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.Set; + + +public class TextFileTransferable extends ByteBufferTransferable { + + private final String text; + + + public TextFileTransferable(String name, String text) { + this(name, text, Charset.forName("UTF-8")); + } + + + public TextFileTransferable(final String name, final String text, final Charset charset) { + // lazy data map for file transfer + super(new AbstractMap() { + + @Override + public Set> entrySet() { + // encode text + Entry entry = new SimpleEntry(name, charset.encode(text)); + + // return memory file entry + return Collections.singleton(entry); + } + }); + + // text transfer + this.text = text; + } + + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { + // check file flavor first, because text/uri-list is also text flavor + if (super.isDataFlavorSupported(flavor)) { + return super.getTransferData(flavor); + } + + // check text flavor + if (flavor.isFlavorTextType()) { + return text; + } + + throw new UnsupportedFlavorException(flavor); + } + + + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { + DataFlavor.javaFileListFlavor, FileTransferable.uriListFlavor, DataFlavor.stringFlavor + }; + } + + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + // file flavor or text flavor + return super.isDataFlavorSupported(flavor) || flavor.isFlavorTextType(); + } + +} diff --git a/source/net/sourceforge/filebot/web/IMDbClient.java b/source/net/sourceforge/filebot/web/IMDbClient.java index 0f463e3e..670963a0 100644 --- a/source/net/sourceforge/filebot/web/IMDbClient.java +++ b/source/net/sourceforge/filebot/web/IMDbClient.java @@ -20,12 +20,12 @@ import java.util.regex.Pattern; import javax.swing.Icon; -import net.sourceforge.filebot.ResourceManager; - import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.SAXException; +import net.sourceforge.filebot.ResourceManager; + public class IMDbClient implements EpisodeListProvider { diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleDescriptor.java b/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleDescriptor.java index 8d745a91..3f3befe1 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleDescriptor.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleDescriptor.java @@ -8,7 +8,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.Map; import java.util.Map.Entry; -import java.util.concurrent.Callable; /** @@ -94,19 +93,13 @@ public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor { @Override - public Callable getDownloadFunction() { - return new Callable() { - - @Override - public ByteBuffer call() throws Exception { - return WebRequest.fetch(new URL(properties.get(Property.ZipDownloadLink))); - } - }; + public ByteBuffer fetch() throws Exception { + return WebRequest.fetch(new URL(properties.get(Property.ZipDownloadLink))); } @Override - public String getArchiveType() { + public String getType() { return "zip"; } diff --git a/source/net/sourceforge/filebot/web/SublightSubtitleClient.java b/source/net/sourceforge/filebot/web/SublightSubtitleClient.java index 4608ac5c..23983cbc 100644 --- a/source/net/sourceforge/filebot/web/SublightSubtitleClient.java +++ b/source/net/sourceforge/filebot/web/SublightSubtitleClient.java @@ -177,7 +177,7 @@ public class SublightSubtitleClient implements SubtitleProvider { @SuppressWarnings("unchecked") - private static Entry[] aliasList = new Entry[] { + private static final Entry[] aliasList = new Entry[] { new SimpleEntry(SubtitleLanguage.PORTUGUESE_BRAZIL, "Brazilian"), new SimpleEntry(SubtitleLanguage.BOSNIAN_LATIN, "Bosnian"), new SimpleEntry(SubtitleLanguage.SERBIAN_LATIN, "Serbian") diff --git a/source/net/sourceforge/filebot/web/SublightSubtitleDescriptor.java b/source/net/sourceforge/filebot/web/SublightSubtitleDescriptor.java index 4b633517..93027d16 100644 --- a/source/net/sourceforge/filebot/web/SublightSubtitleDescriptor.java +++ b/source/net/sourceforge/filebot/web/SublightSubtitleDescriptor.java @@ -2,10 +2,13 @@ package net.sourceforge.filebot.web; +import java.io.ByteArrayInputStream; import java.nio.ByteBuffer; import java.util.Formatter; -import java.util.concurrent.Callable; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import net.sourceforge.tuned.ByteBufferOutputStream; import net.sublight.webservice.Subtitle; @@ -75,20 +78,32 @@ public class SublightSubtitleDescriptor implements SubtitleDescriptor { @Override - public String getArchiveType() { - return "zip"; + public String getType() { + return subtitle.getSubtitleType().value().toLowerCase(); } @Override - public Callable getDownloadFunction() { - return new Callable() { + public ByteBuffer fetch() throws Exception { + byte[] archive = source.getZipArchive(subtitle); + + // the zip archive will contain exactly one subtitle + ZipInputStream stream = new ZipInputStream(new ByteArrayInputStream(archive)); + + try { + // move to subtitle entry + ZipEntry entry = stream.getNextEntry(); - @Override - public ByteBuffer call() throws Exception { - return ByteBuffer.wrap(source.getZipArchive(subtitle)); - } - }; + ByteBufferOutputStream buffer = new ByteBufferOutputStream((int) entry.getSize()); + + // read subtitle data + buffer.transferFully(stream); + + // return plain subtitle data + return buffer.getByteBuffer(); + } finally { + stream.close(); + } } diff --git a/source/net/sourceforge/filebot/web/SubsceneSubtitleDescriptor.java b/source/net/sourceforge/filebot/web/SubsceneSubtitleDescriptor.java index cbcfac89..1ec58002 100644 --- a/source/net/sourceforge/filebot/web/SubsceneSubtitleDescriptor.java +++ b/source/net/sourceforge/filebot/web/SubsceneSubtitleDescriptor.java @@ -6,7 +6,6 @@ import static java.util.Collections.*; import java.net.URL; import java.nio.ByteBuffer; -import java.util.concurrent.Callable; public class SubsceneSubtitleDescriptor implements SubtitleDescriptor { @@ -43,19 +42,13 @@ public class SubsceneSubtitleDescriptor implements SubtitleDescriptor { @Override - public Callable getDownloadFunction() { - return new Callable() { - - @Override - public ByteBuffer call() throws Exception { - return WebRequest.fetch(downloadLink, singletonMap("Referer", referer.toString())); - } - }; + public ByteBuffer fetch() throws Exception { + return WebRequest.fetch(downloadLink, singletonMap("Referer", referer.toString())); } @Override - public String getArchiveType() { + public String getType() { return archiveType; } diff --git a/source/net/sourceforge/filebot/web/SubtitleDescriptor.java b/source/net/sourceforge/filebot/web/SubtitleDescriptor.java index e1cd311f..088f81ac 100644 --- a/source/net/sourceforge/filebot/web/SubtitleDescriptor.java +++ b/source/net/sourceforge/filebot/web/SubtitleDescriptor.java @@ -3,7 +3,6 @@ package net.sourceforge.filebot.web; import java.nio.ByteBuffer; -import java.util.concurrent.Callable; public interface SubtitleDescriptor { @@ -14,9 +13,9 @@ public interface SubtitleDescriptor { String getLanguageName(); - String getArchiveType(); + String getType(); - Callable getDownloadFunction(); + ByteBuffer fetch() throws Exception; } diff --git a/source/net/sourceforge/filebot/web/SubtitleSourceSubtitleDescriptor.java b/source/net/sourceforge/filebot/web/SubtitleSourceSubtitleDescriptor.java index 64ae63f3..50523b62 100644 --- a/source/net/sourceforge/filebot/web/SubtitleSourceSubtitleDescriptor.java +++ b/source/net/sourceforge/filebot/web/SubtitleSourceSubtitleDescriptor.java @@ -4,7 +4,6 @@ package net.sourceforge.filebot.web; import java.net.URL; import java.nio.ByteBuffer; -import java.util.concurrent.Callable; public class SubtitleSourceSubtitleDescriptor implements SubtitleDescriptor { @@ -63,19 +62,13 @@ public class SubtitleSourceSubtitleDescriptor implements SubtitleDescriptor { @Override - public Callable getDownloadFunction() { - return new Callable() { - - @Override - public ByteBuffer call() throws Exception { - return WebRequest.fetch(downloadLink); - } - }; + public ByteBuffer fetch() throws Exception { + return WebRequest.fetch(downloadLink); } @Override - public String getArchiveType() { + public String getType() { return "zip"; } diff --git a/source/net/sourceforge/tuned/FileUtilities.java b/source/net/sourceforge/tuned/FileUtilities.java index 18bc27bb..fa0dcf5e 100644 --- a/source/net/sourceforge/tuned/FileUtilities.java +++ b/source/net/sourceforge/tuned/FileUtilities.java @@ -5,6 +5,8 @@ package net.sourceforge.tuned; import java.io.File; import java.io.FileFilter; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; @@ -150,6 +152,11 @@ public final class FileUtilities { } + public ExtensionFileFilter(Collection extensions) { + this.extensions = extensions.toArray(new String[0]); + } + + @Override public boolean accept(File file) { return hasExtension(file, extensions); @@ -161,8 +168,8 @@ public final class FileUtilities { } - public String[] getExtensions() { - return extensions.clone(); + public List extensions() { + return Arrays.asList(extensions); } } diff --git a/source/net/sourceforge/tuned/ui/AbstractFancyListCellRenderer.java b/source/net/sourceforge/tuned/ui/AbstractFancyListCellRenderer.java index 8ca2298c..cc4086b3 100644 --- a/source/net/sourceforge/tuned/ui/AbstractFancyListCellRenderer.java +++ b/source/net/sourceforge/tuned/ui/AbstractFancyListCellRenderer.java @@ -38,7 +38,7 @@ public abstract class AbstractFancyListCellRenderer extends JPanel implements Li private static final Insets DEFAULT_PADDING = new Insets(7, 7, 7, 7); private static final Insets DEFAULT_MARGIN = new Insets(1, 1, 0, 1); - + public AbstractFancyListCellRenderer() { this(DEFAULT_PADDING, DEFAULT_MARGIN, null); } @@ -121,9 +121,6 @@ public abstract class AbstractFancyListCellRenderer extends JPanel implements Li protected void configureListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - - setBackground(list.getBackground()); - setGradientPainted(isSelected); setBorderPainted(isSelected); diff --git a/source/net/sourceforge/tuned/ui/IconViewCellRenderer.java b/source/net/sourceforge/tuned/ui/IconViewCellRenderer.java deleted file mode 100644 index f1c1cbc8..00000000 --- a/source/net/sourceforge/tuned/ui/IconViewCellRenderer.java +++ /dev/null @@ -1,245 +0,0 @@ - -package net.sourceforge.tuned.ui; - - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Insets; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.geom.RectangularShape; -import java.awt.geom.RoundRectangle2D; - -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.Icon; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.SwingConstants; -import javax.swing.border.EmptyBorder; - - -public class IconViewCellRenderer extends AbstractFancyListCellRenderer { - - private final JLabel iconLabel = new JLabel(); - private final JLabel titleLabel = new JLabel(); - - private final ContentPane contentPane = new ContentPane(); - - - public IconViewCellRenderer() { - super(new Insets(3, 3, 3, 3), new Insets(3, 3, 3, 3)); - - setHighlightingEnabled(false); - - contentPane.add(titleLabel); - contentPane.setBorder(new EmptyBorder(4, 4, 4, 4)); - - iconLabel.setHorizontalAlignment(SwingConstants.CENTER); - iconLabel.setVerticalAlignment(SwingConstants.CENTER); - - JPanel contentPanel = new JPanel(new BorderLayout()); - contentPanel.setOpaque(false); - - Box contentPaneContainer = new Box(BoxLayout.X_AXIS); - contentPaneContainer.add(contentPane); - - contentPanel.add(contentPaneContainer, BorderLayout.WEST); - - add(iconLabel, BorderLayout.WEST); - add(contentPanel, BorderLayout.CENTER); - } - - - @Override - protected void configureListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - super.configureListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - - setGradientPainted(false); - - setText(value.toString()); - contentPane.setGradientPainted(isSelected); - } - - - @Override - public void setForeground(Color fg) { - super.setForeground(fg); - - // label is null while in super constructor - if (titleLabel != null) { - titleLabel.setForeground(fg); - } - } - - - @Override - public void setBackground(Color bg) { - super.setBackground(bg); - - // label is null while in super constructor - if (titleLabel != null) { - titleLabel.setBackground(bg); - } - } - - - public void setIcon(Icon icon) { - iconLabel.setIcon(icon); - } - - - public void setText(String title) { - titleLabel.setText(title); - } - - - protected JComponent getContentPane() { - return contentPane; - } - - - private class ContentPane extends Box { - - private boolean gradientPainted; - - - public ContentPane() { - super(BoxLayout.Y_AXIS); - setOpaque(false); - } - - - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - - RectangularShape shape = new RoundRectangle2D.Float(0, 0, getWidth(), getHeight(), 16, 16); - - if (gradientPainted) { - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setPaint(getGradientStyle().getGradientPaint(shape, getGradientBeginColor(), getGradientEndColor())); - g2d.fill(shape); - } - - super.paintComponent(g); - } - - - public void setGradientPainted(boolean gradientPainted) { - this.gradientPainted = gradientPainted; - } - - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void validate() { - // validate children, yet avoid flickering of the mouse cursor - validateTree(); - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void repaint() { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void repaint(long tm, int x, int y, int width, int height) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void repaint(Rectangle r) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void firePropertyChange(String propertyName, byte oldValue, byte newValue) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void firePropertyChange(String propertyName, char oldValue, char newValue) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void firePropertyChange(String propertyName, short oldValue, short newValue) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void firePropertyChange(String propertyName, int oldValue, int newValue) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void firePropertyChange(String propertyName, long oldValue, long newValue) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void firePropertyChange(String propertyName, float oldValue, float newValue) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void firePropertyChange(String propertyName, double oldValue, double newValue) { - } - - - /** - * Overridden for performance reasons. - */ - @Override - public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { - } - -} diff --git a/source/net/sourceforge/tuned/ui/IconViewPanel.java b/source/net/sourceforge/tuned/ui/IconViewPanel.java deleted file mode 100644 index 291455a9..00000000 --- a/source/net/sourceforge/tuned/ui/IconViewPanel.java +++ /dev/null @@ -1,135 +0,0 @@ - -package net.sourceforge.tuned.ui; - - -import java.awt.AlphaComposite; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Insets; -import java.awt.Paint; -import java.awt.geom.Rectangle2D; - -import javax.swing.DefaultListModel; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.ListModel; -import javax.swing.border.Border; -import javax.swing.border.CompoundBorder; -import javax.swing.border.EmptyBorder; - - -public class IconViewPanel extends JPanel { - - private final JList list = new JList(createModel()); - - private final JLabel titleLabel = new JLabel(); - - private final JPanel headerPanel = new JPanel(new BorderLayout()); - - - public IconViewPanel() { - super(new BorderLayout()); - - list.setLayoutOrientation(JList.HORIZONTAL_WRAP); - list.setVisibleRowCount(-1); - - titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD)); - - headerPanel.setOpaque(false); - headerPanel.add(titleLabel, BorderLayout.WEST); - - setBackground(list.getBackground()); - - headerPanel.setBorder(new CompoundBorder(new GradientLineBorder(290), new EmptyBorder(2, 10, 1, 5))); - list.setBorder(new EmptyBorder(5, 5, 5, 5)); - - JScrollPane listScrollPane = new JScrollPane(list); - listScrollPane.setBorder(null); - - add(headerPanel, BorderLayout.NORTH); - add(listScrollPane, BorderLayout.CENTER); - } - - - protected ListModel createModel() { - return new DefaultListModel(); - } - - - public JList getList() { - return list; - } - - - public JPanel getHeaderPanel() { - return headerPanel; - } - - - public void setTitle(String text) { - titleLabel.setText(text); - } - - - public String getTitle() { - return titleLabel.getText(); - } - - - public void expand() { - // TODO expand - } - - - public void collapse() { - // TODO collapse - } - - - private class GradientLineBorder implements Border { - - private int gradientLineWidth; - - - public GradientLineBorder(int width) { - this.gradientLineWidth = width; - } - - - @Override - public Insets getBorderInsets(Component c) { - return new Insets(0, 0, 1, 0); - } - - - @Override - public boolean isBorderOpaque() { - return false; - } - - - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - Graphics2D g2d = (Graphics2D) g; - - Color beginColor = list.getSelectionBackground().brighter(); - Color endColor = list.getBackground(); - - Rectangle2D shape = new Rectangle2D.Float(x, y + height - 1, gradientLineWidth, 1); - - Paint paint = GradientStyle.LEFT_TO_RIGHT.getGradientPaint(shape, beginColor, endColor); - g2d.setPaint(paint); - - g2d.setComposite(AlphaComposite.SrcOver.derive(0.9f)); - - g2d.fill(shape); - } - } - -} diff --git a/source/net/sourceforge/tuned/ui/ListView.java b/source/net/sourceforge/tuned/ui/ListView.java new file mode 100644 index 00000000..be91af86 --- /dev/null +++ b/source/net/sourceforge/tuned/ui/ListView.java @@ -0,0 +1,204 @@ + +package net.sourceforge.tuned.ui; + + +import static java.lang.Math.*; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; +import java.awt.geom.Rectangle2D; +import java.awt.image.FilteredImageSource; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.DropMode; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JList; +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; +import javax.swing.event.MouseInputAdapter; + + +public class ListView extends JList { + + protected final BlockSelectionHandler blockSelectionHandler = new BlockSelectionHandler(); + + + public ListView(ListModel dataModel) { + super(dataModel); + setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + + // better selection behaviour + putClientProperty("List.isFileList", Boolean.TRUE); + setDropMode(DropMode.ON); + + setLayoutOrientation(JList.VERTICAL_WRAP); + setVisibleRowCount(-1); + setCellRenderer(new ListViewRenderer()); + + addMouseListener(blockSelectionHandler); + addMouseMotionListener(blockSelectionHandler); + } + + + public void addSelectionInterval(Rectangle selection) { + Point p1 = selection.getLocation(); + Point p2 = new Point(p1.x + selection.width, p1.y + selection.height); + + int startIndex = locationToIndex(p1); + int endIndex = locationToIndex(p2); + + for (int i = startIndex; i <= endIndex; i++) { + Rectangle cell = getCellBounds(i, i); + + if (cell != null && selection.intersects(cell)) { + addSelectionInterval(i, i); + } + } + } + + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + + Rectangle selection = blockSelectionHandler.getSelection(); + + // paint block selection + if (selection != null) { + paintBlockSelection((Graphics2D) g, selection); + } + } + + + protected void paintBlockSelection(Graphics2D g2d, Rectangle selection) { + g2d.setPaint(TunedUtilities.derive(getSelectionBackground(), 0.3f)); + g2d.fill(selection); + + g2d.setPaint(getSelectionBackground()); + g2d.draw(selection); + } + + + protected String convertValueToText(Object value) { + return value.toString(); + } + + + protected Icon convertValueToIcon(Object value) { + return null; + } + + + protected class ListViewRenderer extends DefaultListCellRenderer { + + public ListViewRenderer() { + setOpaque(false); + } + + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + Icon icon = convertValueToIcon(value); + + if (isSelected && icon != null) { + // apply selection color tint + icon = new ImageIcon(createImage(new FilteredImageSource(TunedUtilities.getImage(icon).getSource(), new ColorTintImageFilter(list.getSelectionBackground(), 0.5f)))); + } + + setText(convertValueToText(value)); + setIcon(icon); + + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + return this; + } + + + @Override + protected void paintComponent(Graphics g) { + // paint selection background for the text area only, not the whole cell + int iconWidth = (getIcon() == null ? 0 : getIcon().getIconHeight()); + int startX = iconWidth + getIconTextGap(); + Rectangle2D text = getFontMetrics(getFont()).getStringBounds(getText(), g); + + g.setColor(getBackground()); + g.fillRect(startX - 2, 1, (int) (text.getWidth() + 6), getHeight() - 1); + + super.paintComponent(g); + } + }; + + + protected class BlockSelectionHandler extends MouseInputAdapter { + + private Rectangle selection; + + private Point origin; + + + public void mousePressed(MouseEvent e) { + if (SwingUtilities.isLeftMouseButton(e) && !isSelectedIndex(locationToIndex(e.getPoint()))) { + origin = e.getPoint(); + } + } + + + @Override + public void mouseDragged(MouseEvent e) { + if (origin == null) + return; + + // begin selection + if (selection == null) + selection = new Rectangle(); + + // keep point within component bounds + Point p2 = e.getPoint(); + p2.x = max(0, min(getWidth() - 1, p2.x)); + p2.y = max(0, min(getHeight() - 1, p2.y)); + + // update selection bounds + selection.setFrameFromDiagonal(origin, p2); + + // auto-scroll + ensureIndexIsVisible(locationToIndex(p2)); + + // update list selection + clearSelection(); + addSelectionInterval(selection); + + // update view + repaint(); + } + + + @Override + public void mouseReleased(MouseEvent e) { + origin = null; + + // end selection + selection = null; + + // update view + repaint(); + } + + + public Rectangle getSelection() { + return selection; + } + }; + +} diff --git a/test/net/sourceforge/filebot/web/IMDbClientTest.java b/test/net/sourceforge/filebot/web/IMDbClientTest.java index 954f7f1c..e73d7f54 100644 --- a/test/net/sourceforge/filebot/web/IMDbClientTest.java +++ b/test/net/sourceforge/filebot/web/IMDbClientTest.java @@ -84,11 +84,4 @@ public class IMDbClientTest { assertEquals("http://www.imdb.com/title/tt0407362/episodes", imdb.getEpisodeListLink(new MovieDescriptor("Battlestar Galactica", 2004, 407362)).toString()); } - - @Test - public void removeQuotationMarks() throws Exception { - assertEquals("test", imdb.normalizeName("\"test\"")); - - assertEquals("inner \"quotation marks\"", imdb.normalizeName("\"inner \"quotation marks\"\"")); - } } diff --git a/test/net/sourceforge/filebot/web/SublightSubtitleClientTest.java b/test/net/sourceforge/filebot/web/SublightSubtitleClientTest.java index b5de8f11..d9063d13 100644 --- a/test/net/sourceforge/filebot/web/SublightSubtitleClientTest.java +++ b/test/net/sourceforge/filebot/web/SublightSubtitleClientTest.java @@ -59,15 +59,15 @@ public class SublightSubtitleClientTest { @Test public void getSubtitleListAllLanguages() { - List list = client.getSubtitleList(new MovieDescriptor("Babylon 5", 1994, 105946), null); + List list = client.getSubtitleList(new MovieDescriptor("Terminator 2", 1991, 103064), null); SubtitleDescriptor sample = list.get(0); - assertEquals("Babylon.5.S01E01.Midnight.on.the.Firing.Line.AC3.DVDRip.DivX-AMC", sample.getName()); - assertEquals("Slovenian", sample.getLanguageName()); + assertEquals("Terminator.2.Judgment.Day(1991)", sample.getName()); + assertEquals("English", sample.getLanguageName()); // check size - assertTrue(list.size() > 45); + assertTrue(list.size() > 20); } diff --git a/test/net/sourceforge/filebot/web/SubsceneSubtitleClientTest.java b/test/net/sourceforge/filebot/web/SubsceneSubtitleClientTest.java index 3b154aed..307c4fac 100644 --- a/test/net/sourceforge/filebot/web/SubsceneSubtitleClientTest.java +++ b/test/net/sourceforge/filebot/web/SubsceneSubtitleClientTest.java @@ -68,7 +68,7 @@ public class SubsceneSubtitleClientTest { assertEquals("Twin Peaks - First Season", subtitle.getName()); assertEquals("Italian", subtitle.getLanguageName()); - assertEquals("zip", subtitle.getArchiveType()); + assertEquals("zip", subtitle.getType()); }