* rewrite Analyze panel

This commit is contained in:
Reinhard Pointner 2014-07-17 11:53:24 +00:00
parent 7385a8d307
commit 3678e7388d
14 changed files with 441 additions and 450 deletions

View File

@ -42,7 +42,7 @@ public class AnalyzePanel extends JComponent {
// stopped loading, refresh tools // stopped loading, refresh tools
for (int i = 0; i < toolsPanel.getTabCount(); i++) { for (int i = 0; i < toolsPanel.getTabCount(); i++) {
Tool<?> tool = (Tool<?>) toolsPanel.getComponentAt(i); Tool<?> tool = (Tool<?>) toolsPanel.getComponentAt(i);
tool.setSourceModel(fileTreePanel.getFileTree().getRoot()); tool.updateRoot(fileTreePanel.getFileTree().getRoot().getFile());
} }
} }
}; };

View File

@ -5,7 +5,7 @@ import static net.filebot.MediaTypes.*;
import java.awt.Color; import java.awt.Color;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -16,13 +16,13 @@ import javax.swing.JTable;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
import net.miginfocom.swing.MigLayout;
import net.filebot.media.MetaAttributes; import net.filebot.media.MetaAttributes;
import net.filebot.ui.analyze.FileTree.FolderNode; import net.filebot.util.FileUtilities;
import net.filebot.util.ui.LoadingOverlayPane; import net.filebot.util.ui.LoadingOverlayPane;
import net.filebot.web.Episode; import net.filebot.web.Episode;
import net.filebot.web.Movie; import net.filebot.web.Movie;
import net.filebot.web.SearchResult; import net.filebot.web.SearchResult;
import net.miginfocom.swing.MigLayout;
class AttributeTool extends Tool<TableModel> { class AttributeTool extends Tool<TableModel> {
@ -44,12 +44,11 @@ class AttributeTool extends Tool<TableModel> {
} }
@Override @Override
protected TableModel createModelInBackground(FolderNode sourceModel) throws InterruptedException { protected TableModel createModelInBackground(File root) throws InterruptedException {
List<File> files = (root != null) ? FileUtilities.listFiles(root) : Collections.emptyList();
FileAttributesTableModel model = new FileAttributesTableModel(); FileAttributesTableModel model = new FileAttributesTableModel();
for (File file : files) {
for (Iterator<File> iterator = sourceModel.fileIterator(); iterator.hasNext();) {
File file = iterator.next();
if (VIDEO_FILES.accept(file)) { if (VIDEO_FILES.accept(file)) {
try { try {
MetaAttributes attributes = new MetaAttributes(file); MetaAttributes attributes = new MetaAttributes(file);

View File

@ -12,7 +12,7 @@ import java.beans.PropertyChangeEvent;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -31,11 +31,9 @@ import javax.swing.SwingWorker;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
import net.miginfocom.swing.MigLayout;
import net.filebot.ResourceManager; import net.filebot.ResourceManager;
import net.filebot.archive.Archive; import net.filebot.archive.Archive;
import net.filebot.archive.FileMapper; import net.filebot.archive.FileMapper;
import net.filebot.ui.analyze.FileTree.FolderNode;
import net.filebot.util.FileUtilities; import net.filebot.util.FileUtilities;
import net.filebot.util.ui.GradientStyle; import net.filebot.util.ui.GradientStyle;
import net.filebot.util.ui.LoadingOverlayPane; import net.filebot.util.ui.LoadingOverlayPane;
@ -44,6 +42,7 @@ import net.filebot.util.ui.ProgressDialog.Cancellable;
import net.filebot.util.ui.SwingWorkerPropertyChangeAdapter; import net.filebot.util.ui.SwingWorkerPropertyChangeAdapter;
import net.filebot.util.ui.notification.SeparatorBorder; import net.filebot.util.ui.notification.SeparatorBorder;
import net.filebot.vfs.FileInfo; import net.filebot.vfs.FileInfo;
import net.miginfocom.swing.MigLayout;
class ExtractTool extends Tool<TableModel> { class ExtractTool extends Tool<TableModel> {
@ -73,13 +72,12 @@ class ExtractTool extends Tool<TableModel> {
} }
@Override @Override
protected TableModel createModelInBackground(FolderNode sourceModel) throws InterruptedException { protected TableModel createModelInBackground(File root) throws InterruptedException {
List<File> files = (root != null) ? FileUtilities.listFiles(root) : Collections.emptyList();
List<ArchiveEntry> entries = new ArrayList<ArchiveEntry>(); List<ArchiveEntry> entries = new ArrayList<ArchiveEntry>();
try { try {
for (Iterator<File> iterator = sourceModel.fileIterator(); iterator.hasNext();) { for (File file : files) {
File file = iterator.next();
// ignore non-archives files and trailing multi-volume parts // ignore non-archives files and trailing multi-volume parts
if (Archive.VOLUME_ONE_FILTER.accept(file)) { if (Archive.VOLUME_ONE_FILTER.accept(file)) {
Archive archive = new Archive(file); Archive archive = new Archive(file);

View File

@ -1,7 +1,6 @@
package net.filebot.ui.analyze; package net.filebot.ui.analyze;
import static java.util.Collections.*;
import static net.filebot.ui.NotificationLogging.*; import static net.filebot.ui.NotificationLogging.*;
import java.awt.Desktop; import java.awt.Desktop;
@ -10,11 +9,8 @@ import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
@ -36,117 +32,89 @@ import net.filebot.util.ExceptionUtilities;
import net.filebot.util.FilterIterator; import net.filebot.util.FilterIterator;
import net.filebot.util.TreeIterator; import net.filebot.util.TreeIterator;
public class FileTree extends JTree { public class FileTree extends JTree {
public FileTree() { public FileTree() {
super(new DefaultTreeModel(new FolderNode())); super(new DefaultTreeModel(new FolderNode()));
getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
setCellRenderer(new FileTreeCellRenderer()); setCellRenderer(new FileTreeCellRenderer());
setShowsRootHandles(true); setShowsRootHandles(true);
setRootVisible(false); setRootVisible(false);
setRowHeight(22); setRowHeight(22);
setLargeModel(true); setLargeModel(true);
addMouseListener(new ExpandCollapsePopupListener()); addMouseListener(new ExpandCollapsePopupListener());
} }
@Override @Override
public DefaultTreeModel getModel() { public DefaultTreeModel getModel() {
return (DefaultTreeModel) super.getModel(); return (DefaultTreeModel) super.getModel();
} }
public FolderNode getRoot() { public FolderNode getRoot() {
return (FolderNode) getModel().getRoot(); return (FolderNode) getModel().getRoot();
} }
public void clear() { public void clear() {
getRoot().clear(); getModel().setRoot(new FolderNode());
getModel().reload(); getModel().reload();
} }
public void removeTreeNode(TreePath... paths) {
Set<TreeNode> dirtyNodes = new HashSet<TreeNode>();
for (TreePath path : paths) {
AbstractTreeNode node = (AbstractTreeNode) (path.getLastPathComponent());
FolderNode parent = (FolderNode) node.getParent();
if (parent != null) {
parent.remove(node);
dirtyNodes.add(parent);
}
}
for (TreeNode dirtyNode : dirtyNodes) {
getModel().reload(dirtyNode);
}
}
public void expandAll() { public void expandAll() {
for (int row = 0; row < getRowCount(); row++) { for (int row = 0; row < getRowCount(); row++) {
expandRow(row); expandRow(row);
} }
} }
public void collapseAll() { public void collapseAll() {
for (int row = 0; row < getRowCount(); row++) { for (int row = 0; row < getRowCount(); row++) {
collapseRow(row); collapseRow(row);
} }
} }
private class OpenExpandCollapsePopup extends JPopupMenu { private class OpenExpandCollapsePopup extends JPopupMenu {
public OpenExpandCollapsePopup() { public OpenExpandCollapsePopup() {
TreePath[] selectionPaths = getSelectionPaths(); TreePath[] selectionPaths = getSelectionPaths();
Set<File> selectionFiles = null; Set<File> selectionFiles = null;
if (selectionPaths != null) { if (selectionPaths != null) {
selectionFiles = new LinkedHashSet<File>(selectionPaths.length); selectionFiles = new LinkedHashSet<File>(selectionPaths.length);
for (TreePath treePath : selectionPaths) { for (TreePath treePath : selectionPaths) {
Object node = treePath.getLastPathComponent(); Object node = treePath.getLastPathComponent();
if (node instanceof FileNode) { if (node instanceof FileNode) {
selectionFiles.add(((FileNode) node).getFile()); selectionFiles.add(((FileNode) node).getFile());
} }
} }
} }
if (selectionFiles != null && !selectionFiles.isEmpty()) { if (selectionFiles != null && !selectionFiles.isEmpty()) {
JMenuItem openItem = new JMenuItem(new OpenAction("Open", selectionFiles)); JMenuItem openItem = new JMenuItem(new OpenAction("Open", selectionFiles));
openItem.setFont(openItem.getFont().deriveFont(Font.BOLD)); openItem.setFont(openItem.getFont().deriveFont(Font.BOLD));
add(openItem); add(openItem);
Set<File> selectionParentFolders = new LinkedHashSet<File>(selectionFiles.size()); Set<File> selectionParentFolders = new LinkedHashSet<File>(selectionFiles.size());
for (File file : selectionFiles) { for (File file : selectionFiles) {
selectionParentFolders.add(file.getParentFile()); selectionParentFolders.add(file.getParentFile());
} }
add(new OpenAction("Open Folder", selectionParentFolders)); add(new OpenAction("Open Folder", selectionParentFolders));
addSeparator(); addSeparator();
} }
add(expandAction); add(expandAction);
add(collapseAction); add(collapseAction);
} }
private class OpenAction extends AbstractAction { private class OpenAction extends AbstractAction {
public OpenAction(String text, Collection<File> files) { public OpenAction(String text, Collection<File> files) {
super(text); super(text);
putValue("files", files); putValue("files", files);
} }
public void actionPerformed(ActionEvent event) { public void actionPerformed(ActionEvent event) {
try { try {
@ -158,104 +126,91 @@ public class FileTree extends JTree {
} }
} }
} }
private final Action expandAction = new AbstractAction("Expand all", ResourceManager.getIcon("tree.expand")) { private final Action expandAction = new AbstractAction("Expand all", ResourceManager.getIcon("tree.expand")) {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
expandAll(); expandAll();
} }
}; };
private final Action collapseAction = new AbstractAction("Collapse all", ResourceManager.getIcon("tree.collapse")) { private final Action collapseAction = new AbstractAction("Collapse all", ResourceManager.getIcon("tree.collapse")) {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
collapseAll(); collapseAll();
} }
}; };
} }
private class ExpandCollapsePopupListener extends MouseAdapter { private class ExpandCollapsePopupListener extends MouseAdapter {
@Override @Override
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
maybeShowPopup(e); maybeShowPopup(e);
} }
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
maybeShowPopup(e); maybeShowPopup(e);
} }
private void maybeShowPopup(MouseEvent e) { private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) { if (e.isPopupTrigger()) {
TreePath path = getPathForLocation(e.getX(), e.getY()); TreePath path = getPathForLocation(e.getX(), e.getY());
if (!getSelectionModel().isPathSelected(path)) { if (!getSelectionModel().isPathSelected(path)) {
// if clicked node is not selected, set selection to this node (and deselect all other currently selected nodes) // if clicked node is not selected, set selection to this node (and deselect all other currently selected nodes)
setSelectionPath(path); setSelectionPath(path);
} }
OpenExpandCollapsePopup popup = new OpenExpandCollapsePopup(); OpenExpandCollapsePopup popup = new OpenExpandCollapsePopup();
popup.show(e.getComponent(), e.getX(), e.getY()); popup.show(e.getComponent(), e.getX(), e.getY());
} }
} }
} }
public static class AbstractTreeNode implements TreeNode { public static class AbstractTreeNode implements TreeNode {
private TreeNode parent; private TreeNode parent;
@Override @Override
public TreeNode getParent() { public TreeNode getParent() {
return parent; return parent;
} }
public void setParent(TreeNode parent) { public void setParent(TreeNode parent) {
this.parent = parent; this.parent = parent;
} }
@Override @Override
public Enumeration<? extends TreeNode> children() { public Enumeration<? extends TreeNode> children() {
return null; return null;
} }
@Override @Override
public boolean getAllowsChildren() { public boolean getAllowsChildren() {
return false; return false;
} }
@Override @Override
public TreeNode getChildAt(int childIndex) { public TreeNode getChildAt(int childIndex) {
return null; return null;
} }
@Override @Override
public int getChildCount() { public int getChildCount() {
return 0; return 0;
} }
@Override @Override
public int getIndex(TreeNode node) { public int getIndex(TreeNode node) {
return -1; return -1;
} }
@Override @Override
public boolean isLeaf() { public boolean isLeaf() {
@ -263,155 +218,117 @@ public class FileTree extends JTree {
// so that it won't display any good-for-nothing expand buttons // so that it won't display any good-for-nothing expand buttons
return getChildCount() == 0; return getChildCount() == 0;
} }
} }
public static class FileNode extends AbstractTreeNode { public static class FileNode extends AbstractTreeNode {
private final File file; private final File file;
public FileNode(File file) { public FileNode(File file) {
this.file = file; this.file = file;
} }
public File getFile() { public File getFile() {
return file; return file;
} }
@Override @Override
public String toString() { public String toString() {
return file.getName(); return file.getName();
} }
} }
public static class FolderNode extends AbstractTreeNode { public static class FolderNode extends AbstractTreeNode {
private List<AbstractTreeNode> children; private final File file;
private String title;
private final String title;
private final List<TreeNode> children;
/** /**
* Creates a root node (no parent, no title, empty list of children) * Creates a root node (no parent, no title, empty list of children)
*/ */
public FolderNode() { public FolderNode() {
this(null, 5); this(null, "", emptyList());
} }
public FolderNode(String title, int initialCapacity) { public FolderNode(String title, List<TreeNode> children) {
this.title = title; this(null, title, children);
this.children = new ArrayList<AbstractTreeNode>(initialCapacity);
} }
public void setTitle(String title) { public FolderNode(File file, String title, List<TreeNode> children) {
this.file = file;
this.title = title; this.title = title;
this.children = children;
}
public File getFile() {
return file;
} }
@Override @Override
public String toString() { public String toString() {
return title; return title;
} }
public List<AbstractTreeNode> getChildren() { public List<TreeNode> getChildren() {
return Collections.unmodifiableList(children); return children;
} }
public void add(AbstractTreeNode node) {
if (children.add(node)) {
// node added, set parent
node.setParent(this);
}
}
public void remove(AbstractTreeNode node) {
if (children.remove(node)) {
// node removed, reset parent
node.setParent(null);
}
}
public void clear() {
// reset parent of all children
for (AbstractTreeNode node : children) {
node.setParent(null);
}
// clear children
children.clear();
}
@Override @Override
public Enumeration<? extends TreeNode> children() { public Enumeration<? extends TreeNode> children() {
return Collections.enumeration(children); return enumeration(children);
} }
@Override @Override
public boolean getAllowsChildren() { public boolean getAllowsChildren() {
return true; return true;
} }
@Override @Override
public TreeNode getChildAt(int childIndex) { public TreeNode getChildAt(int childIndex) {
return children.get(childIndex); return children.get(childIndex);
} }
@Override @Override
public int getChildCount() { public int getChildCount() {
return children.size(); return children.size();
} }
@Override @Override
public int getIndex(TreeNode node) { public int getIndex(TreeNode node) {
return children.indexOf(node); return children.indexOf(node);
} }
public Iterator<AbstractTreeNode> treeIterator() { public Iterator<TreeNode> treeIterator() {
return new TreeIterator<AbstractTreeNode>(this) { return new TreeIterator<TreeNode>(this) {
@Override @Override
protected Iterator<AbstractTreeNode> children(AbstractTreeNode node) { protected Iterator<TreeNode> children(TreeNode node) {
if (node instanceof FolderNode) if (node instanceof FolderNode)
return ((FolderNode) node).getChildren().iterator(); return ((FolderNode) node).getChildren().iterator();
// can't step into non-folder nodes // can't step into non-folder nodes
return null; return null;
} }
}; };
} }
public Iterator<File> fileIterator() { public Iterator<File> fileIterator() {
return new FilterIterator<AbstractTreeNode, File>(treeIterator()) { return new FilterIterator<TreeNode, File>(treeIterator()) {
@Override @Override
protected File filter(AbstractTreeNode node) { protected File filter(TreeNode node) {
if (node instanceof FileNode) if (node instanceof FileNode)
return ((FileNode) node).getFile(); return ((FileNode) node).getFile();
// filter out non-file nodes // filter out non-file nodes
return null; return null;
} }
}; };
} }
} }
} }

View File

@ -1,7 +1,5 @@
package net.filebot.ui.analyze; package net.filebot.ui.analyze;
import java.awt.datatransfer.Transferable; import java.awt.datatransfer.Transferable;
import java.io.File; import java.io.File;
import java.util.Iterator; import java.util.Iterator;
@ -17,18 +15,16 @@ import net.filebot.ui.analyze.FileTree.FolderNode;
import net.filebot.ui.transfer.FileTransferable; import net.filebot.ui.transfer.FileTransferable;
import net.filebot.ui.transfer.TransferableExportHandler; import net.filebot.ui.transfer.TransferableExportHandler;
class FileTreeExportHandler implements TransferableExportHandler { class FileTreeExportHandler implements TransferableExportHandler {
@Override @Override
public Transferable createTransferable(JComponent c) { public Transferable createTransferable(JComponent c) {
FileTree tree = (FileTree) c; FileTree tree = (FileTree) c;
LinkedHashSet<File> files = new LinkedHashSet<File>(); LinkedHashSet<File> files = new LinkedHashSet<File>();
for (TreePath path : tree.getSelectionPaths()) { for (TreePath path : tree.getSelectionPaths()) {
TreeNode node = (TreeNode) path.getLastPathComponent(); TreeNode node = (TreeNode) path.getLastPathComponent();
if (node instanceof FileNode) { if (node instanceof FileNode) {
files.add(((FileNode) node).getFile()); files.add(((FileNode) node).getFile());
} else if (node instanceof FolderNode) { } else if (node instanceof FolderNode) {
@ -37,23 +33,21 @@ class FileTreeExportHandler implements TransferableExportHandler {
} }
} }
} }
if (!files.isEmpty()) if (files.isEmpty())
return new FileTransferable(files); return null;
return null; return new FileTransferable(files);
} }
@Override @Override
public void exportDone(JComponent source, Transferable data, int action) { public void exportDone(JComponent source, Transferable data, int action) {
} }
@Override @Override
public int getSourceActions(JComponent c) { public int getSourceActions(JComponent c) {
return TransferHandler.COPY; return TransferHandler.COPY;
} }
} }

View File

@ -1,11 +1,8 @@
package net.filebot.ui.analyze; package net.filebot.ui.analyze;
import static net.filebot.ui.transfer.BackgroundFileTransferablePolicy.*; import static net.filebot.ui.transfer.BackgroundFileTransferablePolicy.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
@ -14,36 +11,32 @@ import javax.swing.BorderFactory;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import net.miginfocom.swing.MigLayout;
import net.filebot.ResourceManager; import net.filebot.ResourceManager;
import net.filebot.ui.transfer.DefaultTransferHandler; import net.filebot.ui.transfer.DefaultTransferHandler;
import net.filebot.ui.transfer.LoadAction; import net.filebot.ui.transfer.LoadAction;
import net.filebot.util.ui.LoadingOverlayPane; import net.filebot.util.ui.LoadingOverlayPane;
import net.filebot.util.ui.TunedUtilities; import net.miginfocom.swing.MigLayout;
class FileTreePanel extends JComponent { class FileTreePanel extends JComponent {
private FileTree fileTree = new FileTree(); private FileTree fileTree = new FileTree();
private FileTreeTransferablePolicy transferablePolicy = new FileTreeTransferablePolicy(fileTree); private FileTreeTransferablePolicy transferablePolicy = new FileTreeTransferablePolicy(fileTree);
public FileTreePanel() { public FileTreePanel() {
fileTree.setTransferHandler(new DefaultTransferHandler(transferablePolicy, null)); fileTree.setTransferHandler(new DefaultTransferHandler(transferablePolicy, null));
setBorder(BorderFactory.createTitledBorder("File Tree")); setBorder(BorderFactory.createTitledBorder("File Tree"));
setLayout(new MigLayout("insets 0, nogrid, fill", "align center", "[fill][pref!]")); setLayout(new MigLayout("insets 0, nogrid, fill", "align center", "[fill][pref!]"));
add(new LoadingOverlayPane(new JScrollPane(fileTree), this), "grow, wrap 1.2mm"); add(new LoadingOverlayPane(new JScrollPane(fileTree), this), "grow, wrap 1.2mm");
add(new JButton(loadAction)); add(new JButton(loadAction));
add(new JButton(clearAction), "gap 1.2mm, wrap 1.2mm"); add(new JButton(clearAction), "gap 1.2mm, wrap 1.2mm");
// forward loading events // forward loading events
transferablePolicy.addPropertyChangeListener(new PropertyChangeListener() { transferablePolicy.addPropertyChangeListener(new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
if (LOADING_PROPERTY.equals(evt.getPropertyName())) { if (LOADING_PROPERTY.equals(evt.getPropertyName())) {
@ -51,10 +44,10 @@ class FileTreePanel extends JComponent {
} }
} }
}); });
// update tree when loading is finished // update tree when loading is finished
transferablePolicy.addPropertyChangeListener(new PropertyChangeListener() { transferablePolicy.addPropertyChangeListener(new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
if (LOADING_PROPERTY.equals(evt.getPropertyName()) && !(Boolean) evt.getNewValue()) { if (LOADING_PROPERTY.equals(evt.getPropertyName()) && !(Boolean) evt.getNewValue()) {
@ -62,26 +55,20 @@ class FileTreePanel extends JComponent {
} }
} }
}); });
// Shortcut DELETE
TunedUtilities.installAction(fileTree, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), removeAction);
TunedUtilities.installAction(fileTree, KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), removeAction);
} }
public FileTree getFileTree() { public FileTree getFileTree() {
return fileTree; return fileTree;
} }
public FileTreeTransferablePolicy getTransferablePolicy() { public FileTreeTransferablePolicy getTransferablePolicy() {
return transferablePolicy; return transferablePolicy;
} }
private final LoadAction loadAction = new LoadAction(transferablePolicy); private final LoadAction loadAction = new LoadAction(transferablePolicy);
private final AbstractAction clearAction = new AbstractAction("Clear", ResourceManager.getIcon("action.clear")) { private final AbstractAction clearAction = new AbstractAction("Clear", ResourceManager.getIcon("action.clear")) {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
transferablePolicy.reset(); transferablePolicy.reset();
@ -89,32 +76,9 @@ class FileTreePanel extends JComponent {
fireFileTreeChange(); fireFileTreeChange();
} }
}; };
private final AbstractAction removeAction = new AbstractAction("Remove") {
@Override
public void actionPerformed(ActionEvent e) {
if (fileTree.getSelectionCount() < 1)
return;
int row = fileTree.getMinSelectionRow();
fileTree.removeTreeNode(fileTree.getSelectionPaths());
int maxRow = fileTree.getRowCount() - 1;
if (row > maxRow)
row = maxRow;
fileTree.setSelectionRow(row);
fireFileTreeChange();
}
};
private void fireFileTreeChange() { private void fireFileTreeChange() {
firePropertyChange("filetree", null, fileTree); firePropertyChange("filetree", null, fileTree);
} }
} }

View File

@ -4,17 +4,21 @@ import static net.filebot.ui.NotificationLogging.*;
import static net.filebot.util.FileUtilities.*; import static net.filebot.util.FileUtilities.*;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import net.filebot.ui.analyze.FileTree.AbstractTreeNode; import javax.swing.tree.TreeNode;
import net.filebot.ui.analyze.FileTree.FileNode; import net.filebot.ui.analyze.FileTree.FileNode;
import net.filebot.ui.analyze.FileTree.FolderNode; import net.filebot.ui.analyze.FileTree.FolderNode;
import net.filebot.ui.transfer.BackgroundFileTransferablePolicy; import net.filebot.ui.transfer.BackgroundFileTransferablePolicy;
import net.filebot.util.ExceptionUtilities; import net.filebot.util.ExceptionUtilities;
import net.filebot.util.FastFile; import net.filebot.util.FastFile;
class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<AbstractTreeNode> { class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<TreeNode> {
private final FileTree tree; private final FileTree tree;
@ -30,18 +34,12 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<Abstra
@Override @Override
protected void clear() { protected void clear() {
super.clear(); super.clear();
tree.clear(); tree.clear();
} }
@Override @Override
protected void process(List<AbstractTreeNode> chunks) { protected void process(List<TreeNode> root) {
FolderNode root = tree.getRoot(); tree.getModel().setRoot(root.get(0));
for (AbstractTreeNode node : chunks) {
root.add(node);
}
tree.getModel().reload(); tree.getModel().reload();
} }
@ -53,40 +51,39 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<Abstra
@Override @Override
protected void load(List<File> files) { protected void load(List<File> files) {
try { try {
for (File file : files) { if (files.size() > 1 || containsOnly(files, FILES)) {
// use fast file to minimize system calls like length(), isDirectory(), isFile(), ... files = Arrays.asList(files.get(0).getParentFile());
AbstractTreeNode node = getTreeNode(new FastFile(file.getPath()));
// publish on EDT
publish(node);
} }
// use fast file to minimize system calls like length(), isDirectory(), isFile(), ...
FastFile root = FastFile.create(filter(files, FOLDERS)).get(0);
// publish on EDT
publish(getTreeNode(root));
} catch (InterruptedException e) { } catch (InterruptedException e) {
// supposed to happen if background execution was aborted // supposed to happen if background execution was aborted
} }
} }
private AbstractTreeNode getTreeNode(File file) throws InterruptedException { private TreeNode getTreeNode(File file) throws InterruptedException {
if (Thread.interrupted()) if (Thread.interrupted()) {
throw new InterruptedException(); throw new InterruptedException();
}
if (file.isDirectory()) { if (file.isDirectory()) {
List<File> files = getChildren(file); LinkedList<TreeNode> children = new LinkedList<TreeNode>();
FolderNode node = new FolderNode(getFolderName(file), files.size()); for (File f : getChildren(file)) {
if (f.isHidden())
continue;
// add folders first
for (File f : files) {
if (f.isDirectory()) { if (f.isDirectory()) {
node.add(getTreeNode(f)); children.addFirst(getTreeNode(f));
} else {
children.addLast(getTreeNode(f));
} }
} }
for (File f : files) { return new FolderNode(file, getFolderName(file), new ArrayList<TreeNode>(children));
if (f.isFile()) {
node.add(getTreeNode(f));
}
}
return node;
} }
return new FileNode(file); return new FileNode(file);
@ -94,7 +91,7 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<Abstra
@Override @Override
public String getFileFilterDescription() { public String getFileFilterDescription() {
return "files and folders"; return "folders";
} }
} }

View File

@ -1,14 +1,10 @@
package net.filebot.ui.analyze; package net.filebot.ui.analyze;
import java.awt.Color; import java.awt.Color;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
@ -18,125 +14,106 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel; import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import net.miginfocom.swing.MigLayout;
import net.filebot.ui.analyze.FileTree.FolderNode; import net.filebot.ui.analyze.FileTree.FolderNode;
import net.filebot.ui.transfer.DefaultTransferHandler; import net.filebot.ui.transfer.DefaultTransferHandler;
import net.filebot.util.FileUtilities; import net.filebot.util.FileUtilities;
import net.filebot.util.ui.GradientStyle; import net.filebot.util.ui.GradientStyle;
import net.filebot.util.ui.LoadingOverlayPane; import net.filebot.util.ui.LoadingOverlayPane;
import net.filebot.util.ui.notification.SeparatorBorder; import net.filebot.util.ui.notification.SeparatorBorder;
import net.miginfocom.swing.MigLayout;
class SplitTool extends Tool<TreeModel> {
class SplitTool extends Tool<TreeModel> implements ChangeListener {
private FileTree tree = new FileTree(); private FileTree tree = new FileTree();
private SpinnerNumberModel spinnerModel = new SpinnerNumberModel(4480, 0, Integer.MAX_VALUE, 100); private SpinnerNumberModel spinnerModel = new SpinnerNumberModel(4480, 0, Integer.MAX_VALUE, 100);
public SplitTool() { public SplitTool() {
super("Disks"); super("Disks");
JScrollPane treeScrollPane = new JScrollPane(tree); JScrollPane treeScrollPane = new JScrollPane(tree);
treeScrollPane.setBorder(new SeparatorBorder(2, new Color(0, 0, 0, 90), GradientStyle.TOP_TO_BOTTOM, SeparatorBorder.Position.BOTTOM)); treeScrollPane.setBorder(new SeparatorBorder(2, new Color(0, 0, 0, 90), GradientStyle.TOP_TO_BOTTOM, SeparatorBorder.Position.BOTTOM));
JSpinner spinner = new JSpinner(spinnerModel); JSpinner spinner = new JSpinner(spinnerModel);
spinner.setEditor(new JSpinner.NumberEditor(spinner, "#")); spinner.setEditor(new JSpinner.NumberEditor(spinner, "#"));
setLayout(new MigLayout("insets 0, nogrid, fill", "align center", "[fill][pref!]")); setLayout(new MigLayout("insets 0, nogrid, fill", "align center", "[fill][pref!]"));
add(new LoadingOverlayPane(treeScrollPane, this), "grow, wrap"); add(new LoadingOverlayPane(treeScrollPane, this), "grow, wrap");
add(new JLabel("Split every")); add(new JLabel("Split every"));
add(spinner, "wmax 80, gap top rel, gap bottom unrel"); add(spinner, "wmax 80, gap top rel, gap bottom unrel");
add(new JLabel("MB.")); add(new JLabel("MB."));
tree.setTransferHandler(new DefaultTransferHandler(null, new FileTreeExportHandler())); tree.setTransferHandler(new DefaultTransferHandler(null, new FileTreeExportHandler()));
tree.setDragEnabled(true); tree.setDragEnabled(true);
spinnerModel.addChangeListener(this); spinnerModel.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent evt) {
// update model in foreground, will be much faster than the initial load because length() is cached now
if (getRoot() != null) {
updateRoot(getRoot());
}
}
});
} }
private long getSplitSize() { private long getSplitSize() {
return spinnerModel.getNumber().intValue() * FileUtilities.MEGA; return spinnerModel.getNumber().intValue() * FileUtilities.MEGA;
} }
private FolderNode sourceModel = null;
public void stateChanged(ChangeEvent evt) {
if (sourceModel != null) {
try {
// update model in foreground, will be much faster than the initial load because length() is cached now
setModel(createModelInBackground(sourceModel));
} catch (InterruptedException e) {
// will not happen
Logger.getLogger(getClass().getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
}
@Override @Override
protected TreeModel createModelInBackground(FolderNode sourceModel) throws InterruptedException { protected TreeModel createModelInBackground(File root) throws InterruptedException {
this.sourceModel = sourceModel;
FolderNode root = new FolderNode();
int nextPart = 1; int nextPart = 1;
long splitSize = getSplitSize(); long splitSize = getSplitSize();
List<File> currentPart = new ArrayList<File>(50); List<File> files = (root != null) ? FileUtilities.listFiles(root) : Collections.emptyList();
List<File> remainder = new ArrayList<File>(50);
List<TreeNode> rootGroup = new ArrayList<TreeNode>();
List<File> currentPart = new ArrayList<File>();
List<File> remainder = new ArrayList<File>();
long totalSize = 0; long totalSize = 0;
for (Iterator<File> iterator = sourceModel.fileIterator(); iterator.hasNext();) { for (File f : files) {
File file = iterator.next(); long fileSize = f.length();
long fileSize = file.length();
if (fileSize > splitSize) { if (fileSize > splitSize) {
remainder.add(file); remainder.add(f);
continue; continue;
} }
if (totalSize + fileSize > splitSize) { if (totalSize + fileSize > splitSize) {
// part is full, add node and start with next one // part is full, add node and start with next one
root.add(createStatisticsNode(String.format("Disk %d", nextPart++), currentPart)); rootGroup.add(createStatisticsNode(String.format("Disk %d", nextPart++), currentPart));
// reset total size and file list // reset total size and file list
totalSize = 0; totalSize = 0;
currentPart.clear(); currentPart.clear();
} }
totalSize += fileSize; totalSize += fileSize;
currentPart.add(file); currentPart.add(f);
// unwind thread, if we have been cancelled
if (Thread.interrupted()) {
throw new InterruptedException();
}
} }
if (!currentPart.isEmpty()) { if (!currentPart.isEmpty()) {
// add last part // add last part
root.add(createStatisticsNode(String.format("Disk %d", nextPart++), currentPart)); rootGroup.add(createStatisticsNode(String.format("Disk %d", nextPart++), currentPart));
} }
if (!remainder.isEmpty()) { if (!remainder.isEmpty()) {
root.add(createStatisticsNode("Remainder", remainder)); rootGroup.add(createStatisticsNode("Remainder", remainder));
} }
return new DefaultTreeModel(root); return new DefaultTreeModel(new FolderNode("Volumes", rootGroup));
} }
@Override @Override
protected void setModel(TreeModel model) { protected void setModel(TreeModel model) {
tree.setModel(model); tree.setModel(model);
} }
} }

View File

@ -1,8 +1,8 @@
package net.filebot.ui.analyze; package net.filebot.ui.analyze;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException; import java.util.ConcurrentModificationException;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
@ -10,6 +10,7 @@ import java.util.logging.Logger;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import javax.swing.tree.TreeNode;
import net.filebot.ui.analyze.FileTree.FileNode; import net.filebot.ui.analyze.FileTree.FileNode;
import net.filebot.ui.analyze.FileTree.FolderNode; import net.filebot.ui.analyze.FileTree.FolderNode;
@ -17,63 +18,63 @@ import net.filebot.util.ExceptionUtilities;
import net.filebot.util.FileUtilities; import net.filebot.util.FileUtilities;
import net.filebot.util.ui.LoadingOverlayPane; import net.filebot.util.ui.LoadingOverlayPane;
import org.apache.commons.io.FileUtils;
abstract class Tool<M> extends JComponent { abstract class Tool<M> extends JComponent {
private UpdateModelTask updateTask = null; private UpdateModelTask updateTask = null;
private File root = null;
public Tool(String name) { public Tool(String name) {
setName(name); setName(name);
} }
public File getRoot() {
public void setSourceModel(FolderNode sourceModel) { return root;
}
public void updateRoot(File root) {
this.root = root;
if (updateTask != null) { if (updateTask != null) {
updateTask.cancel(true); updateTask.cancel(true);
} }
Tool.this.firePropertyChange(LoadingOverlayPane.LOADING_PROPERTY, false, true); Tool.this.firePropertyChange(LoadingOverlayPane.LOADING_PROPERTY, false, true);
updateTask = new UpdateModelTask(sourceModel); updateTask = new UpdateModelTask(root);
updateTask.execute(); updateTask.execute();
} }
protected abstract M createModelInBackground(File root) throws InterruptedException;
protected abstract M createModelInBackground(FolderNode sourceModel) throws InterruptedException;
protected abstract void setModel(M model); protected abstract void setModel(M model);
private class UpdateModelTask extends SwingWorker<M, Void> { private class UpdateModelTask extends SwingWorker<M, Void> {
private final FolderNode sourceModel; private final File root;
public UpdateModelTask(File root) {
public UpdateModelTask(FolderNode sourceModel) { this.root = root;
this.sourceModel = sourceModel;
} }
@Override @Override
protected M doInBackground() throws Exception { protected M doInBackground() throws Exception {
return createModelInBackground(sourceModel); return createModelInBackground(root);
} }
@Override @Override
protected void done() { protected void done() {
if (this == updateTask) { if (this == updateTask) {
Tool.this.firePropertyChange(LoadingOverlayPane.LOADING_PROPERTY, true, false); Tool.this.firePropertyChange(LoadingOverlayPane.LOADING_PROPERTY, true, false);
} }
// update task will only be cancelled if a newer update task has been started // update task will only be cancelled if a newer update task has been started
if (this == updateTask && !isCancelled()) { if (this == updateTask && !isCancelled()) {
try { try {
setModel(get()); setModel(get());
} catch (Exception e) { } catch (Exception e) {
Throwable cause = ExceptionUtilities.getRootCause(e); Throwable cause = ExceptionUtilities.getRootCause(e);
if (cause instanceof ConcurrentModificationException || cause instanceof InterruptedException) { if (cause instanceof ConcurrentModificationException || cause instanceof InterruptedException) {
// if it happens, it is supposed to // if it happens, it is supposed to
} else { } else {
@ -84,25 +85,28 @@ abstract class Tool<M> extends JComponent {
} }
} }
} }
protected List<TreeNode> createFileNodes(Collection<File> files) {
protected FolderNode createStatisticsNode(String name, List<File> files) { List<TreeNode> nodes = new ArrayList<TreeNode>(files.size());
FolderNode folder = new FolderNode(null, files.size()); for (File f : files) {
nodes.add(new FileNode(f));
long totalSize = 0;
for (File file : files) {
folder.add(new FileNode(file));
totalSize += file.length();
} }
return nodes;
// format the number of files string (e.g. 1 file, 2 files, ...)
String numberOfFiles = String.format("%,d %s", files.size(), files.size() == 1 ? "file" : "files");
// set node text (e.g. txt (1 file, 42 Byte))
folder.setTitle(String.format("%s (%s, %s)", name, numberOfFiles, FileUtilities.formatSize(totalSize)));
return folder;
} }
protected FolderNode createStatisticsNode(String name, List<File> files) {
long totalCount = 0;
long totalSize = 0;
for (File f : files) {
totalCount += FileUtilities.listFiles(f).size();
totalSize += FileUtils.sizeOf(f);
}
// set node text (e.g. txt (1 file, 42 Byte))
String title = String.format("%s (%,d %s, %s)", name, totalCount, totalCount == 1 ? "file" : "files", FileUtilities.formatSize(totalSize));
return new FolderNode(null, title, createFileNodes(files));
}
} }

View File

@ -1,99 +1,96 @@
package net.filebot.ui.analyze; package net.filebot.ui.analyze;
import static java.util.Collections.*;
import static net.filebot.util.FileUtilities.*;
import java.io.File; import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.LinkedHashMap;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel; import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import net.miginfocom.swing.MigLayout; import net.filebot.MediaTypes;
import net.filebot.media.MediaDetection;
import net.filebot.ui.analyze.FileTree.FolderNode; import net.filebot.ui.analyze.FileTree.FolderNode;
import net.filebot.ui.transfer.DefaultTransferHandler; import net.filebot.ui.transfer.DefaultTransferHandler;
import net.filebot.util.FileUtilities;
import net.filebot.util.ui.LoadingOverlayPane; import net.filebot.util.ui.LoadingOverlayPane;
import net.miginfocom.swing.MigLayout;
class TypeTool extends Tool<TreeModel> { class TypeTool extends Tool<TreeModel> {
private FileTree tree = new FileTree(); private FileTree tree = new FileTree();
public TypeTool() { public TypeTool() {
super("Types"); super("Types");
setLayout(new MigLayout("insets 0, fill")); setLayout(new MigLayout("insets 0, fill"));
JScrollPane treeScrollPane = new JScrollPane(tree); JScrollPane treeScrollPane = new JScrollPane(tree);
treeScrollPane.setBorder(BorderFactory.createEmptyBorder()); treeScrollPane.setBorder(BorderFactory.createEmptyBorder());
add(new LoadingOverlayPane(treeScrollPane, this), "grow"); add(new LoadingOverlayPane(treeScrollPane, this), "grow");
tree.setTransferHandler(new DefaultTransferHandler(null, new FileTreeExportHandler())); tree.setTransferHandler(new DefaultTransferHandler(null, new FileTreeExportHandler()));
tree.setDragEnabled(true); tree.setDragEnabled(true);
} }
@Override @Override
protected TreeModel createModelInBackground(FolderNode sourceModel) throws InterruptedException { protected TreeModel createModelInBackground(File root) throws InterruptedException {
Map<String, List<File>> map = new HashMap<String, List<File>>(); List<File> filesAndFolders = (root != null) ? listFiles(singleton(root), FILE_WALK_MAX_DEPTH, false, true, true) : emptyList();
List<TreeNode> groups = new ArrayList<TreeNode>();
for (Iterator<File> iterator = sourceModel.fileIterator(); iterator.hasNext();) {
File file = iterator.next(); for (Entry<String, FileFilter> it : getMetaTypes().entrySet()) {
List<File> selection = filter(filesAndFolders, it.getValue());
String extension = FileUtilities.getExtension(file); if (selection.size() > 0) {
if (extension != null) { groups.add(createStatisticsNode(it.getKey(), selection));
extension = extension.toLowerCase();
} }
List<File> files = map.get(extension);
if (files == null) {
files = new ArrayList<File>(50);
map.put(extension, files);
}
files.add(file);
} }
List<String> keys = new ArrayList<String>(map.keySet()); SortedMap<String, TreeNode> extensionGroups = new TreeMap<String, TreeNode>(String.CASE_INSENSITIVE_ORDER);
for (Entry<String, List<File>> it : mapByExtension(filter(filesAndFolders, FILES)).entrySet()) {
// sort strings like always, handle null as empty string if (it.getKey() == null)
Collections.sort(keys, new Comparator<String>() { continue;
@Override extensionGroups.put(it.getKey(), createStatisticsNode(it.getKey(), it.getValue()));
public int compare(String s1, String s2) { }
return ((s1 != null) ? s1 : "").compareTo((s2 != null) ? s2 : ""); groups.addAll(extensionGroups.values());
}
});
// create tree model // create tree model
FolderNode root = new FolderNode(); return new DefaultTreeModel(new FolderNode("Types", groups));
for (String key : keys) {
root.add(createStatisticsNode(key, map.get(key)));
// unwind thread, if we have been cancelled
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
return new DefaultTreeModel(root);
} }
public Map<String, FileFilter> getMetaTypes() {
Map<String, FileFilter> types = new LinkedHashMap<String, FileFilter>();
types.put("Video", MediaTypes.VIDEO_FILES);
types.put("Disk Folder", MediaDetection.getDiskFolderFilter());
types.put("Subtitle", MediaTypes.SUBTITLE_FILES);
types.put("Audio", MediaTypes.AUDIO_FILES);
types.put("Archive", MediaTypes.ARCHIVE_FILES);
types.put("Verification", MediaTypes.VERIFICATION_FILES);
try {
types.put("Clutter", MediaDetection.getClutterFileFilter());
} catch (IOException e) {
Logger.getLogger(TypeTool.class.getName()).log(Level.WARNING, e.getMessage());
}
return types;
}
@Override @Override
protected void setModel(TreeModel model) { protected void setModel(TreeModel model) {
tree.setModel(model); tree.setModel(model);
} }
} }

View File

@ -93,7 +93,7 @@ class FilesListTransferablePolicy extends FileTransferablePolicy {
} }
} }
model.addAll(FastFile.get(entries)); model.addAll(FastFile.create(entries));
} }
@Override @Override

View File

@ -96,7 +96,7 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
loadTorrentFiles(files, values); loadTorrentFiles(files, values);
} else { } else {
// load all files from the given folders recursively up do a depth of 32 // load all files from the given folders recursively up do a depth of 32
values.addAll(FastFile.get(listFiles(files))); values.addAll(FastFile.create(listFiles(files)));
} }
model.addAll(values); model.addAll(values);

View File

@ -77,9 +77,10 @@ public class RenameModel extends MatchModel<Object, File> {
for (int i = 0; i < names.size(); i++) { for (int i = 0; i < names.size(); i++) {
if (hasComplement(i)) { if (hasComplement(i)) {
File originalFile = files().get(i); // make sure we're dealing with regular File objects form here on out
FormattedFuture formattedFuture = names.get(i); File originalFile = new File(files().get(i).getPath());
FormattedFuture formattedFuture = names.get(i);
StringBuilder nameBuilder = new StringBuilder(); StringBuilder nameBuilder = new StringBuilder();
// append formatted name, throw exception if not ready // append formatted name, throw exception if not ready

View File

@ -1,6 +1,7 @@
package net.filebot.util; package net.filebot.util;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -8,8 +9,14 @@ import java.util.List;
public class FastFile extends File { public class FastFile extends File {
private Long length; private Long length;
private Long lastModified;
private Boolean exists;
private Boolean isDirectory; private Boolean isDirectory;
private Boolean isFile; private Boolean isFile;
private Boolean isHidden;
private String[] list;
private File[] listFiles;
public FastFile(String path) { public FastFile(String path) {
super(path); super(path);
@ -24,6 +31,11 @@ public class FastFile extends File {
return length != null ? length : (length = super.length()); return length != null ? length : (length = super.length());
} }
@Override
public boolean exists() {
return exists != null ? exists : (exists = super.exists());
}
@Override @Override
public boolean isDirectory() { public boolean isDirectory() {
return isDirectory != null ? isDirectory : (isDirectory = super.isDirectory()); return isDirectory != null ? isDirectory : (isDirectory = super.isDirectory());
@ -35,23 +47,154 @@ public class FastFile extends File {
} }
@Override @Override
public File[] listFiles() { public boolean isHidden() {
String[] names = list(); return isHidden != null ? isHidden : (isHidden = super.isHidden());
if (names == null) }
return null;
@Override
public long lastModified() {
return lastModified != null ? lastModified : (lastModified = super.lastModified());
}
@Override
public String[] list() {
if (list != null) {
return list;
}
String[] names = super.list();
if (names == null) {
names = new String[0];
}
return (list = names);
}
@Override
public File[] listFiles() {
if (listFiles != null) {
return listFiles;
}
String[] names = list();
File[] files = new File[names.length]; File[] files = new File[names.length];
for (int i = 0; i < names.length; i++) { for (int i = 0; i < names.length; i++) {
files[i] = new FastFile(this, names[i]); files[i] = new FastFile(this, names[i]);
} }
return files;
return (listFiles = files);
} }
public static FastFile get(File file) { @Override
return new FastFile(file.getPath()); public boolean canRead() {
return true;
} }
public static List<FastFile> get(Collection<File> files) { @Override
public boolean canWrite() {
return false;
}
@Override
public boolean canExecute() {
return false;
}
@Override
public boolean createNewFile() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public boolean delete() {
throw new UnsupportedOperationException();
}
@Override
public void deleteOnExit() {
throw new UnsupportedOperationException();
}
@Override
public boolean mkdir() {
throw new UnsupportedOperationException();
}
@Override
public boolean mkdirs() {
throw new UnsupportedOperationException();
}
@Override
public boolean renameTo(File dest) {
throw new UnsupportedOperationException();
}
@Override
public boolean setLastModified(long time) {
throw new UnsupportedOperationException();
}
@Override
public boolean setReadOnly() {
throw new UnsupportedOperationException();
}
@Override
public boolean setWritable(boolean writable, boolean ownerOnly) {
throw new UnsupportedOperationException();
}
@Override
public boolean setWritable(boolean writable) {
throw new UnsupportedOperationException();
}
@Override
public boolean setReadable(boolean readable, boolean ownerOnly) {
throw new UnsupportedOperationException();
}
@Override
public boolean setReadable(boolean readable) {
throw new UnsupportedOperationException();
}
@Override
public boolean setExecutable(boolean executable, boolean ownerOnly) {
throw new UnsupportedOperationException();
}
@Override
public boolean setExecutable(boolean executable) {
throw new UnsupportedOperationException();
}
@Override
public long getTotalSpace() {
throw new UnsupportedOperationException();
}
@Override
public long getFreeSpace() {
throw new UnsupportedOperationException();
}
@Override
public long getUsableSpace() {
throw new UnsupportedOperationException();
}
public static List<FastFile> create(Collection<File> files) {
List<FastFile> result = new ArrayList<FastFile>(files.size()); List<FastFile> result = new ArrayList<FastFile>(files.size());
for (File file : files) { for (File file : files) {