mirror of
https://github.com/mitb-archive/filebot
synced 2024-12-24 16:58:51 -05:00
* rewrite Analyze panel
This commit is contained in:
parent
7385a8d307
commit
3678e7388d
@ -42,7 +42,7 @@ public class AnalyzePanel extends JComponent {
|
||||
// stopped loading, refresh tools
|
||||
for (int i = 0; i < toolsPanel.getTabCount(); i++) {
|
||||
Tool<?> tool = (Tool<?>) toolsPanel.getComponentAt(i);
|
||||
tool.setSourceModel(fileTreePanel.getFileTree().getRoot());
|
||||
tool.updateRoot(fileTreePanel.getFileTree().getRoot().getFile());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ import static net.filebot.MediaTypes.*;
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -16,13 +16,13 @@ import javax.swing.JTable;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
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.web.Episode;
|
||||
import net.filebot.web.Movie;
|
||||
import net.filebot.web.SearchResult;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
class AttributeTool extends Tool<TableModel> {
|
||||
|
||||
@ -44,12 +44,11 @@ class AttributeTool extends Tool<TableModel> {
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
for (Iterator<File> iterator = sourceModel.fileIterator(); iterator.hasNext();) {
|
||||
File file = iterator.next();
|
||||
|
||||
for (File file : files) {
|
||||
if (VIDEO_FILES.accept(file)) {
|
||||
try {
|
||||
MetaAttributes attributes = new MetaAttributes(file);
|
||||
|
@ -12,7 +12,7 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -31,11 +31,9 @@ import javax.swing.SwingWorker;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.filebot.ResourceManager;
|
||||
import net.filebot.archive.Archive;
|
||||
import net.filebot.archive.FileMapper;
|
||||
import net.filebot.ui.analyze.FileTree.FolderNode;
|
||||
import net.filebot.util.FileUtilities;
|
||||
import net.filebot.util.ui.GradientStyle;
|
||||
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.notification.SeparatorBorder;
|
||||
import net.filebot.vfs.FileInfo;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
class ExtractTool extends Tool<TableModel> {
|
||||
|
||||
@ -73,13 +72,12 @@ class ExtractTool extends Tool<TableModel> {
|
||||
}
|
||||
|
||||
@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>();
|
||||
|
||||
try {
|
||||
for (Iterator<File> iterator = sourceModel.fileIterator(); iterator.hasNext();) {
|
||||
File file = iterator.next();
|
||||
|
||||
for (File file : files) {
|
||||
// ignore non-archives files and trailing multi-volume parts
|
||||
if (Archive.VOLUME_ONE_FILTER.accept(file)) {
|
||||
Archive archive = new Archive(file);
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
package net.filebot.ui.analyze;
|
||||
|
||||
|
||||
import static java.util.Collections.*;
|
||||
import static net.filebot.ui.NotificationLogging.*;
|
||||
|
||||
import java.awt.Desktop;
|
||||
@ -10,11 +9,8 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
@ -36,7 +32,6 @@ import net.filebot.util.ExceptionUtilities;
|
||||
import net.filebot.util.FilterIterator;
|
||||
import net.filebot.util.TreeIterator;
|
||||
|
||||
|
||||
public class FileTree extends JTree {
|
||||
|
||||
public FileTree() {
|
||||
@ -52,57 +47,32 @@ public class FileTree extends JTree {
|
||||
addMouseListener(new ExpandCollapsePopupListener());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DefaultTreeModel getModel() {
|
||||
return (DefaultTreeModel) super.getModel();
|
||||
}
|
||||
|
||||
|
||||
public FolderNode getRoot() {
|
||||
return (FolderNode) getModel().getRoot();
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
getRoot().clear();
|
||||
getModel().setRoot(new FolderNode());
|
||||
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() {
|
||||
for (int row = 0; row < getRowCount(); row++) {
|
||||
expandRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void collapseAll() {
|
||||
for (int row = 0; row < getRowCount(); row++) {
|
||||
collapseRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class OpenExpandCollapsePopup extends JPopupMenu {
|
||||
|
||||
public OpenExpandCollapsePopup() {
|
||||
@ -139,7 +109,6 @@ public class FileTree extends JTree {
|
||||
add(collapseAction);
|
||||
}
|
||||
|
||||
|
||||
private class OpenAction extends AbstractAction {
|
||||
|
||||
public OpenAction(String text, Collection<File> files) {
|
||||
@ -147,7 +116,6 @@ public class FileTree extends JTree {
|
||||
putValue("files", files);
|
||||
}
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
try {
|
||||
for (Object file : (Collection<?>) getValue("files")) {
|
||||
@ -159,7 +127,6 @@ public class FileTree extends JTree {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Action expandAction = new AbstractAction("Expand all", ResourceManager.getIcon("tree.expand")) {
|
||||
|
||||
@Override
|
||||
@ -180,7 +147,6 @@ public class FileTree extends JTree {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class ExpandCollapsePopupListener extends MouseAdapter {
|
||||
|
||||
@Override
|
||||
@ -188,13 +154,11 @@ public class FileTree extends JTree {
|
||||
maybeShowPopup(e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
maybeShowPopup(e);
|
||||
}
|
||||
|
||||
|
||||
private void maybeShowPopup(MouseEvent e) {
|
||||
if (e.isPopupTrigger()) {
|
||||
TreePath path = getPathForLocation(e.getX(), e.getY());
|
||||
@ -210,53 +174,44 @@ public class FileTree extends JTree {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class AbstractTreeNode implements TreeNode {
|
||||
|
||||
private TreeNode parent;
|
||||
|
||||
|
||||
@Override
|
||||
public TreeNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
public void setParent(TreeNode parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Enumeration<? extends TreeNode> children() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean getAllowsChildren() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TreeNode getChildAt(int childIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getChildCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getIndex(TreeNode node) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isLeaf() {
|
||||
// if we have no children, tell the UI we are a leaf,
|
||||
@ -266,128 +221,91 @@ public class FileTree extends JTree {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class FileNode extends AbstractTreeNode {
|
||||
|
||||
private final File file;
|
||||
|
||||
|
||||
public FileNode(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return file.getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class FolderNode extends AbstractTreeNode {
|
||||
|
||||
private List<AbstractTreeNode> children;
|
||||
private String title;
|
||||
private final File file;
|
||||
|
||||
private final String title;
|
||||
private final List<TreeNode> children;
|
||||
|
||||
/**
|
||||
* Creates a root node (no parent, no title, empty list of children)
|
||||
*/
|
||||
public FolderNode() {
|
||||
this(null, 5);
|
||||
this(null, "", emptyList());
|
||||
}
|
||||
|
||||
public FolderNode(String title, List<TreeNode> children) {
|
||||
this(null, title, children);
|
||||
}
|
||||
|
||||
public FolderNode(String title, int initialCapacity) {
|
||||
public FolderNode(File file, String title, List<TreeNode> children) {
|
||||
this.file = file;
|
||||
this.title = title;
|
||||
this.children = new ArrayList<AbstractTreeNode>(initialCapacity);
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return title;
|
||||
}
|
||||
|
||||
|
||||
public List<AbstractTreeNode> getChildren() {
|
||||
return Collections.unmodifiableList(children);
|
||||
public List<TreeNode> getChildren() {
|
||||
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
|
||||
public Enumeration<? extends TreeNode> children() {
|
||||
return Collections.enumeration(children);
|
||||
return enumeration(children);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean getAllowsChildren() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TreeNode getChildAt(int childIndex) {
|
||||
return children.get(childIndex);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getChildCount() {
|
||||
return children.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getIndex(TreeNode node) {
|
||||
return children.indexOf(node);
|
||||
}
|
||||
|
||||
|
||||
public Iterator<AbstractTreeNode> treeIterator() {
|
||||
return new TreeIterator<AbstractTreeNode>(this) {
|
||||
public Iterator<TreeNode> treeIterator() {
|
||||
return new TreeIterator<TreeNode>(this) {
|
||||
|
||||
@Override
|
||||
protected Iterator<AbstractTreeNode> children(AbstractTreeNode node) {
|
||||
protected Iterator<TreeNode> children(TreeNode node) {
|
||||
if (node instanceof FolderNode)
|
||||
return ((FolderNode) node).getChildren().iterator();
|
||||
|
||||
@ -398,12 +316,11 @@ public class FileTree extends JTree {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public Iterator<File> fileIterator() {
|
||||
return new FilterIterator<AbstractTreeNode, File>(treeIterator()) {
|
||||
return new FilterIterator<TreeNode, File>(treeIterator()) {
|
||||
|
||||
@Override
|
||||
protected File filter(AbstractTreeNode node) {
|
||||
protected File filter(TreeNode node) {
|
||||
if (node instanceof FileNode)
|
||||
return ((FileNode) node).getFile();
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
|
||||
package net.filebot.ui.analyze;
|
||||
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.io.File;
|
||||
import java.util.Iterator;
|
||||
@ -17,13 +15,11 @@ import net.filebot.ui.analyze.FileTree.FolderNode;
|
||||
import net.filebot.ui.transfer.FileTransferable;
|
||||
import net.filebot.ui.transfer.TransferableExportHandler;
|
||||
|
||||
|
||||
class FileTreeExportHandler implements TransferableExportHandler {
|
||||
|
||||
@Override
|
||||
public Transferable createTransferable(JComponent c) {
|
||||
FileTree tree = (FileTree) c;
|
||||
|
||||
LinkedHashSet<File> files = new LinkedHashSet<File>();
|
||||
|
||||
for (TreePath path : tree.getSelectionPaths()) {
|
||||
@ -38,19 +34,17 @@ class FileTreeExportHandler implements TransferableExportHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (!files.isEmpty())
|
||||
return new FileTransferable(files);
|
||||
|
||||
if (files.isEmpty())
|
||||
return null;
|
||||
}
|
||||
|
||||
return new FileTransferable(files);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportDone(JComponent source, Transferable data, int action) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSourceActions(JComponent c) {
|
||||
return TransferHandler.COPY;
|
||||
|
@ -1,11 +1,8 @@
|
||||
|
||||
package net.filebot.ui.analyze;
|
||||
|
||||
|
||||
import static net.filebot.ui.transfer.BackgroundFileTransferablePolicy.*;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
@ -14,15 +11,12 @@ import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.filebot.ResourceManager;
|
||||
import net.filebot.ui.transfer.DefaultTransferHandler;
|
||||
import net.filebot.ui.transfer.LoadAction;
|
||||
import net.filebot.util.ui.LoadingOverlayPane;
|
||||
import net.filebot.util.ui.TunedUtilities;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
class FileTreePanel extends JComponent {
|
||||
|
||||
@ -30,7 +24,6 @@ class FileTreePanel extends JComponent {
|
||||
|
||||
private FileTreeTransferablePolicy transferablePolicy = new FileTreeTransferablePolicy(fileTree);
|
||||
|
||||
|
||||
public FileTreePanel() {
|
||||
fileTree.setTransferHandler(new DefaultTransferHandler(transferablePolicy, null));
|
||||
|
||||
@ -62,18 +55,12 @@ 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() {
|
||||
return fileTree;
|
||||
}
|
||||
|
||||
|
||||
public FileTreeTransferablePolicy getTransferablePolicy() {
|
||||
return transferablePolicy;
|
||||
}
|
||||
@ -90,29 +77,6 @@ class FileTreePanel extends JComponent {
|
||||
}
|
||||
};
|
||||
|
||||
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() {
|
||||
firePropertyChange("filetree", null, fileTree);
|
||||
}
|
||||
|
@ -4,17 +4,21 @@ import static net.filebot.ui.NotificationLogging.*;
|
||||
import static net.filebot.util.FileUtilities.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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.FolderNode;
|
||||
import net.filebot.ui.transfer.BackgroundFileTransferablePolicy;
|
||||
import net.filebot.util.ExceptionUtilities;
|
||||
import net.filebot.util.FastFile;
|
||||
|
||||
class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<AbstractTreeNode> {
|
||||
class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<TreeNode> {
|
||||
|
||||
private final FileTree tree;
|
||||
|
||||
@ -30,18 +34,12 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<Abstra
|
||||
@Override
|
||||
protected void clear() {
|
||||
super.clear();
|
||||
|
||||
tree.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process(List<AbstractTreeNode> chunks) {
|
||||
FolderNode root = tree.getRoot();
|
||||
|
||||
for (AbstractTreeNode node : chunks) {
|
||||
root.add(node);
|
||||
}
|
||||
|
||||
protected void process(List<TreeNode> root) {
|
||||
tree.getModel().setRoot(root.get(0));
|
||||
tree.getModel().reload();
|
||||
}
|
||||
|
||||
@ -53,40 +51,39 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<Abstra
|
||||
@Override
|
||||
protected void load(List<File> files) {
|
||||
try {
|
||||
for (File file : files) {
|
||||
if (files.size() > 1 || containsOnly(files, FILES)) {
|
||||
files = Arrays.asList(files.get(0).getParentFile());
|
||||
}
|
||||
|
||||
// use fast file to minimize system calls like length(), isDirectory(), isFile(), ...
|
||||
AbstractTreeNode node = getTreeNode(new FastFile(file.getPath()));
|
||||
FastFile root = FastFile.create(filter(files, FOLDERS)).get(0);
|
||||
|
||||
// publish on EDT
|
||||
publish(node);
|
||||
}
|
||||
publish(getTreeNode(root));
|
||||
} catch (InterruptedException e) {
|
||||
// supposed to happen if background execution was aborted
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractTreeNode getTreeNode(File file) throws InterruptedException {
|
||||
if (Thread.interrupted())
|
||||
private TreeNode getTreeNode(File file) throws InterruptedException {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
|
||||
if (file.isDirectory()) {
|
||||
List<File> files = getChildren(file);
|
||||
FolderNode node = new FolderNode(getFolderName(file), files.size());
|
||||
LinkedList<TreeNode> children = new LinkedList<TreeNode>();
|
||||
for (File f : getChildren(file)) {
|
||||
if (f.isHidden())
|
||||
continue;
|
||||
|
||||
// add folders first
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
node.add(getTreeNode(f));
|
||||
children.addFirst(getTreeNode(f));
|
||||
} else {
|
||||
children.addLast(getTreeNode(f));
|
||||
}
|
||||
}
|
||||
|
||||
for (File f : files) {
|
||||
if (f.isFile()) {
|
||||
node.add(getTreeNode(f));
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
return new FolderNode(file, getFolderName(file), new ArrayList<TreeNode>(children));
|
||||
}
|
||||
|
||||
return new FileNode(file);
|
||||
@ -94,7 +91,7 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<Abstra
|
||||
|
||||
@Override
|
||||
public String getFileFilterDescription() {
|
||||
return "files and folders";
|
||||
return "folders";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,10 @@
|
||||
|
||||
package net.filebot.ui.analyze;
|
||||
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
@ -18,23 +14,22 @@ import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
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.transfer.DefaultTransferHandler;
|
||||
import net.filebot.util.FileUtilities;
|
||||
import net.filebot.util.ui.GradientStyle;
|
||||
import net.filebot.util.ui.LoadingOverlayPane;
|
||||
import net.filebot.util.ui.notification.SeparatorBorder;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
|
||||
class SplitTool extends Tool<TreeModel> implements ChangeListener {
|
||||
class SplitTool extends Tool<TreeModel> {
|
||||
|
||||
private FileTree tree = new FileTree();
|
||||
|
||||
private SpinnerNumberModel spinnerModel = new SpinnerNumberModel(4480, 0, Integer.MAX_VALUE, 100);
|
||||
|
||||
|
||||
public SplitTool() {
|
||||
super("Disks");
|
||||
|
||||
@ -55,57 +50,45 @@ class SplitTool extends Tool<TreeModel> implements ChangeListener {
|
||||
tree.setTransferHandler(new DefaultTransferHandler(null, new FileTreeExportHandler()));
|
||||
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() {
|
||||
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
|
||||
protected TreeModel createModelInBackground(FolderNode sourceModel) throws InterruptedException {
|
||||
this.sourceModel = sourceModel;
|
||||
|
||||
FolderNode root = new FolderNode();
|
||||
protected TreeModel createModelInBackground(File root) throws InterruptedException {
|
||||
int nextPart = 1;
|
||||
|
||||
long splitSize = getSplitSize();
|
||||
|
||||
List<File> currentPart = new ArrayList<File>(50);
|
||||
List<File> remainder = new ArrayList<File>(50);
|
||||
List<File> files = (root != null) ? FileUtilities.listFiles(root) : Collections.emptyList();
|
||||
|
||||
List<TreeNode> rootGroup = new ArrayList<TreeNode>();
|
||||
List<File> currentPart = new ArrayList<File>();
|
||||
List<File> remainder = new ArrayList<File>();
|
||||
long totalSize = 0;
|
||||
|
||||
for (Iterator<File> iterator = sourceModel.fileIterator(); iterator.hasNext();) {
|
||||
File file = iterator.next();
|
||||
|
||||
long fileSize = file.length();
|
||||
for (File f : files) {
|
||||
long fileSize = f.length();
|
||||
|
||||
if (fileSize > splitSize) {
|
||||
remainder.add(file);
|
||||
remainder.add(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (totalSize + fileSize > splitSize) {
|
||||
// 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
|
||||
totalSize = 0;
|
||||
@ -113,27 +96,21 @@ class SplitTool extends Tool<TreeModel> implements ChangeListener {
|
||||
}
|
||||
|
||||
totalSize += fileSize;
|
||||
currentPart.add(file);
|
||||
|
||||
// unwind thread, if we have been cancelled
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
currentPart.add(f);
|
||||
}
|
||||
|
||||
if (!currentPart.isEmpty()) {
|
||||
// add last part
|
||||
root.add(createStatisticsNode(String.format("Disk %d", nextPart++), currentPart));
|
||||
rootGroup.add(createStatisticsNode(String.format("Disk %d", nextPart++), currentPart));
|
||||
}
|
||||
|
||||
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
|
||||
protected void setModel(TreeModel model) {
|
||||
tree.setModel(model);
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
package net.filebot.ui.analyze;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
@ -10,6 +10,7 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
import net.filebot.ui.analyze.FileTree.FileNode;
|
||||
import net.filebot.ui.analyze.FileTree.FolderNode;
|
||||
@ -17,50 +18,50 @@ import net.filebot.util.ExceptionUtilities;
|
||||
import net.filebot.util.FileUtilities;
|
||||
import net.filebot.util.ui.LoadingOverlayPane;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
abstract class Tool<M> extends JComponent {
|
||||
|
||||
private UpdateModelTask updateTask = null;
|
||||
|
||||
private File root = null;
|
||||
|
||||
public Tool(String name) {
|
||||
setName(name);
|
||||
}
|
||||
|
||||
public File getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public void updateRoot(File root) {
|
||||
this.root = root;
|
||||
|
||||
public void setSourceModel(FolderNode sourceModel) {
|
||||
if (updateTask != null) {
|
||||
updateTask.cancel(true);
|
||||
}
|
||||
|
||||
Tool.this.firePropertyChange(LoadingOverlayPane.LOADING_PROPERTY, false, true);
|
||||
updateTask = new UpdateModelTask(sourceModel);
|
||||
updateTask = new UpdateModelTask(root);
|
||||
updateTask.execute();
|
||||
}
|
||||
|
||||
|
||||
protected abstract M createModelInBackground(FolderNode sourceModel) throws InterruptedException;
|
||||
|
||||
protected abstract M createModelInBackground(File root) throws InterruptedException;
|
||||
|
||||
protected abstract void setModel(M model);
|
||||
|
||||
|
||||
private class UpdateModelTask extends SwingWorker<M, Void> {
|
||||
|
||||
private final FolderNode sourceModel;
|
||||
private final File root;
|
||||
|
||||
|
||||
public UpdateModelTask(FolderNode sourceModel) {
|
||||
this.sourceModel = sourceModel;
|
||||
public UpdateModelTask(File root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected M doInBackground() throws Exception {
|
||||
return createModelInBackground(sourceModel);
|
||||
return createModelInBackground(root);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
if (this == updateTask) {
|
||||
@ -85,24 +86,27 @@ abstract class Tool<M> extends JComponent {
|
||||
}
|
||||
}
|
||||
|
||||
protected List<TreeNode> createFileNodes(Collection<File> files) {
|
||||
List<TreeNode> nodes = new ArrayList<TreeNode>(files.size());
|
||||
for (File f : files) {
|
||||
nodes.add(new FileNode(f));
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
protected FolderNode createStatisticsNode(String name, List<File> files) {
|
||||
FolderNode folder = new FolderNode(null, files.size());
|
||||
|
||||
long totalCount = 0;
|
||||
long totalSize = 0;
|
||||
|
||||
for (File file : files) {
|
||||
folder.add(new FileNode(file));
|
||||
totalSize += file.length();
|
||||
for (File f : files) {
|
||||
totalCount += FileUtilities.listFiles(f).size();
|
||||
totalSize += FileUtils.sizeOf(f);
|
||||
}
|
||||
|
||||
// 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)));
|
||||
String title = String.format("%s (%,d %s, %s)", name, totalCount, totalCount == 1 ? "file" : "files", FileUtilities.formatSize(totalSize));
|
||||
|
||||
return folder;
|
||||
return new FolderNode(null, title, createFileNodes(files));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,33 +1,38 @@
|
||||
|
||||
package net.filebot.ui.analyze;
|
||||
|
||||
import static java.util.Collections.*;
|
||||
import static net.filebot.util.FileUtilities.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
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.JScrollPane;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
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.transfer.DefaultTransferHandler;
|
||||
import net.filebot.util.FileUtilities;
|
||||
import net.filebot.util.ui.LoadingOverlayPane;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
class TypeTool extends Tool<TreeModel> {
|
||||
|
||||
private FileTree tree = new FileTree();
|
||||
|
||||
|
||||
public TypeTool() {
|
||||
super("Types");
|
||||
|
||||
@ -42,54 +47,46 @@ class TypeTool extends Tool<TreeModel> {
|
||||
tree.setDragEnabled(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected TreeModel createModelInBackground(FolderNode sourceModel) throws InterruptedException {
|
||||
Map<String, List<File>> map = new HashMap<String, List<File>>();
|
||||
protected TreeModel createModelInBackground(File root) throws InterruptedException {
|
||||
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();
|
||||
|
||||
String extension = FileUtilities.getExtension(file);
|
||||
if (extension != null) {
|
||||
extension = extension.toLowerCase();
|
||||
for (Entry<String, FileFilter> it : getMetaTypes().entrySet()) {
|
||||
List<File> selection = filter(filesAndFolders, it.getValue());
|
||||
if (selection.size() > 0) {
|
||||
groups.add(createStatisticsNode(it.getKey(), selection));
|
||||
}
|
||||
}
|
||||
|
||||
List<File> files = map.get(extension);
|
||||
if (files == null) {
|
||||
files = new ArrayList<File>(50);
|
||||
map.put(extension, files);
|
||||
SortedMap<String, TreeNode> extensionGroups = new TreeMap<String, TreeNode>(String.CASE_INSENSITIVE_ORDER);
|
||||
for (Entry<String, List<File>> it : mapByExtension(filter(filesAndFolders, FILES)).entrySet()) {
|
||||
if (it.getKey() == null)
|
||||
continue;
|
||||
|
||||
extensionGroups.put(it.getKey(), createStatisticsNode(it.getKey(), it.getValue()));
|
||||
}
|
||||
|
||||
files.add(file);
|
||||
}
|
||||
|
||||
List<String> keys = new ArrayList<String>(map.keySet());
|
||||
|
||||
// sort strings like always, handle null as empty string
|
||||
Collections.sort(keys, new Comparator<String>() {
|
||||
|
||||
@Override
|
||||
public int compare(String s1, String s2) {
|
||||
return ((s1 != null) ? s1 : "").compareTo((s2 != null) ? s2 : "");
|
||||
}
|
||||
});
|
||||
groups.addAll(extensionGroups.values());
|
||||
|
||||
// create tree model
|
||||
FolderNode root = new FolderNode();
|
||||
|
||||
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(new FolderNode("Types", groups));
|
||||
}
|
||||
|
||||
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
|
||||
protected void setModel(TreeModel model) {
|
||||
|
@ -93,7 +93,7 @@ class FilesListTransferablePolicy extends FileTransferablePolicy {
|
||||
}
|
||||
}
|
||||
|
||||
model.addAll(FastFile.get(entries));
|
||||
model.addAll(FastFile.create(entries));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,7 +96,7 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
|
||||
loadTorrentFiles(files, values);
|
||||
} else {
|
||||
// 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);
|
||||
|
@ -77,9 +77,10 @@ public class RenameModel extends MatchModel<Object, File> {
|
||||
|
||||
for (int i = 0; i < names.size(); i++) {
|
||||
if (hasComplement(i)) {
|
||||
File originalFile = files().get(i);
|
||||
FormattedFuture formattedFuture = names.get(i);
|
||||
// make sure we're dealing with regular File objects form here on out
|
||||
File originalFile = new File(files().get(i).getPath());
|
||||
|
||||
FormattedFuture formattedFuture = names.get(i);
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
|
||||
// append formatted name, throw exception if not ready
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.filebot.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@ -8,8 +9,14 @@ import java.util.List;
|
||||
public class FastFile extends File {
|
||||
|
||||
private Long length;
|
||||
private Long lastModified;
|
||||
private Boolean exists;
|
||||
private Boolean isDirectory;
|
||||
private Boolean isFile;
|
||||
private Boolean isHidden;
|
||||
|
||||
private String[] list;
|
||||
private File[] listFiles;
|
||||
|
||||
public FastFile(String path) {
|
||||
super(path);
|
||||
@ -24,6 +31,11 @@ public class FastFile extends File {
|
||||
return length != null ? length : (length = super.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists() {
|
||||
return exists != null ? exists : (exists = super.exists());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return isDirectory != null ? isDirectory : (isDirectory = super.isDirectory());
|
||||
@ -35,23 +47,154 @@ public class FastFile extends File {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File[] listFiles() {
|
||||
String[] names = list();
|
||||
if (names == null)
|
||||
return null;
|
||||
public boolean isHidden() {
|
||||
return isHidden != null ? isHidden : (isHidden = super.isHidden());
|
||||
}
|
||||
|
||||
@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];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
files[i] = new FastFile(this, names[i]);
|
||||
}
|
||||
return files;
|
||||
|
||||
return (listFiles = files);
|
||||
}
|
||||
|
||||
public static FastFile get(File file) {
|
||||
return new FastFile(file.getPath());
|
||||
@Override
|
||||
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());
|
||||
|
||||
for (File file : files) {
|
||||
|
Loading…
Reference in New Issue
Block a user