* refactored and simplified transfer api
* use more GlazedLists stuff (EventList, AutoCompleteSupport) and remove obsolete classes (SimpleListModel, TextCompletion) * don't use SearchResultCache in EpisodeListClient (was only done for better ui interactions) * removed caching from ResourceManager * some improvements based on FindBugs warnings * use args4j for improved argument parsing * updated ant build script * more general MessageBus/Handler (use Object as message type instead of string) * ChecksumComputationService is not a singleton anymore * TemporaryFolder is always recreated if it is deleted by the user, or another instance shutting down * Notifications flicker less when one window is removed and the others are layouted * lots of other refactoring
This commit is contained in:
parent
a401a51c75
commit
0c674849d8
30
build.xml
30
build.xml
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<project name="FileBot" basedir="." default="fatjar">
|
||||
<project name="FileBot" default="fatjar">
|
||||
|
||||
<property name="title" value="${ant.project.name}" />
|
||||
<property name="version" value="1.9" />
|
||||
|
@ -9,20 +9,26 @@
|
|||
<property name="dir.source" location="${basedir}/source" />
|
||||
<property name="dir.test" location="${basedir}/test" />
|
||||
<property name="dir.build" location="${basedir}/build" />
|
||||
<property name="dir.dist" location="${basedir}/dist" />
|
||||
<property name="dir.lib" location="${basedir}/lib" />
|
||||
|
||||
<property name="executable" location="${dir.build}/${title}.jar" />
|
||||
<property name="executable" location="${dir.dist}/${title}.jar" />
|
||||
|
||||
<property name="lib.xerces" value="${dir.lib}/xercesImpl.jar" />
|
||||
<property name="lib.nekohtml" value="${dir.lib}/nekohtml-1.9.7.jar" />
|
||||
<property name="lib.simmetrics" value="${dir.lib}/simmetrics_jar_v1_6_2_d07_02_07.jar" />
|
||||
<property name="lib.xmlrpc" value="${dir.lib}/xmlrpc-client-1.1.jar" />
|
||||
<property name="lib.glazedlists" value="${dir.lib}/glazedlists-1.7.0_java15.jar" />
|
||||
<property name="lib.junit" value="${dir.lib}/junit-4.4.jar" />
|
||||
<property name="lib.xerces" location="${dir.lib}/xercesImpl.jar" />
|
||||
<property name="lib.nekohtml" location="${dir.lib}/nekohtml-1.9.7.jar" />
|
||||
<property name="lib.simmetrics" location="${dir.lib}/simmetrics_jar_v1_6_2_d07_02_07.jar" />
|
||||
<property name="lib.xmlrpc" location="${dir.lib}/xmlrpc-client-1.1.jar" />
|
||||
<property name="lib.glazedlists" location="${dir.lib}/glazedlists-1.7.0_java15.jar" />
|
||||
<property name="lib.args4j" location="${dir.lib}/args4j-2.0.9.jar" />
|
||||
<property name="lib.junit" location="${dir.lib}/junit-4.4.jar" />
|
||||
|
||||
|
||||
|
||||
|
||||
<target name="fatjar" depends="clean, build">
|
||||
<!-- create dist dir -->
|
||||
<mkdir dir="${dir.dist}" />
|
||||
|
||||
<jar destfile="${executable}" duplicate="fail">
|
||||
<fileset dir="${dir.build}" />
|
||||
|
||||
|
@ -63,6 +69,10 @@
|
|||
<zipfileset src="${lib.glazedlists}">
|
||||
<include name="ca/odell/glazedlists/**" />
|
||||
</zipfileset>
|
||||
|
||||
<zipfileset src="${lib.args4j}">
|
||||
<include name="*/**" />
|
||||
</zipfileset>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
|
@ -98,13 +108,13 @@
|
|||
|
||||
|
||||
<target name="clean">
|
||||
<delete file="${executable}" verbose="yes" />
|
||||
<delete dir="${dir.dist}" />
|
||||
<delete dir="${dir.build}" />
|
||||
</target>
|
||||
|
||||
|
||||
<target name="test" depends="clean, build-test, fatjar">
|
||||
<junit printsummary="yes" fork="yes">
|
||||
<junit printsummary="yes" showoutput="yes">
|
||||
<classpath>
|
||||
<pathelement location="${executable}"/>
|
||||
<pathelement location="${lib.junit}"/>
|
||||
|
|
Binary file not shown.
|
@ -1,20 +1,15 @@
|
|||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
import net.sourceforge.filebot.ArgumentBean;
|
||||
import net.sourceforge.filebot.Settings;
|
||||
import net.sourceforge.filebot.ui.FileBotWindow;
|
||||
import net.sourceforge.tuned.MessageBus;
|
||||
|
||||
import org.kohsuke.args4j.CmdLineException;
|
||||
import org.kohsuke.args4j.CmdLineParser;
|
||||
|
||||
|
||||
public class Main {
|
||||
|
@ -24,11 +19,10 @@ public class Main {
|
|||
*/
|
||||
public static void main(String... args) {
|
||||
|
||||
final Arguments arguments = new Arguments(args);
|
||||
final ArgumentBean argumentBean = parseArguments(args);
|
||||
|
||||
if (arguments.containsParameter("clear")) {
|
||||
if (argumentBean.isClear())
|
||||
Settings.getSettings().clear();
|
||||
}
|
||||
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
|
@ -43,7 +37,7 @@ public class Main {
|
|||
FileBotWindow window = new FileBotWindow();
|
||||
|
||||
// publish messages from arguments to the newly created components
|
||||
arguments.publishMessages();
|
||||
argumentBean.publishMessages();
|
||||
|
||||
// start
|
||||
window.setVisible(true);
|
||||
|
@ -51,43 +45,26 @@ public class Main {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
private static class Arguments {
|
||||
|
||||
private final Set<String> parameters = new HashSet<String>(3);
|
||||
private final Map<String, List<String>> messages = new LinkedHashMap<String, List<String>>();
|
||||
|
||||
|
||||
public Arguments(String[] args) {
|
||||
Pattern topicPattern = Pattern.compile("--(\\w+)");
|
||||
|
||||
String currentTopic = null;
|
||||
|
||||
for (String arg : args) {
|
||||
Matcher m = topicPattern.matcher(arg);
|
||||
|
||||
if (m.matches()) {
|
||||
currentTopic = m.group(1).toLowerCase();
|
||||
messages.put(currentTopic, new ArrayList<String>(1));
|
||||
} else if (currentTopic != null) {
|
||||
messages.get(currentTopic).add(arg);
|
||||
} else {
|
||||
parameters.add(arg.toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean containsParameter(String argument) {
|
||||
return parameters.contains(argument);
|
||||
private static ArgumentBean parseArguments(String... args) {
|
||||
|
||||
ArgumentBean argumentBean = new ArgumentBean();
|
||||
CmdLineParser argumentParser = new CmdLineParser(argumentBean);
|
||||
|
||||
try {
|
||||
argumentParser.parseArgument(args);
|
||||
} catch (CmdLineException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
public void publishMessages() {
|
||||
for (String topic : messages.keySet()) {
|
||||
MessageBus.getDefault().publish(topic, messages.get(topic).toArray(new String[0]));
|
||||
}
|
||||
if (argumentBean.isHelp()) {
|
||||
System.out.println("Options:");
|
||||
argumentParser.printUsage(System.out);
|
||||
|
||||
// just print help message and exit afterwards
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
return argumentBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
package net.sourceforge.filebot;
|
||||
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sourceforge.tuned.MessageBus;
|
||||
|
||||
import org.kohsuke.args4j.Option;
|
||||
|
||||
|
||||
public class ArgumentBean {
|
||||
|
||||
@Option(name = "-help", usage = "Print this help message")
|
||||
private boolean help = false;
|
||||
|
||||
@Option(name = "-clear", usage = "Clear history and settings")
|
||||
private boolean clear = false;
|
||||
|
||||
@Message(topic = "list")
|
||||
@Option(name = "--list", usage = "Open file in 'List' panel", metaVar = "<file>")
|
||||
private File listPanelFile;
|
||||
|
||||
@Message(topic = "analyze")
|
||||
@Option(name = "--analyze", usage = "Open file in 'Analyze' panel", metaVar = "<file>")
|
||||
private File analyzePanelFile;
|
||||
|
||||
@Message(topic = "sfv")
|
||||
@Option(name = "--sfv", usage = "Open file in 'SFV' panel", metaVar = "<file>")
|
||||
private File sfvPanelFile;
|
||||
|
||||
|
||||
public boolean isHelp() {
|
||||
return help;
|
||||
}
|
||||
|
||||
|
||||
public boolean isClear() {
|
||||
return clear;
|
||||
}
|
||||
|
||||
|
||||
public File getListPanelFile() {
|
||||
return listPanelFile;
|
||||
}
|
||||
|
||||
|
||||
public File getAnalyzePanelFile() {
|
||||
return analyzePanelFile;
|
||||
}
|
||||
|
||||
|
||||
public File getSfvPanelFile() {
|
||||
return sfvPanelFile;
|
||||
}
|
||||
|
||||
|
||||
public void publishMessages() {
|
||||
for (Field field : getClass().getDeclaredFields()) {
|
||||
|
||||
Message message = field.getAnnotation(Message.class);
|
||||
|
||||
if (message == null)
|
||||
continue;
|
||||
|
||||
try {
|
||||
Object value = field.get(this);
|
||||
|
||||
if (value != null) {
|
||||
MessageBus.getDefault().publish(message.topic(), value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// should not happen
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@Target(FIELD)
|
||||
private @interface Message {
|
||||
|
||||
String topic();
|
||||
}
|
||||
|
||||
}
|
|
@ -13,10 +13,6 @@ import net.sourceforge.tuned.FileUtil;
|
|||
|
||||
public class FileBotUtil {
|
||||
|
||||
private FileBotUtil() {
|
||||
// hide constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid characters in filenames: \, /, :, *, ?, ", <, >, |, \r and \n
|
||||
*/
|
||||
|
@ -107,4 +103,9 @@ public class FileBotUtil {
|
|||
|
||||
};
|
||||
|
||||
|
||||
private FileBotUtil() {
|
||||
// hide constructor
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ public class Settings {
|
|||
public static final String SELECTED_PANEL = "panel";
|
||||
public static final String SEARCH_HISTORY = "search/history";
|
||||
public static final String SUBTITLE_HISTORY = "subtitle/history";
|
||||
public static final String SUBTITLE_LANGUAGE = "subtitle/language";
|
||||
|
||||
private static final Settings settings = new Settings();
|
||||
|
||||
|
|
|
@ -5,10 +5,6 @@ package net.sourceforge.filebot.resources;
|
|||
import java.awt.Image;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
|
@ -16,40 +12,18 @@ import javax.swing.ImageIcon;
|
|||
|
||||
public class ResourceManager {
|
||||
|
||||
private ResourceManager() {
|
||||
// hide constructor
|
||||
}
|
||||
|
||||
private static final Map<String, String> aliasMap = new HashMap<String, String>();
|
||||
|
||||
static {
|
||||
aliasMap.put("tab.loading", "tab.loading.gif");
|
||||
aliasMap.put("tab.history", "action.find.png");
|
||||
aliasMap.put("loading", "loading.gif");
|
||||
}
|
||||
|
||||
private static final Map<String, ImageIcon> iconCache = Collections.synchronizedMap(new WeakHashMap<String, ImageIcon>());
|
||||
|
||||
|
||||
public static ImageIcon getIcon(String name) {
|
||||
return getIcon(name, null);
|
||||
}
|
||||
|
||||
|
||||
public static ImageIcon getIcon(String name, String def) {
|
||||
ImageIcon icon = iconCache.get(name);
|
||||
URL resource = getResource(name, def);
|
||||
|
||||
if (icon == null) {
|
||||
// load image if not in cache
|
||||
URL resource = getResource(name, def);
|
||||
|
||||
if (resource != null) {
|
||||
icon = new ImageIcon(resource);
|
||||
iconCache.put(name, icon);
|
||||
}
|
||||
}
|
||||
if (resource != null)
|
||||
return new ImageIcon(resource);
|
||||
|
||||
return icon;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,14 +47,7 @@ public class ResourceManager {
|
|||
|
||||
|
||||
private static URL getResource(String name) {
|
||||
String resource = null;
|
||||
|
||||
if (aliasMap.containsKey(name))
|
||||
resource = aliasMap.get(name);
|
||||
else
|
||||
resource = name + ".png";
|
||||
|
||||
return ResourceManager.class.getResource(resource);
|
||||
return ResourceManager.class.getResource(name + ".png");
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,4 +60,9 @@ public class ResourceManager {
|
|||
return resource;
|
||||
}
|
||||
|
||||
|
||||
private ResourceManager() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 325 B |
Binary file not shown.
After Width: | Height: | Size: 875 B |
|
@ -6,7 +6,6 @@ import java.io.BufferedInputStream;
|
|||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -33,16 +32,7 @@ public class Torrent {
|
|||
|
||||
|
||||
public Torrent(File torrent) throws IOException {
|
||||
this(new FileInputStream(torrent));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load torrent data from an <code>InputStream</code>. The given stream will be closed
|
||||
* after data has been read.
|
||||
*/
|
||||
public Torrent(InputStream inputStream) throws IOException {
|
||||
this(decodeTorrent(inputStream));
|
||||
this(decodeTorrent(torrent));
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,7 +46,7 @@ public class Torrent {
|
|||
charset = Charset.forName(encoding);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// invalid encoding, just keep using UTF-8
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, e.getMessage());
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid encoding: " + encoding);
|
||||
}
|
||||
|
||||
createdBy = decodeString(torrentMap.get("created by"), charset);
|
||||
|
@ -113,6 +103,17 @@ public class Torrent {
|
|||
}
|
||||
|
||||
|
||||
private static Map<?, ?> decodeTorrent(File torrent) throws IOException {
|
||||
BufferedInputStream in = new BufferedInputStream(new FileInputStream(torrent));
|
||||
|
||||
try {
|
||||
return BDecoder.decode(in);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String decodeString(Object byteArray, Charset charset) {
|
||||
if (byteArray == null)
|
||||
return null;
|
||||
|
@ -173,17 +174,6 @@ public class Torrent {
|
|||
return singleFileTorrent;
|
||||
}
|
||||
|
||||
|
||||
private static Map<?, ?> decodeTorrent(InputStream torrent) throws IOException {
|
||||
BufferedInputStream in = new BufferedInputStream(torrent);
|
||||
|
||||
try {
|
||||
return BDecoder.decode(in);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Entry {
|
||||
|
||||
|
|
|
@ -91,12 +91,14 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
|||
completionList.addMemberList(fetchHistory);
|
||||
*/
|
||||
|
||||
searchField.getEditor().setAction(searchAction);
|
||||
|
||||
searchField.getSelectButton().setModel(createSearchEngines());
|
||||
searchField.getSelectButton().setLabelProvider(createSearchEngineLabelProvider());
|
||||
|
||||
AutoCompleteSupport.install(searchField.getEditor(), searchHistory);
|
||||
|
||||
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
||||
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
||||
}
|
||||
|
||||
|
||||
|
@ -109,9 +111,6 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
|||
protected abstract SearchTask createSearchTask();
|
||||
|
||||
|
||||
protected abstract void configureSelectDialog(SelectDialog<SearchResult> selectDialog);
|
||||
|
||||
|
||||
protected abstract FetchTask createFetchTask(SearchTask searchTask, SearchResult selectedSearchResult);
|
||||
|
||||
|
||||
|
@ -163,6 +162,41 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
|||
protected abstract Collection<SearchResult> doInBackground() throws Exception;
|
||||
|
||||
|
||||
protected SearchResult chooseSearchResult() throws Exception {
|
||||
|
||||
switch (get().size()) {
|
||||
case 0:
|
||||
MessageManager.showWarning(String.format("\"%s\" has not been found.", getSearchText()));
|
||||
return null;
|
||||
case 1:
|
||||
return get().iterator().next();
|
||||
}
|
||||
|
||||
// check if an exact match has been found
|
||||
for (SearchResult searchResult : get()) {
|
||||
if (getSearchText().equalsIgnoreCase(searchResult.getName()))
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
// multiple results have been found, user must select one
|
||||
Window window = SwingUtilities.getWindowAncestor(AbstractSearchPanel.this);
|
||||
|
||||
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(window, get());
|
||||
|
||||
configureSelectDialog(selectDialog);
|
||||
|
||||
selectDialog.setVisible(true);
|
||||
|
||||
// selected value or null if the dialog was canceled by the user
|
||||
return selectDialog.getSelectedValue();
|
||||
}
|
||||
|
||||
|
||||
protected void configureSelectDialog(SelectDialog<SearchResult> selectDialog) throws Exception {
|
||||
selectDialog.setIconImage(TunedUtil.getImage(searchField.getSelectButton().getLabelProvider().getIcon(getClient())));
|
||||
}
|
||||
|
||||
|
||||
public String getSearchText() {
|
||||
return searchText;
|
||||
}
|
||||
|
@ -210,14 +244,9 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
|||
SearchTask task = (SearchTask) evt.getSource();
|
||||
|
||||
try {
|
||||
SearchResult selectedResult = selectSearchResult(task);
|
||||
SearchResult selectedResult = task.chooseSearchResult();
|
||||
|
||||
if (selectedResult == null) {
|
||||
if (task.get().isEmpty()) {
|
||||
// no search results
|
||||
MessageManager.showWarning(String.format("\"%s\" has not been found.", task.getSearchText()));
|
||||
}
|
||||
|
||||
tab.close();
|
||||
return;
|
||||
}
|
||||
|
@ -245,31 +274,6 @@ public abstract class AbstractSearchPanel<S, E, T extends JComponent> extends Fi
|
|||
|
||||
}
|
||||
|
||||
|
||||
private SearchResult selectSearchResult(SearchTask task) throws Exception {
|
||||
Collection<SearchResult> searchResults = task.get();
|
||||
|
||||
switch (searchResults.size()) {
|
||||
case 0:
|
||||
return null;
|
||||
case 1:
|
||||
return searchResults.iterator().next();
|
||||
}
|
||||
|
||||
// multiple results have been found, user must selected one
|
||||
Window window = SwingUtilities.getWindowAncestor(AbstractSearchPanel.this);
|
||||
|
||||
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(window, searchResults);
|
||||
|
||||
selectDialog.setIconImage(TunedUtil.getImage(searchField.getSelectButton().getLabelProvider().getIcon(task.getClient())));
|
||||
|
||||
configureSelectDialog(selectDialog);
|
||||
selectDialog.setVisible(true);
|
||||
|
||||
// selected value or null if canceled by the user
|
||||
return selectDialog.getSelectedValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,14 +4,9 @@ package net.sourceforge.filebot.ui;
|
|||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
|
@ -20,59 +15,48 @@ import javax.swing.ListSelectionModel;
|
|||
import javax.swing.border.TitledBorder;
|
||||
|
||||
import net.sourceforge.filebot.ui.transfer.DefaultTransferHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.ExportHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.FileTransferable;
|
||||
import net.sourceforge.filebot.ui.transfer.Saveable;
|
||||
import net.sourceforge.filebot.ui.transfer.SaveableExportHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.TransferablePolicyImportHandler;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.MutableTransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.TransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transfer.FileExportHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.TransferablePolicy;
|
||||
import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer;
|
||||
import net.sourceforge.tuned.ui.SimpleListModel;
|
||||
import net.sourceforge.tuned.ui.TunedUtil;
|
||||
import ca.odell.glazedlists.BasicEventList;
|
||||
import ca.odell.glazedlists.EventList;
|
||||
import ca.odell.glazedlists.swing.EventListModel;
|
||||
|
||||
|
||||
public class FileBotList extends JPanel implements Saveable {
|
||||
public class FileBotList<E> extends JPanel {
|
||||
|
||||
private final JList list = new JList(new SimpleListModel());
|
||||
protected final EventList<E> model = new BasicEventList<E>();
|
||||
|
||||
private final MutableTransferablePolicy mutableTransferablePolicy = new MutableTransferablePolicy();
|
||||
protected final JList list = new JList(new EventListModel<E>(model));
|
||||
|
||||
private final TitledBorder titledBorder;
|
||||
protected final JScrollPane listScrollPane = new JScrollPane(list);
|
||||
|
||||
private String title;
|
||||
private String title = null;
|
||||
|
||||
|
||||
public FileBotList(boolean enableExport, boolean enableRemoveAction, boolean border) {
|
||||
public FileBotList() {
|
||||
super(new BorderLayout());
|
||||
|
||||
JScrollPane listScrollPane = new JScrollPane(list);
|
||||
|
||||
if (border) {
|
||||
titledBorder = new TitledBorder("");
|
||||
setBorder(titledBorder);
|
||||
} else {
|
||||
titledBorder = null;
|
||||
listScrollPane.setBorder(BorderFactory.createEmptyBorder());
|
||||
}
|
||||
setBorder(new TitledBorder(getTitle()));
|
||||
|
||||
list.setCellRenderer(new DefaultFancyListCellRenderer());
|
||||
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
|
||||
list.setTransferHandler(new DefaultTransferHandler(null, null));
|
||||
list.setDragEnabled(false);
|
||||
|
||||
add(listScrollPane, BorderLayout.CENTER);
|
||||
|
||||
ExportHandler exportHandler = null;
|
||||
// Shortcut DELETE, disabled by default
|
||||
removeAction.setEnabled(false);
|
||||
|
||||
if (enableExport)
|
||||
exportHandler = new SaveableExportHandler(this);
|
||||
|
||||
list.setTransferHandler(new DefaultTransferHandler(new TransferablePolicyImportHandler(mutableTransferablePolicy), exportHandler));
|
||||
list.setDragEnabled(enableExport);
|
||||
|
||||
if (enableRemoveAction) {
|
||||
// Shortcut DELETE
|
||||
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
||||
}
|
||||
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
||||
}
|
||||
|
||||
|
||||
public EventList<E> getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,13 +65,34 @@ public class FileBotList extends JPanel implements Saveable {
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DefaultTransferHandler getTransferHandler() {
|
||||
return (DefaultTransferHandler) list.getTransferHandler();
|
||||
}
|
||||
|
||||
|
||||
public void setTransferablePolicy(TransferablePolicy transferablePolicy) {
|
||||
mutableTransferablePolicy.setTransferablePolicy(transferablePolicy);
|
||||
getTransferHandler().setImportHandler(transferablePolicy);
|
||||
}
|
||||
|
||||
|
||||
public TransferablePolicy getTransferablePolicy() {
|
||||
return mutableTransferablePolicy;
|
||||
TransferablePolicy importHandler = (TransferablePolicy) getTransferHandler().getImportHandler();
|
||||
|
||||
return importHandler;
|
||||
}
|
||||
|
||||
|
||||
public void setExportHandler(FileExportHandler exportHandler) {
|
||||
getTransferHandler().setExportHandler(exportHandler);
|
||||
|
||||
// enable drag if ExportHandler is available
|
||||
list.setDragEnabled(exportHandler != null);
|
||||
}
|
||||
|
||||
|
||||
public FileExportHandler getExportHandler() {
|
||||
return (FileExportHandler) getTransferHandler().getExportHandler();
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,50 +104,18 @@ public class FileBotList extends JPanel implements Saveable {
|
|||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
|
||||
if (titledBorder != null)
|
||||
if (getBorder() instanceof TitledBorder) {
|
||||
TitledBorder titledBorder = (TitledBorder) getBorder();
|
||||
titledBorder.setTitle(title);
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
public SimpleListModel getModel() {
|
||||
return (SimpleListModel) list.getModel();
|
||||
}
|
||||
|
||||
|
||||
public void save(File file) {
|
||||
try {
|
||||
PrintStream out = new PrintStream(file);
|
||||
|
||||
for (Object object : getModel().getCopy()) {
|
||||
out.println(object.toString());
|
||||
}
|
||||
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
// should not happen
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getDefaultFileName() {
|
||||
return title + ".txt";
|
||||
}
|
||||
|
||||
|
||||
public boolean isSaveable() {
|
||||
return !getModel().isEmpty();
|
||||
}
|
||||
|
||||
|
||||
public void load(List<File> files) {
|
||||
FileTransferable tr = new FileTransferable(files);
|
||||
|
||||
if (mutableTransferablePolicy.accept(tr))
|
||||
mutableTransferablePolicy.handleTransferable(tr, false);
|
||||
public Action getRemoveAction() {
|
||||
return removeAction;
|
||||
}
|
||||
|
||||
private final AbstractAction removeAction = new AbstractAction("Remove") {
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
package net.sourceforge.filebot.ui;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import net.sourceforge.filebot.ui.transfer.FileExportHandler;
|
||||
|
||||
|
||||
public class FileBotListExportHandler extends FileExportHandler {
|
||||
|
||||
private final FileBotList<?> list;
|
||||
|
||||
|
||||
public FileBotListExportHandler(FileBotList<?> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canExport() {
|
||||
return !list.getModel().isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void export(OutputStream out) throws IOException {
|
||||
PrintStream printer = new PrintStream(out);
|
||||
|
||||
for (Object entry : list.getModel()) {
|
||||
printer.println(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDefaultFileName() {
|
||||
return list.getTitle() + ".txt";
|
||||
}
|
||||
|
||||
}
|
|
@ -3,51 +3,13 @@ package net.sourceforge.filebot.ui;
|
|||
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import net.sourceforge.filebot.ui.panel.analyze.AnalyzePanel;
|
||||
import net.sourceforge.filebot.ui.panel.list.ListPanel;
|
||||
import net.sourceforge.filebot.ui.panel.rename.RenamePanel;
|
||||
import net.sourceforge.filebot.ui.panel.search.SearchPanel;
|
||||
import net.sourceforge.filebot.ui.panel.sfv.SfvPanel;
|
||||
import net.sourceforge.filebot.ui.panel.subtitle.SubtitlePanel;
|
||||
|
||||
|
||||
public class FileBotPanel extends JPanel {
|
||||
|
||||
private static List<FileBotPanel> registry;
|
||||
|
||||
|
||||
public static synchronized List<FileBotPanel> getAvailablePanels() {
|
||||
if (registry == null) {
|
||||
registry = new ArrayList<FileBotPanel>(6);
|
||||
|
||||
registry.add(new ListPanel());
|
||||
registry.add(new RenamePanel());
|
||||
registry.add(new AnalyzePanel());
|
||||
registry.add(new SearchPanel());
|
||||
registry.add(new SubtitlePanel());
|
||||
registry.add(new SfvPanel());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(registry);
|
||||
}
|
||||
|
||||
|
||||
public static FileBotPanel forName(String name) {
|
||||
for (FileBotPanel panel : registry) {
|
||||
if (panel.getPanelName().equalsIgnoreCase(name))
|
||||
return panel;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final Icon icon;
|
||||
|
||||
|
|
|
@ -18,16 +18,23 @@ import javax.swing.Timer;
|
|||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer;
|
||||
import net.sourceforge.tuned.ui.SimpleListModel;
|
||||
import net.sourceforge.tuned.ui.TunedUtil;
|
||||
import ca.odell.glazedlists.BasicEventList;
|
||||
import ca.odell.glazedlists.EventList;
|
||||
import ca.odell.glazedlists.swing.EventListModel;
|
||||
|
||||
|
||||
class FileBotPanelSelectionList extends JList {
|
||||
|
||||
private static final int SELECTDELAY_ON_DRAG_OVER = 300;
|
||||
|
||||
private final EventList<FileBotPanel> panelModel = new BasicEventList<FileBotPanel>();
|
||||
|
||||
|
||||
public FileBotPanelSelectionList() {
|
||||
|
||||
setModel(new EventListModel<FileBotPanel>(panelModel));
|
||||
|
||||
setCellRenderer(new PanelCellRenderer());
|
||||
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
|
@ -35,12 +42,15 @@ class FileBotPanelSelectionList extends JList {
|
|||
|
||||
// initialize "drag over" panel selection
|
||||
new DropTarget(this, new DragDropListener());
|
||||
|
||||
setModel(new SimpleListModel(FileBotPanel.getAvailablePanels()));
|
||||
}
|
||||
|
||||
|
||||
public EventList<FileBotPanel> getPanelModel() {
|
||||
return panelModel;
|
||||
}
|
||||
|
||||
|
||||
private class PanelCellRenderer extends DefaultFancyListCellRenderer {
|
||||
private static class PanelCellRenderer extends DefaultFancyListCellRenderer {
|
||||
|
||||
public PanelCellRenderer() {
|
||||
super(BorderLayout.CENTER, 10, 0, new Color(0x163264));
|
||||
|
|
|
@ -42,12 +42,17 @@ public class FileBotTree extends JTree {
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DefaultTreeModel getModel() {
|
||||
return (DefaultTreeModel) super.getModel();
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
DefaultTreeModel model = (DefaultTreeModel) getModel();
|
||||
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
|
||||
|
||||
DefaultMutableTreeNode root = (DefaultMutableTreeNode) getModel().getRoot();
|
||||
root.removeAllChildren();
|
||||
model.reload(root);
|
||||
|
||||
getModel().reload(root);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,10 +20,15 @@ import javax.swing.event.ListSelectionListener;
|
|||
|
||||
import net.sourceforge.filebot.Settings;
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.panel.analyze.AnalyzePanel;
|
||||
import net.sourceforge.filebot.ui.panel.list.ListPanel;
|
||||
import net.sourceforge.filebot.ui.panel.rename.RenamePanel;
|
||||
import net.sourceforge.filebot.ui.panel.search.SearchPanel;
|
||||
import net.sourceforge.filebot.ui.panel.sfv.SfvPanel;
|
||||
import net.sourceforge.filebot.ui.panel.subtitle.SubtitlePanel;
|
||||
import net.sourceforge.tuned.MessageBus;
|
||||
import net.sourceforge.tuned.MessageHandler;
|
||||
import net.sourceforge.tuned.ui.ShadowBorder;
|
||||
import net.sourceforge.tuned.ui.SimpleListModel;
|
||||
|
||||
|
||||
public class FileBotWindow extends JFrame implements ListSelectionListener {
|
||||
|
@ -45,6 +50,7 @@ public class FileBotWindow extends JFrame implements ListSelectionListener {
|
|||
icons.add(ResourceManager.getImage("window.icon.big"));
|
||||
setIconImages(icons);
|
||||
|
||||
selectionListPanel.getPanelModel().addAll(createPanels());
|
||||
selectionListPanel.addListSelectionListener(this);
|
||||
|
||||
JComponent contentPane = createContentPane();
|
||||
|
@ -55,7 +61,21 @@ public class FileBotWindow extends JFrame implements ListSelectionListener {
|
|||
|
||||
selectionListPanel.setSelectedIndex(Settings.getSettings().getInt(Settings.SELECTED_PANEL, 3));
|
||||
|
||||
MessageBus.getDefault().addMessageHandler("panel", panelMessageHandler);
|
||||
MessageBus.getDefault().addMessageHandler("panel", panelSelectMessageHandler);
|
||||
}
|
||||
|
||||
|
||||
private List<FileBotPanel> createPanels() {
|
||||
List<FileBotPanel> panels = new ArrayList<FileBotPanel>();
|
||||
|
||||
panels.add(new ListPanel());
|
||||
panels.add(new RenamePanel());
|
||||
panels.add(new AnalyzePanel());
|
||||
panels.add(new SearchPanel());
|
||||
panels.add(new SubtitlePanel());
|
||||
panels.add(new SfvPanel());
|
||||
|
||||
return panels;
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,7 +119,6 @@ public class FileBotWindow extends JFrame implements ListSelectionListener {
|
|||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private JComponent createPageLayer() {
|
||||
JPanel pageLayer = new JPanel(new BorderLayout());
|
||||
|
||||
|
@ -108,10 +127,7 @@ public class FileBotWindow extends JFrame implements ListSelectionListener {
|
|||
pageLayer.add(headerPanel, BorderLayout.NORTH);
|
||||
pageLayer.add(pagePanel, BorderLayout.CENTER);
|
||||
|
||||
SimpleListModel model = (SimpleListModel) selectionListPanel.getModel();
|
||||
|
||||
for (FileBotPanel panel : (List<FileBotPanel>) model.getCopy()) {
|
||||
panel.setVisible(false);
|
||||
for (FileBotPanel panel : selectionListPanel.getPanelModel()) {
|
||||
pagePanel.add(panel, panel.getPanelName());
|
||||
}
|
||||
|
||||
|
@ -132,12 +148,15 @@ public class FileBotWindow extends JFrame implements ListSelectionListener {
|
|||
return contentPane;
|
||||
}
|
||||
|
||||
private final MessageHandler panelMessageHandler = new MessageHandler() {
|
||||
private final MessageHandler panelSelectMessageHandler = new MessageHandler() {
|
||||
|
||||
@Override
|
||||
public void handle(String topic, String... messages) {
|
||||
for (String panel : messages) {
|
||||
selectionListPanel.setSelectedValue(FileBotPanel.forName(panel), true);
|
||||
public void handle(String topic, Object... messages) {
|
||||
if (messages.length >= 1) {
|
||||
Object panel = messages[messages.length - 1];
|
||||
|
||||
if (panel instanceof FileBotPanel)
|
||||
selectionListPanel.setSelectedValue(panel, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,45 +10,63 @@ import java.util.logging.Level;
|
|||
import java.util.logging.Logger;
|
||||
|
||||
import net.sourceforge.filebot.ui.transfer.FileTransferable;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.TransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transfer.TransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transfer.TransferablePolicy.TransferAction;
|
||||
import net.sourceforge.tuned.MessageBus;
|
||||
import net.sourceforge.tuned.MessageHandler;
|
||||
|
||||
|
||||
public class FileTransferableMessageHandler implements MessageHandler {
|
||||
|
||||
private final String name;
|
||||
private final FileBotPanel panel;
|
||||
private final TransferablePolicy transferablePolicy;
|
||||
|
||||
|
||||
public FileTransferableMessageHandler(String name, TransferablePolicy transferablePolicy) {
|
||||
this.name = name;
|
||||
public FileTransferableMessageHandler(FileBotPanel panel, TransferablePolicy transferablePolicy) {
|
||||
this.panel = panel;
|
||||
this.transferablePolicy = transferablePolicy;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(String topic, String... messages) {
|
||||
// change panel
|
||||
MessageBus.getDefault().publish("panel", name);
|
||||
public void handle(String topic, Object... messages) {
|
||||
// switch to panel
|
||||
MessageBus.getDefault().publish("panel", panel);
|
||||
|
||||
List<File> files = new ArrayList<File>(messages.length);
|
||||
|
||||
for (String filename : messages) {
|
||||
try {
|
||||
File file = new File(filename);
|
||||
|
||||
if (file.exists()) {
|
||||
// file might be relative, use absolute file
|
||||
for (Object message : messages) {
|
||||
File file = fromMessage(message);
|
||||
|
||||
if (file == null)
|
||||
continue;
|
||||
|
||||
if (file.exists()) {
|
||||
try {
|
||||
// path may be relative, use absolute path
|
||||
files.add(file.getCanonicalFile());
|
||||
} else {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, String.format("Invalid File: %s", filename));
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
} else {
|
||||
// file doesn't exist
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid File: " + file);
|
||||
}
|
||||
}
|
||||
|
||||
transferablePolicy.handleTransferable(new FileTransferable(files), true);
|
||||
transferablePolicy.handleTransferable(new FileTransferable(files), TransferAction.PUT);
|
||||
}
|
||||
|
||||
|
||||
private File fromMessage(Object message) {
|
||||
|
||||
if (message instanceof File)
|
||||
return (File) message;
|
||||
|
||||
if (message instanceof String)
|
||||
return new File((String) message);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import javax.swing.SwingUtilities;
|
|||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.tuned.ui.ArrayListModel;
|
||||
import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer;
|
||||
import net.sourceforge.tuned.ui.SimpleListModel;
|
||||
import net.sourceforge.tuned.ui.TunedUtil;
|
||||
|
||||
|
||||
|
@ -78,14 +78,14 @@ public class SelectDialog<T> extends JDialog {
|
|||
setLocation(TunedUtil.getPreferredLocation(this));
|
||||
|
||||
// default selection
|
||||
list.setModel(new SimpleListModel(options));
|
||||
list.setModel(new ArrayListModel(options));
|
||||
list.setSelectedIndex(0);
|
||||
|
||||
// Shortcut Enter
|
||||
TunedUtil.registerActionForKeystroke(list, KeyStroke.getKeyStroke("released ENTER"), selectAction);
|
||||
TunedUtil.putActionForKeystroke(list, KeyStroke.getKeyStroke("released ENTER"), selectAction);
|
||||
|
||||
// Shortcut Escape
|
||||
TunedUtil.registerActionForKeystroke(list, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
|
||||
TunedUtil.putActionForKeystroke(list, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class AnalyzePanel extends FileBotPanel {
|
|||
|
||||
fileTreePanel.getFileTree().addPropertyChangeListener(FileTree.CONTENT_PROPERTY, fileTreeChangeListener);
|
||||
|
||||
MessageBus.getDefault().addMessageHandler(getPanelName(), new FileTransferableMessageHandler(getPanelName(), fileTreePanel.getFileTree().getTransferablePolicy()));
|
||||
MessageBus.getDefault().addMessageHandler(getPanelName(), new FileTransferableMessageHandler(this, fileTreePanel.getFileTree().getTransferablePolicy()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,15 +12,12 @@ import java.util.logging.Logger;
|
|||
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import net.sourceforge.filebot.ui.FileBotTree;
|
||||
import net.sourceforge.filebot.ui.transfer.DefaultTransferHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.FileTransferable;
|
||||
import net.sourceforge.filebot.ui.transfer.TransferablePolicyImportHandler;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.TransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transfer.FileTransferablePolicy;
|
||||
|
||||
|
||||
class FileTree extends FileBotTree {
|
||||
|
@ -37,11 +34,11 @@ class FileTree extends FileBotTree {
|
|||
transferablePolicy = new FileTreeTransferablePolicy(this);
|
||||
transferablePolicy.addPropertyChangeListener(LOADING_PROPERTY, new LoadingPropertyChangeListener());
|
||||
|
||||
setTransferHandler(new DefaultTransferHandler(new TransferablePolicyImportHandler(transferablePolicy), null));
|
||||
setTransferHandler(new DefaultTransferHandler(transferablePolicy, null));
|
||||
}
|
||||
|
||||
|
||||
public TransferablePolicy getTransferablePolicy() {
|
||||
public FileTransferablePolicy getTransferablePolicy() {
|
||||
return transferablePolicy;
|
||||
}
|
||||
|
||||
|
@ -58,24 +55,14 @@ class FileTree extends FileBotTree {
|
|||
}
|
||||
}
|
||||
|
||||
DefaultTreeModel model = (DefaultTreeModel) getModel();
|
||||
|
||||
for (TreeNode treeNode : changedNodes) {
|
||||
model.reload(treeNode);
|
||||
getModel().reload(treeNode);
|
||||
}
|
||||
|
||||
contentChanged();
|
||||
}
|
||||
|
||||
|
||||
public void load(List<File> files) {
|
||||
FileTransferable tr = new FileTransferable(files);
|
||||
|
||||
if (transferablePolicy.accept(tr))
|
||||
transferablePolicy.handleTransferable(tr, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
transferablePolicy.reset();
|
||||
|
@ -85,14 +72,12 @@ class FileTree extends FileBotTree {
|
|||
}
|
||||
|
||||
|
||||
private void contentChanged() {
|
||||
synchronized (this) {
|
||||
if (postProcessor != null)
|
||||
postProcessor.cancel(true);
|
||||
|
||||
postProcessor = new PostProcessor();
|
||||
postProcessor.execute();
|
||||
}
|
||||
private synchronized void contentChanged() {
|
||||
if (postProcessor != null)
|
||||
postProcessor.cancel(true);
|
||||
|
||||
postProcessor = new PostProcessor();
|
||||
postProcessor.execute();
|
||||
};
|
||||
|
||||
|
||||
|
@ -105,7 +90,7 @@ class FileTree extends FileBotTree {
|
|||
firePropertyChange(FileTree.LOADING_PROPERTY, null, loading);
|
||||
|
||||
if (!loading) {
|
||||
((DefaultTreeModel) getModel()).reload();
|
||||
getModel().reload();
|
||||
contentChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ class FileTreePanel extends JPanel {
|
|||
buttons.add(Box.createGlue());
|
||||
|
||||
// Shortcut DELETE
|
||||
TunedUtil.registerActionForKeystroke(fileTree, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
||||
TunedUtil.putActionForKeystroke(fileTree, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
||||
|
||||
add(new LoadingOverlayPane(new JScrollPane(fileTree), ResourceManager.getIcon("loading")), BorderLayout.CENTER);
|
||||
add(buttons, BorderLayout.SOUTH);
|
||||
|
|
|
@ -9,7 +9,7 @@ import javax.swing.tree.DefaultMutableTreeNode;
|
|||
import javax.swing.tree.DefaultTreeModel;
|
||||
|
||||
import net.sourceforge.filebot.FileBotUtil;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.BackgroundFileTransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transfer.BackgroundFileTransferablePolicy;
|
||||
|
||||
|
||||
class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<DefaultMutableTreeNode> {
|
||||
|
@ -74,7 +74,7 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<Defaul
|
|||
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
public String getFileFilterDescription() {
|
||||
return "files and folders";
|
||||
}
|
||||
|
||||
|
|
|
@ -12,16 +12,16 @@ import java.util.logging.Logger;
|
|||
import net.sourceforge.filebot.FileBotUtil;
|
||||
import net.sourceforge.filebot.torrent.Torrent;
|
||||
import net.sourceforge.filebot.ui.FileBotList;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.FileTransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transfer.FileTransferablePolicy;
|
||||
import net.sourceforge.tuned.FileUtil;
|
||||
|
||||
|
||||
class FileListTransferablePolicy extends FileTransferablePolicy {
|
||||
|
||||
private FileBotList list;
|
||||
private FileBotList<? super String> list;
|
||||
|
||||
|
||||
public FileListTransferablePolicy(FileBotList list) {
|
||||
public FileListTransferablePolicy(FileBotList<? super String> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
|
@ -50,12 +50,13 @@ class FileListTransferablePolicy extends FileTransferablePolicy {
|
|||
|
||||
private void loadFolderList(List<File> folders) {
|
||||
if (folders.size() == 1) {
|
||||
// if only one folder was dropped, use its name as title
|
||||
list.setTitle(FileUtil.getFolderName(folders.get(0)));
|
||||
}
|
||||
|
||||
for (File folder : folders) {
|
||||
for (File file : folder.listFiles()) {
|
||||
list.getModel().add(FileUtil.getFolderName(file));
|
||||
list.getModel().add(FileUtil.getFileName(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +93,7 @@ class FileListTransferablePolicy extends FileTransferablePolicy {
|
|||
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
public String getFileFilterDescription() {
|
||||
return "files, folders and torrents";
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import javax.swing.border.EmptyBorder;
|
|||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.FileBotList;
|
||||
import net.sourceforge.filebot.ui.FileBotListExportHandler;
|
||||
import net.sourceforge.filebot.ui.FileBotPanel;
|
||||
import net.sourceforge.filebot.ui.FileTransferableMessageHandler;
|
||||
import net.sourceforge.filebot.ui.MessageManager;
|
||||
|
@ -36,10 +37,7 @@ public class ListPanel extends FileBotPanel {
|
|||
|
||||
private static final String INDEX_VARIABLE = "<i>";
|
||||
|
||||
private FileBotList list = new FileBotList(true, true, true);
|
||||
|
||||
private SaveAction saveAction = new SaveAction(list);
|
||||
private LoadAction loadAction = new LoadAction(list.getTransferablePolicy());
|
||||
private FileBotList<String> list = new FileBotList<String>();
|
||||
|
||||
private JTextField textField = new JTextField(String.format("Name - %s", INDEX_VARIABLE), 25);
|
||||
private SpinnerNumberModel fromSpinnerModel = new SpinnerNumberModel(1, 0, Integer.MAX_VALUE, 1);
|
||||
|
@ -50,14 +48,17 @@ public class ListPanel extends FileBotPanel {
|
|||
super("List", ResourceManager.getIcon("panel.list"));
|
||||
|
||||
list.setTransferablePolicy(new FileListTransferablePolicy(list));
|
||||
list.setExportHandler(new FileBotListExportHandler(list));
|
||||
|
||||
list.getRemoveAction().setEnabled(true);
|
||||
|
||||
Box buttons = Box.createHorizontalBox();
|
||||
buttons.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
buttons.add(Box.createHorizontalGlue());
|
||||
|
||||
buttons.add(new JButton(loadAction));
|
||||
buttons.add(new JButton(new LoadAction(list.getTransferablePolicy())));
|
||||
buttons.add(Box.createHorizontalStrut(5));
|
||||
buttons.add(new JButton(saveAction));
|
||||
buttons.add(new JButton(new SaveAction(list.getExportHandler())));
|
||||
buttons.add(Box.createHorizontalGlue());
|
||||
|
||||
list.add(buttons, BorderLayout.SOUTH);
|
||||
|
@ -88,9 +89,9 @@ public class ListPanel extends FileBotPanel {
|
|||
add(spinners, BorderLayout.NORTH);
|
||||
add(list, BorderLayout.CENTER);
|
||||
|
||||
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), createAction);
|
||||
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), createAction);
|
||||
|
||||
MessageBus.getDefault().addMessageHandler(getPanelName(), new FileTransferableMessageHandler(getPanelName(), list.getTransferablePolicy()));
|
||||
MessageBus.getDefault().addMessageHandler(getPanelName(), new FileTransferableMessageHandler(this, list.getTransferablePolicy()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,7 +145,8 @@ public class ListPanel extends FileBotPanel {
|
|||
index += increment;
|
||||
} while (index != (to + increment));
|
||||
|
||||
list.getModel().set(entries);
|
||||
list.getModel().clear();
|
||||
list.getModel().addAll(entries);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,17 +8,17 @@ import java.util.List;
|
|||
|
||||
import net.sourceforge.filebot.FileBotUtil;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.FileEntry;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.FileTransferablePolicy;
|
||||
import net.sourceforge.tuned.ui.SimpleListModel;
|
||||
import net.sourceforge.filebot.ui.transfer.FileTransferablePolicy;
|
||||
import ca.odell.glazedlists.EventList;
|
||||
|
||||
|
||||
class FilesListTransferablePolicy extends FileTransferablePolicy {
|
||||
|
||||
private final SimpleListModel model;
|
||||
private final EventList<? super FileEntry> model;
|
||||
|
||||
|
||||
public FilesListTransferablePolicy(SimpleListModel listModel) {
|
||||
this.model = listModel;
|
||||
public FilesListTransferablePolicy(EventList<? super FileEntry> model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
|
||||
|
@ -47,7 +47,7 @@ class FilesListTransferablePolicy extends FileTransferablePolicy {
|
|||
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
public String getFileFilterDescription() {
|
||||
return "files and folders";
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import javax.swing.SwingUtilities;
|
|||
import javax.swing.SwingWorker;
|
||||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.FileEntry;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry;
|
||||
import net.sourceforge.filebot.ui.panel.rename.matcher.Match;
|
||||
import net.sourceforge.filebot.ui.panel.rename.matcher.Matcher;
|
||||
|
@ -32,8 +33,8 @@ class MatchAction extends AbstractAction {
|
|||
|
||||
private CompositeSimilarityMetric metrics;
|
||||
|
||||
private final RenameList namesList;
|
||||
private final RenameList filesList;
|
||||
private final RenameList<ListEntry> namesList;
|
||||
private final RenameList<FileEntry> filesList;
|
||||
|
||||
private boolean matchName2File;
|
||||
|
||||
|
@ -41,7 +42,7 @@ class MatchAction extends AbstractAction {
|
|||
public static final String MATCH_FILES_2_NAMES_DESCRIPTION = "Match files to names";
|
||||
|
||||
|
||||
public MatchAction(RenameList namesList, RenameList filesList) {
|
||||
public MatchAction(RenameList<ListEntry> namesList, RenameList<FileEntry> filesList) {
|
||||
super("Match");
|
||||
|
||||
this.namesList = namesList;
|
||||
|
@ -77,13 +78,14 @@ class MatchAction extends AbstractAction {
|
|||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
JComponent source = (JComponent) evt.getSource();
|
||||
|
||||
SwingUtilities.getRoot(source).setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
|
||||
RenameList primaryList = matchName2File ? namesList : filesList;
|
||||
RenameList secondaryList = matchName2File ? filesList : namesList;
|
||||
RenameList<ListEntry> primaryList = (RenameList<ListEntry>) (matchName2File ? namesList : filesList);
|
||||
RenameList<ListEntry> secondaryList = (RenameList<ListEntry>) (matchName2File ? filesList : namesList);
|
||||
|
||||
BackgroundMatcher backgroundMatcher = new BackgroundMatcher(primaryList, secondaryList, metrics);
|
||||
SwingWorkerProgressMonitor monitor = new SwingWorkerProgressMonitor(SwingUtilities.getWindowAncestor(source), backgroundMatcher);
|
||||
|
@ -109,15 +111,15 @@ class MatchAction extends AbstractAction {
|
|||
}
|
||||
|
||||
|
||||
private class BackgroundMatcher extends SwingWorker<List<Match>, Void> {
|
||||
private static class BackgroundMatcher extends SwingWorker<List<Match>, Void> {
|
||||
|
||||
private final RenameList primaryList;
|
||||
private final RenameList secondaryList;
|
||||
private final RenameList<ListEntry> primaryList;
|
||||
private final RenameList<ListEntry> secondaryList;
|
||||
|
||||
private final Matcher matcher;
|
||||
|
||||
|
||||
public BackgroundMatcher(RenameList primaryList, RenameList secondaryList, SimilarityMetric similarityMetric) {
|
||||
public BackgroundMatcher(RenameList<ListEntry> primaryList, RenameList<ListEntry> secondaryList, SimilarityMetric similarityMetric) {
|
||||
this.primaryList = primaryList;
|
||||
this.secondaryList = secondaryList;
|
||||
|
||||
|
@ -167,7 +169,6 @@ class MatchAction extends AbstractAction {
|
|||
|
||||
primaryList.getModel().clear();
|
||||
secondaryList.getModel().clear();
|
||||
|
||||
for (Match match : matches) {
|
||||
primaryList.getModel().add(match.getA());
|
||||
secondaryList.getModel().add(match.getB());
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -19,20 +20,35 @@ import net.sourceforge.filebot.torrent.Torrent;
|
|||
import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.StringEntry;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.TorrentEntry;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.CompositeTransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.TextTransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transfer.StringTransferablePolicy;
|
||||
|
||||
|
||||
class NamesListTransferablePolicy extends CompositeTransferablePolicy {
|
||||
class NamesListTransferablePolicy extends FilesListTransferablePolicy {
|
||||
|
||||
private final RenameList list;
|
||||
private final RenameList<ListEntry> list;
|
||||
|
||||
private final TextPolicy textPolicy = new TextPolicy();
|
||||
|
||||
|
||||
public NamesListTransferablePolicy(RenameList list) {
|
||||
this.list = list;
|
||||
public NamesListTransferablePolicy(RenameList<ListEntry> list) {
|
||||
super(list.getModel());
|
||||
|
||||
addPolicy(new FilePolicy());
|
||||
addPolicy(new TextPolicy());
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean accept(Transferable tr) {
|
||||
return textPolicy.accept(tr) || super.accept(tr);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleTransferable(Transferable tr, TransferAction action) {
|
||||
if (super.accept(tr))
|
||||
super.handleTransferable(tr, action);
|
||||
else if (textPolicy.accept(tr))
|
||||
textPolicy.handleTransferable(tr, action);
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,90 +73,81 @@ class NamesListTransferablePolicy extends CompositeTransferablePolicy {
|
|||
|
||||
|
||||
@Override
|
||||
protected void clear() {
|
||||
list.getModel().clear();
|
||||
protected void load(List<File> files) {
|
||||
|
||||
if (FileBotUtil.containsOnlyListFiles(files)) {
|
||||
loadListFiles(files);
|
||||
} else if (FileBotUtil.containsOnlyTorrentFiles(files)) {
|
||||
loadTorrentFiles(files);
|
||||
} else {
|
||||
super.load(files);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void loadListFiles(List<File> files) {
|
||||
try {
|
||||
List<ListEntry> entries = new ArrayList<ListEntry>();
|
||||
|
||||
for (File file : files) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
|
||||
|
||||
String line = null;
|
||||
|
||||
while ((line = in.readLine()) != null) {
|
||||
if (line.trim().length() > 0) {
|
||||
entries.add(new StringEntry(line));
|
||||
}
|
||||
}
|
||||
|
||||
in.close();
|
||||
}
|
||||
|
||||
submit(entries);
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void loadTorrentFiles(List<File> files) {
|
||||
try {
|
||||
List<ListEntry> entries = new ArrayList<ListEntry>();
|
||||
|
||||
for (File file : files) {
|
||||
Torrent torrent = new Torrent(file);
|
||||
|
||||
for (Torrent.Entry entry : torrent.getFiles()) {
|
||||
entries.add(new TorrentEntry(entry));
|
||||
}
|
||||
}
|
||||
|
||||
submit(entries);
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getFileFilterDescription() {
|
||||
return "text files and torrent files";
|
||||
}
|
||||
|
||||
|
||||
private class FilePolicy extends FilesListTransferablePolicy {
|
||||
private class TextPolicy extends StringTransferablePolicy {
|
||||
|
||||
public FilePolicy() {
|
||||
super(list.getModel());
|
||||
@Override
|
||||
protected void clear() {
|
||||
NamesListTransferablePolicy.this.clear();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void load(List<File> files) {
|
||||
|
||||
if (FileBotUtil.containsOnlyListFiles(files)) {
|
||||
loadListFiles(files);
|
||||
} else if (FileBotUtil.containsOnlyTorrentFiles(files)) {
|
||||
loadTorrentFiles(files);
|
||||
} else {
|
||||
super.load(files);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void loadListFiles(List<File> files) {
|
||||
try {
|
||||
List<ListEntry> entries = new ArrayList<ListEntry>();
|
||||
|
||||
for (File file : files) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
|
||||
|
||||
String line = null;
|
||||
|
||||
while ((line = in.readLine()) != null) {
|
||||
if (line.trim().length() > 0) {
|
||||
entries.add(new StringEntry(line));
|
||||
}
|
||||
}
|
||||
|
||||
in.close();
|
||||
}
|
||||
|
||||
submit(entries);
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void loadTorrentFiles(List<File> files) {
|
||||
try {
|
||||
List<ListEntry> entries = new ArrayList<ListEntry>();
|
||||
|
||||
for (File file : files) {
|
||||
Torrent torrent = new Torrent(file);
|
||||
|
||||
for (Torrent.Entry entry : torrent.getFiles()) {
|
||||
entries.add(new TorrentEntry(entry));
|
||||
}
|
||||
}
|
||||
|
||||
submit(entries);
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "text files and torrent files";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
private class TextPolicy extends TextTransferablePolicy {
|
||||
|
||||
@Override
|
||||
protected void load(String text) {
|
||||
protected void load(String string) {
|
||||
List<ListEntry> entries = new ArrayList<ListEntry>();
|
||||
|
||||
String[] lines = text.split("\r?\n");
|
||||
String[] lines = string.split("\r?\n");
|
||||
|
||||
for (String line : lines) {
|
||||
|
||||
|
@ -153,11 +160,6 @@ class NamesListTransferablePolicy extends CompositeTransferablePolicy {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "lines of text";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@ import net.sourceforge.tuned.FileUtil;
|
|||
|
||||
public class RenameAction extends AbstractAction {
|
||||
|
||||
private final RenameList namesList;
|
||||
private final RenameList filesList;
|
||||
private final RenameList<ListEntry> namesList;
|
||||
private final RenameList<FileEntry> filesList;
|
||||
|
||||
|
||||
public RenameAction(RenameList namesList, RenameList filesList) {
|
||||
public RenameAction(RenameList<ListEntry> namesList, RenameList<FileEntry> filesList) {
|
||||
super("Rename", ResourceManager.getIcon("action.rename"));
|
||||
this.namesList = namesList;
|
||||
this.filesList = filesList;
|
||||
|
@ -33,7 +33,7 @@ public class RenameAction extends AbstractAction {
|
|||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
List<ListEntry> nameEntries = namesList.getEntries();
|
||||
List<ListEntry> fileEntries = filesList.getEntries();
|
||||
List<FileEntry> fileEntries = filesList.getEntries();
|
||||
|
||||
int minLength = Math.min(nameEntries.size(), fileEntries.size());
|
||||
|
||||
|
@ -41,7 +41,7 @@ public class RenameAction extends AbstractAction {
|
|||
int errors = 0;
|
||||
|
||||
for (i = 0; i < minLength; i++) {
|
||||
FileEntry fileEntry = (FileEntry) fileEntries.get(i);
|
||||
FileEntry fileEntry = fileEntries.get(i);
|
||||
File f = fileEntry.getFile();
|
||||
|
||||
String newName = nameEntries.get(i).toString() + FileUtil.getExtension(f, true);
|
||||
|
|
|
@ -6,12 +6,12 @@ import java.awt.BorderLayout;
|
|||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
@ -20,25 +20,26 @@ import net.sourceforge.filebot.resources.ResourceManager;
|
|||
import net.sourceforge.filebot.ui.FileBotList;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry;
|
||||
import net.sourceforge.filebot.ui.transfer.LoadAction;
|
||||
import net.sourceforge.filebot.ui.transfer.TransferablePolicy;
|
||||
|
||||
|
||||
class RenameList extends FileBotList {
|
||||
class RenameList<E extends ListEntry> extends FileBotList<E> {
|
||||
|
||||
private JButton loadButton = new JButton();
|
||||
|
||||
|
||||
public RenameList() {
|
||||
super(false, true, true);
|
||||
|
||||
Box buttons = Box.createHorizontalBox();
|
||||
buttons.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
buttons.add(Box.createGlue());
|
||||
buttons.add(new JButton(downAction));
|
||||
buttons.add(new JButton(upAction));
|
||||
buttons.add(Box.createHorizontalStrut(10));
|
||||
buttons.add(new JButton(loadAction));
|
||||
buttons.add(loadButton);
|
||||
buttons.add(Box.createGlue());
|
||||
|
||||
add(buttons, BorderLayout.SOUTH);
|
||||
|
||||
JList list = getListComponent();
|
||||
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
list.addMouseListener(dndReorderMouseAdapter);
|
||||
|
@ -46,69 +47,76 @@ class RenameList extends FileBotList {
|
|||
|
||||
JViewport viewport = (JViewport) list.getParent();
|
||||
viewport.setBackground(list.getBackground());
|
||||
|
||||
getRemoveAction().setEnabled(true);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<ListEntry> getEntries() {
|
||||
return (List<ListEntry>) getModel().getCopy();
|
||||
@Override
|
||||
public void setTransferablePolicy(TransferablePolicy transferablePolicy) {
|
||||
super.setTransferablePolicy(transferablePolicy);
|
||||
loadButton.setAction(new LoadAction(transferablePolicy));
|
||||
}
|
||||
|
||||
|
||||
public List<E> getEntries() {
|
||||
return new ArrayList<E>(getModel());
|
||||
}
|
||||
|
||||
|
||||
private boolean moveEntry(int fromIndex, int toIndex) {
|
||||
if (toIndex < 0 || toIndex >= getModel().size())
|
||||
return false;
|
||||
|
||||
getModel().add(toIndex, getModel().remove(fromIndex));
|
||||
return true;
|
||||
}
|
||||
|
||||
private final AbstractAction upAction = new AbstractAction(null, ResourceManager.getIcon("action.up")) {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int index = getListComponent().getSelectedIndex();
|
||||
int selectedIndex = getListComponent().getSelectedIndex();
|
||||
int toIndex = selectedIndex + 1;
|
||||
|
||||
if (index <= 0) // first element
|
||||
return;
|
||||
|
||||
Object object = getModel().remove(index);
|
||||
|
||||
int newIndex = index - 1;
|
||||
getModel().add(newIndex, object);
|
||||
getListComponent().setSelectedIndex(newIndex);
|
||||
if (moveEntry(selectedIndex, toIndex)) {
|
||||
getListComponent().setSelectedIndex(toIndex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final AbstractAction downAction = new AbstractAction(null, ResourceManager.getIcon("action.down")) {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int index = getListComponent().getSelectedIndex();
|
||||
int selectedIndex = getListComponent().getSelectedIndex();
|
||||
int toIndex = selectedIndex - 1;
|
||||
|
||||
if (index >= getModel().getSize() - 1) // last element
|
||||
return;
|
||||
|
||||
Object object = getModel().remove(index);
|
||||
|
||||
int newIndex = index + 1;
|
||||
getModel().add(newIndex, object);
|
||||
getListComponent().setSelectedIndex(newIndex);
|
||||
if (moveEntry(selectedIndex, toIndex)) {
|
||||
getListComponent().setSelectedIndex(toIndex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected final LoadAction loadAction = new LoadAction(getTransferablePolicy());
|
||||
|
||||
private MouseAdapter dndReorderMouseAdapter = new MouseAdapter() {
|
||||
private final MouseAdapter dndReorderMouseAdapter = new MouseAdapter() {
|
||||
|
||||
private int from = -1;
|
||||
private int fromIndex = -1;
|
||||
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent m) {
|
||||
from = getListComponent().getSelectedIndex();
|
||||
fromIndex = getListComponent().getSelectedIndex();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent m) {
|
||||
int to = getListComponent().getSelectedIndex();
|
||||
int toIndex = getListComponent().getSelectedIndex();
|
||||
|
||||
if (to == from)
|
||||
if (toIndex == fromIndex)
|
||||
return;
|
||||
|
||||
Object object = getModel().remove(from);
|
||||
getModel().add(to, object);
|
||||
from = to;
|
||||
moveEntry(fromIndex, toIndex);
|
||||
|
||||
fromIndex = toIndex;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -27,12 +27,14 @@ import javax.swing.event.ListDataListener;
|
|||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.FileBotPanel;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.FileEntry;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry;
|
||||
|
||||
|
||||
public class RenamePanel extends FileBotPanel {
|
||||
|
||||
private RenameList namesList = new RenameList();
|
||||
private RenameList filesList = new RenameList();
|
||||
private RenameList<ListEntry> namesList = new RenameList<ListEntry>();
|
||||
private RenameList<FileEntry> filesList = new RenameList<FileEntry>();
|
||||
|
||||
private MatchAction matchAction = new MatchAction(namesList, filesList);
|
||||
|
||||
|
@ -52,23 +54,23 @@ public class RenamePanel extends FileBotPanel {
|
|||
filesList.setTitle("Files");
|
||||
filesList.setTransferablePolicy(new FilesListTransferablePolicy(filesList.getModel()));
|
||||
|
||||
RenameListCellRenderer cellrenderer = new RenameListCellRenderer(namesList.getModel(), filesList.getModel());
|
||||
JList namesListComponent = namesList.getListComponent();
|
||||
JList filesListComponent = filesList.getListComponent();
|
||||
|
||||
namesList.getListComponent().setCellRenderer(cellrenderer);
|
||||
filesList.getListComponent().setCellRenderer(cellrenderer);
|
||||
RenameListCellRenderer cellrenderer = new RenameListCellRenderer(namesListComponent.getModel(), filesListComponent.getModel());
|
||||
|
||||
JList list1 = namesList.getListComponent();
|
||||
JList list2 = filesList.getListComponent();
|
||||
namesListComponent.setCellRenderer(cellrenderer);
|
||||
filesListComponent.setCellRenderer(cellrenderer);
|
||||
|
||||
ListSelectionModel selectionModel = new DefaultListSelectionModel();
|
||||
selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
namesList.getListComponent().setSelectionModel(selectionModel);
|
||||
filesList.getListComponent().setSelectionModel(selectionModel);
|
||||
namesListComponent.setSelectionModel(selectionModel);
|
||||
filesListComponent.setSelectionModel(selectionModel);
|
||||
|
||||
viewPortSynchroniser = new ViewPortSynchronizer((JViewport) list1.getParent(), (JViewport) list2.getParent());
|
||||
viewPortSynchroniser = new ViewPortSynchronizer((JViewport) namesListComponent.getParent(), (JViewport) filesListComponent.getParent());
|
||||
|
||||
similarityPanel = new SimilarityPanel(list1, list2);
|
||||
similarityPanel = new SimilarityPanel(namesListComponent, filesListComponent);
|
||||
|
||||
similarityPanel.setVisible(false);
|
||||
similarityPanel.setMetrics(matchAction.getMetrics());
|
||||
|
@ -89,8 +91,8 @@ public class RenamePanel extends FileBotPanel {
|
|||
|
||||
add(box, BorderLayout.CENTER);
|
||||
|
||||
namesList.getModel().addListDataListener(repaintOnDataChange);
|
||||
filesList.getModel().addListDataListener(repaintOnDataChange);
|
||||
namesListComponent.getModel().addListDataListener(repaintOnDataChange);
|
||||
filesListComponent.getModel().addListDataListener(repaintOnDataChange);
|
||||
}
|
||||
|
||||
|
||||
|
@ -120,7 +122,7 @@ public class RenamePanel extends FileBotPanel {
|
|||
return centerBox;
|
||||
}
|
||||
|
||||
private ListDataListener repaintOnDataChange = new ListDataListener() {
|
||||
private final ListDataListener repaintOnDataChange = new ListDataListener() {
|
||||
|
||||
public void contentsChanged(ListDataEvent e) {
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import javax.swing.border.EmptyBorder;
|
|||
import net.sourceforge.filebot.FileBotUtil;
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry;
|
||||
import net.sourceforge.tuned.ui.SimpleListModel;
|
||||
import net.sourceforge.tuned.ui.ArrayListModel;
|
||||
import net.sourceforge.tuned.ui.TunedUtil;
|
||||
|
||||
|
||||
|
@ -51,7 +51,7 @@ public class ValidateNamesDialog extends JDialog {
|
|||
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
|
||||
JList list = new JList(new SimpleListModel(entries));
|
||||
JList list = new JList(new ArrayListModel(entries));
|
||||
list.setEnabled(false);
|
||||
|
||||
list.setCellRenderer(new HighlightListCellRenderer(FileBotUtil.INVALID_CHARACTERS_PATTERN, new CharacterHighlightPainter(new Color(0xFF4200), new Color(0xFF1200)), 4));
|
||||
|
@ -89,7 +89,7 @@ public class ValidateNamesDialog extends JDialog {
|
|||
setPreferredSize(new Dimension(365, 280));
|
||||
pack();
|
||||
|
||||
TunedUtil.registerActionForKeystroke(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
|
||||
TunedUtil.putActionForKeystroke(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
|
||||
}
|
||||
|
||||
|
||||
|
@ -176,7 +176,7 @@ public class ValidateNamesDialog extends JDialog {
|
|||
protected void actionPropertyChanged(Action action, String propertyName) {
|
||||
super.actionPropertyChanged(action, propertyName);
|
||||
|
||||
if (propertyName == ContinueAction.ALPHA) {
|
||||
if (propertyName.equals(ContinueAction.ALPHA)) {
|
||||
alpha = getAlpha(action);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,4 +38,5 @@ public class FileEntry extends AbstractFileEntry {
|
|||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,10 +16,8 @@ public abstract class AbstractNameSimilarityMetric implements SimilarityMetric {
|
|||
protected String normalize(String name) {
|
||||
name = stripChecksum(name);
|
||||
name = normalizeSeparators(name);
|
||||
name = name.trim();
|
||||
name = name.toLowerCase();
|
||||
|
||||
return name;
|
||||
return name.trim().toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public class NumericSimilarityMetric extends AbstractNameSimilarityMetric {
|
|||
|
||||
private static class NumberTokeniser implements InterfaceTokeniser {
|
||||
|
||||
private final String delimiter = "(\\D)+";
|
||||
private static final String delimiter = "(\\D)+";
|
||||
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,9 +8,11 @@ import javax.swing.JComponent;
|
|||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.FileBotList;
|
||||
import net.sourceforge.filebot.ui.FileBotTabComponent;
|
||||
import net.sourceforge.filebot.ui.transfer.DefaultListExportHandler;
|
||||
import net.sourceforge.filebot.web.Episode;
|
||||
|
||||
|
||||
public class EpisodeListPanel extends FileBotList {
|
||||
public class EpisodeListPanel extends FileBotList<Episode> {
|
||||
|
||||
private final FileBotTabComponent tabComponent = new FileBotTabComponent();
|
||||
|
||||
|
@ -20,7 +22,11 @@ public class EpisodeListPanel extends FileBotList {
|
|||
|
||||
|
||||
public EpisodeListPanel() {
|
||||
super(true, true, false);
|
||||
setExportHandler(new DefaultListExportHandler(list));
|
||||
getRemoveAction().setEnabled(true);
|
||||
|
||||
setBorder(null);
|
||||
listScrollPane.setBorder(null);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package net.sourceforge.filebot.ui.panel.search;
|
|||
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
|
@ -32,12 +31,14 @@ import javax.swing.SwingWorker;
|
|||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.FileBotList;
|
||||
import net.sourceforge.filebot.ui.FileBotPanel;
|
||||
import net.sourceforge.filebot.ui.HistoryPanel;
|
||||
import net.sourceforge.filebot.ui.MessageManager;
|
||||
import net.sourceforge.filebot.ui.SelectDialog;
|
||||
import net.sourceforge.filebot.ui.transfer.AdaptiveFileExportHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.FileExportHandler;
|
||||
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;
|
||||
|
@ -118,9 +119,9 @@ public class SearchPanel extends FileBotPanel {
|
|||
|
||||
this.add(mainPanel, BorderLayout.CENTER);
|
||||
|
||||
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
||||
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("UP"), upAction);
|
||||
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("DOWN"), downAction);
|
||||
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
||||
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("UP"), upAction);
|
||||
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("DOWN"), downAction);
|
||||
}
|
||||
|
||||
|
||||
|
@ -179,21 +180,27 @@ public class SearchPanel extends FileBotPanel {
|
|||
}
|
||||
};
|
||||
|
||||
private final SaveAction saveAction = new SaveAction(null) {
|
||||
private final SaveAction saveAction = new SaveAction(new SelectedTabExportHandler());
|
||||
|
||||
|
||||
private class SelectedTabExportHandler extends AdaptiveFileExportHandler {
|
||||
|
||||
/**
|
||||
* @return the <code>FileExportHandler</code> of the currently selected tab
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Component comp = tabbedPane.getSelectedComponent();
|
||||
|
||||
if (comp instanceof Saveable) {
|
||||
setSaveable((Saveable) comp);
|
||||
super.actionPerformed(e);
|
||||
protected FileExportHandler getExportHandler() {
|
||||
try {
|
||||
FileBotList<?> list = (FileBotList<?>) tabbedPane.getSelectedComponent();
|
||||
return list.getExportHandler();
|
||||
} catch (ClassCastException e) {
|
||||
// selected component is the history panel
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class SearchTask extends SwingWorker<Collection<SearchResult>, Void> {
|
||||
|
||||
private final String query;
|
||||
|
@ -267,14 +274,7 @@ public class SearchPanel extends FileBotPanel {
|
|||
}
|
||||
|
||||
SearchResult selectedResult = null;
|
||||
/*
|
||||
* NEEDED??? exact find without cache???
|
||||
/// TODO: ??????
|
||||
if (task.client.getFoundName(task.query) != null) {
|
||||
// a show matching the search term exactly has already been found
|
||||
showname = task.client.getFoundName(task.query);
|
||||
}*/
|
||||
|
||||
|
||||
if (searchResults.size() == 1) {
|
||||
// only one show found, select this one
|
||||
selectedResult = searchResults.iterator().next();
|
||||
|
|
|
@ -92,7 +92,7 @@ public class Checksum {
|
|||
}
|
||||
|
||||
|
||||
public Integer getProgress() {
|
||||
public synchronized Integer getProgress() {
|
||||
if (state == State.INPROGRESS)
|
||||
return computationTask.getProgress();
|
||||
|
||||
|
@ -130,8 +130,10 @@ public class Checksum {
|
|||
@Override
|
||||
public void done(PropertyChangeEvent evt) {
|
||||
try {
|
||||
if (!computationTask.isCancelled()) {
|
||||
setChecksum(computationTask.get());
|
||||
ChecksumComputationTask task = (ChecksumComputationTask) evt.getSource();
|
||||
|
||||
if (!task.isCancelled()) {
|
||||
setChecksum(task.get());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// might happen if file system is corrupt (e.g. CRC errors)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
package net.sourceforge.filebot.ui.panel.sfv;
|
||||
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.io.File;
|
||||
|
@ -15,6 +16,8 @@ import java.util.concurrent.ThreadFactory;
|
|||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
|
@ -23,36 +26,37 @@ import net.sourceforge.tuned.DefaultThreadFactory;
|
|||
|
||||
public class ChecksumComputationService {
|
||||
|
||||
public static final String ACTIVE_PROPERTY = "ACTIVE_PROPERTY";
|
||||
public static final String REMAINING_TASK_COUNT_PROPERTY = "REMAINING_TASK_COUNT_PROPERTY";
|
||||
|
||||
private static final ThreadFactory checksumComputationThreadFactory = new DefaultThreadFactory("ChecksumComputationPool", Thread.MIN_PRIORITY);
|
||||
|
||||
private static final ChecksumComputationService service = new ChecksumComputationService();
|
||||
|
||||
|
||||
public static ChecksumComputationService getService() {
|
||||
return service;
|
||||
}
|
||||
public static final String ACTIVE_PROPERTY = "active";
|
||||
public static final String REMAINING_TASK_COUNT_PROPERTY = "remainingTaskCount";
|
||||
|
||||
private final Map<File, ChecksumComputationExecutor> executors = new HashMap<File, ChecksumComputationExecutor>();
|
||||
|
||||
private final AtomicInteger activeSessionTaskCount = new AtomicInteger(0);
|
||||
private final AtomicInteger remainingTaskCount = new AtomicInteger(0);
|
||||
|
||||
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
||||
private final ThreadFactory threadFactory;
|
||||
|
||||
/**
|
||||
* Property change events will be fired on the event dispatch thread
|
||||
*/
|
||||
private final SwingWorkerPropertyChangeSupport propertyChangeSupport = new SwingWorkerPropertyChangeSupport(this);
|
||||
|
||||
|
||||
private ChecksumComputationService() {
|
||||
// hide constructor
|
||||
public ChecksumComputationService() {
|
||||
this(new DefaultThreadFactory("ChecksumComputationPool", Thread.MIN_PRIORITY));
|
||||
}
|
||||
|
||||
|
||||
public Checksum getChecksum(File file, File workerQueueKey) {
|
||||
public ChecksumComputationService(ThreadFactory threadFactory) {
|
||||
this.threadFactory = threadFactory;
|
||||
}
|
||||
|
||||
|
||||
public Checksum schedule(File file, File workerQueue) {
|
||||
ChecksumComputationTask task = new ChecksumComputationTask(file);
|
||||
Checksum checksum = new Checksum(task);
|
||||
|
||||
getExecutor(workerQueueKey).execute(task);
|
||||
getExecutor(workerQueue).execute(task);
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
@ -63,21 +67,18 @@ public class ChecksumComputationService {
|
|||
}
|
||||
|
||||
|
||||
private void deactivate(boolean shutdownNow) {
|
||||
synchronized (executors) {
|
||||
for (ChecksumComputationExecutor executor : executors.values()) {
|
||||
if (shutdownNow) {
|
||||
executor.shutdownNow();
|
||||
} else {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
executors.clear();
|
||||
|
||||
activeSessionTaskCount.set(0);
|
||||
remainingTaskCount.set(0);
|
||||
private synchronized void deactivate(boolean shutdownNow) {
|
||||
for (ChecksumComputationExecutor executor : executors.values()) {
|
||||
if (shutdownNow)
|
||||
executor.shutdownNow();
|
||||
else
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
executors.clear();
|
||||
|
||||
activeSessionTaskCount.set(0);
|
||||
remainingTaskCount.set(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,26 +97,22 @@ public class ChecksumComputationService {
|
|||
}
|
||||
|
||||
|
||||
public void purge() {
|
||||
synchronized (executors) {
|
||||
for (ChecksumComputationExecutor executor : executors.values()) {
|
||||
executor.purge();
|
||||
}
|
||||
public synchronized void purge() {
|
||||
for (ChecksumComputationExecutor executor : executors.values()) {
|
||||
executor.purge();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ChecksumComputationExecutor getExecutor(File workerQueueKey) {
|
||||
synchronized (executors) {
|
||||
ChecksumComputationExecutor executor = executors.get(workerQueueKey);
|
||||
|
||||
if (executor == null) {
|
||||
executor = new ChecksumComputationExecutor();
|
||||
executors.put(workerQueueKey, executor);
|
||||
}
|
||||
|
||||
return executor;
|
||||
private synchronized ChecksumComputationExecutor getExecutor(File workerQueue) {
|
||||
ChecksumComputationExecutor executor = executors.get(workerQueue);
|
||||
|
||||
if (executor == null) {
|
||||
executor = new ChecksumComputationExecutor();
|
||||
executors.put(workerQueue, executor);
|
||||
}
|
||||
|
||||
return executor;
|
||||
}
|
||||
|
||||
|
||||
|
@ -125,7 +122,7 @@ public class ChecksumComputationService {
|
|||
|
||||
|
||||
public ChecksumComputationExecutor() {
|
||||
super(MINIMUM_POOL_SIZE, MINIMUM_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), checksumComputationThreadFactory);
|
||||
super(MINIMUM_POOL_SIZE, MINIMUM_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,13 +131,7 @@ public class ChecksumComputationService {
|
|||
// for lots of files, use multiple threads
|
||||
// e.g 50 files ~ 1 thread, 1000 files ~ 3 threads, 40000 files ~ 5 threads
|
||||
|
||||
int preferredPoolSize = MINIMUM_POOL_SIZE;
|
||||
|
||||
int queueSize = getQueue().size();
|
||||
|
||||
if (queueSize > 0) {
|
||||
preferredPoolSize += Math.log10(Math.max(queueSize / 10, 1));
|
||||
}
|
||||
int preferredPoolSize = (int) Math.log10(Math.max(getQueue().size() / 10, MINIMUM_POOL_SIZE));
|
||||
|
||||
if (getCorePoolSize() != preferredPoolSize) {
|
||||
setCorePoolSize(preferredPoolSize);
|
||||
|
@ -179,8 +170,8 @@ public class ChecksumComputationService {
|
|||
for (ChecksumComputationTask task : cancelledTasks) {
|
||||
remove(task);
|
||||
}
|
||||
} catch (ConcurrentModificationException ex) {
|
||||
|
||||
} catch (ConcurrentModificationException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,12 +209,12 @@ public class ChecksumComputationService {
|
|||
|
||||
|
||||
private void setActive(boolean active) {
|
||||
SwingUtilities.invokeLater(new FirePropertyChangeRunnable(ACTIVE_PROPERTY, active));
|
||||
propertyChangeSupport.firePropertyChange(ACTIVE_PROPERTY, null, active);
|
||||
}
|
||||
|
||||
|
||||
private void fireRemainingTaskCountChange() {
|
||||
SwingUtilities.invokeLater(new FirePropertyChangeRunnable(REMAINING_TASK_COUNT_PROPERTY, getRemainingTaskCount()));
|
||||
propertyChangeSupport.firePropertyChange(REMAINING_TASK_COUNT_PROPERTY, null, getRemainingTaskCount());
|
||||
}
|
||||
|
||||
|
||||
|
@ -237,21 +228,23 @@ public class ChecksumComputationService {
|
|||
}
|
||||
|
||||
|
||||
private class FirePropertyChangeRunnable implements Runnable {
|
||||
private static class SwingWorkerPropertyChangeSupport extends PropertyChangeSupport {
|
||||
|
||||
private final String property;
|
||||
private final Object newValue;
|
||||
|
||||
|
||||
public FirePropertyChangeRunnable(String property, Object newValue) {
|
||||
this.property = property;
|
||||
this.newValue = newValue;
|
||||
public SwingWorkerPropertyChangeSupport(Object sourceBean) {
|
||||
super(sourceBean);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
propertyChangeSupport.firePropertyChange(property, null, newValue);
|
||||
public void firePropertyChange(final PropertyChangeEvent evt) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
SwingWorkerPropertyChangeSupport.super.firePropertyChange(evt);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,24 +16,28 @@ public class ChecksumRow {
|
|||
|
||||
private HashMap<File, Checksum> checksumMap = new HashMap<File, Checksum>();
|
||||
|
||||
private Long checksumFromFileName = null;
|
||||
/**
|
||||
* Checksum that is embedded in the file name (e.g. My File [49A93C5F].txt)
|
||||
*/
|
||||
private Long embeddedChecksum = null;
|
||||
|
||||
|
||||
public static enum State {
|
||||
OK, UNKNOWN, WARNING, ERROR;
|
||||
OK,
|
||||
WARNING,
|
||||
ERROR,
|
||||
UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
public ChecksumRow(String name) {
|
||||
this.name = name;
|
||||
|
||||
// look for a patter like [49A93C5F]
|
||||
Pattern pattern = Pattern.compile(".*\\[(\\p{XDigit}{8})\\].*");
|
||||
Matcher matcher = pattern.matcher(getName());
|
||||
// look for a checksum pattern like [49A93C5F]
|
||||
Matcher matcher = Pattern.compile("\\[(\\p{XDigit}{8})\\]").matcher(name);
|
||||
|
||||
if (matcher.matches()) {
|
||||
String checksumString = matcher.group(matcher.groupCount());
|
||||
checksumFromFileName = Long.parseLong(checksumString, 16);
|
||||
if (matcher.find()) {
|
||||
embeddedChecksum = Long.parseLong(matcher.group(1), 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,9 +65,9 @@ public class ChecksumRow {
|
|||
return State.ERROR;
|
||||
}
|
||||
|
||||
if (!checksums.isEmpty() && checksumFromFileName != null) {
|
||||
// check if the checksum in the filename matches
|
||||
if (!checksums.contains(checksumFromFileName))
|
||||
if (!checksums.isEmpty() && embeddedChecksum != null) {
|
||||
// check if the embedded checksum matches
|
||||
if (!checksums.contains(embeddedChecksum))
|
||||
return State.WARNING;
|
||||
}
|
||||
|
||||
|
@ -71,8 +75,8 @@ public class ChecksumRow {
|
|||
}
|
||||
|
||||
|
||||
public Checksum getChecksum(File columnRoot) {
|
||||
return checksumMap.get(columnRoot);
|
||||
public Checksum getChecksum(File column) {
|
||||
return checksumMap.get(column);
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,13 +85,13 @@ public class ChecksumRow {
|
|||
}
|
||||
|
||||
|
||||
public void putChecksum(File columnRoot, Checksum checksum) {
|
||||
checksumMap.put(columnRoot, checksum);
|
||||
public void putChecksum(File column, Checksum checksum) {
|
||||
checksumMap.put(column, checksum);
|
||||
}
|
||||
|
||||
|
||||
public void removeChecksum(File columnRoot) {
|
||||
checksumMap.remove(columnRoot);
|
||||
public void removeChecksum(File column) {
|
||||
checksumMap.remove(column);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.sfv;
|
||||
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.sourceforge.filebot.ui.transfer.FileExportHandler;
|
||||
import net.sourceforge.tuned.FileUtil;
|
||||
|
||||
|
||||
public class ChecksumTableExportHandler extends FileExportHandler {
|
||||
|
||||
private final ChecksumTableModel model;
|
||||
|
||||
|
||||
public ChecksumTableExportHandler(ChecksumTableModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canExport() {
|
||||
return model.getRowCount() > 0 && model.getChecksumColumnCount() > 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void export(OutputStream out) throws IOException {
|
||||
export(out, model.getChecksumColumn(0));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDefaultFileName() {
|
||||
return getDefaultFileName(model.getChecksumColumn(0));
|
||||
}
|
||||
|
||||
|
||||
public void export(File file, File column) throws IOException {
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
|
||||
|
||||
try {
|
||||
export(out, column);
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void export(OutputStream out, File column) throws IOException {
|
||||
PrintStream printer = new PrintStream(out);
|
||||
|
||||
SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
|
||||
SimpleDateFormat time = new SimpleDateFormat("HH:mm:ss");
|
||||
|
||||
Date now = new Date();
|
||||
printer.println("; Generated by FileBot on " + date.format(now) + " at " + time.format(now));
|
||||
printer.println(";");
|
||||
printer.println(";");
|
||||
|
||||
Map<String, Checksum> checksumMap = model.getChecksumColumn(column);
|
||||
|
||||
for (Entry<String, Checksum> entry : checksumMap.entrySet()) {
|
||||
printer.println(String.format("%s %s", entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getDefaultFileName(File column) {
|
||||
String name = "";
|
||||
|
||||
if (column != null)
|
||||
name = FileUtil.getFileName(column);
|
||||
|
||||
if (name.isEmpty())
|
||||
name = "name";
|
||||
|
||||
return name + ".sfv";
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@ import java.beans.PropertyChangeEvent;
|
|||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
@ -20,12 +21,19 @@ import net.sourceforge.tuned.FileUtil;
|
|||
|
||||
class ChecksumTableModel extends AbstractTableModel {
|
||||
|
||||
private List<ChecksumRow> rows = new ArrayList<ChecksumRow>();
|
||||
private Map<String, ChecksumRow> rowMap = new HashMap<String, ChecksumRow>();
|
||||
private List<ChecksumRow> rows = new ArrayList<ChecksumRow>(50);
|
||||
|
||||
private List<File> checksumColumnRoots = new ArrayList<File>();
|
||||
/**
|
||||
* Hash map for fast access to the row of a given name
|
||||
*/
|
||||
private Map<String, ChecksumRow> rowMap = new HashMap<String, ChecksumRow>(50);
|
||||
|
||||
private final int checksumColumnsOffset = 2;
|
||||
private List<File> columns = new ArrayList<File>();
|
||||
|
||||
/**
|
||||
* Checksum start at column 3
|
||||
*/
|
||||
private static final int checksumColumnOffset = 2;
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -36,9 +44,11 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
if (columnIndex == 1)
|
||||
return "Name";
|
||||
|
||||
if (columnIndex >= checksumColumnsOffset) {
|
||||
File columnRoot = checksumColumnRoots.get(columnIndex - checksumColumnsOffset);
|
||||
return FileUtil.getFolderName(columnRoot);
|
||||
if (columnIndex >= checksumColumnOffset) {
|
||||
File column = columns.get(columnIndex - checksumColumnOffset);
|
||||
|
||||
// works for files too and simply returns the name unchanged
|
||||
return FileUtil.getFolderName(column);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -53,7 +63,7 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
if (columnIndex == 1)
|
||||
return String.class;
|
||||
|
||||
if (columnIndex >= checksumColumnsOffset)
|
||||
if (columnIndex >= checksumColumnOffset)
|
||||
return Checksum.class;
|
||||
|
||||
return null;
|
||||
|
@ -61,12 +71,17 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
|
||||
|
||||
public int getColumnCount() {
|
||||
return checksumColumnsOffset + getChecksumColumnCount();
|
||||
return checksumColumnOffset + getChecksumColumnCount();
|
||||
}
|
||||
|
||||
|
||||
public int getChecksumColumnCount() {
|
||||
return checksumColumnRoots.size();
|
||||
return columns.size();
|
||||
}
|
||||
|
||||
|
||||
public List<File> getChecksumColumns() {
|
||||
return Collections.unmodifiableList(columns);
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,20 +99,20 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
if (columnIndex == 1)
|
||||
return row.getName();
|
||||
|
||||
if (columnIndex >= checksumColumnsOffset) {
|
||||
File columnRoot = checksumColumnRoots.get(columnIndex - checksumColumnsOffset);
|
||||
return row.getChecksum(columnRoot);
|
||||
if (columnIndex >= checksumColumnOffset) {
|
||||
File column = columns.get(columnIndex - checksumColumnOffset);
|
||||
return row.getChecksum(column);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public synchronized void addAll(List<ChecksumCell> list) {
|
||||
public void addAll(List<ChecksumCell> list) {
|
||||
int firstRow = getRowCount();
|
||||
|
||||
for (ChecksumCell entry : list) {
|
||||
addChecksum(entry.getName(), entry.getChecksum(), entry.getColumnRoot());
|
||||
addChecksum(entry.getName(), entry.getChecksum(), entry.getColumn());
|
||||
}
|
||||
|
||||
int lastRow = getRowCount() - 1;
|
||||
|
@ -108,7 +123,7 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
}
|
||||
|
||||
|
||||
private synchronized void addChecksum(String name, Checksum checksum, File columnRoot) {
|
||||
private void addChecksum(String name, Checksum checksum, File column) {
|
||||
ChecksumRow row = rowMap.get(name);
|
||||
|
||||
if (row == null) {
|
||||
|
@ -117,17 +132,17 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
rowMap.put(name, row);
|
||||
}
|
||||
|
||||
row.putChecksum(columnRoot, checksum);
|
||||
row.putChecksum(column, checksum);
|
||||
checksum.addPropertyChangeListener(checksumListener);
|
||||
|
||||
if (!checksumColumnRoots.contains(columnRoot)) {
|
||||
checksumColumnRoots.add(columnRoot);
|
||||
if (!columns.contains(column)) {
|
||||
columns.add(column);
|
||||
fireTableStructureChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized void removeRows(int... rowIndices) {
|
||||
public void removeRows(int... rowIndices) {
|
||||
ArrayList<ChecksumRow> rowsToRemove = new ArrayList<ChecksumRow>(rowIndices.length);
|
||||
|
||||
for (int i : rowIndices) {
|
||||
|
@ -137,37 +152,35 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
for (Checksum checksum : row.getChecksums()) {
|
||||
checksum.cancelComputationTask();
|
||||
}
|
||||
|
||||
rowMap.remove(row.getName());
|
||||
}
|
||||
|
||||
rows.removeAll(rowsToRemove);
|
||||
fireTableRowsDeleted(rowIndices[0], rowIndices[rowIndices.length - 1]);
|
||||
|
||||
ChecksumComputationService.getService().purge();
|
||||
}
|
||||
|
||||
|
||||
public synchronized void clear() {
|
||||
ChecksumComputationService.getService().reset();
|
||||
|
||||
checksumColumnRoots.clear();
|
||||
public void clear() {
|
||||
columns.clear();
|
||||
rows.clear();
|
||||
rowMap.clear();
|
||||
|
||||
fireTableStructureChanged();
|
||||
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
|
||||
public File getChecksumColumnRoot(int checksumColumnIndex) {
|
||||
return checksumColumnRoots.get(checksumColumnIndex);
|
||||
public File getChecksumColumn(int columnIndex) {
|
||||
return columns.get(columnIndex);
|
||||
}
|
||||
|
||||
|
||||
public Map<String, Checksum> getChecksumColumn(File columnRoot) {
|
||||
public Map<String, Checksum> getChecksumColumn(File column) {
|
||||
LinkedHashMap<String, Checksum> checksumMap = new LinkedHashMap<String, Checksum>();
|
||||
|
||||
for (ChecksumRow row : rows) {
|
||||
Checksum checksum = row.getChecksum(columnRoot);
|
||||
Checksum checksum = row.getChecksum(column);
|
||||
|
||||
if ((checksum != null) && (checksum.getState() == Checksum.State.READY)) {
|
||||
checksumMap.put(row.getName(), checksum);
|
||||
|
@ -189,13 +202,13 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
|
||||
private final String name;
|
||||
private final Checksum checksum;
|
||||
private final File columnRoot;
|
||||
private final File column;
|
||||
|
||||
|
||||
public ChecksumCell(String name, Checksum checksum, File columnRoot) {
|
||||
public ChecksumCell(String name, Checksum checksum, File column) {
|
||||
this.name = name;
|
||||
this.checksum = checksum;
|
||||
this.columnRoot = columnRoot;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
|
||||
|
@ -209,8 +222,8 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
}
|
||||
|
||||
|
||||
public File getColumnRoot() {
|
||||
return columnRoot;
|
||||
public File getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ package net.sourceforge.filebot.ui.panel.sfv;
|
|||
import java.awt.BorderLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
|
@ -32,7 +33,7 @@ public class SfvPanel extends FileBotPanel {
|
|||
|
||||
private SfvTable sfvTable = new SfvTable();
|
||||
|
||||
private TotalProgressPanel totalProgressPanel = new TotalProgressPanel();
|
||||
private TotalProgressPanel totalProgressPanel = new TotalProgressPanel(sfvTable.getChecksumComputationService());
|
||||
|
||||
|
||||
public SfvPanel() {
|
||||
|
@ -61,85 +62,12 @@ public class SfvPanel extends FileBotPanel {
|
|||
add(southPanel, BorderLayout.SOUTH);
|
||||
|
||||
// Shortcut DELETE
|
||||
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
||||
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
||||
|
||||
MessageBus.getDefault().addMessageHandler(getPanelName(), new FileTransferableMessageHandler(getPanelName(), sfvTable.getTransferablePolicy()));
|
||||
MessageBus.getDefault().addMessageHandler(getPanelName(), new FileTransferableMessageHandler(this, sfvTable.getTransferablePolicy()));
|
||||
}
|
||||
|
||||
private final SaveAction saveAction = new SaveAction(sfvTable) {
|
||||
|
||||
private int index;
|
||||
private String name;
|
||||
|
||||
private File folder = null;
|
||||
|
||||
|
||||
@Override
|
||||
protected void save(File file) {
|
||||
sfvTable.save(file, index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getDefaultFileName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected File getDefaultFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ChecksumTableModel model = (ChecksumTableModel) sfvTable.getModel();
|
||||
|
||||
ArrayList<File> options = new ArrayList<File>();
|
||||
|
||||
for (int i = 0; i < model.getChecksumColumnCount(); i++) {
|
||||
options.add(model.getChecksumColumnRoot(i));
|
||||
}
|
||||
|
||||
File selected = null;
|
||||
|
||||
if (options.size() > 1) {
|
||||
SelectDialog<File> selectDialog = new SelectDialog<File>(SwingUtilities.getWindowAncestor(SfvPanel.this), options) {
|
||||
|
||||
@Override
|
||||
protected String convertValueToString(Object value) {
|
||||
File columnRoot = (File) value;
|
||||
return FileUtil.getFolderName(columnRoot);
|
||||
}
|
||||
};
|
||||
|
||||
selectDialog.setText("Select checksum column:");
|
||||
selectDialog.setVisible(true);
|
||||
selected = selectDialog.getSelectedValue();
|
||||
} else if (options.size() == 1) {
|
||||
selected = options.get(0);
|
||||
}
|
||||
|
||||
if (selected == null)
|
||||
return;
|
||||
|
||||
index = options.indexOf(selected);
|
||||
name = FileUtil.getFileName(selected);
|
||||
|
||||
if (name.isEmpty())
|
||||
name = "name";
|
||||
|
||||
name += ".sfv";
|
||||
|
||||
// selected is either a folder or a sfv file
|
||||
if (selected.isDirectory()) {
|
||||
folder = selected;
|
||||
}
|
||||
|
||||
super.actionPerformed(e);
|
||||
}
|
||||
};
|
||||
private final SaveAction saveAction = new ChecksumTableSaveAction();
|
||||
|
||||
private final LoadAction loadAction = new LoadAction(sfvTable.getTransferablePolicy());
|
||||
|
||||
|
@ -169,4 +97,68 @@ public class SfvPanel extends FileBotPanel {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
private class ChecksumTableSaveAction extends SaveAction {
|
||||
|
||||
private File selectedColumn = null;
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean canExport() {
|
||||
return selectedColumn != null && sfvTable.getExportHandler().canExport();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void export(File file) throws IOException {
|
||||
sfvTable.getExportHandler().export(file, selectedColumn);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getDefaultFileName() {
|
||||
return sfvTable.getExportHandler().getDefaultFileName(selectedColumn);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected File getDefaultFolder() {
|
||||
// if column is a folder use it as default folder in file dialog
|
||||
return selectedColumn.isDirectory() ? selectedColumn : null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
List<File> options = sfvTable.getModel().getChecksumColumns();
|
||||
|
||||
this.selectedColumn = null;
|
||||
|
||||
if (options.size() == 1) {
|
||||
// auto-select if there is only one option
|
||||
this.selectedColumn = options.get(0);
|
||||
} else if (options.size() > 1) {
|
||||
// show user his/her options
|
||||
SelectDialog<File> selectDialog = new SelectDialog<File>(SwingUtilities.getWindowAncestor(SfvPanel.this), options) {
|
||||
|
||||
@Override
|
||||
protected String convertValueToString(Object value) {
|
||||
return FileUtil.getFolderName((File) value);
|
||||
}
|
||||
};
|
||||
|
||||
selectDialog.setText("Select checksum column:");
|
||||
selectDialog.setVisible(true);
|
||||
|
||||
this.selectedColumn = selectDialog.getSelectedValue();
|
||||
}
|
||||
|
||||
if (this.selectedColumn != null) {
|
||||
// continue if a column was selected
|
||||
super.actionPerformed(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,14 +2,6 @@
|
|||
package net.sourceforge.filebot.ui.panel.sfv;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
|
@ -20,26 +12,20 @@ import net.sourceforge.filebot.ui.panel.sfv.ChecksumTableModel.ChecksumTableMode
|
|||
import net.sourceforge.filebot.ui.panel.sfv.renderer.ChecksumTableCellRenderer;
|
||||
import net.sourceforge.filebot.ui.panel.sfv.renderer.StateIconTableCellRenderer;
|
||||
import net.sourceforge.filebot.ui.transfer.DefaultTransferHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.ExportHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.ImportHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.Saveable;
|
||||
import net.sourceforge.filebot.ui.transfer.SaveableExportHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.TransferablePolicyImportHandler;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.TransferablePolicy;
|
||||
import net.sourceforge.tuned.FileUtil;
|
||||
|
||||
|
||||
class SfvTable extends JTable implements Saveable {
|
||||
class SfvTable extends JTable {
|
||||
|
||||
private final SfvTransferablePolicy transferablePolicy;
|
||||
private final ChecksumTableExportHandler exportHandler;
|
||||
|
||||
private final ChecksumComputationService checksumComputationService = new ChecksumComputationService();
|
||||
|
||||
|
||||
public SfvTable() {
|
||||
ChecksumTableModel model = (ChecksumTableModel) getModel();
|
||||
|
||||
transferablePolicy = new SfvTransferablePolicy(model);
|
||||
|
||||
setModel(model);
|
||||
transferablePolicy = new SfvTransferablePolicy(getModel(), checksumComputationService);
|
||||
exportHandler = new ChecksumTableExportHandler(getModel());
|
||||
|
||||
setFillsViewportHeight(true);
|
||||
setAutoCreateRowSorter(true);
|
||||
|
@ -50,10 +36,7 @@ class SfvTable extends JTable implements Saveable {
|
|||
|
||||
setRowHeight(20);
|
||||
|
||||
ImportHandler importHandler = new TransferablePolicyImportHandler(transferablePolicy);
|
||||
ExportHandler exportHandler = new SaveableExportHandler(this);
|
||||
|
||||
setTransferHandler(new DefaultTransferHandler(importHandler, exportHandler));
|
||||
setTransferHandler(new DefaultTransferHandler(transferablePolicy, exportHandler));
|
||||
setDragEnabled(true);
|
||||
|
||||
setDefaultRenderer(ChecksumRow.State.class, new StateIconTableCellRenderer());
|
||||
|
@ -61,17 +44,39 @@ class SfvTable extends JTable implements Saveable {
|
|||
}
|
||||
|
||||
|
||||
public TransferablePolicy getTransferablePolicy() {
|
||||
public SfvTransferablePolicy getTransferablePolicy() {
|
||||
return transferablePolicy;
|
||||
}
|
||||
|
||||
|
||||
public ChecksumTableExportHandler getExportHandler() {
|
||||
return exportHandler;
|
||||
}
|
||||
|
||||
|
||||
public ChecksumComputationService getChecksumComputationService() {
|
||||
return checksumComputationService;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DefaultTransferHandler getTransferHandler() {
|
||||
return (DefaultTransferHandler) super.getTransferHandler();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected TableModel createDefaultDataModel() {
|
||||
return new ChecksumTableModel();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ChecksumTableModel getModel() {
|
||||
return (ChecksumTableModel) super.getModel();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void createDefaultColumnsFromModel() {
|
||||
super.createDefaultColumnsFromModel();
|
||||
|
@ -90,82 +95,30 @@ class SfvTable extends JTable implements Saveable {
|
|||
|
||||
|
||||
public void clear() {
|
||||
checksumComputationService.reset();
|
||||
transferablePolicy.reset();
|
||||
|
||||
((ChecksumTableModel) getModel()).clear();
|
||||
}
|
||||
|
||||
|
||||
public String getDefaultFileName() {
|
||||
ChecksumTableModel model = (ChecksumTableModel) getModel();
|
||||
File columnRoot = model.getChecksumColumnRoot(0);
|
||||
|
||||
String name = "";
|
||||
|
||||
if (columnRoot != null)
|
||||
name = FileUtil.getFileName(columnRoot);
|
||||
|
||||
if (name.isEmpty())
|
||||
name = "name";
|
||||
|
||||
return name + ".sfv";
|
||||
}
|
||||
|
||||
|
||||
public boolean isSaveable() {
|
||||
return getModel().getRowCount() > 0;
|
||||
getModel().clear();
|
||||
}
|
||||
|
||||
|
||||
public void removeRows(int... rowIndices) {
|
||||
ChecksumTableModel model = (ChecksumTableModel) getModel();
|
||||
model.removeRows(rowIndices);
|
||||
getModel().removeRows(rowIndices);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void tableChanged(TableModelEvent e) {
|
||||
// only request repaint when progress changes, or selection will go haywire
|
||||
if (e.getType() == ChecksumTableModelEvent.CHECKSUM_PROGRESS) {
|
||||
repaint();
|
||||
} else {
|
||||
super.tableChanged(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void save(File file, int checksumColumnIndex) {
|
||||
try {
|
||||
PrintStream out = new PrintStream(file);
|
||||
|
||||
ChecksumTableModel model = (ChecksumTableModel) getModel();
|
||||
File columnRoot = model.getChecksumColumnRoot(checksumColumnIndex);
|
||||
|
||||
if (columnRoot != null) {
|
||||
SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
|
||||
SimpleDateFormat time = new SimpleDateFormat("HH:mm:ss");
|
||||
|
||||
Date now = new Date();
|
||||
out.println("; Generated by FileBot on " + date.format(now) + " at " + time.format(now));
|
||||
out.println(";");
|
||||
out.println(";");
|
||||
|
||||
Map<String, Checksum> checksumMap = model.getChecksumColumn(columnRoot);
|
||||
|
||||
for (String name : checksumMap.keySet()) {
|
||||
out.println(name + " " + checksumMap.get(name).getChecksumString());
|
||||
}
|
||||
if (e.getType() == TableModelEvent.DELETE) {
|
||||
// remove cancelled task from queue
|
||||
checksumComputationService.purge();
|
||||
}
|
||||
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
// should not happen
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void save(File file) {
|
||||
save(file, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,21 +14,24 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import net.sourceforge.filebot.FileBotUtil;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.BackgroundFileTransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transfer.BackgroundFileTransferablePolicy;
|
||||
|
||||
|
||||
class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTableModel.ChecksumCell> {
|
||||
|
||||
private ChecksumTableModel tableModel;
|
||||
private final ChecksumTableModel tableModel;
|
||||
private final ChecksumComputationService checksumComputationService;
|
||||
|
||||
|
||||
public SfvTransferablePolicy(ChecksumTableModel tableModel) {
|
||||
public SfvTransferablePolicy(ChecksumTableModel tableModel, ChecksumComputationService checksumComputationService) {
|
||||
this.tableModel = tableModel;
|
||||
this.checksumComputationService = checksumComputationService;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void clear() {
|
||||
checksumComputationService.reset();
|
||||
tableModel.clear();
|
||||
}
|
||||
|
||||
|
@ -60,11 +63,11 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||
|
||||
publish(new ChecksumTableModel.ChecksumCell(filename, new Checksum(checksumString), sfvFile));
|
||||
|
||||
File compareColumnRoot = sfvFile.getParentFile();
|
||||
File compareFile = new File(compareColumnRoot, filename);
|
||||
File column = sfvFile.getParentFile();
|
||||
File file = new File(column, filename);
|
||||
|
||||
if (compareFile.exists()) {
|
||||
publish(new ChecksumTableModel.ChecksumCell(filename, ChecksumComputationService.getService().getChecksum(compareFile, compareColumnRoot), compareColumnRoot));
|
||||
if (file.exists()) {
|
||||
publish(new ChecksumTableModel.ChecksumCell(filename, checksumComputationService.schedule(file, column), column));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +80,7 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
public String getFileFilterDescription() {
|
||||
return "files, folders and sfv files";
|
||||
}
|
||||
|
||||
|
@ -105,7 +108,7 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||
}
|
||||
|
||||
|
||||
protected void load(File file, File columnRoot, String prefix) {
|
||||
protected void load(File file, File column, String prefix) {
|
||||
if (Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
|
||||
|
@ -113,10 +116,10 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||
// load all files in the file tree
|
||||
String newPrefix = prefix + file.getName() + "/";
|
||||
for (File f : file.listFiles()) {
|
||||
load(f, columnRoot, newPrefix);
|
||||
load(f, column, newPrefix);
|
||||
}
|
||||
} else if (file.isFile()) {
|
||||
publish(new ChecksumTableModel.ChecksumCell(prefix + file.getName(), ChecksumComputationService.getService().getChecksum(file, columnRoot), columnRoot));
|
||||
publish(new ChecksumTableModel.ChecksumCell(prefix + file.getName(), checksumComputationService.schedule(file, column), column));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,14 +18,18 @@ class TotalProgressPanel extends Box {
|
|||
|
||||
private int millisToSetVisible = 200;
|
||||
|
||||
private JProgressBar progressBar = new JProgressBar(0, 0);
|
||||
private final JProgressBar progressBar = new JProgressBar(0, 0);
|
||||
|
||||
private final ChecksumComputationService checksumComputationService;
|
||||
|
||||
|
||||
public TotalProgressPanel() {
|
||||
public TotalProgressPanel(ChecksumComputationService checksumComputationService) {
|
||||
super(BoxLayout.Y_AXIS);
|
||||
|
||||
// start invisible
|
||||
super.setVisible(false);
|
||||
this.checksumComputationService = checksumComputationService;
|
||||
|
||||
// invisible by default
|
||||
setVisible(false);
|
||||
|
||||
progressBar.setStringPainted(true);
|
||||
progressBar.setBorderPainted(false);
|
||||
|
@ -37,10 +41,11 @@ class TotalProgressPanel extends Box {
|
|||
setBorder(BorderFactory.createCompoundBorder(margin, title));
|
||||
|
||||
add(progressBar);
|
||||
ChecksumComputationService.getService().addPropertyChangeListener(executorListener);
|
||||
|
||||
checksumComputationService.addPropertyChangeListener(progressListener);
|
||||
}
|
||||
|
||||
private PropertyChangeListener executorListener = new PropertyChangeListener() {
|
||||
private PropertyChangeListener progressListener = new PropertyChangeListener() {
|
||||
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
|
||||
|
@ -54,24 +59,23 @@ class TotalProgressPanel extends Box {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
setVisible(ChecksumComputationService.getService().isActive());
|
||||
setVisible(checksumComputationService.isActive());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// hide when not active
|
||||
setVisible(false);
|
||||
}
|
||||
} else if (property == ChecksumComputationService.REMAINING_TASK_COUNT_PROPERTY) {
|
||||
|
||||
int taskCount = ChecksumComputationService.getService().getActiveSessionTaskCount();
|
||||
int progress = taskCount - ChecksumComputationService.getService().getRemainingTaskCount();
|
||||
int taskCount = checksumComputationService.getActiveSessionTaskCount();
|
||||
int progress = taskCount - checksumComputationService.getRemainingTaskCount();
|
||||
|
||||
progressBar.setValue(progress);
|
||||
progressBar.setMaximum(taskCount);
|
||||
|
||||
progressBar.setString(progressBar.getValue() + " / " + progressBar.getMaximum());
|
||||
}
|
||||
|
||||
if (!ChecksumComputationService.getService().isActive()) {
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ package net.sourceforge.filebot.ui.panel.subtitle;
|
|||
import java.util.Locale;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
|
||||
|
@ -16,7 +15,7 @@ class Language implements Comparable<Language> {
|
|||
private final Locale locale;
|
||||
|
||||
private final String code;
|
||||
private final ImageIcon icon;
|
||||
private final Icon icon;
|
||||
|
||||
|
||||
public Language(String languageName) {
|
||||
|
@ -57,13 +56,11 @@ class Language implements Comparable<Language> {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof Language) {
|
||||
if (obj instanceof Language)
|
||||
return getName().equalsIgnoreCase(((Language) obj).getName());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -26,13 +26,12 @@ public class LanguageResolver {
|
|||
* @return the locale for this language or null if no locale for this language exists
|
||||
*/
|
||||
public synchronized Locale getLocale(String languageName) {
|
||||
languageName = languageName.toLowerCase();
|
||||
|
||||
Locale locale = cache.get(languageName);
|
||||
Locale locale = cache.get(languageName.toLowerCase());
|
||||
|
||||
if (locale == null) {
|
||||
locale = findLocale(languageName);
|
||||
cache.put(languageName, locale);
|
||||
cache.put(languageName.toLowerCase(), locale);
|
||||
}
|
||||
|
||||
return locale;
|
||||
|
@ -59,16 +58,17 @@ public class LanguageResolver {
|
|||
/**
|
||||
* Find the {@link Locale} for a given language name.
|
||||
*
|
||||
* @param languageName lower-case language name
|
||||
* @param languageName language name
|
||||
* @return {@link Locale} for the given language, or null if no matching {@link Locale} is
|
||||
* available
|
||||
*/
|
||||
private Locale findLocale(String languageName) {
|
||||
for (Locale locale : Locale.getAvailableLocales()) {
|
||||
if (locale.getDisplayLanguage(Locale.ENGLISH).toLowerCase().equals(languageName))
|
||||
if (locale.getDisplayLanguage(Locale.ENGLISH).equalsIgnoreCase(languageName))
|
||||
return locale;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import java.util.TreeMap;
|
|||
import javax.swing.JPanel;
|
||||
import javax.swing.JToggleButton;
|
||||
|
||||
import net.sourceforge.filebot.Settings;
|
||||
import ca.odell.glazedlists.EventList;
|
||||
import ca.odell.glazedlists.FunctionList;
|
||||
import ca.odell.glazedlists.ListSelection;
|
||||
|
@ -31,13 +30,14 @@ public class LanguageSelectionPanel extends JPanel {
|
|||
private final ListSelection<Language> selectionModel;
|
||||
|
||||
private final Map<String, Boolean> defaultSelection = new TreeMap<String, Boolean>(String.CASE_INSENSITIVE_ORDER);
|
||||
private final Map<String, Boolean> globalSelection = Settings.getSettings().asBooleanMap(Settings.SUBTITLE_LANGUAGE);
|
||||
|
||||
|
||||
// private final Map<String, Boolean> globalSelection = Settings.getSettings().asBooleanMap(Settings.SUBTITLE_LANGUAGE);
|
||||
|
||||
public LanguageSelectionPanel(EventList<SubtitlePackage> source) {
|
||||
super(new FlowLayout(FlowLayout.RIGHT, 5, 1));
|
||||
|
||||
defaultSelection.putAll(globalSelection);
|
||||
// defaultSelection.putAll(globalSelection);
|
||||
|
||||
EventList<Language> languageList = new FunctionList<SubtitlePackage, Language>(source, new LanguageFunction());
|
||||
EventList<Language> languageSet = new UniqueList<Language>(languageList);
|
||||
|
@ -68,7 +68,7 @@ public class LanguageSelectionPanel extends JPanel {
|
|||
String key = language.getName();
|
||||
|
||||
defaultSelection.put(key, selected);
|
||||
globalSelection.put(key, selected);
|
||||
// globalSelection.put(key, selected);
|
||||
|
||||
if (selected)
|
||||
selectionModel.select(language);
|
||||
|
|
|
@ -14,6 +14,7 @@ import javax.swing.SwingConstants;
|
|||
|
||||
import net.sourceforge.tuned.ui.ColorTintImageFilter;
|
||||
import net.sourceforge.tuned.ui.IconViewCellRenderer;
|
||||
import net.sourceforge.tuned.ui.TunedUtil;
|
||||
|
||||
|
||||
public class SubtitleCellRenderer extends IconViewCellRenderer {
|
||||
|
@ -52,10 +53,10 @@ public class SubtitleCellRenderer extends IconViewCellRenderer {
|
|||
|
||||
info1.setIcon(icon);
|
||||
|
||||
ImageIcon icon = subtitle.getArchiveIcon();
|
||||
Icon icon = subtitle.getArchiveIcon();
|
||||
|
||||
if (isSelected) {
|
||||
setIcon(new ImageIcon(createImage(new FilteredImageSource(icon.getImage().getSource(), new ColorTintImageFilter(list.getSelectionBackground(), 0.5f)))));
|
||||
setIcon(new ImageIcon(createImage(new FilteredImageSource(TunedUtil.getImage(icon).getSource(), new ColorTintImageFilter(list.getSelectionBackground(), 0.5f)))));
|
||||
|
||||
info1.setForeground(list.getSelectionForeground());
|
||||
info2.setForeground(list.getSelectionForeground());
|
||||
|
|
|
@ -4,6 +4,7 @@ package net.sourceforge.filebot.ui.panel.subtitle;
|
|||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.SwingWorker.StateValue;
|
||||
|
||||
|
@ -57,7 +58,7 @@ public class SubtitlePackage extends AbstractBean {
|
|||
}
|
||||
|
||||
|
||||
public ImageIcon getArchiveIcon() {
|
||||
public Icon getArchiveIcon() {
|
||||
return archiveIcon;
|
||||
}
|
||||
|
||||
|
@ -68,9 +69,9 @@ public class SubtitlePackage extends AbstractBean {
|
|||
}
|
||||
|
||||
|
||||
public synchronized void download() {
|
||||
public synchronized void startDownload() {
|
||||
if (downloadTask != null)
|
||||
throw new IllegalStateException("Download has been started already");
|
||||
throw new IllegalStateException("Download has already been started");
|
||||
|
||||
downloadTask = subtitleDescriptor.createDownloadTask();
|
||||
downloadTask.addPropertyChangeListener(new DownloadTaskPropertyChangeAdapter());
|
||||
|
|
|
@ -8,7 +8,6 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.sourceforge.filebot.ListChangeSynchronizer;
|
||||
import net.sourceforge.filebot.Settings;
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.AbstractSearchPanel;
|
||||
|
@ -18,6 +17,7 @@ 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.ListChangeSynchronizer;
|
||||
import net.sourceforge.tuned.ui.LabelProvider;
|
||||
import net.sourceforge.tuned.ui.SimpleLabelProvider;
|
||||
|
||||
|
@ -63,12 +63,6 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleClient, SubtitleP
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void configureSelectDialog(SelectDialog<SearchResult> selectDialog) {
|
||||
selectDialog.setText("Select a Show / Movie:");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected FetchTask createFetchTask(SearchTask searchTask, SearchResult selectedSearchResult) {
|
||||
return new SubtitleFetchTask(searchTask.getClient(), selectedSearchResult, searchTask.getTabPanel());
|
||||
|
@ -93,6 +87,13 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleClient, SubtitleP
|
|||
return getClient().search(getSearchText());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void configureSelectDialog(SelectDialog<SearchResult> selectDialog) throws Exception {
|
||||
super.configureSelectDialog(selectDialog);
|
||||
selectDialog.setText("Select a Show / Movie:");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.transfer;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
|
||||
public abstract class AdaptiveFileExportHandler extends FileExportHandler {
|
||||
|
||||
/**
|
||||
* @return the <code>FileExportHandler</code> that that should be used, or
|
||||
* <code>null</code> if export is not possible in the first place
|
||||
*/
|
||||
protected abstract FileExportHandler getExportHandler();
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canExport() {
|
||||
FileExportHandler handler = getExportHandler();
|
||||
|
||||
if (handler == null)
|
||||
return false;
|
||||
|
||||
return handler.canExport();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void export(OutputStream out) throws IOException {
|
||||
getExportHandler().export(out);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDefaultFileName() {
|
||||
return getExportHandler().getDefaultFileName();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.transfer;
|
||||
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
|
||||
|
||||
|
||||
public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferablePolicy {
|
||||
|
||||
public static final String LOADING_PROPERTY = "loading";
|
||||
|
||||
private BackgroundWorker worker = null;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean accept(Transferable tr) {
|
||||
if (isActive())
|
||||
return false;
|
||||
|
||||
return super.accept(tr);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void handleTransferable(Transferable tr, TransferAction action) {
|
||||
List<File> files = getFilesFromTransferable(tr);
|
||||
|
||||
if (action != TransferAction.ADD)
|
||||
clear();
|
||||
|
||||
worker = new BackgroundWorker(files);
|
||||
worker.addPropertyChangeListener(new BackgroundWorkerListener());
|
||||
worker.execute();
|
||||
}
|
||||
|
||||
|
||||
public synchronized boolean isActive() {
|
||||
return (worker != null) && !worker.isDone();
|
||||
}
|
||||
|
||||
|
||||
public synchronized void reset() {
|
||||
if (isActive()) {
|
||||
worker.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Receives data chunks from the publish method asynchronously on the Event Dispatch
|
||||
* Thread.
|
||||
*
|
||||
* @param chunks
|
||||
*/
|
||||
protected abstract void process(List<V> chunks);
|
||||
|
||||
|
||||
/**
|
||||
* Sends data chunks to the process method.
|
||||
*
|
||||
* @param chunks
|
||||
*/
|
||||
protected synchronized final void publish(V... chunks) {
|
||||
if (worker != null) {
|
||||
worker.publishChunks(chunks);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class BackgroundWorker extends SwingWorker<Void, V> {
|
||||
|
||||
private final List<File> files;
|
||||
|
||||
|
||||
public BackgroundWorker(List<File> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Void doInBackground() {
|
||||
load(files);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void publishChunks(V... chunks) {
|
||||
if (!isCancelled()) {
|
||||
publish(chunks);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void process(List<V> chunks) {
|
||||
if (!isCancelled()) {
|
||||
BackgroundFileTransferablePolicy.this.process(chunks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class BackgroundWorkerListener extends SwingWorkerPropertyChangeAdapter {
|
||||
|
||||
@Override
|
||||
public void started(PropertyChangeEvent evt) {
|
||||
propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, null, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void done(PropertyChangeEvent evt) {
|
||||
propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
||||
|
||||
|
||||
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
|
||||
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
|
||||
}
|
||||
|
||||
|
||||
public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
|
||||
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.transfer;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import javax.swing.JList;
|
||||
import javax.swing.ListModel;
|
||||
|
||||
|
||||
public class DefaultListExportHandler extends FileExportHandler {
|
||||
|
||||
private final JList list;
|
||||
|
||||
|
||||
public DefaultListExportHandler(JList list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canExport() {
|
||||
return list.getModel().getSize() > 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void export(OutputStream out) throws IOException {
|
||||
PrintStream printer = new PrintStream(out);
|
||||
|
||||
ListModel model = list.getModel();
|
||||
|
||||
for (int i = 0; i < model.getSize(); i++) {
|
||||
printer.println(model.getElementAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDefaultFileName() {
|
||||
return list.getClientProperty("title") + ".txt";
|
||||
}
|
||||
}
|
|
@ -94,16 +94,31 @@ public class DefaultTransferHandler extends TransferHandler {
|
|||
}
|
||||
|
||||
|
||||
public ImportHandler getImportHandler() {
|
||||
return importHandler;
|
||||
}
|
||||
|
||||
|
||||
public void setImportHandler(ImportHandler importHandler) {
|
||||
this.importHandler = importHandler;
|
||||
}
|
||||
|
||||
|
||||
public ExportHandler getExportHandler() {
|
||||
return exportHandler;
|
||||
}
|
||||
|
||||
|
||||
public void setExportHandler(ExportHandler exportHandler) {
|
||||
this.exportHandler = exportHandler;
|
||||
}
|
||||
|
||||
|
||||
public ClipboardHandler getClipboardHandler() {
|
||||
return clipboardHandler;
|
||||
}
|
||||
|
||||
|
||||
public void setClipboardHandler(ClipboardHandler clipboardHandler) {
|
||||
this.clipboardHandler = clipboardHandler;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,11 @@ package net.sourceforge.filebot.ui.transfer;
|
|||
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -16,19 +19,31 @@ import net.sourceforge.filebot.Settings;
|
|||
import net.sourceforge.tuned.TemporaryFolder;
|
||||
|
||||
|
||||
public class SaveableExportHandler implements ExportHandler {
|
||||
public abstract class FileExportHandler implements ExportHandler {
|
||||
|
||||
private final Saveable saveable;
|
||||
public abstract boolean canExport();
|
||||
|
||||
|
||||
public abstract void export(OutputStream out) throws IOException;
|
||||
|
||||
public SaveableExportHandler(Saveable saveable) {
|
||||
this.saveable = saveable;
|
||||
|
||||
public abstract String getDefaultFileName();
|
||||
|
||||
|
||||
public void export(File file) throws IOException {
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
|
||||
|
||||
try {
|
||||
export(out);
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSourceActions(JComponent c) {
|
||||
if ((saveable == null) || !saveable.isSaveable())
|
||||
if (!canExport())
|
||||
return TransferHandler.NONE;
|
||||
|
||||
return TransferHandler.MOVE | TransferHandler.COPY;
|
||||
|
@ -38,11 +53,12 @@ public class SaveableExportHandler implements ExportHandler {
|
|||
@Override
|
||||
public Transferable createTransferable(JComponent c) {
|
||||
try {
|
||||
// Remove invalid characters from default filename
|
||||
String name = FileBotUtil.validateFileName(saveable.getDefaultFileName());
|
||||
// remove invalid characters from file name
|
||||
String name = FileBotUtil.validateFileName(getDefaultFileName());
|
||||
|
||||
File temporaryFile = TemporaryFolder.getFolder(Settings.ROOT).createFile(name);
|
||||
saveable.save(temporaryFile);
|
||||
|
||||
export(temporaryFile);
|
||||
|
||||
return new FileTransferable(temporaryFile);
|
||||
} catch (IOException e) {
|
||||
|
@ -58,4 +74,5 @@ public class SaveableExportHandler implements ExportHandler {
|
|||
public void exportDone(JComponent source, Transferable data, int action) {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -56,7 +56,6 @@ public class FileTransferable implements Transferable {
|
|||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return line separated list of file uris
|
||||
*/
|
||||
private String getUriList() {
|
||||
|
@ -72,7 +71,7 @@ public class FileTransferable implements Transferable {
|
|||
|
||||
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return supportedFlavors;
|
||||
return supportedFlavors.clone();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.transfer;
|
||||
|
||||
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.io.File;
|
||||
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;
|
||||
|
||||
|
||||
public abstract class FileTransferablePolicy extends TransferablePolicy {
|
||||
|
||||
@Override
|
||||
public boolean accept(Transferable tr) {
|
||||
List<File> files = getFilesFromTransferable(tr);
|
||||
|
||||
if (files.isEmpty())
|
||||
return false;
|
||||
|
||||
return accept(files);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<File> getFilesFromTransferable(Transferable tr) {
|
||||
try {
|
||||
if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
|
||||
// file list flavor
|
||||
return (List<File>) tr.getTransferData(DataFlavor.javaFileListFlavor);
|
||||
} else if (tr.isDataFlavorSupported(FileTransferable.uriListFlavor)) {
|
||||
// file uri list flavor
|
||||
String transferString = (String) tr.getTransferData(FileTransferable.uriListFlavor);
|
||||
|
||||
String lines[] = transferString.split("\r?\n");
|
||||
ArrayList<File> files = new ArrayList<File>(lines.length);
|
||||
|
||||
for (String line : lines) {
|
||||
if (line.startsWith("#")) {
|
||||
// the line is a comment (as per the RFC 2483)
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
File file = new File(new URI(line));
|
||||
|
||||
if (!file.exists())
|
||||
throw new FileNotFoundException(file.toString());
|
||||
|
||||
files.add(file);
|
||||
} catch (Exception e) {
|
||||
// URISyntaxException, IllegalArgumentException, FileNotFoundException
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid file url: " + line);
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
} catch (UnsupportedFlavorException e) {
|
||||
// should not happen
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
// should not happen
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleTransferable(Transferable tr, TransferAction action) {
|
||||
List<File> files = getFilesFromTransferable(tr);
|
||||
|
||||
if (action != TransferAction.ADD)
|
||||
clear();
|
||||
|
||||
load(files);
|
||||
}
|
||||
|
||||
|
||||
protected boolean accept(List<File> files) {
|
||||
for (File f : files)
|
||||
if (!accept(f))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected void load(List<File> files) {
|
||||
for (File file : files) {
|
||||
load(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected boolean accept(File file) {
|
||||
return file.isFile() || file.isDirectory();
|
||||
}
|
||||
|
||||
|
||||
protected void clear() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected void load(File file) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public String getFileFilterDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,7 +8,7 @@ import javax.swing.AbstractAction;
|
|||
import javax.swing.JFileChooser;
|
||||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.TransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transfer.TransferablePolicy.TransferAction;
|
||||
|
||||
|
||||
public class LoadAction extends AbstractAction {
|
||||
|
@ -18,6 +18,7 @@ public class LoadAction extends AbstractAction {
|
|||
|
||||
public LoadAction(TransferablePolicy transferablePolicy) {
|
||||
super("Load", ResourceManager.getIcon("action.load"));
|
||||
|
||||
this.transferablePolicy = transferablePolicy;
|
||||
}
|
||||
|
||||
|
@ -35,10 +36,14 @@ public class LoadAction extends AbstractAction {
|
|||
|
||||
FileTransferable transferable = new FileTransferable(chooser.getSelectedFiles());
|
||||
|
||||
boolean add = ((e.getModifiers() & ActionEvent.CTRL_MASK) != 0);
|
||||
TransferAction action = TransferAction.PUT;
|
||||
|
||||
// if CTRL was pressed when the button was clicked, assume ADD action (same as with dnd)
|
||||
if ((e.getModifiers() & ActionEvent.CTRL_MASK) != 0)
|
||||
action = TransferAction.ADD;
|
||||
|
||||
if (transferablePolicy.accept(transferable))
|
||||
transferablePolicy.handleTransferable(transferable, add);
|
||||
transferablePolicy.handleTransferable(transferable, action);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,8 +4,12 @@ package net.sourceforge.filebot.ui.transfer;
|
|||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFileChooser;
|
||||
|
||||
import net.sourceforge.filebot.FileBotUtil;
|
||||
|
@ -14,22 +18,32 @@ import net.sourceforge.filebot.resources.ResourceManager;
|
|||
|
||||
public class SaveAction extends AbstractAction {
|
||||
|
||||
protected Saveable saveable;
|
||||
protected final FileExportHandler exportHandler;
|
||||
|
||||
|
||||
public SaveAction(Saveable saveable) {
|
||||
public SaveAction(FileExportHandler exportHandler) {
|
||||
super("Save as ...", ResourceManager.getIcon("action.save"));
|
||||
this.saveable = saveable;
|
||||
this.exportHandler = exportHandler;
|
||||
}
|
||||
|
||||
|
||||
protected void save(File file) {
|
||||
saveable.save(file);
|
||||
protected SaveAction() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
|
||||
protected boolean canExport() {
|
||||
return exportHandler.canExport();
|
||||
}
|
||||
|
||||
|
||||
protected void export(File file) throws IOException {
|
||||
exportHandler.export(file);
|
||||
}
|
||||
|
||||
|
||||
protected String getDefaultFileName() {
|
||||
return saveable.getDefaultFileName();
|
||||
return exportHandler.getDefaultFileName();
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,18 +52,8 @@ public class SaveAction extends AbstractAction {
|
|||
}
|
||||
|
||||
|
||||
protected boolean isSaveable() {
|
||||
return saveable.isSaveable();
|
||||
}
|
||||
|
||||
|
||||
protected void setSaveable(Saveable saveable) {
|
||||
this.saveable = saveable;
|
||||
}
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (!isSaveable())
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
if (!canExport())
|
||||
return;
|
||||
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
|
@ -58,10 +62,13 @@ public class SaveAction extends AbstractAction {
|
|||
|
||||
chooser.setSelectedFile(new File(getDefaultFolder(), FileBotUtil.validateFileName(getDefaultFileName())));
|
||||
|
||||
if (chooser.showSaveDialog(null) != JFileChooser.APPROVE_OPTION)
|
||||
if (chooser.showSaveDialog((JComponent) evt.getSource()) != JFileChooser.APPROVE_OPTION)
|
||||
return;
|
||||
|
||||
save(chooser.getSelectedFile());
|
||||
try {
|
||||
export(chooser.getSelectedFile());
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.transfer;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
public interface Saveable {
|
||||
|
||||
public abstract void save(File file);
|
||||
|
||||
|
||||
public abstract boolean isSaveable();
|
||||
|
||||
|
||||
public abstract String getDefaultFileName();
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.transfer;
|
||||
|
||||
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
public abstract class StringTransferablePolicy extends TransferablePolicy {
|
||||
|
||||
@Override
|
||||
public boolean accept(Transferable tr) {
|
||||
return tr.isDataFlavorSupported(DataFlavor.stringFlavor);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleTransferable(Transferable tr, TransferAction action) {
|
||||
String string;
|
||||
|
||||
try {
|
||||
string = (String) tr.getTransferData(DataFlavor.stringFlavor);
|
||||
} catch (UnsupportedFlavorException e) {
|
||||
// should no happen
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
// should no happen
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if (action != TransferAction.ADD)
|
||||
clear();
|
||||
|
||||
load(string);
|
||||
}
|
||||
|
||||
|
||||
protected void clear() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected abstract void load(String string);
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.transfer;
|
||||
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.dnd.InvalidDnDOperationException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.TransferHandler;
|
||||
import javax.swing.TransferHandler.TransferSupport;
|
||||
|
||||
|
||||
public abstract class TransferablePolicy implements ImportHandler {
|
||||
|
||||
public abstract boolean accept(Transferable tr);
|
||||
|
||||
|
||||
public abstract void handleTransferable(Transferable tr, TransferAction action);
|
||||
|
||||
|
||||
public static enum TransferAction {
|
||||
PUT(TransferHandler.MOVE),
|
||||
ADD(TransferHandler.COPY),
|
||||
LINK(TransferHandler.LINK);
|
||||
|
||||
private final int dndConstant;
|
||||
|
||||
|
||||
private TransferAction(int dndConstant) {
|
||||
this.dndConstant = dndConstant;
|
||||
}
|
||||
|
||||
|
||||
public int getDnDConstant() {
|
||||
return dndConstant;
|
||||
}
|
||||
|
||||
|
||||
public static TransferAction fromDnDConstant(int dndConstant) {
|
||||
for (TransferAction action : values()) {
|
||||
if (dndConstant == action.dndConstant)
|
||||
return action;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unsupported dndConstant: " + dndConstant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canImport(TransferSupport support) {
|
||||
if (support.isDrop())
|
||||
support.setShowDropLocation(false);
|
||||
|
||||
try {
|
||||
return accept(support.getTransferable());
|
||||
} catch (InvalidDnDOperationException e) {
|
||||
// final drop may cause this exception because, the transfer data can only be accessed
|
||||
// *after* the drop has been accepted, but canImport is called before that
|
||||
|
||||
// just assume that the transferable will be accepted, accept will be called in importData again anyway
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean importData(TransferSupport support) {
|
||||
Transferable transferable = support.getTransferable();
|
||||
|
||||
try {
|
||||
if (accept(transferable)) {
|
||||
handleTransferable(transferable, getTransferAction(support));
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, e.toString(), e);
|
||||
}
|
||||
|
||||
// transferable was not accepted, or transfer failed
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
protected TransferAction getTransferAction(TransferSupport support) {
|
||||
if (support.isDrop()) {
|
||||
return TransferAction.fromDnDConstant(support.getDropAction());
|
||||
}
|
||||
|
||||
// use PUT by default (e.g. clipboard transfers)
|
||||
return TransferAction.PUT;
|
||||
}
|
||||
|
||||
}
|
|
@ -6,9 +6,6 @@ import java.io.File;
|
|||
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.FileTransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.CompositeTransferablePolicy;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.TransferablePolicy;
|
||||
|
||||
|
||||
public class TransferablePolicyFileFilter extends FileFilter {
|
||||
|
@ -32,12 +29,10 @@ public class TransferablePolicyFileFilter extends FileFilter {
|
|||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
if (transferablePolicy instanceof CompositeTransferablePolicy) {
|
||||
CompositeTransferablePolicy multi = (CompositeTransferablePolicy) transferablePolicy;
|
||||
return multi.getDescription(FileTransferablePolicy.class);
|
||||
if (transferablePolicy instanceof FileTransferablePolicy) {
|
||||
return ((FileTransferablePolicy) transferablePolicy).getFileFilterDescription();
|
||||
}
|
||||
|
||||
return transferablePolicy.getDescription();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.transfer;
|
||||
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.dnd.InvalidDnDOperationException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.TransferHandler;
|
||||
import javax.swing.TransferHandler.TransferSupport;
|
||||
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.TransferablePolicy;
|
||||
|
||||
|
||||
public class TransferablePolicyImportHandler implements ImportHandler {
|
||||
|
||||
private final TransferablePolicy transferablePolicy;
|
||||
|
||||
|
||||
public TransferablePolicyImportHandler(TransferablePolicy transferablePolicy) {
|
||||
this.transferablePolicy = transferablePolicy;
|
||||
}
|
||||
|
||||
private boolean canImportCache = false;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canImport(TransferSupport support) {
|
||||
if (support.isDrop())
|
||||
support.setShowDropLocation(false);
|
||||
|
||||
Transferable t = support.getTransferable();
|
||||
|
||||
try {
|
||||
canImportCache = transferablePolicy.accept(t);
|
||||
} catch (InvalidDnDOperationException e) {
|
||||
// for some reason the last transferable has no drop current
|
||||
}
|
||||
|
||||
return canImportCache;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean importData(TransferSupport support) {
|
||||
boolean add = false;
|
||||
|
||||
if (support.isDrop() && (support.getDropAction() == TransferHandler.COPY))
|
||||
add = true;
|
||||
|
||||
Transferable t = support.getTransferable();
|
||||
|
||||
try {
|
||||
transferablePolicy.handleTransferable(t, add);
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -11,7 +11,6 @@ import java.net.URLEncoder;
|
|||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
|
@ -29,9 +28,7 @@ import org.xml.sax.SAXException;
|
|||
|
||||
public class AnidbClient implements EpisodeListClient {
|
||||
|
||||
private final SearchResultCache searchResultCache = new SearchResultCache();
|
||||
|
||||
private final String host = "anidb.net";
|
||||
private static final String host = "anidb.net";
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -48,9 +45,6 @@ public class AnidbClient implements EpisodeListClient {
|
|||
|
||||
@Override
|
||||
public List<SearchResult> search(String searchterm) throws IOException, SAXException {
|
||||
if (searchResultCache.containsKey(searchterm)) {
|
||||
return Collections.singletonList(searchResultCache.get(searchterm));
|
||||
}
|
||||
|
||||
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
|
||||
|
||||
|
@ -91,8 +85,6 @@ public class AnidbClient implements EpisodeListClient {
|
|||
}
|
||||
}
|
||||
|
||||
searchResultCache.addAll(searchResults);
|
||||
|
||||
return searchResults;
|
||||
}
|
||||
|
||||
|
@ -122,7 +114,7 @@ public class AnidbClient implements EpisodeListClient {
|
|||
number = numberFormat.format(Integer.parseInt(number));
|
||||
|
||||
// no seasons for anime
|
||||
episodes.add(new Episode(searchResult.getName(), null, number, title));
|
||||
episodes.add(new Episode(searchResult.getName(), number, title));
|
||||
} catch (NumberFormatException ex) {
|
||||
// ignore node, episode is probably some kind of special (S1, S2, ...)
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@ package net.sourceforge.filebot.web;
|
|||
|
||||
public class Episode {
|
||||
|
||||
private String showName;
|
||||
private String numberOfSeason;
|
||||
private String numberOfEpisode;
|
||||
private String title;
|
||||
private final String showName;
|
||||
private final String numberOfSeason;
|
||||
private final String numberOfEpisode;
|
||||
private final String title;
|
||||
|
||||
|
||||
public Episode(String showname, String numberOfSeason, String numberOfEpisode, String title) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.net.URL;
|
|||
import java.net.URLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -60,8 +61,8 @@ public class HtmlUtil {
|
|||
public static Document getHtmlDocument(URL url, Map<String, String> requestHeaders) throws IOException, SAXException {
|
||||
URLConnection connection = url.openConnection();
|
||||
|
||||
for (String key : requestHeaders.keySet()) {
|
||||
connection.addRequestProperty(key, requestHeaders.get(key));
|
||||
for (Entry<String, String> entry : requestHeaders.entrySet()) {
|
||||
connection.addRequestProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return getHtmlDocument(connection);
|
||||
|
|
|
@ -9,8 +9,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -21,23 +19,10 @@ import redstone.xmlrpc.XmlRpcFault;
|
|||
|
||||
/**
|
||||
* Client for the OpenSubtitles XML-RPC API.
|
||||
*
|
||||
*/
|
||||
public class OpenSubtitlesClient {
|
||||
|
||||
/**
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td>Main server:</td>
|
||||
* <td>http://www.opensubtitles.org/xml-rpc</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Developing tests:</td>
|
||||
* <td>http://dev.opensubtitles.org/xml-rpc</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
private final String url = "http://www.opensubtitles.org/xml-rpc";
|
||||
private static final String url = "http://www.opensubtitles.org/xml-rpc";
|
||||
|
||||
private final String useragent;
|
||||
|
||||
|
@ -60,7 +45,7 @@ public class OpenSubtitlesClient {
|
|||
|
||||
|
||||
/**
|
||||
* Login as user and use english as language
|
||||
* Login as user and use English as language
|
||||
*
|
||||
* @param username
|
||||
* @param password
|
||||
|
@ -77,8 +62,9 @@ public class OpenSubtitlesClient {
|
|||
*
|
||||
* @param username username (blank for anonymous user)
|
||||
* @param password password (blank for anonymous user)
|
||||
* @param language <a href="http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes">ISO639</a>
|
||||
* 2 letter codes as language and later communication will be done in this
|
||||
* @param language <a
|
||||
* href="http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes">ISO639</a>
|
||||
* 2-letter codes as language and later communication will be done in this
|
||||
* language if applicable (error codes and so on).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -116,7 +102,7 @@ public class OpenSubtitlesClient {
|
|||
|
||||
|
||||
/**
|
||||
* Check status whether it is OK or not
|
||||
* Check whether status is OK or not
|
||||
*
|
||||
* @param status status code and message (e.g. 200 OK, 401 Unauthorized, ...)
|
||||
* @throws XmlRpcFault thrown if status code is not OK
|
||||
|
@ -139,9 +125,7 @@ public class OpenSubtitlesClient {
|
|||
XmlRpcClient rpc = new XmlRpcClient(url, false);
|
||||
return rpc.invoke(method, arguments);
|
||||
} catch (MalformedURLException e) {
|
||||
// will never happen
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, "Invalid xml-rpc url: " + url, e);
|
||||
return null;
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,14 +153,15 @@ public class OpenSubtitlesClient {
|
|||
|
||||
Map<String, List<Map<String, String>>> response = (Map<String, List<Map<String, String>>>) invoke("SearchSubtitles", token, searchList);
|
||||
|
||||
ArrayList<OpenSubtitlesSubtitleDescriptor> subs = new ArrayList<OpenSubtitlesSubtitleDescriptor>();
|
||||
List<OpenSubtitlesSubtitleDescriptor> subs = new ArrayList<OpenSubtitlesSubtitleDescriptor>();
|
||||
|
||||
if (!(response.get("data") instanceof List))
|
||||
throw new XmlRpcException("Illegal response: " + response.toString());
|
||||
|
||||
// if there was an error data may not be a list
|
||||
for (Map<String, String> subtitle : response.get("data")) {
|
||||
subs.add(new OpenSubtitlesSubtitleDescriptor(subtitle));
|
||||
try {
|
||||
for (Map<String, String> subtitle : response.get("data")) {
|
||||
subs.add(new OpenSubtitlesSubtitleDescriptor(subtitle));
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
// if the response is an error message, generic types won't match
|
||||
throw new XmlRpcException("Illegal response: " + response.toString(), e);
|
||||
}
|
||||
|
||||
return subs;
|
||||
|
|
|
@ -31,12 +31,14 @@ public class OpenSubtitlesHasher {
|
|||
|
||||
FileChannel fileChannel = new FileInputStream(file).getChannel();
|
||||
|
||||
long head = computeHashForChunk(fileChannel, 0, chunkSizeForFile);
|
||||
long tail = computeHashForChunk(fileChannel, Math.max(size - HASH_CHUNK_SIZE, 0), chunkSizeForFile);
|
||||
|
||||
fileChannel.close();
|
||||
|
||||
return String.format("%016x", size + head + tail);
|
||||
try {
|
||||
long head = computeHashForChunk(fileChannel, 0, chunkSizeForFile);
|
||||
long tail = computeHashForChunk(fileChannel, Math.max(size - HASH_CHUNK_SIZE, 0), chunkSizeForFile);
|
||||
|
||||
return String.format("%016x", size + head + tail);
|
||||
} finally {
|
||||
fileChannel.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import net.sourceforge.filebot.resources.ResourceManager;
|
|||
|
||||
/**
|
||||
* {@link SubtitleClient} for OpenSubtitles.
|
||||
*
|
||||
*/
|
||||
public class OpenSubtitlesSubtitleClient implements SubtitleClient {
|
||||
|
||||
|
@ -102,7 +101,7 @@ public class OpenSubtitlesSubtitleClient implements SubtitleClient {
|
|||
|
||||
private class LogoutTimer {
|
||||
|
||||
private final long LOGOUT_DELAY = 12 * 60 * 1000; // 12 minutes
|
||||
private static final long LOGOUT_DELAY = 12 * 60 * 1000; // 12 minutes
|
||||
|
||||
private Timer daemon = null;
|
||||
private LogoutTimerTask currentTimerTask = null;
|
||||
|
|
|
@ -4,6 +4,7 @@ package net.sourceforge.filebot.web;
|
|||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
@ -58,7 +59,7 @@ public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor {
|
|||
|
||||
|
||||
public OpenSubtitlesSubtitleDescriptor(Map<String, String> properties) {
|
||||
this.properties = properties;
|
||||
this.properties = new HashMap<String, String>(properties);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
|
||||
package net.sourceforge.filebot.web;
|
||||
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
public class SearchResultCache {
|
||||
|
||||
private final ConcurrentHashMap<String, SearchResult> cache = new ConcurrentHashMap<String, SearchResult>();
|
||||
|
||||
|
||||
public boolean containsKey(String name) {
|
||||
return cache.containsKey(key(name));
|
||||
}
|
||||
|
||||
|
||||
public SearchResult get(String name) {
|
||||
return cache.get(key(name));
|
||||
}
|
||||
|
||||
|
||||
public void add(SearchResult searchResult) {
|
||||
cache.putIfAbsent(key(searchResult.getName()), searchResult);
|
||||
}
|
||||
|
||||
|
||||
public void addAll(Iterable<SearchResult> searchResults) {
|
||||
for (SearchResult searchResult : searchResults) {
|
||||
add(searchResult);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String key(String name) {
|
||||
return name.toLowerCase();
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,6 @@ import java.net.URI;
|
|||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -34,12 +33,10 @@ import org.xml.sax.SAXException;
|
|||
|
||||
public class SubsceneSubtitleClient implements SubtitleClient {
|
||||
|
||||
private final SearchResultCache searchResultCache = new SearchResultCache();
|
||||
private static final String host = "subscene.com";
|
||||
|
||||
private final Map<String, Integer> languageFilterMap = new ConcurrentHashMap<String, Integer>(50);
|
||||
|
||||
private final String host = "subscene.com";
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -55,9 +52,6 @@ public class SubsceneSubtitleClient implements SubtitleClient {
|
|||
|
||||
@Override
|
||||
public List<SearchResult> search(String searchterm) throws IOException, SAXException {
|
||||
if (searchResultCache.containsKey(searchterm)) {
|
||||
return Collections.singletonList(searchResultCache.get(searchterm));
|
||||
}
|
||||
|
||||
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
|
||||
|
||||
|
@ -103,8 +97,6 @@ public class SubsceneSubtitleClient implements SubtitleClient {
|
|||
}
|
||||
}
|
||||
|
||||
searchResultCache.addAll(searchResults);
|
||||
|
||||
return searchResults;
|
||||
}
|
||||
|
||||
|
@ -224,7 +216,7 @@ public class SubsceneSubtitleClient implements SubtitleClient {
|
|||
Matcher matcher = hrefPattern.matcher(href);
|
||||
|
||||
if (!matcher.matches())
|
||||
throw new IllegalArgumentException("Cannot extract download parameters: " + href);
|
||||
throw new IllegalArgumentException("Cannot parse download parameters: " + href);
|
||||
|
||||
String subtitleId = matcher.group(1);
|
||||
String typeId = matcher.group(2);
|
||||
|
|
|
@ -10,7 +10,6 @@ import java.net.URL;
|
|||
import java.net.URLEncoder;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
|
@ -33,9 +32,7 @@ import org.xml.sax.SAXException;
|
|||
|
||||
public class TVDotComClient implements EpisodeListClient {
|
||||
|
||||
private final SearchResultCache searchResultCache = new SearchResultCache();
|
||||
|
||||
private final String host = "www.tv.com";
|
||||
private static final String host = "www.tv.com";
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -58,9 +55,6 @@ public class TVDotComClient implements EpisodeListClient {
|
|||
|
||||
@Override
|
||||
public List<SearchResult> search(String searchterm) throws IOException, SAXException {
|
||||
if (searchResultCache.containsKey(searchterm)) {
|
||||
return Collections.singletonList(searchResultCache.get(searchterm));
|
||||
}
|
||||
|
||||
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
|
||||
|
||||
|
@ -81,8 +75,6 @@ public class TVDotComClient implements EpisodeListClient {
|
|||
}
|
||||
}
|
||||
|
||||
searchResultCache.addAll(searchResults);
|
||||
|
||||
return searchResults;
|
||||
}
|
||||
|
||||
|
@ -99,7 +91,7 @@ public class TVDotComClient implements EpisodeListClient {
|
|||
List<Future<List<Episode>>> futures = new ArrayList<Future<List<Episode>>>(seasonCount);
|
||||
|
||||
if (seasonCount > 1) {
|
||||
// max. 12 threads so we don't get too many concurrent downloads
|
||||
// max. 12 threads so we don't get too many concurrent connections
|
||||
ExecutorService executor = Executors.newFixedThreadPool(Math.min(seasonCount - 1, 12));
|
||||
|
||||
// we already have the document for season 1, start with season 2
|
||||
|
@ -111,7 +103,7 @@ public class TVDotComClient implements EpisodeListClient {
|
|||
executor.shutdown();
|
||||
}
|
||||
|
||||
List<Episode> episodes = new ArrayList<Episode>(150);
|
||||
List<Episode> episodes = new ArrayList<Episode>(25 * seasonCount);
|
||||
|
||||
// get episode list from season 1 document
|
||||
episodes.addAll(getEpisodeList(searchResult, 1, dom));
|
||||
|
|
|
@ -6,7 +6,6 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
@ -23,9 +22,7 @@ import org.xml.sax.SAXException;
|
|||
|
||||
public class TVRageClient implements EpisodeListClient {
|
||||
|
||||
private final SearchResultCache searchResultCache = new SearchResultCache();
|
||||
|
||||
private final String host = "www.tvrage.com";
|
||||
private static final String host = "www.tvrage.com";
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -48,9 +45,6 @@ public class TVRageClient implements EpisodeListClient {
|
|||
|
||||
@Override
|
||||
public List<SearchResult> search(String searchterm) throws SAXException, IOException, ParserConfigurationException {
|
||||
if (searchResultCache.containsKey(searchterm)) {
|
||||
return Collections.singletonList(searchResultCache.get(searchterm));
|
||||
}
|
||||
|
||||
String searchUri = String.format("http://" + host + "/feeds/search.php?show=" + URLEncoder.encode(searchterm, "UTF-8"));
|
||||
|
||||
|
@ -68,8 +62,6 @@ public class TVRageClient implements EpisodeListClient {
|
|||
searchResults.add(new TVRageSearchResult(name, showid, link));
|
||||
}
|
||||
|
||||
searchResultCache.addAll(searchResults);
|
||||
|
||||
return searchResults;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.nio.charset.Charset;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -35,7 +36,7 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
|
|||
DONE
|
||||
}
|
||||
|
||||
private final int BUFFER_SIZE = 4 * 1024;
|
||||
private static final int BUFFER_SIZE = 4 * 1024;
|
||||
|
||||
private URL url;
|
||||
private ByteBuffer postdata;
|
||||
|
@ -175,15 +176,15 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
|
|||
|
||||
int i = 0;
|
||||
|
||||
for (String key : parameters.keySet()) {
|
||||
for (Entry<String, String> entry : parameters.entrySet()) {
|
||||
if (i > 0)
|
||||
sb.append("&");
|
||||
|
||||
sb.append(key);
|
||||
sb.append(entry.getKey());
|
||||
sb.append("=");
|
||||
|
||||
try {
|
||||
sb.append(URLEncoder.encode(parameters.get(key), "UTF-8"));
|
||||
sb.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// will never happen
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
|
|
|
@ -16,9 +16,9 @@ public class FileUtil {
|
|||
|
||||
public static String formatSize(long size) {
|
||||
if (size >= MEGA)
|
||||
return String.format("%d MB", (double) size / MEGA);
|
||||
return String.format("%d MB", size / MEGA);
|
||||
else if (size >= KILO)
|
||||
return String.format("%d KB", (double) size / KILO);
|
||||
return String.format("%d KB", size / KILO);
|
||||
else
|
||||
return String.format("%d Byte", size);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
package net.sourceforge.filebot;
|
||||
package net.sourceforge.tuned;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
@ -9,7 +9,6 @@ import ca.odell.glazedlists.event.ListEvent;
|
|||
import ca.odell.glazedlists.event.ListEventListener;
|
||||
|
||||
|
||||
//TODO: testcase, class doc
|
||||
public class ListChangeSynchronizer<E> implements ListEventListener<E> {
|
||||
|
||||
private final List<E> target;
|
|
@ -19,19 +19,7 @@ public class MessageBus {
|
|||
return instance;
|
||||
}
|
||||
|
||||
private final Map<String, List<MessageHandler>> handlers = new HashMap<String, List<MessageHandler>>() {
|
||||
|
||||
@Override
|
||||
public List<MessageHandler> get(Object key) {
|
||||
return super.get(key.toString().toLowerCase());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<MessageHandler> put(String key, List<MessageHandler> value) {
|
||||
return super.put(key.toLowerCase(), value);
|
||||
}
|
||||
};
|
||||
private final Map<String, List<MessageHandler>> handlers = new HashMap<String, List<MessageHandler>>();
|
||||
|
||||
|
||||
private MessageBus() {
|
||||
|
@ -40,11 +28,12 @@ public class MessageBus {
|
|||
|
||||
|
||||
public synchronized void addMessageHandler(String topic, MessageHandler handler) {
|
||||
List<MessageHandler> list = handlers.get(topic);
|
||||
|
||||
List<MessageHandler> list = handlers.get(topic.toLowerCase());
|
||||
|
||||
if (list == null) {
|
||||
list = new ArrayList<MessageHandler>(3);
|
||||
handlers.put(topic, list);
|
||||
handlers.put(topic.toLowerCase(), list);
|
||||
}
|
||||
|
||||
list.add(handler);
|
||||
|
@ -52,7 +41,7 @@ public class MessageBus {
|
|||
|
||||
|
||||
public synchronized void removeMessageHandler(String topic, MessageHandler handler) {
|
||||
List<MessageHandler> list = handlers.get(topic);
|
||||
List<MessageHandler> list = handlers.get(topic.toLowerCase());
|
||||
|
||||
if (list != null) {
|
||||
list.remove(handler);
|
||||
|
@ -61,7 +50,7 @@ public class MessageBus {
|
|||
|
||||
|
||||
public synchronized MessageHandler[] getHandlers(String topic) {
|
||||
List<MessageHandler> list = handlers.get(topic);
|
||||
List<MessageHandler> list = handlers.get(topic.toLowerCase());
|
||||
|
||||
if (list == null)
|
||||
return new MessageHandler[0];
|
||||
|
@ -70,17 +59,15 @@ public class MessageBus {
|
|||
}
|
||||
|
||||
|
||||
public void publish(final String topic, final String... messages) {
|
||||
|
||||
public void publish(final String topic, final Object... messages) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (MessageHandler handler : getHandlers(topic)) {
|
||||
handler.handle(topic, messages);
|
||||
for (MessageHandler handler : getHandlers(topic.toLowerCase())) {
|
||||
handler.handle(topic.toLowerCase(), messages);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
package net.sourceforge.tuned;
|
||||
|
||||
|
||||
|
||||
|
||||
public interface MessageHandler {
|
||||
|
||||
public void handle(String topic, String... messages);
|
||||
public void handle(String topic, Object... messages);
|
||||
|
||||
}
|
||||
|
|
|
@ -44,10 +44,14 @@ public class PreferencesList<T> extends AbstractList<T> {
|
|||
}
|
||||
|
||||
|
||||
//TODO: assert invalid index
|
||||
@Override
|
||||
public void add(int index, T element) {
|
||||
copy(index, index + 1, size() - index);
|
||||
int size = size();
|
||||
|
||||
if (index > size)
|
||||
throw new IndexOutOfBoundsException(String.format("Index: %d, Size: %d", index, size));
|
||||
|
||||
copy(index, index + 1, size - index);
|
||||
|
||||
setImpl(index, element);
|
||||
}
|
||||
|
@ -99,12 +103,6 @@ public class PreferencesList<T> extends AbstractList<T> {
|
|||
}
|
||||
|
||||
|
||||
public void set(List<T> data) {
|
||||
clear();
|
||||
addAll(data);
|
||||
}
|
||||
|
||||
|
||||
public static <T> PreferencesList<T> map(Preferences prefs, Class<T> type) {
|
||||
return new PreferencesList<T>(PreferencesMap.map(prefs, type));
|
||||
}
|
||||
|
@ -113,4 +111,5 @@ public class PreferencesList<T> extends AbstractList<T> {
|
|||
public static <T> PreferencesList<T> map(Preferences prefs, Adapter<T> adapter) {
|
||||
return new PreferencesList<T>(PreferencesMap.map(prefs, adapter));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -81,12 +81,6 @@ public class PreferencesMap<T> implements Map<String, T> {
|
|||
}
|
||||
|
||||
|
||||
public void set(Map<String, T> data) {
|
||||
clear();
|
||||
putAll(data);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
if (key instanceof String) {
|
||||
|
@ -134,8 +128,8 @@ public class PreferencesMap<T> implements Map<String, T> {
|
|||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends T> map) {
|
||||
for (String key : map.keySet()) {
|
||||
put(key, map.get(key));
|
||||
for (Map.Entry<? extends String, ? extends T> entry : map.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@ public class TemporaryFolder {
|
|||
|
||||
public static TemporaryFolder getFolder(String name) {
|
||||
synchronized (folders) {
|
||||
TemporaryFolder folder = folders.get(name);
|
||||
TemporaryFolder folder = folders.get(name.toLowerCase());
|
||||
|
||||
if (folder == null) {
|
||||
folder = new TemporaryFolder(new File(tmpdir, name));
|
||||
folders.put(name, folder);
|
||||
folders.put(name.toLowerCase(), folder);
|
||||
}
|
||||
|
||||
return folder;
|
||||
|
@ -63,14 +63,12 @@ public class TemporaryFolder {
|
|||
* @throws IOException if an I/O error occurred
|
||||
*/
|
||||
public File createFile(String name) throws IOException {
|
||||
if (!root.exists()) {
|
||||
root.mkdir();
|
||||
}
|
||||
|
||||
File file = new File(root, name);
|
||||
File file = new File(getFolder(), name);
|
||||
file.createNewFile();
|
||||
|
||||
return file;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,16 +85,12 @@ public class TemporaryFolder {
|
|||
* @see File#createTempFile(String, String)
|
||||
*/
|
||||
public File createFile(String prefix, String suffix) throws IOException {
|
||||
if (!root.exists()) {
|
||||
root.mkdir();
|
||||
}
|
||||
|
||||
return File.createTempFile(prefix, suffix, root);
|
||||
return File.createTempFile(prefix, suffix, getFolder());
|
||||
}
|
||||
|
||||
|
||||
public boolean deleteFile(String name) {
|
||||
return new File(root, name).delete();
|
||||
return new File(getFolder(), name).delete();
|
||||
}
|
||||
|
||||
|
||||
|
@ -106,20 +100,15 @@ public class TemporaryFolder {
|
|||
* @return the {@link File} object for this {@link TemporaryFolder}
|
||||
*/
|
||||
public File getFolder() {
|
||||
if (!root.exists())
|
||||
root.mkdirs();
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
public TemporaryFolder createFolder(String name) {
|
||||
if (!root.exists()) {
|
||||
root.mkdir();
|
||||
}
|
||||
|
||||
TemporaryFolder folder = new TemporaryFolder(new File(root, name));
|
||||
|
||||
folder.root.mkdir();
|
||||
|
||||
return folder;
|
||||
return new TemporaryFolder(new File(getFolder(), name));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
package net.sourceforge.tuned.ui;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.swing.ListModel;
|
||||
import javax.swing.event.ListDataListener;
|
||||
|
||||
|
||||
public class ArrayListModel implements ListModel {
|
||||
|
||||
private final ArrayList<Object> data;
|
||||
|
||||
|
||||
public ArrayListModel(Collection<? extends Object> data) {
|
||||
this.data = new ArrayList<Object>(data);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int index) {
|
||||
return data.get(index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
// ignore, model is unmodifiable
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void removeListDataListener(ListDataListener l) {
|
||||
// ignore, model is unmodifiable
|
||||
}
|
||||
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
|
||||
package net.sourceforge.tuned.ui;
|
||||
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.RadialGradientPaint;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.MultipleGradientPaint.CycleMethod;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
import javax.swing.border.Border;
|
||||
|
||||
|
||||
public class FancyBorder implements Border {
|
||||
|
||||
private int borderWidth;
|
||||
|
||||
private float[] dist;
|
||||
private Color[] colors;
|
||||
|
||||
private float radius;
|
||||
|
||||
|
||||
public FancyBorder(int width, Color... colors) {
|
||||
this.borderWidth = width;
|
||||
|
||||
this.dist = new float[colors.length];
|
||||
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
this.dist[i] = (1.0f / colors.length) * i;
|
||||
}
|
||||
|
||||
this.colors = colors;
|
||||
|
||||
this.radius = 100;
|
||||
}
|
||||
|
||||
|
||||
public FancyBorder(int width, float[] dist, Color[] colors, float radius) {
|
||||
this.borderWidth = width;
|
||||
this.dist = dist;
|
||||
this.colors = colors;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets(Component c) {
|
||||
|
||||
int horizontalOffset = 8;
|
||||
return new Insets(borderWidth, borderWidth + horizontalOffset, borderWidth, borderWidth + horizontalOffset);
|
||||
}
|
||||
|
||||
|
||||
@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;
|
||||
|
||||
float arch = Math.min(width, height) / 2;
|
||||
|
||||
Shape shape = new RoundRectangle2D.Float(x + borderWidth, y + borderWidth, width - borderWidth * 2, height - borderWidth * 2, arch, arch);
|
||||
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
Point2D center = new Point2D.Float(width, 0);
|
||||
g2d.setPaint(new RadialGradientPaint(center, radius, dist, colors, CycleMethod.REFLECT));
|
||||
|
||||
g2d.setStroke(new BasicStroke(borderWidth));
|
||||
|
||||
g2d.draw(shape);
|
||||
}
|
||||
}
|
|
@ -13,10 +13,12 @@ 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;
|
||||
|
@ -24,8 +26,10 @@ import javax.swing.border.EmptyBorder;
|
|||
|
||||
public class IconViewPanel extends JPanel {
|
||||
|
||||
private final JList list = new JList(new SimpleListModel());
|
||||
private final JLabel title = new JLabel();
|
||||
private final JList list = new JList(createModel());
|
||||
|
||||
private final JLabel titleLabel = new JLabel();
|
||||
|
||||
private final JPanel headerPanel = new JPanel(new BorderLayout());
|
||||
|
||||
|
||||
|
@ -35,10 +39,10 @@ public class IconViewPanel extends JPanel {
|
|||
list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
|
||||
list.setVisibleRowCount(-1);
|
||||
|
||||
title.setFont(title.getFont().deriveFont(Font.BOLD));
|
||||
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD));
|
||||
|
||||
headerPanel.setOpaque(false);
|
||||
headerPanel.add(title, BorderLayout.WEST);
|
||||
headerPanel.add(titleLabel, BorderLayout.WEST);
|
||||
|
||||
setBackground(list.getBackground());
|
||||
|
||||
|
@ -53,13 +57,23 @@ public class IconViewPanel extends JPanel {
|
|||
}
|
||||
|
||||
|
||||
protected ListModel createModel() {
|
||||
return new DefaultListModel();
|
||||
}
|
||||
|
||||
|
||||
public JPanel getHeaderPanel() {
|
||||
return headerPanel;
|
||||
}
|
||||
|
||||
|
||||
public void setTitle(String text) {
|
||||
title.setText(text);
|
||||
titleLabel.setText(text);
|
||||
}
|
||||
|
||||
|
||||
public String getTitle() {
|
||||
return titleLabel.getText();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public class ProgressDialog extends JDialog {
|
|||
setLocation(TunedUtil.getPreferredLocation(this));
|
||||
|
||||
// Shortcut Escape
|
||||
TunedUtil.registerActionForKeystroke(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
|
||||
TunedUtil.putActionForKeystroke(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,25 +17,25 @@ import javax.swing.KeyStroke;
|
|||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.ComboBoxUI;
|
||||
import javax.swing.plaf.basic.BasicComboBoxUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
|
||||
|
||||
public class SelectButtonTextField<T> extends JPanel {
|
||||
|
||||
private SelectButton<T> selectButton;
|
||||
private SelectButton<T> selectButton = new SelectButton<T>();
|
||||
|
||||
private ComboBoxTextField editor = new ComboBoxTextField();
|
||||
|
||||
private Color borderColor = new Color(0xA4A4A4);
|
||||
|
||||
|
||||
public SelectButtonTextField() {
|
||||
setLayout(new BorderLayout(0, 0));
|
||||
|
||||
selectButton = new SelectButton<T>();
|
||||
selectButton.addActionListener(textFieldFocusOnClick);
|
||||
|
||||
Color borderColor = new Color(0xA4A4A4);
|
||||
|
||||
Border lineBorder = BorderFactory.createLineBorder(borderColor, 1);
|
||||
Border matteBorder = BorderFactory.createMatteBorder(1, 0, 1, 1, borderColor);
|
||||
Border emptyBorder = BorderFactory.createEmptyBorder(0, 3, 0, 3);
|
||||
|
@ -48,8 +48,8 @@ public class SelectButtonTextField<T> extends JPanel {
|
|||
|
||||
setPreferredSize(new Dimension(280, 22));
|
||||
|
||||
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinClientAction(-1));
|
||||
TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinClientAction(1));
|
||||
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinClientAction(-1));
|
||||
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinClientAction(1));
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,7 +57,7 @@ public class SelectButtonTextField<T> extends JPanel {
|
|||
* Convenience method for <code>getEditor().getSelectedItem().toString()</code>
|
||||
*/
|
||||
public String getText() {
|
||||
return getEditor().getSelectedItem().toString();
|
||||
return editor.getText();
|
||||
}
|
||||
|
||||
|
||||
|
@ -116,6 +116,28 @@ public class SelectButtonTextField<T> extends JPanel {
|
|||
// don't reset the UI delegate if laf is changed, or we use our custom ui
|
||||
}
|
||||
|
||||
|
||||
public String getText() {
|
||||
return ((TextFieldComboBoxUI) getUI()).getEditor().getText();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
// super.actionPerformed(e);
|
||||
// Object newItem = getEditor().getItem();
|
||||
// setPopupVisible(false);
|
||||
// getModel().setSelectedItem(newItem);
|
||||
// String oldCommand = getActionCommand();
|
||||
// setActionCommand("comboBoxEdited");
|
||||
//
|
||||
//TODO sysout
|
||||
System.out.println("combobox: " + e);
|
||||
// for (ActionListener actionListener : getActionListeners()) {
|
||||
// actionListener.actionPerformed(e);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,14 +145,48 @@ public class SelectButtonTextField<T> extends JPanel {
|
|||
|
||||
@Override
|
||||
protected JButton createArrowButton() {
|
||||
JButton b = new JButton(ResourceManager.getIcon("action.list"));
|
||||
|
||||
b.setContentAreaFilled(false);
|
||||
b.setFocusable(false);
|
||||
|
||||
return b;
|
||||
return new JButton(ResourceManager.getIcon("action.list"));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void configureArrowButton() {
|
||||
super.configureArrowButton();
|
||||
|
||||
arrowButton.setContentAreaFilled(false);
|
||||
arrowButton.setFocusable(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void configureEditor() {
|
||||
editor.setEnabled(comboBox.isEnabled());
|
||||
editor.setFocusable(comboBox.isFocusable());
|
||||
editor.setFont(comboBox.getFont());
|
||||
|
||||
editor.addFocusListener(createFocusListener());
|
||||
}
|
||||
|
||||
|
||||
public JTextComponent getEditor() {
|
||||
return (JTextComponent) editor;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected FocusListener createFocusListener() {
|
||||
// return new FocusHandler() {
|
||||
//
|
||||
// /**
|
||||
// * Prevent action events from being fired on focusLost.
|
||||
// */
|
||||
// @Override
|
||||
// public void focusLost(FocusEvent e) {
|
||||
// if (isPopupVisible(comboBox))
|
||||
// setPopupVisible(comboBox, false);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package net.sourceforge.tuned.ui;
|
|||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
|
@ -15,11 +16,11 @@ import net.sourceforge.tuned.ExceptionUtil;
|
|||
public class SimpleLabelProvider<T> implements LabelProvider<T> {
|
||||
|
||||
private final Method getIconMethod;
|
||||
private final Method getNameMethod;
|
||||
private final Method getTextMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Same as <code>new SimpleLabelProvider<T>(T.class)</code>.
|
||||
* Factory method for {@link #SimpleLabelProvider(Class)}.
|
||||
*
|
||||
* @return new <code>LabelProvider</code>
|
||||
*/
|
||||
|
@ -29,13 +30,15 @@ public class SimpleLabelProvider<T> implements LabelProvider<T> {
|
|||
|
||||
|
||||
/**
|
||||
* Create a new LabelProvider which will use the <code>getName</code> and
|
||||
* <code>getIcon</code> method of the given class.
|
||||
* Create a new LabelProvider which will use the <code>getText</code>, <code>getName</code>
|
||||
* or <code>toString</code> method for text and the <code>getIcon</code> method for the
|
||||
* icon.
|
||||
*
|
||||
* @param type a class that has a <code>getName</code> and a <code>getIcon</code> method
|
||||
* @param type a class that has one of the text methods and the icon method
|
||||
*/
|
||||
public SimpleLabelProvider(Class<T> type) {
|
||||
this(type, "getName", "getIcon");
|
||||
getTextMethod = findAnyMethod(type, "getText", "getName", "toString");
|
||||
getIconMethod = findAnyMethod(type, "getIcon");
|
||||
}
|
||||
|
||||
|
||||
|
@ -43,23 +46,32 @@ public class SimpleLabelProvider<T> implements LabelProvider<T> {
|
|||
* 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 getText a method name such as <code>getText</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);
|
||||
public SimpleLabelProvider(Class<T> type, String getText, String getIcon) {
|
||||
getTextMethod = findAnyMethod(type, getText);
|
||||
getIconMethod = findAnyMethod(type, getIcon);
|
||||
}
|
||||
|
||||
|
||||
private Method findAnyMethod(Class<T> type, String... names) {
|
||||
for (String name : names) {
|
||||
try {
|
||||
return type.getMethod(name);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// try next method name
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Method not found: " + Arrays.toString(names));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getText(T value) {
|
||||
try {
|
||||
return (String) getNameMethod.invoke(value);
|
||||
return (String) getTextMethod.invoke(value);
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUtil.asRuntimeException(e);
|
||||
}
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
|
||||
package net.sourceforge.tuned.ui;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.AbstractListModel;
|
||||
|
||||
|
||||
public class SimpleListModel extends AbstractListModel {
|
||||
|
||||
private final List<Object> list;
|
||||
|
||||
|
||||
public SimpleListModel() {
|
||||
list = Collections.synchronizedList(new ArrayList<Object>());
|
||||
}
|
||||
|
||||
|
||||
public SimpleListModel(Collection<? extends Object> collection) {
|
||||
list = Collections.synchronizedList(new ArrayList<Object>(collection));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
|
||||
public void add(Object object) {
|
||||
int index = list.size();
|
||||
list.add(object);
|
||||
fireIntervalAdded(this, index, index);
|
||||
}
|
||||
|
||||
|
||||
public void add(int index, Object object) {
|
||||
list.add(index, object);
|
||||
fireIntervalAdded(this, index, index);
|
||||
}
|
||||
|
||||
|
||||
public void addAll(Collection<? extends Object> c) {
|
||||
int begin = list.size();
|
||||
list.addAll(c);
|
||||
int end = list.size() - 1;
|
||||
|
||||
if (end >= 0) {
|
||||
fireIntervalAdded(this, begin, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
int end = list.size() - 1;
|
||||
list.clear();
|
||||
|
||||
if (end >= 0) {
|
||||
fireIntervalRemoved(this, 0, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return list.contains(o);
|
||||
}
|
||||
|
||||
|
||||
public int indexOf(Object o) {
|
||||
return list.indexOf(o);
|
||||
}
|
||||
|
||||
|
||||
public boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
public int lastIndexOf(Object o) {
|
||||
return list.lastIndexOf(o);
|
||||
}
|
||||
|
||||
|
||||
public Object remove(int index) {
|
||||
Object object = list.remove(index);
|
||||
|
||||
fireIntervalRemoved(this, index, index);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
public void remove(Object object) {
|
||||
synchronized (list) {
|
||||
remove(indexOf(object));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void sort() {
|
||||
synchronized (list) {
|
||||
Collections.sort(list, null);
|
||||
}
|
||||
|
||||
fireContentsChanged(this, 0, list.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
public List<? extends Object> getCopy() {
|
||||
synchronized (list) {
|
||||
return new ArrayList<Object>(list);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void set(Collection<? extends Object> c) {
|
||||
int end = Math.max(list.size(), c.size()) - 1;
|
||||
|
||||
synchronized (list) {
|
||||
list.clear();
|
||||
list.addAll(c);
|
||||
}
|
||||
|
||||
if (end >= 0) {
|
||||
fireContentsChanged(this, 0, end);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
|
||||
package net.sourceforge.tuned.ui;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
|
||||
public class TextCompletion {
|
||||
|
||||
private Set<String> completionTerms = Collections.synchronizedSet(new TreeSet<String>(String.CASE_INSENSITIVE_ORDER));
|
||||
|
||||
private int completionStartLength = 1;
|
||||
|
||||
private JTextComponent component;
|
||||
|
||||
|
||||
public TextCompletion(JTextComponent component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
|
||||
public void hook() {
|
||||
component.getDocument().addDocumentListener(documentListener);
|
||||
}
|
||||
|
||||
|
||||
public void unhook() {
|
||||
component.getDocument().removeDocumentListener(documentListener);
|
||||
}
|
||||
|
||||
|
||||
public void addTerm(String term) {
|
||||
completionTerms.add(term);
|
||||
}
|
||||
|
||||
|
||||
public void addTerms(Collection<String> terms) {
|
||||
completionTerms.addAll(terms);
|
||||
}
|
||||
|
||||
|
||||
public void removeTerm(String term) {
|
||||
completionTerms.remove(term);
|
||||
}
|
||||
|
||||
|
||||
public void removeTerms(Collection<String> terms) {
|
||||
completionTerms.removeAll(terms);
|
||||
}
|
||||
|
||||
|
||||
public void setStartLength(int codeCompletionStartLength) {
|
||||
this.completionStartLength = codeCompletionStartLength;
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getTerms() {
|
||||
return completionTerms;
|
||||
}
|
||||
|
||||
|
||||
public int getStartLength() {
|
||||
return completionStartLength;
|
||||
}
|
||||
|
||||
|
||||
private void complete() {
|
||||
String text = component.getText();
|
||||
|
||||
if (text.length() < completionStartLength)
|
||||
return;
|
||||
|
||||
String completionTerm = findCompletionTerm(text);
|
||||
|
||||
if (completionTerm == null)
|
||||
return;
|
||||
|
||||
component.setText(completionTerm);
|
||||
component.select(text.length(), completionTerm.length());
|
||||
}
|
||||
|
||||
|
||||
private String findCompletionTerm(String text) {
|
||||
for (String completionTerm : completionTerms) {
|
||||
if (text.length() >= completionTerm.length())
|
||||
continue;
|
||||
|
||||
String compareTerm = completionTerm.substring(0, text.length());
|
||||
|
||||
if (text.equalsIgnoreCase(compareTerm))
|
||||
return completionTerm;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private final DocumentListener documentListener = new DocumentListener() {
|
||||
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
}
|
||||
|
||||
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
SwingUtilities.invokeLater(doComplete);
|
||||
}
|
||||
|
||||
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final Runnable doComplete = new Runnable() {
|
||||
|
||||
public void run() {
|
||||
complete();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -13,20 +13,24 @@ import java.awt.image.BufferedImage;
|
|||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.Timer;
|
||||
|
||||
|
||||
public class TunedUtil {
|
||||
|
||||
private TunedUtil() {
|
||||
// hide constructor
|
||||
public static void checkEventDispatchThread() {
|
||||
if (!SwingUtilities.isEventDispatchThread()) {
|
||||
throw new IllegalStateException("Method must be accessed from the Swing Event Dispatch Thread, but was called on Thread \"" + Thread.currentThread().getName() + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void registerActionForKeystroke(JComponent component, KeyStroke keystroke, Action action) {
|
||||
public static void putActionForKeystroke(JComponent component, KeyStroke keystroke, Action action) {
|
||||
Integer key = action.hashCode();
|
||||
component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(keystroke, key);
|
||||
component.getActionMap().put(key, action);
|
||||
|
@ -47,10 +51,9 @@ public class TunedUtil {
|
|||
|
||||
|
||||
public static Image getImage(Icon icon) {
|
||||
//TODO uncomment
|
||||
// if (icon instanceof ImageIcon) {
|
||||
// return ((ImageIcon) icon).getImage();
|
||||
// }
|
||||
if (icon instanceof ImageIcon) {
|
||||
return ((ImageIcon) icon).getImage();
|
||||
}
|
||||
|
||||
BufferedImage image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
|
@ -78,4 +81,9 @@ public class TunedUtil {
|
|||
return timer;
|
||||
}
|
||||
|
||||
|
||||
private TunedUtil() {
|
||||
// hide constructor
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,17 +5,12 @@ package net.sourceforge.tuned.ui.notification;
|
|||
import javax.swing.SwingConstants;
|
||||
|
||||
|
||||
class Factor extends Object implements SwingConstants {
|
||||
class Factor implements SwingConstants {
|
||||
|
||||
public double fx = 0;
|
||||
public double fy = 0;
|
||||
public final double fx;
|
||||
public final double fy;
|
||||
|
||||
|
||||
public Factor() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public Factor(double fx, double fy) {
|
||||
this.fx = fx;
|
||||
this.fy = fy;
|
||||
|
|
|
@ -6,13 +6,15 @@
|
|||
package net.sourceforge.tuned.ui.notification;
|
||||
|
||||
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
import net.sourceforge.tuned.ui.TunedUtil;
|
||||
|
||||
|
||||
public class NotificationManager {
|
||||
|
||||
private NotificationLayout layout;
|
||||
private final NotificationLayout layout;
|
||||
|
||||
|
||||
public NotificationManager() {
|
||||
|
@ -21,45 +23,25 @@ public class NotificationManager {
|
|||
|
||||
|
||||
public NotificationManager(NotificationLayout layout) {
|
||||
setLayoutManager(layout);
|
||||
}
|
||||
|
||||
|
||||
public void setLayoutManager(NotificationLayout layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
|
||||
public NotificationLayout getLayoutManager() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
||||
public void show(NotificationWindow notification) {
|
||||
if (layout == null)
|
||||
return;
|
||||
TunedUtil.checkEventDispatchThread();
|
||||
|
||||
notification.addComponentListener(new RemoveListener(layout));
|
||||
notification.addWindowListener(new RemoveListener());
|
||||
layout.add(notification);
|
||||
|
||||
notification.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
private static class RemoveListener extends ComponentAdapter {
|
||||
private class RemoveListener extends WindowAdapter {
|
||||
|
||||
private NotificationLayout layout;
|
||||
|
||||
|
||||
public RemoveListener(NotificationLayout layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
NotificationWindow window = (NotificationWindow) e.getSource();
|
||||
layout.remove(window);
|
||||
window.dispose();
|
||||
public void windowClosing(WindowEvent e) {
|
||||
layout.remove((NotificationWindow) e.getWindow());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.awt.event.ComponentEvent;
|
|||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
import javax.swing.JWindow;
|
||||
import javax.swing.Timer;
|
||||
|
@ -21,7 +22,7 @@ import net.sourceforge.tuned.ui.TunedUtil;
|
|||
|
||||
public class NotificationWindow extends JWindow {
|
||||
|
||||
private int timeout;
|
||||
private final int timeout;
|
||||
|
||||
|
||||
public NotificationWindow(Window owner, int timeout) {
|
||||
|
@ -35,17 +36,12 @@ public class NotificationWindow extends JWindow {
|
|||
|
||||
setAlwaysOnTop(true);
|
||||
|
||||
if (closeOnClick)
|
||||
if (closeOnClick) {
|
||||
getGlassPane().addMouseListener(clickListener);
|
||||
getGlassPane().setVisible(true);
|
||||
}
|
||||
|
||||
getGlassPane().setVisible(true);
|
||||
|
||||
addComponentListener(visibleListener);
|
||||
}
|
||||
|
||||
|
||||
public NotificationWindow(int timeout) {
|
||||
this((Window) null, timeout);
|
||||
addComponentListener(closeOnTimeout);
|
||||
}
|
||||
|
||||
|
||||
|
@ -54,21 +50,23 @@ public class NotificationWindow extends JWindow {
|
|||
}
|
||||
|
||||
|
||||
public NotificationWindow() {
|
||||
this((Window) null, -1);
|
||||
}
|
||||
|
||||
|
||||
public final void close() {
|
||||
TunedUtil.checkEventDispatchThread();
|
||||
|
||||
// window events are not fired automatically, required for layout updates
|
||||
processWindowEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
|
||||
|
||||
setVisible(false);
|
||||
|
||||
// component hidden is not fired automatically
|
||||
// component events are not fired automatically, used to cancel timeout timer
|
||||
processComponentEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN));
|
||||
|
||||
dispose();
|
||||
}
|
||||
|
||||
private ComponentListener visibleListener = new ComponentAdapter() {
|
||||
private final ComponentListener closeOnTimeout = new ComponentAdapter() {
|
||||
|
||||
private Timer timer;
|
||||
private Timer timer = null;
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -94,7 +92,7 @@ public class NotificationWindow extends JWindow {
|
|||
|
||||
};
|
||||
|
||||
private MouseAdapter clickListener = new MouseAdapter() {
|
||||
private final MouseAdapter clickListener = new MouseAdapter() {
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
|
|
|
@ -29,7 +29,10 @@ public class SeparatorBorder extends AbstractBorder {
|
|||
|
||||
|
||||
public static enum Position {
|
||||
TOP, BOTTOM, LEFT, RIGHT;
|
||||
TOP,
|
||||
BOTTOM,
|
||||
LEFT,
|
||||
RIGHT;
|
||||
|
||||
public Rectangle2D getRectangle(RectangularShape shape, int borderWidth) {
|
||||
switch (this) {
|
||||
|
@ -72,10 +75,6 @@ public class SeparatorBorder extends AbstractBorder {
|
|||
}
|
||||
|
||||
|
||||
protected SeparatorBorder() {
|
||||
}
|
||||
|
||||
|
||||
public SeparatorBorder(int height, Color color, Position position) {
|
||||
this(height, color, null, null, position);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
package net.sourceforge.filebot;
|
||||
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.kohsuke.args4j.CmdLineException;
|
||||
import org.kohsuke.args4j.CmdLineParser;
|
||||
|
||||
|
||||
public class ArgumentBeanTest {
|
||||
|
||||
@Test
|
||||
public void clear() throws Exception {
|
||||
ArgumentBean bean = parse("--sfv", "One Piece", "-clear");
|
||||
|
||||
assertTrue(bean.isClear());
|
||||
assertFalse(bean.isHelp());
|
||||
assertEquals("One Piece", bean.getSfvPanelFile().getName());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void noClear() throws Exception {
|
||||
ArgumentBean bean = parse("-help", "--sfv", "One Piece");
|
||||
|
||||
assertTrue(bean.isHelp());
|
||||
assertFalse(bean.isClear());
|
||||
assertEquals("One Piece", bean.getSfvPanelFile().getName());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void oneArgument() throws Exception {
|
||||
ArgumentBean bean = parse("--sfv", "One Piece.sfv");
|
||||
|
||||
assertFalse(bean.isClear());
|
||||
assertFalse(bean.isHelp());
|
||||
assertEquals("One Piece.sfv", bean.getSfvPanelFile().getName());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void mixedArguments() throws Exception {
|
||||
ArgumentBean bean = parse("--list", "Twin Peaks.txt", "--sfv", "Death Note.sfv");
|
||||
|
||||
assertEquals("Twin Peaks.txt", bean.getListPanelFile().getName());
|
||||
assertEquals("Death Note.sfv", bean.getSfvPanelFile().getName());
|
||||
}
|
||||
|
||||
|
||||
private static ArgumentBean parse(String... args) throws CmdLineException {
|
||||
ArgumentBean bean = new ArgumentBean();
|
||||
|
||||
new CmdLineParser(bean).parseArgument(args);
|
||||
|
||||
return bean;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ import org.junit.runners.Suite.SuiteClasses;
|
|||
|
||||
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses( { MatcherTestSuite.class, WebTestSuite.class })
|
||||
@SuiteClasses( { MatcherTestSuite.class, WebTestSuite.class, ArgumentBeanTest.class })
|
||||
public class FileBotTestSuite {
|
||||
|
||||
public static Test suite() {
|
||||
|
|
Loading…
Reference in New Issue