1
0
mirror of https://github.com/mitb-archive/filebot synced 2024-08-13 17:03:45 -04:00

* dnd move: cancel background threads when calling BackgroundFileTransferablePolicy.clear()

* added FastFile, which minimizes fs calls by remembering the results
* use File directly (and not the holder FileEntry) in RenamePanel
This commit is contained in:
Reinhard Pointner 2009-02-12 22:04:17 +00:00
parent 5733cfbcdc
commit 9d7af8bd96
16 changed files with 177 additions and 131 deletions

View File

@ -2,6 +2,7 @@
package net.sourceforge.filebot.similarity;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
@ -35,8 +36,13 @@ public class SeasonEpisodeSimilarityMetric implements SimilarityMetric {
}
protected Collection<SxE> parse(Object o) {
return seasonEpisodeMatcher.match(o.toString());
protected Collection<SxE> parse(Object object) {
if (object instanceof File) {
// parse file name
object = ((File) object).getName();
}
return seasonEpisodeMatcher.match(object.toString());
}

View File

@ -178,7 +178,7 @@ public class Torrent {
public static class Entry {
private final String name;
private final Long length;
private final long length;
private final String path;
@ -194,7 +194,7 @@ public class Torrent {
}
public Long getLength() {
public long getLength() {
return length;
}

View File

@ -12,6 +12,7 @@ import net.sourceforge.filebot.ui.panel.analyze.FileTree.FileNode;
import net.sourceforge.filebot.ui.panel.analyze.FileTree.FolderNode;
import net.sourceforge.filebot.ui.transfer.BackgroundFileTransferablePolicy;
import net.sourceforge.tuned.ExceptionUtilities;
import net.sourceforge.tuned.FastFile;
import net.sourceforge.tuned.FileUtilities;
@ -33,6 +34,8 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<Abstra
@Override
protected void clear() {
super.clear();
tree.clear();
}
@ -59,7 +62,7 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<Abstra
protected void load(List<File> files) {
try {
for (File file : files) {
AbstractTreeNode node = getTreeNode(file);
AbstractTreeNode node = getTreeNode(new FastFile(file.getPath()));
// publish on EDT
publish(node);

View File

@ -1,33 +0,0 @@
package net.sourceforge.filebot.ui.panel.rename;
import java.io.File;
import net.sourceforge.tuned.FileUtilities;
class FileEntry extends AbstractFileEntry {
private final File file;
private final String type;
public FileEntry(File file) {
super(FileUtilities.getName(file), file.length());
this.file = file;
this.type = FileUtilities.getType(file);
}
public File getFile() {
return file;
}
public String getType() {
return type;
}
}

View File

@ -10,14 +10,15 @@ import java.util.Arrays;
import java.util.List;
import net.sourceforge.filebot.ui.transfer.FileTransferablePolicy;
import net.sourceforge.tuned.FastFile;
class FilesListTransferablePolicy extends FileTransferablePolicy {
private final List<? super FileEntry> model;
private final List<File> model;
public FilesListTransferablePolicy(List<? super FileEntry> model) {
public FilesListTransferablePolicy(List<File> model) {
this.model = model;
}
@ -48,7 +49,7 @@ class FilesListTransferablePolicy extends FileTransferablePolicy {
protected void loadFiles(List<File> files) {
for (File file : files) {
model.add(new FileEntry(file));
model.add(new FastFile(file.getPath()));
}
}

View File

@ -6,6 +6,7 @@ import java.awt.Cursor;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@ -30,6 +31,7 @@ import net.sourceforge.filebot.similarity.SeasonEpisodeSimilarityMetric;
import net.sourceforge.filebot.similarity.SimilarityMetric;
import net.sourceforge.filebot.similarity.SeasonEpisodeMatcher.SxE;
import net.sourceforge.filebot.web.Episode;
import net.sourceforge.tuned.FileUtilities;
import net.sourceforge.tuned.ui.ProgressDialog;
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
import net.sourceforge.tuned.ui.ProgressDialog.Cancellable;
@ -59,12 +61,12 @@ class MatchAction extends AbstractAction {
metrics[0] = new LengthEqualsMetric() {
@Override
protected long getLength(Object o) {
if (o instanceof AbstractFileEntry) {
return ((AbstractFileEntry) o).getLength();
protected long getLength(Object object) {
if (object instanceof AbstractFileEntry) {
return ((AbstractFileEntry) object).getLength();
}
return super.getLength(o);
return super.getLength(object);
}
};
@ -90,7 +92,18 @@ class MatchAction extends AbstractAction {
};
// 3. pass: match by generic name similarity (slow, but most matches will have been determined in second pass)
metrics[2] = new NameSimilarityMetric();
metrics[2] = new NameSimilarityMetric() {
@Override
protected String normalize(Object object) {
if (object instanceof File) {
// compare to filename without extension
object = FileUtilities.getName((File) object);
}
return super.normalize(object);
}
};
return Arrays.asList(metrics);
}
@ -151,19 +164,19 @@ class MatchAction extends AbstractAction {
}
protected class BackgroundMatcher extends SwingWorker<List<Match<Object, FileEntry>>, Void> implements Cancellable {
protected class BackgroundMatcher extends SwingWorker<List<Match<Object, File>>, Void> implements Cancellable {
private final Matcher<Object, FileEntry> matcher;
private final Matcher<Object, File> matcher;
public BackgroundMatcher(RenameModel model, Collection<SimilarityMetric> metrics) {
// match names against files
this.matcher = new Matcher<Object, FileEntry>(model.names(), model.files(), metrics);
this.matcher = new Matcher<Object, File>(model.names(), model.files(), metrics);
}
@Override
protected List<Match<Object, FileEntry>> doInBackground() throws Exception {
protected List<Match<Object, File>> doInBackground() throws Exception {
return matcher.match();
}
@ -174,12 +187,12 @@ class MatchAction extends AbstractAction {
return;
try {
List<Match<Object, FileEntry>> matches = get();
List<Match<Object, File>> matches = get();
model.clear();
// put new data into model
for (Match<Object, FileEntry> match : matches) {
for (Match<Object, File> match : matches) {
model.names().add(match.getValue());
model.files().add(match.getCandidate());
}

View File

@ -2,29 +2,24 @@
package net.sourceforge.filebot.ui.panel.rename;
class StringEntry {
class MutableString {
private String value;
public StringEntry(Object value) {
setValue(value);
public MutableString(Object value) {
set(value);
}
public String getValue() {
return value;
}
public void setValue(Object value) {
public void set(Object value) {
this.value = String.valueOf(value);
}
@Override
public String toString() {
return getValue();
return value;
}
}

View File

@ -80,12 +80,13 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
}
protected void submit(List<StringEntry> entries) {
List<StringEntry> invalidEntries = new ArrayList<StringEntry>();
protected void submit(List<MutableString> entries) {
List<MutableString> invalidEntries = new ArrayList<MutableString>();
for (StringEntry entry : entries) {
if (isInvalidFileName(entry.getValue()))
for (MutableString entry : entries) {
if (isInvalidFileName(entry.toString())) {
invalidEntries.add(entry);
}
}
if (!invalidEntries.isEmpty()) {
@ -103,7 +104,7 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
protected void load(String string) {
List<StringEntry> entries = new ArrayList<StringEntry>();
List<MutableString> entries = new ArrayList<MutableString>();
Scanner scanner = new Scanner(string).useDelimiter(LINE_SEPARATOR);
@ -111,7 +112,7 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
String line = scanner.next();
if (line.trim().length() > 0) {
entries.add(new StringEntry(line));
entries.add(new MutableString(line));
}
}
@ -145,7 +146,7 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
protected void loadListFiles(List<File> files) {
try {
List<StringEntry> entries = new ArrayList<StringEntry>();
List<MutableString> entries = new ArrayList<MutableString>();
for (File file : files) {
Scanner scanner = new Scanner(file, "UTF-8").useDelimiter(LINE_SEPARATOR);
@ -154,7 +155,7 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
String line = scanner.next();
if (line.trim().length() > 0) {
entries.add(new StringEntry(line));
entries.add(new MutableString(line));
}
}

View File

@ -36,19 +36,18 @@ 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, FileEntry> match : model.matches()) {
File source = match.getCandidate().getFile();
for (Match<Object, File> match : model.matches()) {
File source = match.getCandidate();
String extension = FileUtilities.getExtension(source);
StringBuilder nameBuilder = new StringBuilder();
nameBuilder.append(match.getValue());
StringBuilder name = new StringBuilder();
name.append(match.getValue());
if (extension != null) {
nameBuilder.append(".").append(extension);
name.append(".").append(extension);
}
File target = new File(source.getParentFile(), nameBuilder.toString());
File target = new File(source.getParentFile(), name.toString());
todoQueue.addLast(new Match<File, File>(source, target));
}

View File

@ -10,6 +10,7 @@ import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.io.File;
import javax.swing.Box;
import javax.swing.BoxLayout;
@ -18,6 +19,7 @@ import javax.swing.JList;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import net.sourceforge.tuned.FileUtilities;
import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer;
@ -47,17 +49,19 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
super.configureListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
// show extension label only for items of the files model
if (value instanceof FileEntry) {
FileEntry entry = (FileEntry) value;
if (value instanceof File) {
File file = (File) value;
this.setText(FileUtilities.getName(file));
extension.setText(getType(file));
extension.setAlpha(1.0f);
extension.setText(entry.getType());
extension.setVisible(true);
} else {
extension.setVisible(false);
}
extension.setAlpha(1.0f);
if (index >= model.matchCount()) {
if (isSelected) {
setGradientColors(noMatchGradientBeginColor, noMatchGradientEndColor);
@ -68,6 +72,20 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
}
}
protected String getType(File file) {
if (file.isDirectory())
return "Folder";
String extension = FileUtilities.getExtension(file);
if (!extension.isEmpty())
return extension;
// some file with no extension
return "File";
}
protected class ExtensionLabel extends JLabel {

View File

@ -2,6 +2,7 @@
package net.sourceforge.filebot.ui.panel.rename;
import java.io.File;
import java.util.AbstractList;
import java.util.Collection;
@ -13,7 +14,7 @@ import ca.odell.glazedlists.EventList;
class RenameModel {
private final EventList<Object> names = new BasicEventList<Object>();
private final EventList<FileEntry> files = new BasicEventList<FileEntry>();
private final EventList<File> files = new BasicEventList<File>();
public EventList<Object> names() {
@ -21,7 +22,7 @@ class RenameModel {
}
public EventList<FileEntry> files() {
public EventList<File> files() {
return files;
}
@ -37,19 +38,19 @@ class RenameModel {
}
public Match<Object, FileEntry> getMatch(int index) {
public Match<Object, File> getMatch(int index) {
if (index >= matchCount())
throw new IndexOutOfBoundsException();
return new Match<Object, FileEntry>(names.get(index), files.get(index));
return new Match<Object, File>(names.get(index), files.get(index));
}
public Collection<Match<Object, FileEntry>> matches() {
return new AbstractList<Match<Object, FileEntry>>() {
public Collection<Match<Object, File>> matches() {
return new AbstractList<Match<Object, File>>() {
@Override
public Match<Object, FileEntry> get(int index) {
public Match<Object, File> get(int index) {
return getMatch(index);
}

View File

@ -44,7 +44,7 @@ public class RenamePanel extends FileBotPanel {
private RenameList<Object> namesList = new RenameList<Object>(model.names());
private RenameList<FileEntry> filesList = new RenameList<FileEntry>(model.files());
private RenameList<File> filesList = new RenameList<File>(model.files());
private MatchAction matchAction = new MatchAction(model);
@ -111,7 +111,7 @@ public class RenamePanel extends FileBotPanel {
// repaint on change
model.names().addListEventListener(new RepaintHandler<Object>());
model.files().addListEventListener(new RepaintHandler<FileEntry>());
model.files().addListEventListener(new RepaintHandler<File>());
}
protected final Action showPopupAction = new AbstractAction("Show Popup") {
@ -164,14 +164,7 @@ public class RenamePanel extends FileBotPanel {
// clear names list
model.names().clear();
// gather File objects from model
List<File> files = new ArrayList<File>();
for (FileEntry entry : model.files()) {
files.add(entry.getFile());
}
AutoFetchEpisodeListMatcher worker = new AutoFetchEpisodeListMatcher(client, files, matchAction.getMetrics()) {
AutoFetchEpisodeListMatcher worker = new AutoFetchEpisodeListMatcher(client, model.files(), matchAction.getMetrics()) {
@Override
protected void done() {
@ -179,20 +172,20 @@ public class RenamePanel extends FileBotPanel {
setAutoMatchInProgress(false);
try {
List<StringEntry> names = new ArrayList<StringEntry>();
List<FileEntry> files = new ArrayList<FileEntry>();
List<MutableString> names = new ArrayList<MutableString>();
List<File> files = new ArrayList<File>();
List<StringEntry> invalidNames = new ArrayList<StringEntry>();
List<MutableString> invalidNames = new ArrayList<MutableString>();
for (Match<File, Episode> match : get()) {
StringEntry name = new StringEntry(match.getCandidate());
MutableString name = new MutableString(match.getCandidate());
if (isInvalidFileName(name.toString())) {
invalidNames.add(name);
}
names.add(name);
files.add(new FileEntry(match.getValue()));
files.add(match.getValue());
}
if (!invalidNames.isEmpty()) {
@ -205,15 +198,13 @@ public class RenamePanel extends FileBotPanel {
}
}
// add remaining file entries
for (File file : remainingFiles()) {
files.add(new FileEntry(file));
}
model.clear();
model.names().addAll(names);
model.files().addAll(files);
// add remaining file entries
model.files().addAll(remainingFiles());
} catch (Exception e) {
Logger.getLogger("ui").log(Level.WARNING, ExceptionUtilities.getRootCauseMessage(e), e);
}

View File

@ -31,7 +31,7 @@ import net.sourceforge.tuned.ui.TunedUtilities;
class ValidateNamesDialog extends JDialog {
private final Collection<StringEntry> entries;
private final Collection<MutableString> entries;
private boolean cancelled = true;
@ -40,7 +40,7 @@ class ValidateNamesDialog extends JDialog {
protected final Action cancelAction = new CancelAction();
public ValidateNamesDialog(Window owner, Collection<StringEntry> entries) {
public ValidateNamesDialog(Window owner, Collection<MutableString> entries) {
super(owner, "Invalid Names", ModalityType.DOCUMENT_MODAL);
this.entries = entries;
@ -94,8 +94,8 @@ class ValidateNamesDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
for (StringEntry entry : entries) {
entry.setValue(validateFileName(entry.getValue()));
for (MutableString entry : entries) {
entry.set(validateFileName(entry.toString()));
}
setEnabled(false);

View File

@ -41,13 +41,22 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
}
@Override
protected void clear() {
// stop other workers on clear (before starting new worker)
reset();
}
public void reset() {
synchronized (workers) {
for (BackgroundWorker worker : workers) {
worker.cancel(true);
if (workers.size() > 0) {
// avoid ConcurrentModificationException by iterating over a copy
for (BackgroundWorker worker : new ArrayList<BackgroundWorker>(workers)) {
// worker.cancel() will invoke worker.done() which will invoke workers.remove(worker)
worker.cancel(true);
}
}
workers.clear();
}
}
@ -70,6 +79,7 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
public BackgroundWorker(List<File> files) {
this.files = files;
// register this worker
synchronized (workers) {
if (workers.add(this) && workers.size() == 1) {

View File

@ -0,0 +1,55 @@
package net.sourceforge.tuned;
import java.io.File;
public class FastFile extends File {
private Long length;
private Boolean isDirectory;
private Boolean isFile;
public FastFile(String path) {
super(path);
}
public FastFile(File parent, String child) {
super(parent, child);
}
@Override
public long length() {
return length != null ? length : (length = super.length());
}
@Override
public boolean isDirectory() {
return isDirectory != null ? isDirectory : (isDirectory = super.isDirectory());
}
@Override
public boolean isFile() {
return isFile != null ? isFile : (isFile = super.isFile());
}
@Override
public File[] listFiles() {
String[] names = list();
File[] files = new File[names.length];
for (int i = 0; i < names.length; i++) {
files[i] = new FastFile(this, names[i]);
}
return files;
}
}

View File

@ -94,20 +94,6 @@ public final class FileUtilities {
}
public static String getType(File file) {
if (file.isDirectory())
return "Folder";
String extension = getExtension(file.getName());
if (!extension.isEmpty())
return extension;
// some file with no extension
return "File";
}
public static boolean containsOnly(Iterable<File> files, FileFilter filter) {
for (File file : files) {
if (!filter.accept(file))