* changed IconProvider to LabelProvider (provides text and icon)

* Changed EpisodeListClient and SubtitleClient from abstract classes to interfaces
* OpenSubtitlesSubtitleClient: remove shutdownhook if not needed anymore
* some refactoring
This commit is contained in:
Reinhard Pointner 2008-07-13 17:59:05 +00:00
parent a341922a30
commit a401a51c75
26 changed files with 331 additions and 356 deletions

View File

@ -4,11 +4,7 @@ package net.sourceforge.filebot;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.List;
import java.util.regex.Pattern;
@ -22,17 +18,17 @@ public class FileBotUtil {
}
/**
* invalid characters: \, /, :, *, ?, ", <, >, |, \r and \n
* Invalid characters in filenames: \, /, :, *, ?, ", <, >, |, \r and \n
*/
public static final String INVALID_CHARACTERS = "\\/:*?\"<>|\r\n";
public static final Pattern INVALID_CHARACTERS_PATTERN = Pattern.compile(String.format("[%s]+", Pattern.quote(INVALID_CHARACTERS)));
/**
* Strip string of invalid characters
* Strip filename of invalid characters
*
* @param filename original filename
* @return filename stripped of invalid characters
* @return valid filename stripped of invalid characters
*/
public static String validateFileName(String filename) {
// strip invalid characters from filename
@ -47,7 +43,7 @@ public class FileBotUtil {
private static final String[] TORRENT_FILE_EXTENSIONS = { "torrent" };
private static final String[] SFV_FILE_EXTENSIONS = { "sfv" };
private static final String[] LIST_FILE_EXTENSIONS = { "txt", "list", "" };
private static final String[] SUBTITLE_FILE_EXTENSIONS = { "srt", "sub", "ssa" };
private static final String[] SUBTITLE_FILE_EXTENSIONS = { "srt", "sub", "ssa", "smi" };
public static boolean containsOnlyFolders(List<File> files) {
@ -75,7 +71,7 @@ public class FileBotUtil {
}
private static boolean containsOnly(List<File> files, String[] extensions) {
public static boolean containsOnly(List<File> files, String... extensions) {
for (File file : files) {
if (!FileUtil.hasExtension(file, extensions))
return false;
@ -111,12 +107,4 @@ public class FileBotUtil {
};
//TODO needed??
public static void writeToFile(File file, ByteBuffer data) throws IOException {
FileChannel channel = new FileOutputStream(file).getChannel();
channel.write(data);
channel.close();
}
}

View File

@ -31,6 +31,7 @@ import javax.swing.SwingWorker;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.filebot.web.SearchResult;
import net.sourceforge.tuned.ExceptionUtil;
import net.sourceforge.tuned.ui.LabelProvider;
import net.sourceforge.tuned.ui.SelectButtonTextField;
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
import net.sourceforge.tuned.ui.TunedUtil;
@ -45,7 +46,7 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
private final HistoryPanel historyPanel = new HistoryPanel();
private final SelectButtonTextField<S> searchField;
private final SelectButtonTextField<S> searchField = new SelectButtonTextField<S>();
private final EventList<String> searchHistory = new BasicEventList<String>();
@ -55,8 +56,6 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
setLayout(new BorderLayout(10, 5));
searchField = new SelectButtonTextField<S>();
Box searchBox = Box.createHorizontalBox();
searchBox.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
@ -92,12 +91,21 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
completionList.addMemberList(fetchHistory);
*/
searchField.getSelectButton().setModel(createSearchEngines());
searchField.getSelectButton().setLabelProvider(createSearchEngineLabelProvider());
AutoCompleteSupport.install(searchField.getEditor(), searchHistory);
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
}
protected abstract List<S> createSearchEngines();
protected abstract LabelProvider<S> createSearchEngineLabelProvider();
protected abstract SearchTask createSearchTask();
@ -185,7 +193,7 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
tab.setTitle(task.getSearchText());
tab.setLoading(true);
tab.setIcon(searchField.getSelectButton().getIconProvider().getIcon(task.getClient()));
tab.setIcon(searchField.getSelectButton().getLabelProvider().getIcon(task.getClient()));
tab.addTo(tabbedPane);
@ -253,7 +261,7 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(window, searchResults);
selectDialog.setIconImage(TunedUtil.getImage(searchField.getSelectButton().getIconProvider().getIcon(task.getClient())));
selectDialog.setIconImage(TunedUtil.getImage(searchField.getSelectButton().getLabelProvider().getIcon(task.getClient())));
configureSelectDialog(selectDialog);
selectDialog.setVisible(true);
@ -372,7 +380,7 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
String title = task.getSearchResult().toString();
URI link = getLink(task.getClient(), task.getSearchResult());
Icon icon = searchField.getSelectButton().getIconProvider().getIcon(task.getClient());
Icon icon = searchField.getSelectButton().getLabelProvider().getIcon(task.getClient());
String info = task.getStatusMessage();
String duration = String.format("%,d ms", task.getDuration());

View File

@ -3,7 +3,6 @@ package net.sourceforge.filebot.ui.panel.search;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.SwingWorker;
@ -33,12 +32,13 @@ class FetchEpisodeListTask extends SwingWorker<List<Episode>, Void> {
protected List<Episode> doInBackground() throws Exception {
long start = System.currentTimeMillis();
Iterator<Episode> itr = searchEngine.getEpisodeList(searchResult, numberOfSeason).iterator();
List<Episode> list = new ArrayList<Episode>();
ArrayList<Episode> list = new ArrayList<Episode>();
while (itr.hasNext())
list.add(itr.next());
if (numberOfSeason == SeasonSpinnerModel.ALL_SEASONS) {
list.addAll(searchEngine.getEpisodeList(searchResult));
} else {
list.addAll(searchEngine.getEpisodeList(searchResult, numberOfSeason));
}
duration = System.currentTimeMillis() - start;
return list;

View File

@ -10,7 +10,9 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URI;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -24,7 +26,6 @@ import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
@ -37,13 +38,17 @@ import net.sourceforge.filebot.ui.MessageManager;
import net.sourceforge.filebot.ui.SelectDialog;
import net.sourceforge.filebot.ui.transfer.SaveAction;
import net.sourceforge.filebot.ui.transfer.Saveable;
import net.sourceforge.filebot.web.AnidbClient;
import net.sourceforge.filebot.web.Episode;
import net.sourceforge.filebot.web.EpisodeListClient;
import net.sourceforge.filebot.web.SearchResult;
import net.sourceforge.filebot.web.TVDotComClient;
import net.sourceforge.filebot.web.TVRageClient;
import net.sourceforge.tuned.ExceptionUtil;
import net.sourceforge.tuned.ui.LabelProvider;
import net.sourceforge.tuned.ui.SelectButton;
import net.sourceforge.tuned.ui.SelectButtonTextField;
import net.sourceforge.tuned.ui.SimpleIconProvider;
import net.sourceforge.tuned.ui.SimpleLabelProvider;
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
import net.sourceforge.tuned.ui.TunedUtil;
@ -54,7 +59,7 @@ public class SearchPanel extends FileBotPanel {
private HistoryPanel historyPanel = new HistoryPanel();
private SpinnerNumberModel seasonSpinnerModel = new SpinnerNumberModel(SeasonSpinnerEditor.ALL_SEASONS, SeasonSpinnerEditor.ALL_SEASONS, Integer.MAX_VALUE, 1);
private SeasonSpinnerModel seasonSpinnerModel = new SeasonSpinnerModel();
private SelectButtonTextField<EpisodeListClient> searchField;
@ -64,8 +69,8 @@ public class SearchPanel extends FileBotPanel {
searchField = new SelectButtonTextField<EpisodeListClient>();
searchField.getSelectButton().setModel(EpisodeListClient.getAvailableEpisodeListClients());
searchField.getSelectButton().setIconProvider(SimpleIconProvider.forClass(EpisodeListClient.class));
searchField.getSelectButton().setModel(createSearchEngines());
searchField.getSelectButton().setLabelProvider(createSearchEngineLabelProvider());
searchField.getSelectButton().addPropertyChangeListener(SelectButton.SELECTED_VALUE, selectButtonListener);
@ -119,9 +124,19 @@ public class SearchPanel extends FileBotPanel {
}
public void setSeasonValue(Object value) {
if (value != null)
seasonSpinnerModel.setValue(value);
protected List<EpisodeListClient> createSearchEngines() {
List<EpisodeListClient> engines = new ArrayList<EpisodeListClient>(3);
engines.add(new TVDotComClient());
engines.add(new AnidbClient());
engines.add(new TVRageClient());
return engines;
}
protected LabelProvider<EpisodeListClient> createSearchEngineLabelProvider() {
return SimpleLabelProvider.forClass(EpisodeListClient.class);
}
private final PropertyChangeListener selectButtonListener = new PropertyChangeListener() {
@ -130,12 +145,10 @@ public class SearchPanel extends FileBotPanel {
EpisodeListClient client = searchField.getSelected();
if (!client.hasSingleSeasonSupport()) {
seasonSpinnerModel.setValue(SeasonSpinnerEditor.ALL_SEASONS);
seasonSpinnerModel.setMaximum(SeasonSpinnerEditor.ALL_SEASONS);
seasonSpinnerModel.lock(SeasonSpinnerModel.ALL_SEASONS);
} else {
seasonSpinnerModel.setMaximum(Integer.MAX_VALUE);
seasonSpinnerModel.unlock();
}
}
};
@ -145,7 +158,7 @@ public class SearchPanel extends FileBotPanel {
public void actionPerformed(ActionEvent e) {
EpisodeListClient searchEngine = searchField.getSelected();
SearchTask task = new SearchTask(searchEngine, searchField.getText(), seasonSpinnerModel.getNumber().intValue());
SearchTask task = new SearchTask(searchEngine, searchField.getText(), seasonSpinnerModel.getSeason());
task.addPropertyChangeListener(new SearchTaskListener());
task.execute();
@ -155,14 +168,14 @@ public class SearchPanel extends FileBotPanel {
private final AbstractAction upAction = new AbstractAction("Up") {
public void actionPerformed(ActionEvent e) {
setSeasonValue(seasonSpinnerModel.getNextValue());
seasonSpinnerModel.setValue(seasonSpinnerModel.getNextValue());
}
};
private final AbstractAction downAction = new AbstractAction("Down") {
public void actionPerformed(ActionEvent e) {
setSeasonValue(seasonSpinnerModel.getPreviousValue());
seasonSpinnerModel.setValue(seasonSpinnerModel.getPreviousValue());
}
};
@ -216,7 +229,7 @@ public class SearchPanel extends FileBotPanel {
String title = task.query;
if (task.numberOfSeason != SeasonSpinnerEditor.ALL_SEASONS) {
if (task.numberOfSeason != SeasonSpinnerModel.ALL_SEASONS) {
title += String.format(" - Season %d", task.numberOfSeason);
}
@ -292,7 +305,7 @@ public class SearchPanel extends FileBotPanel {
//TODO fix
// Settings.getSettings().putStringList(Settings.SEARCH_HISTORY, searchFieldCompletion.getTerms());
if (task.numberOfSeason != SeasonSpinnerEditor.ALL_SEASONS) {
if (task.numberOfSeason != SeasonSpinnerModel.ALL_SEASONS) {
title += String.format(" - Season %d", task.numberOfSeason);
}

View File

@ -10,7 +10,6 @@ import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@ -18,9 +17,7 @@ import javax.swing.event.ChangeListener;
class SeasonSpinnerEditor extends JPanel implements ChangeListener {
public static final int ALL_SEASONS = 0;
private JLabel text = new JLabel();
private final JLabel text = new JLabel();
public SeasonSpinnerEditor(JSpinner spinner) {
@ -44,13 +41,11 @@ class SeasonSpinnerEditor extends JPanel implements ChangeListener {
private void setValueFromSpinner(JSpinner spinner) {
SpinnerNumberModel model = (SpinnerNumberModel) spinner.getModel();
int i = model.getNumber().intValue();
int season = ((SeasonSpinnerModel) spinner.getModel()).getSeason();
if (i == ALL_SEASONS)
if (season == SeasonSpinnerModel.ALL_SEASONS)
text.setText("All Seasons");
else
text.setText("Season " + i);
text.setText("Season " + season);
}
}

View File

@ -0,0 +1,32 @@
package net.sourceforge.filebot.ui.panel.search;
import javax.swing.SpinnerNumberModel;
public class SeasonSpinnerModel extends SpinnerNumberModel {
public static final int ALL_SEASONS = 0;
public SeasonSpinnerModel() {
super(ALL_SEASONS, ALL_SEASONS, Integer.MAX_VALUE, 1);
}
public int getSeason() {
return getNumber().intValue();
}
public void lock(int maxSeason) {
setMaximum(maxSeason);
}
public void unlock() {
setMaximum(Integer.MAX_VALUE);
}
}

View File

@ -15,8 +15,8 @@ public class Checksum {
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
public static final String STATE_PROPERTY = "DOWNLOAD_STATE";
public static final String PROGRESS_PROPERTY = "DOWNLOAD_PROGRESS";
public static final String STATE_PROPERTY = "state";
public static final String PROGRESS_PROPERTY = "progress";
private Long checksum = null;
private State state = State.PENDING;

View File

@ -93,10 +93,10 @@ class ChecksumTableModel extends AbstractTableModel {
}
public synchronized void addAll(List<Entry> list) {
public synchronized void addAll(List<ChecksumCell> list) {
int firstRow = getRowCount();
for (Entry entry : list) {
for (ChecksumCell entry : list) {
addChecksum(entry.getName(), entry.getChecksum(), entry.getColumnRoot());
}
@ -185,16 +185,14 @@ class ChecksumTableModel extends AbstractTableModel {
};
public static class Entry {
public static class ChecksumCell {
private String name;
private Checksum checksum;
private File columnRoot;
private final String name;
private final Checksum checksum;
private final File columnRoot;
public Entry(String name, Checksum checksum, File columnRoot) {
public ChecksumCell(String name, Checksum checksum, File columnRoot) {
this.name = name;
this.checksum = checksum;
this.columnRoot = columnRoot;

View File

@ -17,7 +17,7 @@ import net.sourceforge.filebot.FileBotUtil;
import net.sourceforge.filebot.ui.transferablepolicies.BackgroundFileTransferablePolicy;
class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTableModel.Entry> {
class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTableModel.ChecksumCell> {
private ChecksumTableModel tableModel;
@ -34,7 +34,7 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
@Override
protected void process(List<ChecksumTableModel.Entry> chunks) {
protected void process(List<ChecksumTableModel.ChecksumCell> chunks) {
tableModel.addAll(chunks);
}
@ -58,13 +58,13 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
String filename = matcher.group(1);
String checksumString = matcher.group(2);
publish(new ChecksumTableModel.Entry(filename, new Checksum(checksumString), sfvFile));
publish(new ChecksumTableModel.ChecksumCell(filename, new Checksum(checksumString), sfvFile));
File compareColumnRoot = sfvFile.getParentFile();
File compareFile = new File(compareColumnRoot, filename);
if (compareFile.exists()) {
publish(new ChecksumTableModel.Entry(filename, ChecksumComputationService.getService().getChecksum(compareFile, compareColumnRoot), compareColumnRoot));
publish(new ChecksumTableModel.ChecksumCell(filename, ChecksumComputationService.getService().getChecksum(compareFile, compareColumnRoot), compareColumnRoot));
}
}
@ -116,7 +116,7 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
load(f, columnRoot, newPrefix);
}
} else if (file.isFile()) {
publish(new ChecksumTableModel.Entry(prefix + file.getName(), ChecksumComputationService.getService().getChecksum(file, columnRoot), columnRoot));
publish(new ChecksumTableModel.ChecksumCell(prefix + file.getName(), ChecksumComputationService.getService().getChecksum(file, columnRoot), columnRoot));
}
}
}

View File

@ -13,10 +13,13 @@ import net.sourceforge.filebot.Settings;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.filebot.ui.AbstractSearchPanel;
import net.sourceforge.filebot.ui.SelectDialog;
import net.sourceforge.filebot.web.OpenSubtitlesSubtitleClient;
import net.sourceforge.filebot.web.SearchResult;
import net.sourceforge.filebot.web.SubsceneSubtitleClient;
import net.sourceforge.filebot.web.SubtitleClient;
import net.sourceforge.filebot.web.SubtitleDescriptor;
import net.sourceforge.tuned.ui.SimpleIconProvider;
import net.sourceforge.tuned.ui.LabelProvider;
import net.sourceforge.tuned.ui.SimpleLabelProvider;
public class SubtitlePanel extends AbstractSearchPanel<SubtitleClient, SubtitlePackage, SubtitleDownloadPanel> {
@ -27,9 +30,6 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleClient, SubtitleP
getHistoryPanel().setColumnHeader1("Show / Movie");
getHistoryPanel().setColumnHeader2("Number of Subtitles");
getSearchField().getSelectButton().setModel(SubtitleClient.getAvailableSubtitleClients());
getSearchField().getSelectButton().setIconProvider(SimpleIconProvider.forClass(SubtitleClient.class));
List<String> persistentSearchHistory = Settings.getSettings().asStringList(Settings.SUBTITLE_HISTORY);
getSearchHistory().addAll(persistentSearchHistory);
@ -38,6 +38,23 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleClient, SubtitleP
}
@Override
protected List<SubtitleClient> createSearchEngines() {
List<SubtitleClient> engines = new ArrayList<SubtitleClient>(2);
engines.add(new OpenSubtitlesSubtitleClient());
engines.add(new SubsceneSubtitleClient());
return engines;
}
@Override
protected LabelProvider<SubtitleClient> createSearchEngineLabelProvider() {
return SimpleLabelProvider.forClass(SubtitleClient.class);
}
@Override
protected SearchTask createSearchTask() {
SubtitleDownloadPanel panel = new SubtitleDownloadPanel();

View File

@ -92,26 +92,20 @@ public class DefaultTransferHandler extends TransferHandler {
if (clipboardHandler != null)
clipboardHandler.exportToClipboard(comp, clip, action);
}
public void setImportHandler(ImportHandler importHandler) {
this.importHandler = importHandler;
}
public void setImportHandler(ImportHandler importHandler) {
this.importHandler = importHandler;
}
public void setExportHandler(ExportHandler exportHandler) {
this.exportHandler = exportHandler;
}
public void setExportHandler(ExportHandler exportHandler) {
this.exportHandler = exportHandler;
}
public void setClipboardHandler(ClipboardHandler clipboardHandler) {
this.clipboardHandler = clipboardHandler;
}
public void setClipboardHandler(ClipboardHandler clipboardHandler) {
this.clipboardHandler = clipboardHandler;
}
}

View File

@ -10,7 +10,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -84,8 +83,6 @@ public abstract class FileTransferablePolicy implements TransferablePolicy {
if ((files == null) || files.isEmpty())
return;
Collections.sort(files);
if (!add)
clear();

View File

@ -17,6 +17,8 @@ import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.tuned.XPathUtil;
@ -25,16 +27,23 @@ import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class AnidbClient extends EpisodeListClient {
public class AnidbClient implements EpisodeListClient {
private final SearchResultCache searchResultCache = new SearchResultCache();
private final String host = "anidb.net";
public AnidbClient() {
super("AniDB", ResourceManager.getIcon("search.anidb"));
};
@Override
public String getName() {
return "AniDB";
}
@Override
public Icon getIcon() {
return ResourceManager.getIcon("search.anidb");
}
@Override

View File

@ -3,72 +3,34 @@ package net.sourceforge.filebot.web;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.swing.Icon;
public abstract class EpisodeListClient {
public interface EpisodeListClient {
private static List<EpisodeListClient> registry;
public static synchronized List<EpisodeListClient> getAvailableEpisodeListClients() {
if (registry == null) {
registry = new ArrayList<EpisodeListClient>(3);
registry.add(new TVDotComClient());
registry.add(new AnidbClient());
registry.add(new TVRageClient());
}
return Collections.unmodifiableList(registry);
}
private final String name;
private final Icon icon;
public EpisodeListClient(String name, Icon icon) {
this.name = name;
this.icon = icon;
}
public Collection<SearchResult> search(String searchterm) throws Exception;
public abstract Collection<SearchResult> search(String searchterm) throws Exception;
public boolean hasSingleSeasonSupport();
public abstract boolean hasSingleSeasonSupport();
public Collection<Episode> getEpisodeList(SearchResult searchResult) throws Exception;
public abstract Collection<Episode> getEpisodeList(SearchResult searchResult) throws Exception;
public Collection<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception;
public abstract Collection<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception;
public URI getEpisodeListLink(SearchResult searchResult);
public abstract URI getEpisodeListLink(SearchResult searchResult);
public URI getEpisodeListLink(SearchResult searchResult, int season);
public abstract URI getEpisodeListLink(SearchResult searchResult, int season);
public String getName();
public String getName() {
return name;
}
public Icon getIcon() {
return icon;
}
@Override
public String toString() {
return name;
}
public Icon getIcon();
}

View File

@ -11,6 +11,8 @@ import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import net.sourceforge.filebot.Settings;
import net.sourceforge.filebot.resources.ResourceManager;
@ -19,17 +21,22 @@ import net.sourceforge.filebot.resources.ResourceManager;
* {@link SubtitleClient} for OpenSubtitles.
*
*/
public class OpenSubtitlesSubtitleClient extends SubtitleClient {
public class OpenSubtitlesSubtitleClient implements SubtitleClient {
private final OpenSubtitlesClient client = new OpenSubtitlesClient(String.format("%s v%s", Settings.NAME, Settings.VERSION));
private final LogoutTimer logoutTimer = new LogoutTimer();
public OpenSubtitlesSubtitleClient() {
super("OpenSubtitles", ResourceManager.getIcon("search.opensubtitles"));
Runtime.getRuntime().addShutdownHook(new Thread(doLogout));
@Override
public String getName() {
return "OpenSubtitles";
}
@Override
public Icon getIcon() {
return ResourceManager.getIcon("search.opensubtitles");
}
@ -63,6 +70,7 @@ public class OpenSubtitlesSubtitleClient extends SubtitleClient {
private synchronized void login() throws Exception {
if (!client.isLoggedOn()) {
client.loginAnonymous();
Runtime.getRuntime().addShutdownHook(logoutShutdownHook);
}
logoutTimer.restart();
@ -77,11 +85,13 @@ public class OpenSubtitlesSubtitleClient extends SubtitleClient {
client.logout();
} catch (Exception e) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, "Exception while deactivating session", e);
} finally {
Runtime.getRuntime().removeShutdownHook(logoutShutdownHook);
}
}
}
private final Runnable doLogout = new Runnable() {
private final Thread logoutShutdownHook = new Thread() {
@Override
public void run() {

View File

@ -21,6 +21,8 @@ import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.Icon;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.tuned.FileUtil;
import net.sourceforge.tuned.XPathUtil;
@ -30,7 +32,7 @@ import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class SubsceneSubtitleClient extends SubtitleClient {
public class SubsceneSubtitleClient implements SubtitleClient {
private final SearchResultCache searchResultCache = new SearchResultCache();
@ -39,8 +41,15 @@ public class SubsceneSubtitleClient extends SubtitleClient {
private final String host = "subscene.com";
public SubsceneSubtitleClient() {
super("Subscene", ResourceManager.getIcon("search.subscene"));
@Override
public String getName() {
return "Subscene";
}
@Override
public Icon getIcon() {
return ResourceManager.getIcon("search.subscene");
}

View File

@ -3,62 +3,26 @@ package net.sourceforge.filebot.web;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import javax.swing.Icon;
public abstract class SubtitleClient {
public interface SubtitleClient {
private static List<SubtitleClient> registry;
public static synchronized List<SubtitleClient> getAvailableSubtitleClients() {
if (registry == null) {
registry = new ArrayList<SubtitleClient>(2);
registry.add(new OpenSubtitlesSubtitleClient());
registry.add(new SubsceneSubtitleClient());
}
return Collections.unmodifiableList(registry);
}
private final String name;
private final Icon icon;
public SubtitleClient(String name, Icon icon) {
this.name = name;
this.icon = icon;
}
public Collection<SearchResult> search(String searchterm) throws Exception;
public abstract Collection<SearchResult> search(String searchterm) throws Exception;
public Collection<SubtitleDescriptor> getSubtitleList(SearchResult searchResult, Locale language) throws Exception;
public abstract Collection<SubtitleDescriptor> getSubtitleList(SearchResult searchResult, Locale language) throws Exception;
public URI getSubtitleListLink(SearchResult searchResult);
public abstract URI getSubtitleListLink(SearchResult searchResult);
public String getName();
public String getName() {
return name;
}
public Icon getIcon();
public Icon getIcon() {
return icon;
}
@Override
public String toString() {
return name;
}
}

View File

@ -21,6 +21,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.swing.Icon;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.tuned.XPathUtil;
@ -29,15 +31,22 @@ import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class TVDotComClient extends EpisodeListClient {
public class TVDotComClient implements EpisodeListClient {
private final SearchResultCache searchResultCache = new SearchResultCache();
private final String host = "www.tv.com";
public TVDotComClient() {
super("TV.com", ResourceManager.getIcon("search.tvdotcom"));
@Override
public String getName() {
return "TV.com";
}
@Override
public Icon getIcon() {
return ResourceManager.getIcon("search.tvdotcom");
}

View File

@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.Icon;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@ -20,15 +21,22 @@ import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class TVRageClient extends EpisodeListClient {
public class TVRageClient implements EpisodeListClient {
private final SearchResultCache searchResultCache = new SearchResultCache();
private final String host = "www.tvrage.com";
public TVRageClient() {
super("TVRage", ResourceManager.getIcon("search.tvrage"));
@Override
public String getName() {
return "TVRage";
}
@Override
public Icon getIcon() {
return ResourceManager.getIcon("search.tvrage");
}

View File

@ -1,62 +0,0 @@
package net.sourceforge.tuned;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
public class BasicCachingList<E> extends AbstractList<E> {
private final List<E> source;
private final ArrayList<E> cache;
public BasicCachingList(List<E> source) {
this.source = source;
int sourceSize = source.size();
this.cache = new ArrayList<E>(sourceSize);
// fill cache with null values
for (int i = 0; i < sourceSize; i++) {
cache.add(null);
}
}
@Override
public synchronized E get(int index) {
E value = cache.get(index);
if (value == null) {
value = source.get(index);
cache.set(index, value);
}
return value;
}
@Override
public synchronized boolean add(E value) {
cache.add(value);
return source.add(value);
}
@Override
public synchronized E remove(int index) {
source.remove(index);
return cache.remove(index);
}
@Override
public synchronized int size() {
return cache.size();
}
}

View File

@ -5,8 +5,11 @@ package net.sourceforge.tuned.ui;
import javax.swing.Icon;
public interface IconProvider<T> {
public interface LabelProvider<T> {
public String getText(T value);
public Icon getIcon(T value);
}

View File

@ -1,15 +0,0 @@
package net.sourceforge.tuned.ui;
import javax.swing.Icon;
public class NullIconProvider<T extends Object> implements IconProvider<T> {
@Override
public Icon getIcon(Object value) {
return null;
}
}

View File

@ -0,0 +1,21 @@
package net.sourceforge.tuned.ui;
import javax.swing.Icon;
public class NullLabelProvider<T extends Object> implements LabelProvider<T> {
@Override
public Icon getIcon(T value) {
return null;
}
@Override
public String getText(T value) {
return value.toString();
}
}

View File

@ -41,7 +41,7 @@ public class SelectButton<T> extends JButton {
private List<T> model = new ArrayList<T>(0);
private SingleSelectionModel selectionModel = new DefaultSingleSelectionModel();
private IconProvider<T> iconProvider = new NullIconProvider<T>();
private LabelProvider<T> labelProvider = new NullLabelProvider<T>();
private boolean hover = false;
@ -62,21 +62,23 @@ public class SelectButton<T> extends JButton {
public void setModel(List<T> model) {
this.model = model;
this.model.clear();
this.model.addAll(model);
setSelectedIndex(0);
}
public IconProvider<T> getIconProvider() {
return iconProvider;
public LabelProvider<T> getLabelProvider() {
return labelProvider;
}
public void setIconProvider(IconProvider<T> iconProvider) {
this.iconProvider = iconProvider;
public void setLabelProvider(LabelProvider<T> labelProvider) {
this.labelProvider = labelProvider;
// update icon
this.setIcon(iconProvider.getIcon(getSelectedValue()));
this.setIcon(labelProvider.getIcon(getSelectedValue()));
}
@ -112,7 +114,7 @@ public class SelectButton<T> extends JButton {
T value = model.get(i);
setIcon(iconProvider.getIcon(value));
setIcon(labelProvider.getIcon(value));
firePropertyChange(SELECTED_VALUE, null, value);
}
@ -179,7 +181,7 @@ public class SelectButton<T> extends JButton {
JPopupMenu popup = new JPopupMenu();
for (T value : model) {
SelectPopupMenuItem item = new SelectPopupMenuItem(value, iconProvider.getIcon(value));
SelectPopupMenuItem item = new SelectPopupMenuItem(labelProvider.getText(value), labelProvider.getIcon(value), value);
if (value == getSelectedValue())
item.setSelected(true);
@ -197,8 +199,8 @@ public class SelectButton<T> extends JButton {
private final T value;
public SelectPopupMenuItem(T value, Icon icon) {
super(value.toString(), icon);
public SelectPopupMenuItem(String text, Icon icon, T value) {
super(text, icon);
this.value = value;

View File

@ -1,65 +0,0 @@
package net.sourceforge.tuned.ui;
import java.lang.reflect.Method;
import javax.swing.Icon;
import net.sourceforge.tuned.ExceptionUtil;
/**
* <code>IconProvider</code> based on reflection.
*/
public class SimpleIconProvider<T> implements IconProvider<T> {
private final Method getIconMethod;
/**
* Same as <code>new SimpleIconProvider&lt;T&gt;(T.class)</code>.
*
* @return new <code>IconProvider</code>
*/
public static <T> SimpleIconProvider<T> forClass(Class<T> type) {
return new SimpleIconProvider<T>(type);
}
/**
* Create a new IconProvider which will use the <code>getIcon</code> method of the given
* class.
*
* @param type a class with a <code>getIcon</code> method
*/
public SimpleIconProvider(Class<T> type) {
this(type, "getIcon");
}
/**
* Create a new IconProvider which will use a specified method of a given class
*
* @param type a class with the specified method
* @param getIcon a method name such as <code>getIcon</code>
*/
public SimpleIconProvider(Class<T> type, String getIcon) {
try {
getIconMethod = type.getMethod(getIcon);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public Icon getIcon(T value) {
try {
return (Icon) getIconMethod.invoke(value);
} catch (Exception e) {
throw ExceptionUtil.asRuntimeException(e);
}
}
}

View File

@ -0,0 +1,78 @@
package net.sourceforge.tuned.ui;
import java.lang.reflect.Method;
import javax.swing.Icon;
import net.sourceforge.tuned.ExceptionUtil;
/**
* <code>LabelProvider</code> based on reflection.
*/
public class SimpleLabelProvider<T> implements LabelProvider<T> {
private final Method getIconMethod;
private final Method getNameMethod;
/**
* Same as <code>new SimpleLabelProvider&lt;T&gt;(T.class)</code>.
*
* @return new <code>LabelProvider</code>
*/
public static <T> SimpleLabelProvider<T> forClass(Class<T> type) {
return new SimpleLabelProvider<T>(type);
}
/**
* Create a new LabelProvider which will use the <code>getName</code> and
* <code>getIcon</code> method of the given class.
*
* @param type a class that has a <code>getName</code> and a <code>getIcon</code> method
*/
public SimpleLabelProvider(Class<T> type) {
this(type, "getName", "getIcon");
}
/**
* Create a new LabelProvider which will use a specified method of a given class
*
* @param type a class with the specified method
* @param getName a method name such as <code>getName</code>
* @param getIcon a method name such as <code>getIcon</code>
*/
public SimpleLabelProvider(Class<T> type, String getName, String getIcon) {
try {
getNameMethod = type.getMethod(getName);
getIconMethod = type.getMethod(getIcon);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String getText(T value) {
try {
return (String) getNameMethod.invoke(value);
} catch (Exception e) {
throw ExceptionUtil.asRuntimeException(e);
}
}
@Override
public Icon getIcon(T value) {
try {
return (Icon) getIconMethod.invoke(value);
} catch (Exception e) {
throw ExceptionUtil.asRuntimeException(e);
}
}
}