* encapsulate the two rename Eventlists into RenameModel

* improved NameSimilarityMetric
* mostly refactoring
This commit is contained in:
Reinhard Pointner 2009-01-17 11:03:09 +00:00
parent c217d06eeb
commit c5c12513fa
25 changed files with 239 additions and 148 deletions

View File

@ -30,7 +30,7 @@ public class NameSimilarityMetric implements SimilarityMetric {
String name = removeEmbeddedChecksum(object.toString());
// normalize separators
name = name.replaceAll("[\\._ ]+", " ");
name = name.replaceAll("[^\\p{Alnum}]+", " ");
// normalize case and trim
return name.trim().toLowerCase();

View File

@ -65,7 +65,7 @@ public abstract class AbstractSearchPanel<S, E> extends FileBotPanel {
tabbedPaneGroup.setBorder(BorderFactory.createTitledBorder("Search Results"));
tabbedPaneGroup.add(tabbedPane, "grow, wrap 8px");
setLayout(new MigLayout("nogrid, fill, insets 0 0 5px 0"));
setLayout(new MigLayout("nogrid, fill, insets 10px 10px 15px 10px"));
add(searchTextField, "alignx center, gapafter indent");
add(new JButton(searchAction), "gap 18px, wrap 10px");
add(tabbedPaneGroup, "grow");

View File

@ -26,17 +26,16 @@ import ca.odell.glazedlists.swing.EventListModel;
public class FileBotList<E> extends JComponent {
protected final EventList<E> model = new BasicEventList<E>();
protected EventList<E> model = new BasicEventList<E>();
protected final JList list = new JList(new EventListModel<E>(model));
protected JList list = new JList(new EventListModel<E>(model));
protected final JScrollPane listScrollPane = new JScrollPane(list);
protected JScrollPane listScrollPane = new JScrollPane(list);
private String title = null;
public FileBotList() {
setLayout(new BorderLayout());
setBorder(new TitledBorder(getTitle()));
@ -60,6 +59,12 @@ public class FileBotList<E> extends JComponent {
}
public void setModel(EventList<E> model) {
this.model = model;
list.setModel(new EventListModel<E>(model));
}
public JList getListComponent() {
return list;
}

View File

@ -133,7 +133,7 @@ public class FileBotWindow extends JFrame implements ListSelectionListener {
private JComponent createPageLayer() {
JPanel pageLayer = new JPanel(new BorderLayout());
pagePanel.setBorder(new EmptyBorder(10, 110, 10, 10));
pagePanel.setBorder(new EmptyBorder(0, 95, 0, 0));
pageLayer.add(headerPanel, BorderLayout.NORTH);
pageLayer.add(pagePanel, BorderLayout.CENTER);

View File

@ -29,7 +29,7 @@ public class AnalyzePanel extends FileBotPanel {
toolsPanel.setBorder(BorderFactory.createTitledBorder("Tools"));
setLayout(new MigLayout("insets 0, gapx 50, fill"));
setLayout(new MigLayout("insets dialog, gapx 50, fill"));
add(fileTreePanel, "grow, sizegroupx column");
add(toolsPanel, "grow, sizegroupx column");

View File

@ -5,7 +5,7 @@ package net.sourceforge.filebot.ui.panel.episodelist;
import javax.swing.SpinnerNumberModel;
public class SeasonSpinnerModel extends SpinnerNumberModel {
class SeasonSpinnerModel extends SpinnerNumberModel {
public static final int ALL_SEASONS = 0;

View File

@ -18,6 +18,7 @@ import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SpinnerNumberModel;
import javax.swing.JSpinner.NumberEditor;
import net.miginfocom.swing.MigLayout;
import net.sourceforge.filebot.ResourceManager;
@ -57,10 +58,10 @@ public class ListPanel extends FileBotPanel {
JSpinner fromSpinner = new JSpinner(fromSpinnerModel);
JSpinner toSpinner = new JSpinner(toSpinnerModel);
fromSpinner.setEditor(new JSpinner.NumberEditor(fromSpinner, "#"));
toSpinner.setEditor(new JSpinner.NumberEditor(toSpinner, "#"));
fromSpinner.setEditor(new NumberEditor(fromSpinner, "#"));
toSpinner.setEditor(new NumberEditor(toSpinner, "#"));
setLayout(new MigLayout("nogrid, fill, insets 6px 2px 6px 2px", "align center"));
setLayout(new MigLayout("nogrid, fill, insets dialog", "align center"));
add(new JLabel("Pattern:"), "gapbefore indent");
add(textField, "gap related, wmin 2cm");

View File

@ -2,7 +2,7 @@
package net.sourceforge.filebot.ui.panel.rename;
public class AbstractFileEntry {
class AbstractFileEntry {
private final String name;
private final long length;

View File

@ -1,4 +1,7 @@
package net.sourceforge.filebot.ui.panel.rename;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
@ -17,7 +20,7 @@ import javax.swing.text.JTextComponent;
import net.sourceforge.tuned.ui.GradientStyle;
public class CharacterHighlightPainter implements Highlighter.HighlightPainter {
class CharacterHighlightPainter implements Highlighter.HighlightPainter {
private Color gradientBeginColor;
private Color gradientEndColor;

View File

@ -7,7 +7,7 @@ import java.io.File;
import net.sourceforge.tuned.FileUtil;
public class FileEntry extends AbstractFileEntry {
class FileEntry extends AbstractFileEntry {
private final File file;
private final String type;

View File

@ -23,7 +23,7 @@ import net.sourceforge.tuned.ui.AbstractFancyListCellRenderer;
import net.sourceforge.tuned.ui.TunedUtil;
public class HighlightListCellRenderer extends AbstractFancyListCellRenderer {
class HighlightListCellRenderer extends AbstractFancyListCellRenderer {
private final JTextComponent textComponent = new JTextField();

View File

@ -33,19 +33,17 @@ import net.sourceforge.tuned.ui.ProgressDialog.Cancellable;
class MatchAction extends AbstractAction {
private final List<Object> namesModel;
private final List<FileEntry> filesModel;
private final RenameModel model;
private final SimilarityMetric[] metrics;
public MatchAction(List<Object> namesModel, List<FileEntry> filesModel) {
public MatchAction(RenameModel model) {
super("Match", ResourceManager.getIcon("action.match"));
putValue(SHORT_DESCRIPTION, "Match names to files");
this.namesModel = namesModel;
this.filesModel = filesModel;
this.model = model;
metrics = new SimilarityMetric[3];
@ -75,7 +73,7 @@ class MatchAction extends AbstractAction {
SwingUtilities.getRoot(eventSource).setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
BackgroundMatcher backgroundMatcher = new BackgroundMatcher(namesModel, filesModel, Arrays.asList(metrics));
BackgroundMatcher backgroundMatcher = new BackgroundMatcher(model, Arrays.asList(metrics));
backgroundMatcher.execute();
try {
@ -118,17 +116,16 @@ class MatchAction extends AbstractAction {
protected static class BackgroundMatcher extends SwingWorker<List<Match<Object, FileEntry>>, Void> implements Cancellable {
private final List<Object> namesModel;
private final List<FileEntry> filesModel;
private final RenameModel model;
private final Matcher<Object, FileEntry> matcher;
public BackgroundMatcher(List<Object> namesModel, List<FileEntry> filesModel, List<SimilarityMetric> metrics) {
this.namesModel = namesModel;
this.filesModel = filesModel;
public BackgroundMatcher(RenameModel model, List<SimilarityMetric> metrics) {
this.model = model;
this.matcher = new Matcher<Object, FileEntry>(namesModel, filesModel, metrics);
// match names against files
this.matcher = new Matcher<Object, FileEntry>(model.names(), model.files(), metrics);
}
@ -144,18 +141,12 @@ class MatchAction extends AbstractAction {
return;
try {
List<Match<Object, FileEntry>> matches = get();
// put new data into model
model.setData(get());
namesModel.clear();
filesModel.clear();
for (Match<Object, FileEntry> match : matches) {
namesModel.add(match.getValue());
filesModel.add(match.getCandidate());
}
namesModel.addAll(matcher.remainingValues());
namesModel.addAll(matcher.remainingCandidates());
// insert objects that could not be matched at the end
model.names().addAll(matcher.remainingValues());
model.files().addAll(matcher.remainingCandidates());
} catch (Exception e) {
Logger.getLogger("global").log(Level.SEVERE, e.toString(), e);
}

View File

@ -6,6 +6,7 @@ import static java.awt.datatransfer.DataFlavor.stringFlavor;
import static net.sourceforge.filebot.FileBotUtil.LIST_FILE_EXTENSIONS;
import static net.sourceforge.filebot.FileBotUtil.TORRENT_FILE_EXTENSIONS;
import static net.sourceforge.filebot.FileBotUtil.containsOnly;
import static net.sourceforge.filebot.FileBotUtil.containsOnlyFolders;
import static net.sourceforge.filebot.FileBotUtil.isInvalidFileName;
import static net.sourceforge.tuned.FileUtil.getNameWithoutExtension;
@ -14,6 +15,7 @@ import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
@ -22,26 +24,38 @@ import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import net.sourceforge.filebot.torrent.Torrent;
import net.sourceforge.filebot.ui.transfer.FileTransferablePolicy;
import net.sourceforge.tuned.FileUtil;
class NamesListTransferablePolicy extends FilesListTransferablePolicy {
class NamesListTransferablePolicy extends FileTransferablePolicy {
private final RenameList<Object> list;
public NamesListTransferablePolicy(RenameList<Object> list) {
super(list.getModel());
this.list = list;
}
@Override
protected void clear() {
list.getModel().clear();
}
@Override
public boolean accept(Transferable tr) {
return tr.isDataFlavorSupported(stringFlavor) || super.accept(tr);
}
@Override
protected boolean accept(List<File> files) {
return true;
}
@Override
public void handleTransferable(Transferable tr, TransferAction action) {
if (action == TransferAction.PUT) {
@ -111,13 +125,25 @@ class NamesListTransferablePolicy extends FilesListTransferablePolicy {
loadListFiles(files);
} else if (containsOnly(files, TORRENT_FILE_EXTENSIONS)) {
loadTorrentFiles(files);
} else if (containsOnlyFolders(files)) {
// load files from each folder
for (File folder : files) {
loadFiles(Arrays.asList(folder.listFiles()));
}
} else {
super.load(files);
loadFiles(files);
}
}
private void loadListFiles(List<File> files) {
protected void loadFiles(List<File> files) {
for (File file : files) {
list.getModel().add(new AbstractFileEntry(FileUtil.getFileName(file), file.length()));
}
}
protected void loadListFiles(List<File> files) {
try {
List<StringEntry> entries = new ArrayList<StringEntry>();
@ -142,7 +168,7 @@ class NamesListTransferablePolicy extends FilesListTransferablePolicy {
}
private void loadTorrentFiles(List<File> files) {
protected void loadTorrentFiles(List<File> files) {
try {
List<AbstractFileEntry> entries = new ArrayList<AbstractFileEntry>();

View File

@ -7,8 +7,6 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
@ -18,49 +16,44 @@ import net.sourceforge.filebot.similarity.Match;
import net.sourceforge.tuned.FileUtil;
public class RenameAction extends AbstractAction {
class RenameAction extends AbstractAction {
private final List<Object> namesModel;
private final List<FileEntry> filesModel;
private final RenameModel model;
public RenameAction(List<Object> namesModel, List<FileEntry> filesModel) {
public RenameAction(RenameModel model) {
super("Rename", ResourceManager.getIcon("action.rename"));
putValue(SHORT_DESCRIPTION, "Rename files");
this.namesModel = namesModel;
this.filesModel = filesModel;
this.model = model;
}
public void actionPerformed(ActionEvent evt) {
Deque<Match<File, File>> renameMatches = new ArrayDeque<Match<File, File>>();
Deque<Match<File, File>> revertMatches = new ArrayDeque<Match<File, File>>();
Deque<Match<File, File>> todoQueue = new ArrayDeque<Match<File, File>>();
Deque<Match<File, File>> doneQueue = new ArrayDeque<Match<File, File>>();
Iterator<Object> names = namesModel.iterator();
Iterator<FileEntry> files = filesModel.iterator();
while (names.hasNext() && files.hasNext()) {
File source = files.next().getFile();
for (Match<Object, FileEntry> match : model.matches()) {
File source = match.getCandidate().getFile();
String targetName = names.next().toString() + FileUtil.getExtension(source, true);
File target = new File(source.getParentFile(), targetName);
String newName = match.getValue().toString() + FileUtil.getExtension(source, true);
File target = new File(source.getParentFile(), newName);
renameMatches.addLast(new Match<File, File>(source, target));
todoQueue.addLast(new Match<File, File>(source, target));
}
try {
int renameCount = renameMatches.size();
int renameCount = todoQueue.size();
for (Match<File, File> match : renameMatches) {
for (Match<File, File> match : todoQueue) {
// rename file
if (!match.getValue().renameTo(match.getCandidate()))
throw new IOException(String.format("Failed to rename file: %s.", match.getValue().getName()));
// revert in reverse order if renaming of all matches fails
revertMatches.addFirst(match);
doneQueue.addFirst(match);
}
// renamed all matches successfully
@ -72,7 +65,7 @@ public class RenameAction extends AbstractAction {
boolean revertFailed = false;
// revert rename operations
for (Match<File, File> match : revertMatches) {
for (Match<File, File> match : doneQueue) {
if (!match.getCandidate().renameTo(match.getValue())) {
revertFailed = true;
}

View File

@ -6,8 +6,6 @@ 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.JButton;
@ -20,29 +18,29 @@ import net.sourceforge.filebot.ResourceManager;
import net.sourceforge.filebot.ui.FileBotList;
import net.sourceforge.filebot.ui.transfer.LoadAction;
import net.sourceforge.filebot.ui.transfer.TransferablePolicy;
import ca.odell.glazedlists.EventList;
class RenameList<E> extends FileBotList<E> {
private JButton loadButton = new JButton();
public RenameList() {
public RenameList(EventList<E> model) {
// replace default model with given model
setModel(model);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.addMouseListener(dndReorderMouseAdapter);
list.addMouseMotionListener(dndReorderMouseAdapter);
JViewport viewport = (JViewport) list.getParent();
viewport.setBackground(list.getBackground());
getViewPort().setBackground(list.getBackground());
getRemoveAction().setEnabled(true);
JPanel buttonPanel = new JPanel(new MigLayout("insets 1.2mm, nogrid, fill", "align center"));
buttonPanel.add(new JButton(downAction));
buttonPanel.add(new JButton(downAction), "gap 10px");
buttonPanel.add(new JButton(upAction), "gap 0");
buttonPanel.add(loadButton, "gap 10px");
buttonPanel.add(new JButton(loadAction), "gap 10px");
add(buttonPanel, BorderLayout.SOUTH);
}
@ -51,31 +49,34 @@ class RenameList<E> extends FileBotList<E> {
@Override
public void setTransferablePolicy(TransferablePolicy transferablePolicy) {
super.setTransferablePolicy(transferablePolicy);
loadButton.setAction(new LoadAction(transferablePolicy));
loadAction.putValue(LoadAction.TRANSFERABLE_POLICY, transferablePolicy);
}
public List<E> getEntries() {
return new ArrayList<E>(getModel());
}
private boolean moveEntry(int fromIndex, int toIndex) {
protected boolean moveEntry(int fromIndex, int toIndex) {
if (toIndex < 0 || toIndex >= getModel().size())
return false;
// move element
getModel().add(toIndex, getModel().remove(fromIndex));
return true;
}
public JViewport getViewPort() {
return listScrollPane.getViewport();
}
private final LoadAction loadAction = new LoadAction(null);
private final AbstractAction upAction = new AbstractAction(null, ResourceManager.getIcon("action.up")) {
public void actionPerformed(ActionEvent e) {
int selectedIndex = getListComponent().getSelectedIndex();
int toIndex = selectedIndex + 1;
int index = getListComponent().getSelectedIndex();
if (moveEntry(selectedIndex, toIndex)) {
getListComponent().setSelectedIndex(toIndex);
if (moveEntry(index, index - 1)) {
getListComponent().setSelectedIndex(index - 1);
}
}
};
@ -83,11 +84,10 @@ class RenameList<E> extends FileBotList<E> {
private final AbstractAction downAction = new AbstractAction(null, ResourceManager.getIcon("action.down")) {
public void actionPerformed(ActionEvent e) {
int selectedIndex = getListComponent().getSelectedIndex();
int toIndex = selectedIndex - 1;
int index = getListComponent().getSelectedIndex();
if (moveEntry(selectedIndex, toIndex)) {
getListComponent().setSelectedIndex(toIndex);
if (moveEntry(index, index + 1)) {
getListComponent().setSelectedIndex(index + 1);
}
}
};

View File

@ -15,25 +15,21 @@ import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListModel;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer;
class RenameListCellRenderer extends DefaultFancyListCellRenderer {
private final ListModel names;
private final ListModel files;
private final RenameModel model;
private final ExtensionLabel extension = new ExtensionLabel();
public RenameListCellRenderer(ListModel names, ListModel files) {
this.names = names;
this.files = files;
public RenameListCellRenderer(RenameModel model) {
this.model = model;
setHighlightingEnabled(false);
@ -50,7 +46,8 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
public void configureListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.configureListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if ((list.getModel() == files) && (value instanceof FileEntry)) {
// show extension label only for items of the files model
if (value instanceof FileEntry) {
FileEntry entry = (FileEntry) value;
extension.setText(entry.getType());
@ -61,7 +58,7 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
extension.setAlpha(1.0f);
if (index >= getMinLength()) {
if (index >= model.matchCount()) {
if (isSelected) {
setGradientColors(noMatchGradientBeginColor, noMatchGradientEndColor);
} else {
@ -71,19 +68,8 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
}
}
private int getMinLength() {
if ((names == null) || (files == null))
return 0;
int n1 = names.getSize();
int n2 = files.getSize();
return Math.min(n1, n2);
}
private class ExtensionLabel extends JLabel {
protected class ExtensionLabel extends JLabel {
private final Insets margin = new Insets(0, 10, 0, 0);
private final Insets padding = new Insets(0, 6, 0, 5);

View File

@ -0,0 +1,76 @@
package net.sourceforge.filebot.ui.panel.rename;
import java.util.AbstractList;
import java.util.Collection;
import net.sourceforge.filebot.similarity.Match;
import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
class RenameModel {
private final EventList<Object> names = new BasicEventList<Object>();
private final EventList<FileEntry> files = new BasicEventList<FileEntry>();
public EventList<Object> names() {
return names;
}
public EventList<FileEntry> files() {
return files;
}
public void clear() {
names.clear();
files.clear();
}
public void setData(Collection<Match<Object, FileEntry>> matches) {
// clear names and files
clear();
// add all matches
for (Match<Object, FileEntry> match : matches) {
names.add(match.getValue());
files.add(match.getCandidate());
}
}
public int matchCount() {
return Math.min(names.size(), files.size());
}
public Match<Object, FileEntry> getMatch(int index) {
if (index >= matchCount())
throw new IndexOutOfBoundsException();
return new Match<Object, FileEntry>(names.get(index), files.get(index));
}
public Collection<Match<Object, FileEntry>> matches() {
return new AbstractList<Match<Object, FileEntry>>() {
@Override
public Match<Object, FileEntry> get(int index) {
return getMatch(index);
}
@Override
public int size() {
return matchCount();
}
};
}
}

View File

@ -6,8 +6,6 @@ import java.awt.Insets;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
@ -20,12 +18,15 @@ import ca.odell.glazedlists.event.ListEventListener;
public class RenamePanel extends FileBotPanel {
private RenameList<Object> namesList = new RenameList<Object>();
private RenameList<FileEntry> filesList = new RenameList<FileEntry>();
private RenameModel model = new RenameModel();
private MatchAction matchAction = new MatchAction(namesList.getModel(), filesList.getModel());
private RenameList<Object> namesList = new RenameList<Object>(model.names());
private RenameAction renameAction = new RenameAction(namesList.getModel(), filesList.getModel());
private RenameList<FileEntry> filesList = new RenameList<FileEntry>(model.files());
private MatchAction matchAction = new MatchAction(model);
private RenameAction renameAction = new RenameAction(model);
public RenamePanel() {
@ -37,22 +38,20 @@ public class RenamePanel extends FileBotPanel {
filesList.setTitle("Current");
filesList.setTransferablePolicy(new FilesListTransferablePolicy(filesList.getModel()));
JList namesListComponent = namesList.getListComponent();
JList filesListComponent = filesList.getListComponent();
RenameListCellRenderer cellrenderer = new RenameListCellRenderer(model);
RenameListCellRenderer cellrenderer = new RenameListCellRenderer(namesListComponent.getModel(), filesListComponent.getModel());
namesListComponent.setCellRenderer(cellrenderer);
filesListComponent.setCellRenderer(cellrenderer);
namesList.getListComponent().setCellRenderer(cellrenderer);
filesList.getListComponent().setCellRenderer(cellrenderer);
ListSelectionModel selectionModel = new DefaultListSelectionModel();
selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
namesListComponent.setSelectionModel(selectionModel);
filesListComponent.setSelectionModel(selectionModel);
// use the same selection model for both lists to synchronize selection
namesList.getListComponent().setSelectionModel(selectionModel);
filesList.getListComponent().setSelectionModel(selectionModel);
// synchronize viewports
new ViewPortSynchronizer((JViewport) namesListComponent.getParent(), (JViewport) filesListComponent.getParent());
new ViewPortSynchronizer(namesList.getViewPort(), filesList.getViewPort());
// create Match button
JButton matchButton = new JButton(matchAction);
@ -64,7 +63,7 @@ public class RenamePanel extends FileBotPanel {
renameButton.setVerticalTextPosition(SwingConstants.BOTTOM);
renameButton.setHorizontalTextPosition(SwingConstants.CENTER);
setLayout(new MigLayout("fill, insets 0, gapx 10px", null, "align 33%"));
setLayout(new MigLayout("fill, insets dialog, gapx 10px", null, "align 33%"));
add(namesList, "grow");
@ -77,8 +76,9 @@ public class RenamePanel extends FileBotPanel {
add(filesList, "grow");
namesList.getModel().addListEventListener(new RepaintHandler<Object>());
filesList.getModel().addListEventListener(new RepaintHandler<FileEntry>());
// repaint on change
model.names().addListEventListener(new RepaintHandler<Object>());
model.files().addListEventListener(new RepaintHandler<FileEntry>());
}

View File

@ -2,7 +2,7 @@
package net.sourceforge.filebot.ui.panel.rename;
public class StringEntry {
class StringEntry {
private String value;

View File

@ -29,7 +29,7 @@ import net.sourceforge.tuned.ui.ArrayListModel;
import net.sourceforge.tuned.ui.TunedUtil;
public class ValidateNamesDialog extends JDialog {
class ValidateNamesDialog extends JDialog {
private final Collection<StringEntry> entries;

View File

@ -8,11 +8,12 @@ import java.io.IOException;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import net.miginfocom.swing.MigLayout;
import net.sourceforge.filebot.ResourceManager;
@ -38,17 +39,19 @@ public class SfvPanel extends FileBotPanel {
public SfvPanel() {
super("SFV", ResourceManager.getIcon("panel.sfv"));
setBorder(BorderFactory.createTitledBorder("SFV"));
JPanel contentPane = new JPanel(new MigLayout("insets 0, nogrid, fill", null, "align bottom"));
contentPane.setBorder(new TitledBorder("SFV"));
setLayout(new MigLayout("insets 0, nogrid, fill", "", "align bottom"));
this.setLayout(new MigLayout("insets dialog, fill"));
this.add(contentPane, "grow");
add(new JScrollPane(sfvTable), "grow, wrap 10px");
contentPane.add(new JScrollPane(sfvTable), "grow, wrap 10px");
add(new JButton(loadAction), "gap 15px, gap bottom 4px");
add(new JButton(saveAction), "gap rel, gap bottom 4px");
add(new JButton(clearAction), "gap rel, gap bottom 4px");
contentPane.add(new JButton(loadAction), "gap 15px, gap bottom 4px");
contentPane.add(new JButton(saveAction), "gap rel, gap bottom 4px");
contentPane.add(new JButton(clearAction), "gap rel, gap bottom 4px");
add(totalProgressPanel, "gap left indent:push, gap bottom 2px, gap right 7px, hidemode 3");
contentPane.add(totalProgressPanel, "gap left indent:push, gap bottom 2px, gap right 7px, hidemode 3");
// Shortcut DELETE
TunedUtil.putActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);

View File

@ -10,7 +10,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
@ -30,7 +29,7 @@ public abstract class FileTransferablePolicy extends TransferablePolicy {
public boolean accept(Transferable tr) {
List<File> files = getFilesFromTransferable(tr);
if (files.isEmpty())
if (files == null || files.isEmpty())
return false;
return accept(files);
@ -82,7 +81,7 @@ public abstract class FileTransferablePolicy extends TransferablePolicy {
throw new RuntimeException(e);
}
return Collections.EMPTY_LIST;
return null;
}

View File

@ -13,17 +13,23 @@ import net.sourceforge.filebot.ui.transfer.TransferablePolicy.TransferAction;
public class LoadAction extends AbstractAction {
private final TransferablePolicy transferablePolicy;
public static final String TRANSFERABLE_POLICY = "transferable policy";
public LoadAction(TransferablePolicy transferablePolicy) {
super("Load", ResourceManager.getIcon("action.load"));
this.transferablePolicy = transferablePolicy;
putValue(TRANSFERABLE_POLICY, transferablePolicy);
}
public void actionPerformed(ActionEvent e) {
// get transferable policy from action properties
TransferablePolicy transferablePolicy = (TransferablePolicy) getValue(TRANSFERABLE_POLICY);
if (transferablePolicy == null)
return;
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new TransferablePolicyFileFilter(transferablePolicy));
@ -45,5 +51,4 @@ public class LoadAction extends AbstractAction {
if (transferablePolicy.accept(transferable))
transferablePolicy.handleTransferable(transferable, action);
}
}

View File

@ -16,7 +16,7 @@ public class NameSimilarityMetricTest {
public void getSimilarity() {
// normalize separators, lower-case
assertEquals(1, metric.getSimilarity("test s01e01 first", "test.S01E01.First"));
assertEquals(1, metric.getSimilarity("test s01e02 second", "test_S01E02_Second"));
assertEquals(1, metric.getSimilarity("test s01e02 second", "test_[S01E02]_Second"));
assertEquals(1, metric.getSimilarity("test s01e03 third", "__test__S01E03__Third__"));
assertEquals(1, metric.getSimilarity("test s01e04 four", "test s01e04 four"));

View File

@ -88,6 +88,9 @@ public class SeasonEpisodeSimilarityMetricTest {
// first two digits <= 29
assertEquals(null, metric.match("The 4400"));
// test lookbehind
assertEquals(null, metric.match("720p"));
}
}