Refactor Filter / Tools

This commit is contained in:
Reinhard Pointner 2016-11-02 00:07:08 +08:00
parent fcf3bd75f2
commit 8656af9508
10 changed files with 144 additions and 131 deletions

View File

@ -8,6 +8,7 @@ import java.awt.Color;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CancellationException;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
@ -48,10 +49,10 @@ class AttributeTool extends Tool<TableModel> {
} }
@Override @Override
protected TableModel createModelInBackground(File root) { protected TableModel createModelInBackground(List<File> root) {
FileAttributesTableModel model = new FileAttributesTableModel(); FileAttributesTableModel model = new FileAttributesTableModel();
if (root == null) { if (root.isEmpty()) {
return model; return model;
} }
@ -74,6 +75,10 @@ class AttributeTool extends Tool<TableModel> {
model.addRow(String.format("%s::%d", "OMDb", movie.getImdbId()), metaObject, originalName, file); model.addRow(String.format("%s::%d", "OMDb", movie.getImdbId()), metaObject, originalName, file);
} }
} }
if (Thread.interrupted()) {
throw new CancellationException();
}
} }
return model; return model;

View File

@ -2,11 +2,10 @@ package net.filebot.ui.filter;
import static net.filebot.Logging.*; import static net.filebot.Logging.*;
import static net.filebot.UserFiles.*; import static net.filebot.UserFiles.*;
import static net.filebot.util.ExceptionUtilities.*;
import static net.filebot.util.FileUtilities.*; import static net.filebot.util.FileUtilities.*;
import static net.filebot.util.ui.SwingUI.*;
import java.awt.Color; import java.awt.Color;
import java.awt.event.ActionEvent;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.util.ArrayList; import java.util.ArrayList;
@ -21,7 +20,6 @@ import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
@ -76,8 +74,8 @@ class ExtractTool extends Tool<TableModel> {
} }
@Override @Override
protected TableModel createModelInBackground(File root) throws InterruptedException { protected TableModel createModelInBackground(List<File> root) throws Exception {
if (root == null) { if (root.isEmpty()) {
return new ArchiveEntryModel(); return new ArchiveEntryModel();
} }
@ -85,46 +83,34 @@ class ExtractTool extends Tool<TableModel> {
List<File> files = listFiles(root, Archive.VOLUME_ONE_FILTER, HUMAN_NAME_ORDER); List<File> files = listFiles(root, Archive.VOLUME_ONE_FILTER, HUMAN_NAME_ORDER);
List<ArchiveEntry> entries = new ArrayList<ArchiveEntry>(); List<ArchiveEntry> entries = new ArrayList<ArchiveEntry>();
try { for (File file : files) {
for (File file : files) { try (Archive archive = Archive.open(file)) {
try (Archive archive = Archive.open(file)) { for (FileInfo it : archive.listFiles()) {
for (FileInfo it : archive.listFiles()) { entries.add(new ArchiveEntry(file, it));
entries.add(new ArchiveEntry(file, it));
}
} }
}
// unwind thread, if we have been cancelled
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
} catch (Exception e) {
// unwind thread, if we have been cancelled // unwind thread, if we have been cancelled
if (findCause(e, InterruptedException.class) != null) { if (Thread.interrupted()) {
throw findCause(e, InterruptedException.class); throw new CancellationException();
} }
log.log(Level.WARNING, e.getMessage(), e);
} }
return new ArchiveEntryModel(entries); return new ArchiveEntryModel(entries);
} }
private Action extractAction = new AbstractAction("Extract All", ResourceManager.getIcon("package.extract")) { private Action extractAction = newAction("Extract All", ResourceManager.getIcon("package.extract"), evt -> {
List<File> archives = ((ArchiveEntryModel) table.getModel()).getArchiveList();
if (archives.isEmpty())
return;
@Override File selectedFile = showOpenDialogSelectFolder(archives.get(0).getParentFile(), "Extract to ...", evt);
public void actionPerformed(ActionEvent evt) { if (selectedFile == null)
final List<File> archives = ((ArchiveEntryModel) table.getModel()).getArchiveList(); return;
if (archives.isEmpty())
return;
File selectedFile = showOpenDialogSelectFolder(archives.get(0).getParentFile(), "Extract to ...", evt); ExtractWorker worker = new ExtractWorker(archives, selectedFile, null, true, ConflictAction.AUTO);
if (selectedFile == null) ProgressMonitor.runTask("Extract", "Extracting files...", worker);
return; });
ExtractWorker worker = new ExtractWorker(archives, selectedFile, null, true, ConflictAction.AUTO);
ProgressMonitor.runTask("Extract", "Extracting files...", worker);
}
};
private static class ArchiveEntry { private static class ArchiveEntry {
@ -199,7 +185,7 @@ class ExtractTool extends Tool<TableModel> {
} }
protected static class ExtractWorker implements ProgressWorker<Void> { private static class ExtractWorker implements ProgressWorker<Void> {
private final File[] archives; private final File[] archives;
private final File outputFolder; private final File outputFolder;

View File

@ -8,7 +8,6 @@ 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.Enumeration; import java.util.Enumeration;
import java.util.Iterator; import java.util.Iterator;
@ -54,8 +53,20 @@ public class FileTree extends JTree {
return (DefaultTreeModel) super.getModel(); return (DefaultTreeModel) super.getModel();
} }
public FolderNode getRoot() { public List<File> getRoot() {
return (FolderNode) getModel().getRoot(); FolderNode model = (FolderNode) getModel().getRoot();
return model.getChildren().stream().map(node -> {
if (node instanceof FolderNode) {
FolderNode folder = (FolderNode) node;
return folder.getFile();
}
if (node instanceof FileNode) {
FileNode file = (FileNode) node;
return file.getFile();
}
return null;
}).collect(toList());
} }
public void clear() { public void clear() {
@ -258,15 +269,16 @@ public class FileTree extends JTree {
private final String title; private final String title;
private final List<TreeNode> children; private final List<TreeNode> children;
/**
* Creates a root node (no parent, no title, empty list of children)
*/
public FolderNode() { public FolderNode() {
this(null, "", new ArrayList<TreeNode>(0)); this(emptyList()); // empty root node
}
public FolderNode(List<TreeNode> children) {
this(null, "/", children); // root node
} }
public FolderNode(String title, List<TreeNode> children) { public FolderNode(String title, List<TreeNode> children) {
this(null, title, children); this(null, title, children); // virtual node
} }
public FolderNode(File file, String title, List<TreeNode> children) { public FolderNode(File file, String title, List<TreeNode> children) {
@ -318,8 +330,9 @@ public class FileTree extends JTree {
@Override @Override
protected Iterator<TreeNode> children(TreeNode 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;
@ -333,8 +346,9 @@ public class FileTree extends JTree {
@Override @Override
protected File filter(TreeNode 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

@ -63,8 +63,10 @@ class FileTreePanel extends JComponent {
fireFileTreeChange(); fireFileTreeChange();
}); });
public static final String FILE_TREE_PROPERTY = "FILE_TREE";
private void fireFileTreeChange() { private void fireFileTreeChange() {
firePropertyChange("filetree", null, fileTree); firePropertyChange(FILE_TREE_PROPERTY, null, fileTree);
} }
} }

View File

@ -2,14 +2,15 @@ package net.filebot.ui.filter;
import static net.filebot.Logging.*; import static net.filebot.Logging.*;
import static net.filebot.Settings.*; import static net.filebot.Settings.*;
import static net.filebot.util.ExceptionUtilities.*;
import static net.filebot.util.FileUtilities.*; import static net.filebot.util.FileUtilities.*;
import static net.filebot.util.ui.SwingUI.*; import static net.filebot.util.ui.SwingUI.*;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.tree.TreeNode; import javax.swing.tree.TreeNode;
@ -18,7 +19,6 @@ import net.filebot.mac.MacAppUtilities;
import net.filebot.ui.filter.FileTree.FileNode; import net.filebot.ui.filter.FileTree.FileNode;
import net.filebot.ui.filter.FileTree.FolderNode; import net.filebot.ui.filter.FileTree.FolderNode;
import net.filebot.ui.transfer.BackgroundFileTransferablePolicy; import net.filebot.ui.transfer.BackgroundFileTransferablePolicy;
import net.filebot.util.ExceptionUtilities;
import net.filebot.util.FastFile; import net.filebot.util.FastFile;
class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<TreeNode> { class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<TreeNode> {
@ -42,46 +42,36 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<TreeNo
@Override @Override
protected void process(List<TreeNode> root) { protected void process(List<TreeNode> root) {
tree.getModel().setRoot(root.get(0)); tree.getModel().setRoot(new FolderNode(root));
tree.getModel().reload(); tree.getModel().reload();
} }
@Override @Override
protected void process(Exception e) { protected void process(Exception e) {
log.log(Level.WARNING, ExceptionUtilities.getRootCauseMessage(e), e); log.log(Level.WARNING, getRootCauseMessage(e), e);
}
@Override
protected void handleInBackground(List<File> files, TransferAction action) {
super.handleInBackground(files, action);
} }
@Override @Override
protected void load(List<File> files, TransferAction action) { protected void load(List<File> files, TransferAction action) {
// make sure we have access to the parent folder structure, not just the dropped file
if (isMacSandbox()) {
MacAppUtilities.askUnlockFolders(getWindow(tree), files);
}
try { try {
if (files.size() > 1 || containsOnly(files, FILES)) {
files = Arrays.asList(files.get(0).getParentFile());
}
// make sure we have access to the parent folder structure, not just the dropped file
if (isMacSandbox()) {
MacAppUtilities.askUnlockFolders(getWindow(tree), files);
}
// use fast file to minimize system calls like length(), isDirectory(), isFile(), ... // use fast file to minimize system calls like length(), isDirectory(), isFile(), ...
FastFile root = new FastFile(filter(files, FOLDERS).get(0)); TreeNode[] node = files.stream().map(FastFile::new).map(this::getTreeNode).toArray(TreeNode[]::new);
// publish on EDT // publish on EDT
TreeNode[] node = { getTreeNode(root) };
publish(node); publish(node);
} catch (InterruptedException e) { } catch (CancellationException e) {
// supposed to happen if background execution was aborted // supposed to happen if background execution was aborted
} }
} }
private TreeNode getTreeNode(File file) throws InterruptedException { private TreeNode getTreeNode(File file) {
if (Thread.interrupted()) { if (Thread.interrupted()) {
throw new InterruptedException(); throw new CancellationException();
} }
if (file.isDirectory()) { if (file.isDirectory()) {

View File

@ -21,11 +21,11 @@ public class FilterPanel extends JComponent {
add(fileTreePanel, "grow 1, w 300:pref:500"); add(fileTreePanel, "grow 1, w 300:pref:500");
add(toolsPanel, "grow 2"); add(toolsPanel, "grow 2");
fileTreePanel.addPropertyChangeListener("filetree", evt -> { fileTreePanel.addPropertyChangeListener(FileTreePanel.FILE_TREE_PROPERTY, evt -> {
// 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.updateRoot(fileTreePanel.getFileTree().getRoot().getFile()); tool.setRoot(fileTreePanel.getFileTree().getRoot());
} }
}); });
} }

View File

@ -11,6 +11,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.CancellationException;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -53,8 +54,8 @@ class MediaInfoTool extends Tool<TableModel> {
} }
@Override @Override
protected TableModel createModelInBackground(File root) { protected TableModel createModelInBackground(List<File> root) {
if (root == null) { if (root.isEmpty()) {
return new MediaInfoTableModel(); return new MediaInfoTableModel();
} }
@ -74,9 +75,13 @@ class MediaInfoTool extends Tool<TableModel> {
}); });
}); });
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
debug.finest(e.getMessage()); debug.finest(e::toString);
} catch (Exception e) { } catch (Exception e) {
debug.warning(e.getMessage()); debug.warning(e::toString);
}
if (Thread.interrupted()) {
throw new CancellationException();
} }
}); });
} }

View File

@ -7,13 +7,12 @@ import java.awt.Color;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CancellationException;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JSpinner; import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel; import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
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 javax.swing.tree.TreeNode;
@ -51,14 +50,11 @@ class SplitTool extends Tool<TreeModel> {
tree.setTransferHandler(new DefaultTransferHandler(null, new FileTreeExportHandler())); tree.setTransferHandler(new DefaultTransferHandler(null, new FileTreeExportHandler()));
tree.setDragEnabled(true); tree.setDragEnabled(true);
spinnerModel.addChangeListener(new ChangeListener() { // update model in foreground, will be much faster than the initial load because length() is cached now
spinnerModel.addChangeListener(evt -> {
@Override List<File> root = getRoot();
public void stateChanged(ChangeEvent evt) { if (root.size() > 0) {
// update model in foreground, will be much faster than the initial load because length() is cached now setRoot(root);
if (getRoot() != null) {
updateRoot(getRoot());
}
} }
}); });
} }
@ -68,8 +64,8 @@ class SplitTool extends Tool<TreeModel> {
} }
@Override @Override
protected TreeModel createModelInBackground(File root) throws InterruptedException { protected TreeModel createModelInBackground(List<File> root) {
if (root == null) { if (root.isEmpty()) {
return new DefaultTreeModel(new FolderNode("Volumes", emptyList())); return new DefaultTreeModel(new FolderNode("Volumes", emptyList()));
} }
@ -93,7 +89,7 @@ class SplitTool extends Tool<TreeModel> {
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
rootGroup.add(createStatisticsNode(String.format("Disk %d", nextPart++), currentPart)); rootGroup.add(createStatisticsNode(nextPart++, currentPart));
// reset total size and file list // reset total size and file list
totalSize = 0; totalSize = 0;
@ -102,11 +98,15 @@ class SplitTool extends Tool<TreeModel> {
totalSize += fileSize; totalSize += fileSize;
currentPart.add(f); currentPart.add(f);
if (Thread.interrupted()) {
throw new CancellationException();
}
} }
if (!currentPart.isEmpty()) { if (!currentPart.isEmpty()) {
// add last part // add last part
rootGroup.add(createStatisticsNode(String.format("Disk %d", nextPart++), currentPart)); rootGroup.add(createStatisticsNode(nextPart++, currentPart));
} }
if (!remainder.isEmpty()) { if (!remainder.isEmpty()) {
@ -121,4 +121,9 @@ class SplitTool extends Tool<TreeModel> {
tree.setModel(model); tree.setModel(model);
} }
protected FolderNode createStatisticsNode(int disk, List<File> files) {
System.out.println(files);
return createStatisticsNode(String.format("Disk %,d", disk), files);
}
} }

View File

@ -1,60 +1,66 @@
package net.filebot.ui.filter; package net.filebot.ui.filter;
import static java.util.Collections.*;
import static java.util.stream.Collectors.*;
import static net.filebot.Logging.*; import static net.filebot.Logging.*;
import static net.filebot.util.ExceptionUtilities.*;
import static net.filebot.util.FileUtilities.*;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.List; import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import javax.swing.tree.TreeNode; import javax.swing.tree.TreeNode;
import org.apache.commons.io.FileUtils;
import net.filebot.ui.filter.FileTree.FileNode; import net.filebot.ui.filter.FileTree.FileNode;
import net.filebot.ui.filter.FileTree.FolderNode; import net.filebot.ui.filter.FileTree.FolderNode;
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;
abstract class Tool<M> extends JComponent { abstract class Tool<M> extends JComponent {
private UpdateModelTask updateTask = null; private List<File> root = emptyList();
private File root = null;
private UpdateModelTask updateTask;
public Tool(String name) { public Tool(String name) {
setName(name); setName(name);
} }
public File getRoot() { public List<File> getRoot() {
return root; return root;
} }
public void updateRoot(File root) { public void setRoot(List<File> root) {
this.root = root; this.root = root;
if (updateTask != null) { if (updateTask != null) {
updateTask.cancel(true); updateTask.cancel(true);
} }
Tool.this.firePropertyChange(LoadingOverlayPane.LOADING_PROPERTY, false, true); setLoading(true);
updateTask = new UpdateModelTask(root); updateTask = new UpdateModelTask(root);
updateTask.execute(); updateTask.execute();
} }
protected abstract M createModelInBackground(File root) throws InterruptedException; protected void setLoading(boolean loading) {
firePropertyChange(LoadingOverlayPane.LOADING_PROPERTY, !loading, loading);
}
protected abstract M createModelInBackground(List<File> root) throws Exception;
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 File root; private final List<File> root;
public UpdateModelTask(File root) { public UpdateModelTask(List<File> root) {
this.root = root; this.root = root;
} }
@ -66,7 +72,7 @@ abstract class Tool<M> extends JComponent {
@Override @Override
protected void done() { protected void done() {
if (this == updateTask) { if (this == updateTask) {
Tool.this.firePropertyChange(LoadingOverlayPane.LOADING_PROPERTY, true, false); setLoading(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
@ -74,14 +80,12 @@ abstract class Tool<M> extends JComponent {
try { try {
setModel(get()); setModel(get());
} catch (Exception e) { } catch (Exception e) {
Throwable cause = ExceptionUtilities.getRootCause(e); Throwable cause = getRootCause(e);
if (cause instanceof ConcurrentModificationException || cause instanceof InterruptedException) { if (cause instanceof InterruptedException || cause instanceof CancellationException) {
// if it happens, it is supposed to debug.log(Level.FINEST, e, e::toString); // if it happens, it is supposed to
debug.log(Level.FINEST, e.getMessage(), e);
} else { } else {
// should not happen debug.log(Level.WARNING, e, e::toString); // should not happen
debug.log(Level.WARNING, e.getMessage(), e);
} }
} }
} }
@ -89,26 +93,17 @@ abstract class Tool<M> extends JComponent {
} }
protected List<TreeNode> createFileNodes(Collection<File> files) { protected List<TreeNode> createFileNodes(Collection<File> files) {
List<TreeNode> nodes = new ArrayList<TreeNode>(files.size()); return files.stream().map(FileNode::new).collect(toList());
for (File f : files) {
nodes.add(new FileNode(f));
}
return nodes;
} }
protected FolderNode createStatisticsNode(String name, List<File> files) { protected FolderNode createStatisticsNode(String name, List<File> files) {
long totalCount = 0; List<File> selection = listFiles(files, FILES, null);
long totalSize = 0; long size = selection.stream().mapToLong(File::length).sum();
for (File f : files) {
totalCount += FileUtilities.listFiles(f, FileUtilities.FILES).size();
totalSize += FileUtils.sizeOf(f);
}
// set node text (e.g. txt (1 file, 42 Byte)) // 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)); String title = String.format("%s (%,d %s, %s)", name, selection.size(), selection.size() == 1 ? "file" : "files", FileUtilities.formatSize(size));
return new FolderNode(null, title, createFileNodes(files)); return new FolderNode(title, createFileNodes(files));
} }
} }

View File

@ -10,6 +10,7 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.CancellationException;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
@ -44,12 +45,13 @@ class TypeTool extends Tool<TreeModel> {
} }
@Override @Override
protected TreeModel createModelInBackground(File root) throws InterruptedException { protected TreeModel createModelInBackground(List<File> root) {
if (root == null) { if (root.isEmpty()) {
return new DefaultTreeModel(new FolderNode("Types", emptyList())); return new DefaultTreeModel(new FolderNode("Types", emptyList()));
} }
List<File> filesAndFolders = listFiles(root, NOT_HIDDEN, HUMAN_NAME_ORDER); List<File> filesAndFolders = listFiles(root, NOT_HIDDEN, HUMAN_NAME_ORDER);
List<TreeNode> groups = new ArrayList<TreeNode>(); List<TreeNode> groups = new ArrayList<TreeNode>();
for (Entry<String, FileFilter> it : getMetaTypes().entrySet()) { for (Entry<String, FileFilter> it : getMetaTypes().entrySet()) {
@ -57,15 +59,24 @@ class TypeTool extends Tool<TreeModel> {
if (selection.size() > 0) { if (selection.size() > 0) {
groups.add(createStatisticsNode(it.getKey(), selection)); groups.add(createStatisticsNode(it.getKey(), selection));
} }
if (Thread.interrupted()) {
throw new CancellationException();
}
} }
SortedMap<String, TreeNode> extensionGroups = new TreeMap<String, TreeNode>(String.CASE_INSENSITIVE_ORDER); 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())); for (Entry<String, List<File>> it : mapByExtension(filter(filesAndFolders, FILES)).entrySet()) {
if (it.getKey() != null) {
extensionGroups.put(it.getKey(), createStatisticsNode(it.getKey(), it.getValue()));
}
if (Thread.interrupted()) {
throw new CancellationException();
}
} }
groups.addAll(extensionGroups.values()); groups.addAll(extensionGroups.values());
// create tree model // create tree model