* added "Edit Format" action to "Fetch Episode List" action popup in rename panel
* add support for episode array transferable to episode list panel and rename panel * renamed ScriptFormat to ExpressionFormat * misc. changes
This commit is contained in:
parent
2de1b8a1b0
commit
10a7fd5b4c
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -4,8 +4,6 @@ package net.sourceforge.filebot;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.AbstractList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -78,23 +76,6 @@ public final class FileBotUtilities {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public static List<String> asFileNameList(final List<File> list) {
|
||||
return new AbstractList<String>() {
|
||||
|
||||
@Override
|
||||
public String get(int index) {
|
||||
return FileUtilities.getName(list.get(index));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final FileFilter TORRENT_FILES = new ExtensionFileFilter("torrent");
|
||||
public static final FileFilter SFV_FILES = new ExtensionFileFilter("sfv");
|
||||
public static final FileFilter LIST_FILES = new ExtensionFileFilter("txt", "list", "");
|
||||
|
|
|
@ -4,7 +4,6 @@ package net.sourceforge.filebot;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.prefs.BackingStoreException;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
|
@ -47,6 +46,16 @@ public final class Settings {
|
|||
}
|
||||
|
||||
|
||||
public String get(String key) {
|
||||
return get(key, null);
|
||||
}
|
||||
|
||||
|
||||
public String get(String key, String def) {
|
||||
return prefs.get(key, def);
|
||||
}
|
||||
|
||||
|
||||
public void put(String key, String value) {
|
||||
prefs.put(key, value);
|
||||
}
|
||||
|
@ -59,21 +68,21 @@ public final class Settings {
|
|||
}
|
||||
|
||||
|
||||
public String get(String key) {
|
||||
return get(key, null);
|
||||
public void remove(String key) {
|
||||
prefs.remove(key);
|
||||
}
|
||||
|
||||
|
||||
public String get(String key, String def) {
|
||||
return prefs.get(key, def);
|
||||
}
|
||||
|
||||
|
||||
public Entry<String, String> entry(String key) {
|
||||
public PreferencesEntry<String> entry(String key) {
|
||||
return new PreferencesEntry<String>(prefs, key, new StringAdapter());
|
||||
}
|
||||
|
||||
|
||||
public <T> PreferencesEntry<T> entry(String key, Adapter<T> adapter) {
|
||||
return new PreferencesEntry<T>(prefs, key, adapter);
|
||||
}
|
||||
|
||||
|
||||
public Map<String, String> asMap() {
|
||||
return PreferencesMap.map(prefs);
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 397 B |
|
@ -19,7 +19,7 @@ import java.util.Scanner;
|
|||
import java.util.TreeMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.sourceforge.filebot.FileBotUtilities;
|
||||
import net.sourceforge.tuned.FileUtilities;
|
||||
|
||||
|
||||
public class SeriesNameMatcher {
|
||||
|
@ -261,12 +261,23 @@ public class SeriesNameMatcher {
|
|||
Map<File, String[]> namesByFolder = new LinkedHashMap<File, String[]>();
|
||||
|
||||
for (Entry<File, List<File>> entry : filesByFolder.entrySet()) {
|
||||
namesByFolder.put(entry.getKey(), FileBotUtilities.asFileNameList(entry.getValue()).toArray(new String[0]));
|
||||
namesByFolder.put(entry.getKey(), names(entry.getValue()));
|
||||
}
|
||||
|
||||
return namesByFolder;
|
||||
}
|
||||
|
||||
|
||||
protected String[] names(List<File> files) {
|
||||
String[] names = new String[files.size()];
|
||||
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
names[i] = FileUtilities.getName(files.get(i));
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
protected static class SeriesNameCollection extends AbstractCollection<String> {
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
package net.sourceforge.filebot.ui;
|
||||
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
|
||||
import net.sourceforge.filebot.web.Episode;
|
||||
|
||||
|
||||
public class EpisodeExpressionFormat extends ExpressionFormat {
|
||||
|
||||
public EpisodeExpressionFormat(String format) throws ScriptException {
|
||||
super(format);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bindings getBindings(Object value) {
|
||||
Episode episode = (Episode) value;
|
||||
|
||||
Bindings bindings = new SimpleBindings();
|
||||
|
||||
bindings.put("n", nonNull(episode.getSeriesName()));
|
||||
bindings.put("s", nonNull(episode.getSeasonNumber()));
|
||||
bindings.put("e", nonNull(episode.getEpisodeNumber()));
|
||||
bindings.put("t", nonNull(episode.getTitle()));
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
|
||||
private String nonNull(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
|
||||
}
|
|
@ -47,6 +47,7 @@ import net.sourceforge.filebot.Settings;
|
|||
import net.sourceforge.filebot.web.Episode;
|
||||
import net.sourceforge.filebot.web.Episode.EpisodeFormat;
|
||||
import net.sourceforge.tuned.ExceptionUtilities;
|
||||
import net.sourceforge.tuned.PreferencesMap.PreferencesEntry;
|
||||
import net.sourceforge.tuned.ui.GradientStyle;
|
||||
import net.sourceforge.tuned.ui.LinkButton;
|
||||
import net.sourceforge.tuned.ui.TunedUtilities;
|
||||
|
@ -58,14 +59,17 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
|
||||
private Format selectedFormat = null;
|
||||
|
||||
protected JFormattedTextField preview = new JFormattedTextField(getPreviewSample());
|
||||
protected final JFormattedTextField preview = new JFormattedTextField();
|
||||
|
||||
protected JLabel errorMessage = new JLabel(ResourceManager.getIcon("dialog.cancel"));
|
||||
protected JTextField editor = new JTextField();
|
||||
protected final JLabel errorMessage = new JLabel(ResourceManager.getIcon("dialog.cancel"));
|
||||
protected final JTextField editor = new JTextField();
|
||||
|
||||
protected Color defaultColor = preview.getForeground();
|
||||
protected Color errorColor = Color.red;
|
||||
|
||||
protected final PreferencesEntry<String> persistentFormat = Settings.userRoot().entry("dialog.format");
|
||||
protected final PreferencesEntry<String> persistentSample = Settings.userRoot().entry("dialog.sample");
|
||||
|
||||
|
||||
public EpisodeFormatDialog(Window owner) {
|
||||
super(owner, "Episode Format", ModalityType.DOCUMENT_MODAL);
|
||||
|
@ -73,7 +77,10 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
|
||||
editor.setFont(new Font(MONOSPACED, PLAIN, 14));
|
||||
editor.setText(Settings.userRoot().get("dialog.format"));
|
||||
|
||||
// restore state
|
||||
preview.setValue(getPreviewSample());
|
||||
editor.setText(persistentFormat.getValue());
|
||||
|
||||
preview.setBorder(BorderFactory.createEmptyBorder());
|
||||
|
||||
|
@ -201,7 +208,7 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
|
||||
|
||||
protected Episode getPreviewSample() {
|
||||
String sample = Settings.userRoot().get("dialog.sample");
|
||||
String sample = persistentSample.getValue();
|
||||
|
||||
if (sample != null) {
|
||||
try {
|
||||
|
@ -211,6 +218,7 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
}
|
||||
}
|
||||
|
||||
// default sample
|
||||
return new Episode("Dark Angel", "3", "1", "Labyrinth");
|
||||
}
|
||||
|
||||
|
@ -250,7 +258,7 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
Exception exception = null;
|
||||
|
||||
try {
|
||||
Format format = new EpisodeScriptFormat(editor.getText().trim());
|
||||
Format format = new EpisodeExpressionFormat(editor.getText().trim());
|
||||
|
||||
// check if format produces empty strings
|
||||
if (format.format(preview.getValue()).trim().isEmpty()) {
|
||||
|
@ -285,11 +293,11 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
dispose();
|
||||
|
||||
if (checkEpisodeFormat()) {
|
||||
Settings.userRoot().put("dialog.format", editor.getText());
|
||||
persistentFormat.setValue(editor.getText());
|
||||
}
|
||||
|
||||
if (checkPreviewSample()) {
|
||||
Settings.userRoot().put("dialog.sample", preview.getValue().toString());
|
||||
persistentSample.setValue(EpisodeFormat.getInstance().format(preview.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,7 +322,7 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
try {
|
||||
finish(new EpisodeScriptFormat(editor.getText()));
|
||||
finish(new EpisodeExpressionFormat(editor.getText()));
|
||||
} catch (ScriptException e) {
|
||||
Logger.getLogger("ui").log(Level.WARNING, ExceptionUtilities.getRootCauseMessage(e), e);
|
||||
}
|
||||
|
@ -369,7 +377,7 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
|
||||
public void updateText(Object episode) {
|
||||
try {
|
||||
setText(new EpisodeScriptFormat(format).format(episode));
|
||||
setText(new EpisodeExpressionFormat(format).format(episode));
|
||||
setForeground(defaultColor);
|
||||
} catch (Exception e) {
|
||||
setText(ExceptionUtilities.getRootCauseMessage(e));
|
||||
|
|
|
@ -10,4 +10,4 @@ example[1]: {n} - {if (s) s+'x'}{e.pad(2)}
|
|||
example[2]: {n} - {if (s) 'S'+s.pad(2)}E{e.pad(2)}
|
||||
|
||||
# uglyfy name
|
||||
example[3]: {n.replace(/\\s+/g,'.').toLowerCase()}
|
||||
example[3]: {n.replace(/\\s/g,'.').toLowerCase()}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
|
||||
package net.sourceforge.filebot.ui;
|
||||
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
|
||||
import net.sourceforge.filebot.web.Episode;
|
||||
|
||||
|
||||
public class EpisodeScriptFormat extends ScriptFormat {
|
||||
|
||||
public EpisodeScriptFormat(String format) throws ScriptException {
|
||||
super(format);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Bindings getBindings(Object object) {
|
||||
Episode episode = (Episode) object;
|
||||
|
||||
Bindings bindings = new SimpleBindings();
|
||||
|
||||
bindings.put("n", episode.getSeriesName());
|
||||
bindings.put("s", episode.getSeasonNumber());
|
||||
bindings.put("e", episode.getEpisodeNumber());
|
||||
bindings.put("t", episode.getTitle());
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
String.prototype.pad = Number.prototype.pad = function(length, padding) {
|
||||
var s = this.toString();
|
||||
|
||||
// use default padding, if padding is undefined or empty
|
||||
var p = padding ? padding.toString() : '0';
|
||||
|
||||
while (s.length < length) {
|
||||
s = p + s;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
|
@ -19,14 +19,14 @@ import javax.script.ScriptEngineManager;
|
|||
import javax.script.ScriptException;
|
||||
|
||||
|
||||
public abstract class ScriptFormat extends Format {
|
||||
public abstract class ExpressionFormat extends Format {
|
||||
|
||||
private final String format;
|
||||
|
||||
private final Object[] expressions;
|
||||
|
||||
|
||||
public ScriptFormat(String format) throws ScriptException {
|
||||
public ExpressionFormat(String format) throws ScriptException {
|
||||
this.format = format;
|
||||
this.expressions = compile(format, (Compilable) initScriptEngine());
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public abstract class ScriptFormat extends Format {
|
|||
protected ScriptEngine initScriptEngine() throws ScriptException {
|
||||
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
|
||||
|
||||
engine.eval(new InputStreamReader(getClass().getResourceAsStream("ScriptFormat.global.js")));
|
||||
engine.eval(new InputStreamReader(getClass().getResourceAsStream("ExpressionFormat.global.js")));
|
||||
|
||||
return engine;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ public abstract class ScriptFormat extends Format {
|
|||
}
|
||||
|
||||
|
||||
protected abstract Bindings getBindings(Object object);
|
||||
protected abstract Bindings getBindings(Object value);
|
||||
|
||||
|
||||
@Override
|
|
@ -9,7 +9,7 @@ import net.sourceforge.filebot.ui.transfer.TextFileExportHandler;
|
|||
|
||||
public class FileBotListExportHandler extends TextFileExportHandler {
|
||||
|
||||
private final FileBotList<?> list;
|
||||
protected final FileBotList<?> list;
|
||||
|
||||
|
||||
public FileBotListExportHandler(FileBotList<?> list) {
|
||||
|
@ -19,7 +19,7 @@ public class FileBotListExportHandler extends TextFileExportHandler {
|
|||
|
||||
@Override
|
||||
public boolean canExport() {
|
||||
return !list.getModel().isEmpty();
|
||||
return list.getModel().size() > 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
String.prototype.pad = function(length, padding) {
|
||||
if (padding == undefined) {
|
||||
padding = '0';
|
||||
}
|
||||
|
||||
var s = this;
|
||||
|
||||
if (parseInt(this) >= 0 && padding.length >= 1) {
|
||||
while (s.length < length) {
|
||||
s = padding.concat(s)
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.episodelist;
|
||||
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import net.sourceforge.filebot.ui.FileBotList;
|
||||
import net.sourceforge.filebot.ui.FileBotListExportHandler;
|
||||
import net.sourceforge.filebot.ui.transfer.ArrayTransferable;
|
||||
import net.sourceforge.filebot.ui.transfer.CompositeTranserable;
|
||||
import net.sourceforge.filebot.web.Episode;
|
||||
|
||||
|
||||
public class EpisodeListExportHandler extends FileBotListExportHandler {
|
||||
|
||||
public EpisodeListExportHandler(FileBotList<Episode> list) {
|
||||
super(list);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Transferable createTransferable(JComponent c) {
|
||||
Transferable episodeArray = new ArrayTransferable<Episode>(list.getModel().toArray(new Episode[0]));
|
||||
Transferable textFile = super.createTransferable(c);
|
||||
|
||||
return new CompositeTranserable(episodeArray, textFile);
|
||||
}
|
||||
}
|
|
@ -23,7 +23,6 @@ import net.sourceforge.filebot.ResourceManager;
|
|||
import net.sourceforge.filebot.Settings;
|
||||
import net.sourceforge.filebot.ui.AbstractSearchPanel;
|
||||
import net.sourceforge.filebot.ui.FileBotList;
|
||||
import net.sourceforge.filebot.ui.FileBotListExportHandler;
|
||||
import net.sourceforge.filebot.ui.FileBotTab;
|
||||
import net.sourceforge.filebot.ui.SelectDialog;
|
||||
import net.sourceforge.filebot.ui.transfer.FileExportHandler;
|
||||
|
@ -296,7 +295,7 @@ public class EpisodeListPanel extends AbstractSearchPanel<EpisodeListClient, Epi
|
|||
|
||||
public EpisodeListTab() {
|
||||
// set export handler for episode list
|
||||
setExportHandler(new FileBotListExportHandler(this));
|
||||
setExportHandler(new EpisodeListExportHandler(this));
|
||||
|
||||
// allow removal of episode list entries
|
||||
getRemoveAction().setEnabled(true);
|
||||
|
|
|
@ -11,7 +11,6 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import net.sourceforge.filebot.FileBotUtilities;
|
||||
import net.sourceforge.filebot.torrent.Torrent;
|
||||
import net.sourceforge.filebot.ui.FileBotList;
|
||||
import net.sourceforge.filebot.ui.transfer.FileTransferablePolicy;
|
||||
|
@ -50,7 +49,7 @@ class FileListTransferablePolicy extends FileTransferablePolicy {
|
|||
} else if (containsOnly(files, TORRENT_FILES)) {
|
||||
loadTorrents(files);
|
||||
} else {
|
||||
list.getModel().addAll(FileBotUtilities.asFileNameList(files));
|
||||
loadFiles(files);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,19 +61,19 @@ class FileListTransferablePolicy extends FileTransferablePolicy {
|
|||
}
|
||||
|
||||
for (File folder : folders) {
|
||||
list.getModel().addAll(FileBotUtilities.asFileNameList(Arrays.asList(folder.listFiles())));
|
||||
loadFiles(Arrays.asList(folder.listFiles()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void loadTorrents(List<File> torrentFiles) throws IOException {
|
||||
List<Torrent> torrents = new ArrayList<Torrent>(torrentFiles.size());
|
||||
private void loadTorrents(List<File> files) throws IOException {
|
||||
List<Torrent> torrents = new ArrayList<Torrent>(files.size());
|
||||
|
||||
for (File file : torrentFiles) {
|
||||
for (File file : files) {
|
||||
torrents.add(new Torrent(file));
|
||||
}
|
||||
|
||||
if (torrentFiles.size() == 1) {
|
||||
if (torrents.size() == 1) {
|
||||
list.setTitle(FileUtilities.getNameWithoutExtension(torrents.get(0).getName()));
|
||||
}
|
||||
|
||||
|
@ -86,6 +85,13 @@ class FileListTransferablePolicy extends FileTransferablePolicy {
|
|||
}
|
||||
|
||||
|
||||
private void loadFiles(List<File> files) {
|
||||
for (File file : files) {
|
||||
list.getModel().add(FileUtilities.getName(file));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getFileFilterDescription() {
|
||||
return "files, folders and torrents";
|
||||
|
|
|
@ -39,12 +39,12 @@ import net.sourceforge.tuned.ui.ProgressDialog.Cancellable;
|
|||
|
||||
class MatchAction extends AbstractAction {
|
||||
|
||||
private final RenameModel model;
|
||||
private final RenameModel<Object, File> model;
|
||||
|
||||
private final Collection<SimilarityMetric> metrics;
|
||||
|
||||
|
||||
public MatchAction(RenameModel model) {
|
||||
public MatchAction(RenameModel<Object, File> model) {
|
||||
super("Match", ResourceManager.getIcon("action.match"));
|
||||
|
||||
this.model = model;
|
||||
|
@ -169,7 +169,7 @@ class MatchAction extends AbstractAction {
|
|||
private final Matcher<Object, File> matcher;
|
||||
|
||||
|
||||
public BackgroundMatcher(RenameModel model, Collection<SimilarityMetric> metrics) {
|
||||
public BackgroundMatcher(RenameModel<Object, File> model, Collection<SimilarityMetric> metrics) {
|
||||
// match names against files
|
||||
this.matcher = new Matcher<Object, File>(model.names(), model.files(), metrics);
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
class MutableString {
|
||||
|
||||
private String value;
|
||||
|
||||
|
||||
public MutableString(Object value) {
|
||||
set(value);
|
||||
}
|
||||
|
||||
|
||||
public void set(Object value) {
|
||||
this.value = String.valueOf(value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -9,6 +9,7 @@ import static net.sourceforge.tuned.FileUtilities.FOLDERS;
|
|||
import static net.sourceforge.tuned.FileUtilities.containsOnly;
|
||||
import static net.sourceforge.tuned.FileUtilities.getNameWithoutExtension;
|
||||
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -16,18 +17,22 @@ import java.io.FileNotFoundException;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sourceforge.filebot.torrent.Torrent;
|
||||
import net.sourceforge.filebot.ui.transfer.ArrayTransferable;
|
||||
import net.sourceforge.filebot.ui.transfer.FileTransferablePolicy;
|
||||
import net.sourceforge.tuned.FileUtilities;
|
||||
import net.sourceforge.filebot.web.Episode;
|
||||
|
||||
|
||||
class NamesListTransferablePolicy extends FileTransferablePolicy {
|
||||
|
||||
private static final DataFlavor episodeArrayFlavor = ArrayTransferable.flavor(Episode.class);
|
||||
|
||||
private final List<Object> model;
|
||||
|
||||
|
||||
|
@ -60,7 +65,10 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
|
|||
clear();
|
||||
}
|
||||
|
||||
if (tr.isDataFlavorSupported(stringFlavor)) {
|
||||
if (tr.isDataFlavorSupported(episodeArrayFlavor)) {
|
||||
// episode array transferable
|
||||
model.addAll(Arrays.asList((Episode[]) tr.getTransferData((episodeArrayFlavor))));
|
||||
} else if (tr.isDataFlavorSupported(stringFlavor)) {
|
||||
// string transferable
|
||||
load((String) tr.getTransferData(stringFlavor));
|
||||
} else if (super.accept(tr)) {
|
||||
|
@ -71,7 +79,7 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
|
|||
|
||||
|
||||
protected void load(String string) {
|
||||
List<MutableString> entries = new ArrayList<MutableString>();
|
||||
List<String> values = new ArrayList<String>();
|
||||
|
||||
Scanner scanner = new Scanner(string).useDelimiter(LINE_SEPARATOR);
|
||||
|
||||
|
@ -79,41 +87,36 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
|
|||
String line = scanner.next();
|
||||
|
||||
if (line.trim().length() > 0) {
|
||||
entries.add(new MutableString(line));
|
||||
values.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
model.addAll(entries);
|
||||
model.addAll(values);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void load(List<File> files) throws FileNotFoundException {
|
||||
List<Object> values = new ArrayList<Object>();
|
||||
|
||||
if (containsOnly(files, LIST_FILES)) {
|
||||
loadListFiles(files);
|
||||
loadListFiles(files, values);
|
||||
} else if (containsOnly(files, TORRENT_FILES)) {
|
||||
loadTorrentFiles(files);
|
||||
loadTorrentFiles(files, values);
|
||||
} else if (containsOnly(files, FOLDERS)) {
|
||||
// load files from each folder
|
||||
for (File folder : files) {
|
||||
loadFiles(Arrays.asList(folder.listFiles()));
|
||||
Collections.addAll(values, folder.listFiles());
|
||||
}
|
||||
} else {
|
||||
loadFiles(files);
|
||||
values.addAll(files);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void loadFiles(List<File> files) {
|
||||
for (File file : files) {
|
||||
model.add(new AbstractFileEntry(FileUtilities.getName(file), file.length()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void loadListFiles(List<File> files) throws FileNotFoundException {
|
||||
List<String> values = new ArrayList<String>();
|
||||
|
||||
model.addAll(values);
|
||||
}
|
||||
|
||||
|
||||
protected void loadListFiles(List<File> files, List<Object> values) throws FileNotFoundException {
|
||||
for (File file : files) {
|
||||
// don't use new Scanner(File) because of BUG 6368019 (http://bugs.sun.com/view_bug.do?bug_id=6368019)
|
||||
Scanner scanner = new Scanner(new FileInputStream(file), "UTF-8").useDelimiter(LINE_SEPARATOR);
|
||||
|
@ -128,25 +131,18 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
|
|||
|
||||
scanner.close();
|
||||
}
|
||||
|
||||
model.addAll(values);
|
||||
}
|
||||
|
||||
|
||||
protected void loadTorrentFiles(List<File> files) {
|
||||
protected void loadTorrentFiles(List<File> files, List<Object> values) {
|
||||
try {
|
||||
List<AbstractFileEntry> entries = new ArrayList<AbstractFileEntry>();
|
||||
|
||||
for (File file : files) {
|
||||
Torrent torrent = new Torrent(file);
|
||||
|
||||
for (Torrent.Entry entry : torrent.getFiles()) {
|
||||
entries.add(new AbstractFileEntry(getNameWithoutExtension(entry.getName()), entry.getLength()));
|
||||
values.add(new AbstractFileEntry(getNameWithoutExtension(entry.getName()), entry.getLength()));
|
||||
}
|
||||
}
|
||||
|
||||
// add torrent entries directly without checking file names for invalid characters
|
||||
model.addAll(entries);
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger("global").log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
|
|
|
@ -5,10 +5,13 @@ package net.sourceforge.filebot.ui.panel.rename;
|
|||
import static net.sourceforge.filebot.FileBotUtilities.isInvalidFileName;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.text.Format;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import ca.odell.glazedlists.EventList;
|
||||
import ca.odell.glazedlists.TransformedList;
|
||||
import ca.odell.glazedlists.event.ListEvent;
|
||||
|
@ -18,6 +21,8 @@ public class NamesViewEventList extends TransformedList<Object, String> {
|
|||
|
||||
private final List<String> names = new ArrayList<String>();
|
||||
|
||||
private final Map<Class<?>, Format> formatMap = new HashMap<Class<?>, Format>();
|
||||
|
||||
private final Component parent;
|
||||
|
||||
|
||||
|
@ -43,7 +48,43 @@ public class NamesViewEventList extends TransformedList<Object, String> {
|
|||
}
|
||||
|
||||
|
||||
protected String format(Object object) {
|
||||
public void setFormat(Class<?> type, Format format) {
|
||||
if (format != null) {
|
||||
// insert new format for type
|
||||
formatMap.put(type, format);
|
||||
} else {
|
||||
// restore default format for type
|
||||
formatMap.remove(type);
|
||||
}
|
||||
|
||||
updates.beginEvent(true);
|
||||
|
||||
List<Integer> changes = new ArrayList<Integer>();
|
||||
|
||||
// reformat all elements of the source list
|
||||
for (int i = 0; i < source.size(); i++) {
|
||||
String newValue = format(source.get(i));
|
||||
String oldValue = names.set(i, newValue);
|
||||
|
||||
if (!newValue.equals(oldValue)) {
|
||||
updates.elementUpdated(i, oldValue, newValue);
|
||||
changes.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
submit(new IndexView<String>(names, changes));
|
||||
|
||||
updates.commitEvent();
|
||||
}
|
||||
|
||||
|
||||
private String format(Object object) {
|
||||
for (Entry<Class<?>, Format> entry : formatMap.entrySet()) {
|
||||
if (entry.getKey().isInstance(object)) {
|
||||
return entry.getValue().format(object);
|
||||
}
|
||||
}
|
||||
|
||||
return object.toString();
|
||||
}
|
||||
|
||||
|
@ -51,7 +92,7 @@ public class NamesViewEventList extends TransformedList<Object, String> {
|
|||
@Override
|
||||
public void listChanged(ListEvent<Object> listChanges) {
|
||||
EventList<Object> source = listChanges.getSourceList();
|
||||
IndexView<String> newValues = new IndexView<String>(names);
|
||||
List<Integer> changes = new ArrayList<Integer>();
|
||||
|
||||
while (listChanges.next()) {
|
||||
int index = listChanges.getIndex();
|
||||
|
@ -60,11 +101,11 @@ public class NamesViewEventList extends TransformedList<Object, String> {
|
|||
switch (type) {
|
||||
case ListEvent.INSERT:
|
||||
names.add(index, format(source.get(index)));
|
||||
newValues.getIndexFilter().add(index);
|
||||
changes.add(index);
|
||||
break;
|
||||
case ListEvent.UPDATE:
|
||||
names.set(index, format(source.get(index)));
|
||||
newValues.getIndexFilter().add(index);
|
||||
changes.add(index);
|
||||
break;
|
||||
case ListEvent.DELETE:
|
||||
names.remove(index);
|
||||
|
@ -72,7 +113,7 @@ public class NamesViewEventList extends TransformedList<Object, String> {
|
|||
}
|
||||
}
|
||||
|
||||
submit(newValues);
|
||||
submit(new IndexView<String>(names, changes));
|
||||
|
||||
listChanges.reset();
|
||||
updates.forwardEvent(listChanges);
|
||||
|
@ -80,17 +121,17 @@ public class NamesViewEventList extends TransformedList<Object, String> {
|
|||
|
||||
|
||||
protected void submit(List<String> values) {
|
||||
IndexView<String> invalidValues = new IndexView<String>(values);
|
||||
List<Integer> issues = new ArrayList<Integer>();
|
||||
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
if (isInvalidFileName(values.get(i))) {
|
||||
invalidValues.getIndexFilter().add(i);
|
||||
issues.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidValues.size() > 0) {
|
||||
if (issues.size() > 0) {
|
||||
// validate names
|
||||
ValidateNamesDialog.showDialog(parent, invalidValues);
|
||||
ValidateNamesDialog.showDialog(parent, new IndexView<String>(values, issues));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,34 +140,30 @@ public class NamesViewEventList extends TransformedList<Object, String> {
|
|||
|
||||
private final List<E> source;
|
||||
|
||||
private final List<Integer> indexFilter = new ArrayList<Integer>();
|
||||
private final List<Integer> filter;
|
||||
|
||||
|
||||
public IndexView(List<E> source) {
|
||||
public IndexView(List<E> source, List<Integer> filter) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
public List<Integer> getIndexFilter() {
|
||||
return indexFilter;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
return source.get(indexFilter.get(index));
|
||||
return source.get(filter.get(index));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
return source.set(indexFilter.get(index), element);
|
||||
return source.set(filter.get(index), element);
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return indexFilter.size();
|
||||
return filter.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ import net.sourceforge.tuned.FileUtilities;
|
|||
|
||||
class RenameAction extends AbstractAction {
|
||||
|
||||
private final RenameModel model;
|
||||
private final RenameModel<String, File> model;
|
||||
|
||||
|
||||
public RenameAction(RenameModel model) {
|
||||
public RenameAction(RenameModel<String, File> model) {
|
||||
super("Rename", ResourceManager.getIcon("action.rename"));
|
||||
|
||||
putValue(SHORT_DESCRIPTION, "Rename files");
|
||||
|
@ -36,12 +36,11 @@ class RenameAction extends AbstractAction {
|
|||
Deque<Match<File, File>> todoQueue = new ArrayDeque<Match<File, File>>();
|
||||
Deque<Match<File, File>> doneQueue = new ArrayDeque<Match<File, File>>();
|
||||
|
||||
for (Match<Object, File> match : model.matches()) {
|
||||
for (Match<String, File> match : model.matches()) {
|
||||
File source = match.getCandidate();
|
||||
String extension = FileUtilities.getExtension(source);
|
||||
|
||||
StringBuilder name = new StringBuilder();
|
||||
name.append(match.getValue());
|
||||
StringBuilder name = new StringBuilder(match.getValue());
|
||||
|
||||
if (extension != null) {
|
||||
name.append(".").append(extension);
|
||||
|
@ -77,7 +76,7 @@ class RenameAction extends AbstractAction {
|
|||
for (Match<File, File> match : doneQueue) {
|
||||
revertSuccess &= match.getCandidate().renameTo(match.getValue());
|
||||
}
|
||||
|
||||
|
||||
if (!revertSuccess) {
|
||||
Logger.getLogger("ui").severe("Failed to revert all rename operations.");
|
||||
}
|
||||
|
|
|
@ -25,12 +25,12 @@ import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer;
|
|||
|
||||
class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
||||
|
||||
private final RenameModel model;
|
||||
private final RenameModel<?, ?> model;
|
||||
|
||||
private final ExtensionLabel extension = new ExtensionLabel();
|
||||
|
||||
|
||||
public RenameListCellRenderer(RenameModel model) {
|
||||
public RenameListCellRenderer(RenameModel<?, ?> model) {
|
||||
this.model = model;
|
||||
|
||||
setHighlightingEnabled(false);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.AbstractList;
|
||||
import java.util.Collection;
|
||||
|
||||
|
@ -11,18 +10,24 @@ import ca.odell.glazedlists.BasicEventList;
|
|||
import ca.odell.glazedlists.EventList;
|
||||
|
||||
|
||||
class RenameModel {
|
||||
class RenameModel<N, V> {
|
||||
|
||||
private final EventList<Object> names = new BasicEventList<Object>();
|
||||
private final EventList<File> files = new BasicEventList<File>();
|
||||
private final EventList<N> names;
|
||||
private final EventList<V> files;
|
||||
|
||||
|
||||
public EventList<Object> names() {
|
||||
public RenameModel(EventList<N> names, EventList<V> files) {
|
||||
this.names = names;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
|
||||
public EventList<N> names() {
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
public EventList<File> files() {
|
||||
public EventList<V> files() {
|
||||
return files;
|
||||
}
|
||||
|
||||
|
@ -38,19 +43,19 @@ class RenameModel {
|
|||
}
|
||||
|
||||
|
||||
public Match<Object, File> getMatch(int index) {
|
||||
public Match<N, V> getMatch(int index) {
|
||||
if (index >= matchCount())
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
||||
return new Match<Object, File>(names.get(index), files.get(index));
|
||||
return new Match<N, V>(names.get(index), files.get(index));
|
||||
}
|
||||
|
||||
|
||||
public Collection<Match<Object, File>> matches() {
|
||||
return new AbstractList<Match<Object, File>>() {
|
||||
public Collection<Match<N, V>> matches() {
|
||||
return new AbstractList<Match<N, V>>() {
|
||||
|
||||
@Override
|
||||
public Match<Object, File> get(int index) {
|
||||
public Match<N, V> get(int index) {
|
||||
return getMatch(index);
|
||||
}
|
||||
|
||||
|
@ -62,4 +67,16 @@ class RenameModel {
|
|||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <S, V> RenameModel<S, V> create() {
|
||||
return new RenameModel<S, V>((EventList<S>) new BasicEventList<Object>(), (EventList<V>) new BasicEventList<Object>());
|
||||
}
|
||||
|
||||
|
||||
public static <S, V> RenameModel<S, V> wrap(EventList<S> names, EventList<V> values) {
|
||||
return new RenameModel<S, V>(names, values);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.awt.event.ActionEvent;
|
|||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.text.Format;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
@ -24,6 +25,7 @@ import javax.swing.Action;
|
|||
import javax.swing.DefaultListSelectionModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
@ -34,15 +36,20 @@ import net.sourceforge.filebot.Settings;
|
|||
import net.sourceforge.filebot.similarity.Match;
|
||||
import net.sourceforge.filebot.similarity.NameSimilarityMetric;
|
||||
import net.sourceforge.filebot.similarity.SimilarityMetric;
|
||||
import net.sourceforge.filebot.ui.EpisodeExpressionFormat;
|
||||
import net.sourceforge.filebot.ui.EpisodeFormatDialog;
|
||||
import net.sourceforge.filebot.ui.FileBotPanel;
|
||||
import net.sourceforge.filebot.ui.SelectDialog;
|
||||
import net.sourceforge.filebot.web.AnidbClient;
|
||||
import net.sourceforge.filebot.web.Episode;
|
||||
import net.sourceforge.filebot.web.EpisodeListClient;
|
||||
import net.sourceforge.filebot.web.SearchResult;
|
||||
import net.sourceforge.filebot.web.TVDotComClient;
|
||||
import net.sourceforge.filebot.web.TVRageClient;
|
||||
import net.sourceforge.filebot.web.TheTVDBClient;
|
||||
import net.sourceforge.tuned.ExceptionUtilities;
|
||||
import net.sourceforge.tuned.FileUtilities.FileNameFormat;
|
||||
import net.sourceforge.tuned.PreferencesMap.PreferencesEntry;
|
||||
import net.sourceforge.tuned.ui.ActionPopup;
|
||||
import net.sourceforge.tuned.ui.LoadingOverlayPane;
|
||||
import ca.odell.glazedlists.event.ListEvent;
|
||||
|
@ -51,17 +58,19 @@ import ca.odell.glazedlists.event.ListEventListener;
|
|||
|
||||
public class RenamePanel extends FileBotPanel {
|
||||
|
||||
private RenameModel model = new RenameModel();
|
||||
protected final RenameModel<Object, File> model = RenameModel.create();
|
||||
|
||||
private RenameList<String> namesList = new RenameList<String>(new NamesViewEventList(this, model.names()));
|
||||
protected final NamesViewEventList namesView = new NamesViewEventList(this, model.names());
|
||||
|
||||
private RenameList<File> filesList = new RenameList<File>(model.files());
|
||||
protected final RenameList<String> namesList = new RenameList<String>(namesView);
|
||||
|
||||
private MatchAction matchAction = new MatchAction(model);
|
||||
protected final RenameList<File> filesList = new RenameList<File>(model.files());
|
||||
|
||||
private RenameAction renameAction = new RenameAction(model);
|
||||
protected final MatchAction matchAction = new MatchAction(model);
|
||||
|
||||
private ActionPopup matchActionPopup = new ActionPopup("Fetch Episode List", ResourceManager.getIcon("action.fetch"));
|
||||
protected final RenameAction renameAction = new RenameAction(RenameModel.wrap(namesView, model.files()));
|
||||
|
||||
protected final PreferencesEntry<String> persistentFormat = Settings.userRoot().entry("rename.format");
|
||||
|
||||
|
||||
public RenamePanel() {
|
||||
|
@ -73,6 +82,11 @@ public class RenamePanel extends FileBotPanel {
|
|||
filesList.setTitle("Current");
|
||||
filesList.setTransferablePolicy(new FilesListTransferablePolicy(filesList.getModel()));
|
||||
|
||||
namesView.setFormat(File.class, new FileNameFormat());
|
||||
|
||||
// restore custom format
|
||||
restoreEpisodeFormat();
|
||||
|
||||
RenameListCellRenderer cellrenderer = new RenameListCellRenderer(model);
|
||||
|
||||
namesList.getListComponent().setCellRenderer(cellrenderer);
|
||||
|
@ -98,13 +112,8 @@ public class RenamePanel extends FileBotPanel {
|
|||
renameButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
renameButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
|
||||
// create actions for match popup
|
||||
matchActionPopup.add(new AutoFetchEpisodeListAction(new TVRageClient()));
|
||||
matchActionPopup.add(new AutoFetchEpisodeListAction(new AnidbClient()));
|
||||
matchActionPopup.add(new AutoFetchEpisodeListAction(new TheTVDBClient(Settings.userRoot().get("thetvdb.apikey"))));
|
||||
|
||||
// set match action popup
|
||||
matchButton.setComponentPopupMenu(matchActionPopup);
|
||||
// set fetch action popup
|
||||
matchButton.setComponentPopupMenu(createFetchPopup());
|
||||
matchButton.addActionListener(showPopupAction);
|
||||
|
||||
setLayout(new MigLayout("fill, insets dialog, gapx 10px", null, "align 33%"));
|
||||
|
@ -120,26 +129,64 @@ public class RenamePanel extends FileBotPanel {
|
|||
|
||||
add(filesList, "grow, sizegroupx list");
|
||||
|
||||
// set action popup status message while episode list matcher is working
|
||||
namesList.addPropertyChangeListener(LOADING_PROPERTY, new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
matchActionPopup.setStatus((Boolean) evt.getNewValue() ? "in progress" : null);
|
||||
}
|
||||
});
|
||||
|
||||
// repaint on change
|
||||
model.names().addListEventListener(new RepaintHandler<Object>());
|
||||
model.files().addListEventListener(new RepaintHandler<File>());
|
||||
}
|
||||
|
||||
|
||||
protected ActionPopup createFetchPopup() {
|
||||
final ActionPopup actionPopup = new ActionPopup("Fetch Episode List", ResourceManager.getIcon("action.fetch"));
|
||||
|
||||
// create actions for match popup
|
||||
actionPopup.add(new AutoFetchEpisodeListAction(new TVRageClient()));
|
||||
actionPopup.add(new AutoFetchEpisodeListAction(new AnidbClient()));
|
||||
actionPopup.add(new AutoFetchEpisodeListAction(new TVDotComClient()));
|
||||
actionPopup.add(new AutoFetchEpisodeListAction(new TheTVDBClient(Settings.userRoot().get("thetvdb.apikey"))));
|
||||
|
||||
actionPopup.addSeparator();
|
||||
actionPopup.addDescription(new JLabel("Options:"));
|
||||
|
||||
actionPopup.add(new AbstractAction("Edit Format", ResourceManager.getIcon("action.format")) {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Format format = EpisodeFormatDialog.showDialog(RenamePanel.this);
|
||||
|
||||
if (format != null) {
|
||||
if (format instanceof EpisodeExpressionFormat) {
|
||||
persistentFormat.setValue(((EpisodeExpressionFormat) format).getFormat());
|
||||
} else {
|
||||
persistentFormat.remove();
|
||||
}
|
||||
|
||||
namesView.setFormat(Episode.class, format);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return actionPopup;
|
||||
}
|
||||
|
||||
|
||||
private void restoreEpisodeFormat() {
|
||||
String format = persistentFormat.getValue();
|
||||
|
||||
if (format != null) {
|
||||
try {
|
||||
namesView.setFormat(Episode.class, new EpisodeExpressionFormat(format));
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger("ui").log(Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final Action showPopupAction = new AbstractAction("Show Popup") {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// show popup on actionPerformed only when names list is empty
|
||||
if (model.names().isEmpty()) {
|
||||
if (model.names().isEmpty() && !model.files().isEmpty()) {
|
||||
JComponent source = (JComponent) e.getSource();
|
||||
|
||||
// display popup below component
|
||||
|
|
|
@ -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;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
|
||||
public class ArrayTransferable<T> implements Transferable {
|
||||
|
||||
public static DataFlavor flavor(Class<?> componentType) {
|
||||
return new DataFlavor(Array.newInstance(componentType, 0).getClass(), "Array");
|
||||
}
|
||||
|
||||
private final T[] array;
|
||||
|
||||
|
||||
public ArrayTransferable(T... array) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
|
||||
if (isDataFlavorSupported(flavor)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return new DataFlavor[] { new DataFlavor(array.getClass(), "Array") };
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDataFlavorSupported(DataFlavor flavor) {
|
||||
return array.getClass().equals(flavor.getRepresentationClass());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
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;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
|
||||
public class CompositeTranserable implements Transferable {
|
||||
|
||||
private final Transferable[] transferables;
|
||||
|
||||
private final DataFlavor[] flavors;
|
||||
|
||||
|
||||
public CompositeTranserable(Transferable... transferables) {
|
||||
this.transferables = transferables;
|
||||
|
||||
Collection<DataFlavor> flavors = new ArrayList<DataFlavor>();
|
||||
|
||||
for (Transferable transferable : transferables) {
|
||||
Collections.addAll(flavors, transferable.getTransferDataFlavors());
|
||||
}
|
||||
|
||||
this.flavors = flavors.toArray(new DataFlavor[0]);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
|
||||
Transferable transferable = getTransferable(flavor);
|
||||
|
||||
if (transferable == null)
|
||||
return null;
|
||||
|
||||
return transferable.getTransferData(flavor);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return flavors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDataFlavorSupported(DataFlavor flavor) {
|
||||
return getTransferable(flavor) != null;
|
||||
}
|
||||
|
||||
|
||||
protected Transferable getTransferable(DataFlavor flavor) {
|
||||
for (Transferable transferable : transferables) {
|
||||
if (transferable.isDataFlavorSupported(flavor))
|
||||
return transferable;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -46,6 +46,12 @@ public class ByteBufferOutputStream extends OutputStream {
|
|||
}
|
||||
|
||||
|
||||
public synchronized void write(ByteBuffer src) throws IOException {
|
||||
ensureCapacity(buffer.position() + src.remaining());
|
||||
buffer.put(src);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void write(byte[] src, int offset, int length) throws IOException {
|
||||
ensureCapacity(buffer.position() + length);
|
||||
|
|
|
@ -4,6 +4,9 @@ package net.sourceforge.tuned;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.Format;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -157,6 +160,22 @@ public final class FileUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static class FileNameFormat extends Format {
|
||||
|
||||
@Override
|
||||
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
|
||||
return toAppendTo.append(FileUtilities.getName((File) obj));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object parseObject(String source, ParsePosition pos) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dummy constructor to prevent instantiation.
|
||||
|
|
|
@ -333,6 +333,11 @@ public class PreferencesMap<T> implements Map<String, T> {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void remove() {
|
||||
adapter.remove(prefs, key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.awt.event.ActionListener;
|
|||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
|
@ -19,11 +20,11 @@ import net.miginfocom.swing.MigLayout;
|
|||
|
||||
public class ActionPopup extends JPopupMenu {
|
||||
|
||||
protected JLabel headerLabel = new JLabel();
|
||||
protected JLabel descriptionLabel = new JLabel();
|
||||
protected JLabel statusLabel = new JLabel();
|
||||
protected final JLabel headerLabel = new JLabel();
|
||||
protected final JLabel descriptionLabel = new JLabel();
|
||||
protected final JLabel statusLabel = new JLabel();
|
||||
|
||||
protected JPanel actionPanel = new JPanel(new MigLayout("insets 0, wrap 1"));
|
||||
protected final JPanel actionPanel = new JPanel(new MigLayout("nogrid, insets 0, fill"));
|
||||
|
||||
|
||||
public ActionPopup(String label, Icon icon) {
|
||||
|
@ -31,22 +32,37 @@ public class ActionPopup extends JPopupMenu {
|
|||
headerLabel.setIcon(icon);
|
||||
headerLabel.setIconTextGap(5);
|
||||
|
||||
actionPanel.setOpaque(false);
|
||||
|
||||
statusLabel.setFont(statusLabel.getFont().deriveFont(10f));
|
||||
statusLabel.setForeground(Color.GRAY);
|
||||
|
||||
actionPanel.setOpaque(false);
|
||||
|
||||
setLayout(new MigLayout("nogrid, fill, insets 0"));
|
||||
|
||||
add(headerLabel, "gapx 5px 5px, gapy 3px 1px, wrap 3px");
|
||||
add(new JSeparator(), "growx, wrap 1px");
|
||||
add(descriptionLabel, "gapx 4px, wrap 3px");
|
||||
add(actionPanel, "gapx 12px 12px, wrap");
|
||||
add(actionPanel, "growx, wrap 0px");
|
||||
add(new JSeparator(), "growx, wrap 0px");
|
||||
add(statusLabel, "growx, h 11px!, gapx 3px, wrap 1px");
|
||||
}
|
||||
|
||||
|
||||
public void addDescription(JComponent component) {
|
||||
actionPanel.add(component, "gapx 4px, wrap 3px");
|
||||
}
|
||||
|
||||
|
||||
public void addAction(JComponent component) {
|
||||
actionPanel.add(component, "gapx 12px 12px, wrap");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addSeparator() {
|
||||
actionPanel.add(new JSeparator(), "growx, wrap 1px");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JMenuItem add(Action a) {
|
||||
LinkButton link = new LinkButton(a);
|
||||
|
@ -61,7 +77,7 @@ public class ActionPopup extends JPopupMenu {
|
|||
link.setRolloverEnabled(false);
|
||||
link.setColor(link.getRolloverColor());
|
||||
|
||||
actionPanel.add(link);
|
||||
addAction(link);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -84,16 +100,6 @@ public class ActionPopup extends JPopupMenu {
|
|||
}
|
||||
|
||||
|
||||
public void setDescription(String string) {
|
||||
descriptionLabel.setText(string);
|
||||
}
|
||||
|
||||
|
||||
public String getDescription() {
|
||||
return descriptionLabel.getText();
|
||||
}
|
||||
|
||||
|
||||
public void setStatus(String string) {
|
||||
statusLabel.setText(string);
|
||||
}
|
||||
|
|
|
@ -14,11 +14,11 @@ import javax.script.SimpleBindings;
|
|||
import org.junit.Test;
|
||||
|
||||
|
||||
public class ScriptFormatTest {
|
||||
public class ExpressionFormatTest {
|
||||
|
||||
@Test
|
||||
public void compile() throws Exception {
|
||||
ScriptFormat format = new TestScriptFormat("");
|
||||
ExpressionFormat format = new TestScriptFormat("");
|
||||
|
||||
Object[] expression = format.compile("name: {name}, number: {number}", (Compilable) format.initScriptEngine());
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class ScriptFormatTest {
|
|||
}
|
||||
|
||||
|
||||
protected static class TestScriptFormat extends ScriptFormat {
|
||||
protected static class TestScriptFormat extends ExpressionFormat {
|
||||
|
||||
public TestScriptFormat(String format) throws ScriptException {
|
||||
super(format);
|
Loading…
Reference in New Issue