mirror of
https://github.com/mitb-archive/filebot
synced 2024-08-13 17:03:45 -04:00
* improved BackgroundTransferablePolicy
* improved ChecksumComputationService * (... both don't "leak" threads anymore)
This commit is contained in:
parent
ee6dc82d50
commit
2026c60b1d
@ -108,12 +108,7 @@ public class FileFormat {
|
|||||||
if (file.isDirectory())
|
if (file.isDirectory())
|
||||||
return "Folder";
|
return "Folder";
|
||||||
|
|
||||||
return getFileType(file.getName());
|
String extension = getExtension(file.getName(), false);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String getFileType(String name) {
|
|
||||||
String extension = getExtension(name, false);
|
|
||||||
|
|
||||||
if (!extension.isEmpty())
|
if (!extension.isEmpty())
|
||||||
return extension;
|
return extension;
|
||||||
|
@ -10,6 +10,7 @@ import java.util.List;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
import javax.swing.tree.DefaultMutableTreeNode;
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
import javax.swing.tree.DefaultTreeModel;
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
@ -31,7 +32,7 @@ class FileTree extends FileBotTree {
|
|||||||
|
|
||||||
|
|
||||||
public FileTree() {
|
public FileTree() {
|
||||||
FileTreeTransferPolicy transferPolicy = new FileTreeTransferPolicy(this);
|
FileTreeTransferablePolicy transferPolicy = new FileTreeTransferablePolicy(this);
|
||||||
transferPolicy.addPropertyChangeListener(LOADING_PROPERTY, new LoadingPropertyChangeListener());
|
transferPolicy.addPropertyChangeListener(LOADING_PROPERTY, new LoadingPropertyChangeListener());
|
||||||
|
|
||||||
setTransferablePolicy(transferPolicy);
|
setTransferablePolicy(transferPolicy);
|
||||||
@ -71,16 +72,20 @@ class FileTree extends FileBotTree {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
FileTreeTransferPolicy transferPolicy = ((FileTreeTransferPolicy) getTransferablePolicy());
|
((FileTreeTransferablePolicy) getTransferablePolicy()).reset();
|
||||||
boolean loading = transferPolicy.isActive();
|
|
||||||
|
|
||||||
if (loading) {
|
// there may still be some runnables from the transfer in the event queue,
|
||||||
transferPolicy.cancelAll();
|
// clear the model, after those runnables have finished,
|
||||||
}
|
// otherwise it may happen, that stuff is added, after the model has been cleared
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
|
||||||
super.clear();
|
@Override
|
||||||
|
public void run() {
|
||||||
|
FileTree.super.clear();
|
||||||
|
contentChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
contentChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,17 +6,18 @@ import java.io.File;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.tree.DefaultMutableTreeNode;
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
|
|
||||||
import net.sourceforge.filebot.FileBotUtil;
|
import net.sourceforge.filebot.FileBotUtil;
|
||||||
import net.sourceforge.filebot.ui.transferablepolicies.BackgroundFileTransferablePolicy;
|
import net.sourceforge.filebot.ui.transferablepolicies.BackgroundFileTransferablePolicy;
|
||||||
|
|
||||||
|
|
||||||
class FileTreeTransferPolicy extends BackgroundFileTransferablePolicy<DefaultMutableTreeNode> {
|
class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<DefaultMutableTreeNode> {
|
||||||
|
|
||||||
private FileTree tree;
|
private final FileTree tree;
|
||||||
|
|
||||||
|
|
||||||
public FileTreeTransferPolicy(FileTree tree) {
|
public FileTreeTransferablePolicy(FileTree tree) {
|
||||||
this.tree = tree;
|
this.tree = tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,18 +36,26 @@ class FileTreeTransferPolicy extends BackgroundFileTransferablePolicy<DefaultMut
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void process(List<DefaultMutableTreeNode> chunks) {
|
protected void process(List<DefaultMutableTreeNode> chunks) {
|
||||||
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
|
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
|
||||||
|
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
|
||||||
|
|
||||||
for (DefaultMutableTreeNode node : chunks) {
|
for (DefaultMutableTreeNode node : chunks) {
|
||||||
root.add(node);
|
root.add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model.reload(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void load(List<File> files) {
|
protected void load(List<File> files) {
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
publish(getTree(file));
|
DefaultMutableTreeNode node = getTree(file);
|
||||||
|
|
||||||
|
if (Thread.currentThread().isInterrupted())
|
||||||
|
return;
|
||||||
|
|
||||||
|
publish(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +19,7 @@ import javax.swing.ListModel;
|
|||||||
import javax.swing.border.CompoundBorder;
|
import javax.swing.border.CompoundBorder;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
import net.sourceforge.filebot.ui.panel.rename.entry.AbstractFileEntry;
|
import net.sourceforge.filebot.ui.panel.rename.entry.FileEntry;
|
||||||
import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer;
|
import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer;
|
||||||
|
|
||||||
|
|
||||||
@ -50,8 +50,8 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
|||||||
public void configureListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
public void configureListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||||
super.configureListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
super.configureListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||||
|
|
||||||
if ((list.getModel() == files) && (value instanceof AbstractFileEntry<?>)) {
|
if ((list.getModel() == files) && (value instanceof FileEntry)) {
|
||||||
AbstractFileEntry<?> entry = (AbstractFileEntry<?>) value;
|
FileEntry entry = (FileEntry) value;
|
||||||
|
|
||||||
extension.setText(entry.getType());
|
extension.setText(entry.getType());
|
||||||
extension.setVisible(true);
|
extension.setVisible(true);
|
||||||
@ -86,7 +86,7 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
|||||||
private class ExtensionLabel extends JLabel {
|
private class ExtensionLabel extends JLabel {
|
||||||
|
|
||||||
private final Insets margin = new Insets(0, 10, 0, 0);
|
private final Insets margin = new Insets(0, 10, 0, 0);
|
||||||
private final Insets padding = new Insets(1, 6, 1, 5);
|
private final Insets padding = new Insets(0, 6, 0, 5);
|
||||||
private final int arc = 10;
|
private final int arc = 10;
|
||||||
|
|
||||||
private Color gradientBeginColor = new Color(0xFFCC00);
|
private Color gradientBeginColor = new Color(0xFFCC00);
|
||||||
@ -97,7 +97,7 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
|||||||
|
|
||||||
public ExtensionLabel() {
|
public ExtensionLabel() {
|
||||||
setOpaque(false);
|
setOpaque(false);
|
||||||
setForeground(new Color(42, 42, 42));
|
setForeground(new Color(0x141414));
|
||||||
|
|
||||||
setBorder(new CompoundBorder(new EmptyBorder(margin), new EmptyBorder(padding)));
|
setBorder(new CompoundBorder(new EmptyBorder(margin), new EmptyBorder(padding)));
|
||||||
}
|
}
|
||||||
@ -120,7 +120,6 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
|||||||
g2d.setPaint(getForeground());
|
g2d.setPaint(getForeground());
|
||||||
|
|
||||||
Rectangle2D textBounds = g2d.getFontMetrics().getStringBounds(getText(), g2d);
|
Rectangle2D textBounds = g2d.getFontMetrics().getStringBounds(getText(), g2d);
|
||||||
|
|
||||||
g2d.drawString(getText(), (float) (shape.getCenterX() - textBounds.getX() - (textBounds.getWidth() / 2f)), (float) (shape.getCenterY() - textBounds.getY() - (textBounds.getHeight() / 2)));
|
g2d.drawString(getText(), (float) (shape.getCenterX() - textBounds.getX() - (textBounds.getWidth() / 2f)), (float) (shape.getCenterY() - textBounds.getY() - (textBounds.getHeight() / 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,25 +4,11 @@ package net.sourceforge.filebot.ui.panel.rename.entry;
|
|||||||
|
|
||||||
public abstract class AbstractFileEntry<T> extends ListEntry<T> {
|
public abstract class AbstractFileEntry<T> extends ListEntry<T> {
|
||||||
|
|
||||||
private final long length;
|
public AbstractFileEntry(String name, T value) {
|
||||||
|
|
||||||
private final String type;
|
|
||||||
|
|
||||||
|
|
||||||
public AbstractFileEntry(String name, T value, String type, long length) {
|
|
||||||
super(name, value);
|
super(name, value);
|
||||||
this.length = length;
|
|
||||||
this.type = type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public long getLength() {
|
public abstract long getLength();
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,18 @@ import net.sourceforge.filebot.FileFormat;
|
|||||||
public class FileEntry extends AbstractFileEntry<File> {
|
public class FileEntry extends AbstractFileEntry<File> {
|
||||||
|
|
||||||
public FileEntry(File file) {
|
public FileEntry(File file) {
|
||||||
super(FileFormat.getFileName(file), file, FileFormat.getFileType(file), file.length());
|
super(FileFormat.getFileName(file), file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLength() {
|
||||||
|
return getValue().length();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return FileFormat.getFileType(getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,13 @@ import net.sourceforge.filebot.torrent.Torrent.Entry;
|
|||||||
public class TorrentEntry extends AbstractFileEntry<Torrent.Entry> {
|
public class TorrentEntry extends AbstractFileEntry<Torrent.Entry> {
|
||||||
|
|
||||||
public TorrentEntry(Entry value) {
|
public TorrentEntry(Entry value) {
|
||||||
super(FileFormat.getNameWithoutExtension(value.getName()), value, FileFormat.getFileType(value.getName()), value.getLength());
|
super(FileFormat.getNameWithoutExtension(value.getName()), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLength() {
|
||||||
|
return getValue().getLength();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,8 @@ public class Checksum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Checksum(ChecksumComputationTask computationTask) {
|
protected Checksum(ChecksumComputationTask computationTask) {
|
||||||
this.computationTask = computationTask;
|
this.computationTask = computationTask;
|
||||||
|
|
||||||
this.computationTask.addPropertyChangeListener(new ComputationTaskPropertyChangeListener());
|
this.computationTask.addPropertyChangeListener(new ComputationTaskPropertyChangeListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,12 +18,16 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
|
import net.sourceforge.tuned.DefaultThreadFactory;
|
||||||
|
|
||||||
|
|
||||||
public class ChecksumComputationService {
|
public class ChecksumComputationService {
|
||||||
|
|
||||||
public static final String ACTIVE_PROPERTY = "ACTIVE_PROPERTY";
|
public static final String ACTIVE_PROPERTY = "ACTIVE_PROPERTY";
|
||||||
public static final String REMAINING_TASK_COUNT_PROPERTY = "REMAINING_TASK_COUNT_PROPERTY";
|
public static final String REMAINING_TASK_COUNT_PROPERTY = "REMAINING_TASK_COUNT_PROPERTY";
|
||||||
|
|
||||||
|
private static final ThreadFactory checksumComputationThreadFactory = new DefaultThreadFactory("ChecksumComputationPool", Thread.MIN_PRIORITY);
|
||||||
|
|
||||||
private static final ChecksumComputationService service = new ChecksumComputationService();
|
private static final ChecksumComputationService service = new ChecksumComputationService();
|
||||||
|
|
||||||
|
|
||||||
@ -44,22 +48,35 @@ public class ChecksumComputationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ChecksumComputationTask submit(File file, File workerQueueKey) {
|
public Checksum getChecksum(File file, File workerQueueKey) {
|
||||||
ChecksumComputationTask task = new ChecksumComputationTask(file);
|
ChecksumComputationTask task = new ChecksumComputationTask(file);
|
||||||
|
Checksum checksum = new Checksum(task);
|
||||||
|
|
||||||
getExecutor(workerQueueKey).execute(task);
|
getExecutor(workerQueueKey).execute(task);
|
||||||
|
|
||||||
return task;
|
return checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void cancelAll() {
|
public void reset() {
|
||||||
|
deactivate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void deactivate(boolean shutdownNow) {
|
||||||
synchronized (executors) {
|
synchronized (executors) {
|
||||||
for (ChecksumComputationExecutor executor : executors.values()) {
|
for (ChecksumComputationExecutor executor : executors.values()) {
|
||||||
executor.shutdownNow();
|
if (shutdownNow) {
|
||||||
|
executor.shutdownNow();
|
||||||
|
} else {
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setActive(false);
|
executors.clear();
|
||||||
|
|
||||||
|
activeSessionTaskCount.set(0);
|
||||||
|
remainingTaskCount.set(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +125,7 @@ public class ChecksumComputationService {
|
|||||||
|
|
||||||
|
|
||||||
public ChecksumComputationExecutor() {
|
public ChecksumComputationExecutor() {
|
||||||
super(MINIMUM_POOL_SIZE, MINIMUM_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new ChecksumComputationThreadFactory());
|
super(MINIMUM_POOL_SIZE, MINIMUM_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), checksumComputationThreadFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -191,6 +208,7 @@ public class ChecksumComputationService {
|
|||||||
super.afterExecute(r, t);
|
super.afterExecute(r, t);
|
||||||
|
|
||||||
if (remainingTaskCount.decrementAndGet() <= 0) {
|
if (remainingTaskCount.decrementAndGet() <= 0) {
|
||||||
|
deactivate(false);
|
||||||
setActive(false);
|
setActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,15 +218,6 @@ public class ChecksumComputationService {
|
|||||||
|
|
||||||
|
|
||||||
private void setActive(boolean active) {
|
private void setActive(boolean active) {
|
||||||
if (!active) {
|
|
||||||
activeSessionTaskCount.set(0);
|
|
||||||
remainingTaskCount.set(0);
|
|
||||||
|
|
||||||
synchronized (executors) {
|
|
||||||
executors.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater(new FirePropertyChangeRunnable(ACTIVE_PROPERTY, active));
|
SwingUtilities.invokeLater(new FirePropertyChangeRunnable(ACTIVE_PROPERTY, active));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,46 +240,18 @@ public class ChecksumComputationService {
|
|||||||
private class FirePropertyChangeRunnable implements Runnable {
|
private class FirePropertyChangeRunnable implements Runnable {
|
||||||
|
|
||||||
private final String property;
|
private final String property;
|
||||||
private final Object oldValue;
|
|
||||||
private final Object newValue;
|
private final Object newValue;
|
||||||
|
|
||||||
|
|
||||||
public FirePropertyChangeRunnable(String property, Object oldValue, Object newValue) {
|
|
||||||
this.property = property;
|
|
||||||
this.oldValue = oldValue;
|
|
||||||
this.newValue = newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public FirePropertyChangeRunnable(String property, Object newValue) {
|
public FirePropertyChangeRunnable(String property, Object newValue) {
|
||||||
this(property, null, newValue);
|
this.property = property;
|
||||||
|
this.newValue = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
propertyChangeSupport.firePropertyChange(property, oldValue, newValue);
|
propertyChangeSupport.firePropertyChange(property, null, newValue);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class ChecksumComputationThreadFactory implements ThreadFactory {
|
|
||||||
|
|
||||||
private static final AtomicInteger poolNumber = new AtomicInteger(0);
|
|
||||||
|
|
||||||
private final ThreadGroup group = new ThreadGroup("ChecksumComputationPool");
|
|
||||||
private final AtomicInteger threadNumber = new AtomicInteger(0);
|
|
||||||
|
|
||||||
private final String namePrefix = String.format("%s-%d-thread-", group.getName(), poolNumber.incrementAndGet());
|
|
||||||
|
|
||||||
|
|
||||||
public Thread newThread(Runnable r) {
|
|
||||||
Thread t = new Thread(group, r, namePrefix + threadNumber.incrementAndGet(), 0);
|
|
||||||
|
|
||||||
t.setDaemon(false);
|
|
||||||
t.setPriority(Thread.MIN_PRIORITY);
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,15 +147,7 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||||||
|
|
||||||
|
|
||||||
public synchronized void clear() {
|
public synchronized void clear() {
|
||||||
|
ChecksumComputationService.getService().reset();
|
||||||
// stop any running computations
|
|
||||||
for (ChecksumRow row : rows) {
|
|
||||||
for (Checksum checksum : row.getChecksums()) {
|
|
||||||
checksum.cancelComputationTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ChecksumComputationService.getService().cancelAll();
|
|
||||||
|
|
||||||
checksumColumnRoots.clear();
|
checksumColumnRoots.clear();
|
||||||
rows.clear();
|
rows.clear();
|
||||||
|
@ -12,6 +12,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.ListSelectionModel;
|
import javax.swing.ListSelectionModel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.event.TableModelEvent;
|
import javax.swing.event.TableModelEvent;
|
||||||
import javax.swing.table.TableColumn;
|
import javax.swing.table.TableColumn;
|
||||||
import javax.swing.table.TableModel;
|
import javax.swing.table.TableModel;
|
||||||
@ -90,9 +91,18 @@ class SfvTable extends JTable implements TransferablePolicySupport, Saveable {
|
|||||||
|
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
((BackgroundFileTransferablePolicy<?>) getTransferablePolicy()).cancelAll();
|
((BackgroundFileTransferablePolicy<?>) getTransferablePolicy()).reset();
|
||||||
|
|
||||||
((ChecksumTableModel) getModel()).clear();
|
// there may still be some runnables from the transfer in the event queue,
|
||||||
|
// clear the model, after those runnables have finished,
|
||||||
|
// otherwise it may happen, that stuff is added, after the model has been cleared
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
((ChecksumTableModel) getModel()).clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,7 +35,6 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void clear() {
|
protected void clear() {
|
||||||
cancelAll();
|
|
||||||
tableModel.clear();
|
tableModel.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +70,7 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||||||
File compareFile = new File(compareColumnRoot, filename);
|
File compareFile = new File(compareColumnRoot, filename);
|
||||||
|
|
||||||
if (compareFile.exists()) {
|
if (compareFile.exists()) {
|
||||||
publish(new ChecksumTableModel.Entry(filename, new Checksum(ChecksumComputationService.getService().submit(compareFile, compareColumnRoot)), compareColumnRoot));
|
publish(new ChecksumTableModel.Entry(filename, ChecksumComputationService.getService().getChecksum(compareFile, compareColumnRoot), compareColumnRoot));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,8 +122,7 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||||||
load(f, columnRoot, newPrefix);
|
load(f, columnRoot, newPrefix);
|
||||||
}
|
}
|
||||||
} else if (file.isFile()) {
|
} else if (file.isFile()) {
|
||||||
publish(new ChecksumTableModel.Entry(prefix + file.getName(), new Checksum(ChecksumComputationService.getService().submit(file, columnRoot)), columnRoot));
|
publish(new ChecksumTableModel.Entry(prefix + file.getName(), ChecksumComputationService.getService().getChecksum(file, columnRoot), columnRoot));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,19 +9,26 @@ import java.io.File;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
|
import net.sourceforge.tuned.DefaultThreadFactory;
|
||||||
|
|
||||||
|
|
||||||
public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferablePolicy {
|
public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferablePolicy {
|
||||||
|
|
||||||
public static final String LOADING_PROPERTY = "loading";
|
public static final String LOADING_PROPERTY = "loading";
|
||||||
|
|
||||||
|
private static final ThreadFactory backgroundTransferThreadFactory = new DefaultThreadFactory("BackgroundTransferPool", Thread.NORM_PRIORITY);
|
||||||
|
|
||||||
private SingleThreadExecutor executor = null;
|
private SingleThreadExecutor executor = null;
|
||||||
|
|
||||||
|
private final AtomicInteger count = new AtomicInteger(0);
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleTransferable(Transferable tr, boolean add) {
|
public void handleTransferable(Transferable tr, boolean add) {
|
||||||
@ -33,39 +40,54 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||||||
if (!add)
|
if (!add)
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
submit(new LoadFilesTask(files));
|
execute(new LoadFilesTask(files));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void submit(Runnable task) {
|
protected synchronized void execute(Runnable task) {
|
||||||
synchronized (this) {
|
if (executor == null) {
|
||||||
if (executor == null) {
|
executor = new SingleThreadExecutor();
|
||||||
executor = new SingleThreadExecutor();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
executor.submit(task);
|
executor.execute(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
synchronized (this) {
|
return count.get() > 0;
|
||||||
if (executor == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return executor.isActive();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void cancelAll() {
|
private synchronized void setActive(final boolean active) {
|
||||||
synchronized (this) {
|
|
||||||
if (executor != null) {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
// interrupt all threads
|
|
||||||
executor.shutdownNow();
|
@Override
|
||||||
executor = null;
|
public void run() {
|
||||||
|
propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, null, active);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private synchronized void deactivate(boolean shutdownNow) {
|
||||||
|
if (executor != null) {
|
||||||
|
if (shutdownNow) {
|
||||||
|
executor.shutdownNow();
|
||||||
|
} else {
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
executor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
count.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public synchronized void reset() {
|
||||||
|
deactivate(true);
|
||||||
|
setActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -75,7 +97,7 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||||||
* @param chunks
|
* @param chunks
|
||||||
*/
|
*/
|
||||||
protected final void publish(V... chunks) {
|
protected final void publish(V... chunks) {
|
||||||
SwingUtilities.invokeLater(new ProcessChunksTask(chunks, Thread.currentThread()));
|
SwingUtilities.invokeLater(new ProcessChunksTask(chunks));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -90,7 +112,7 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||||||
|
|
||||||
private class LoadFilesTask implements Runnable {
|
private class LoadFilesTask implements Runnable {
|
||||||
|
|
||||||
private List<File> files;
|
private final List<File> files;
|
||||||
|
|
||||||
|
|
||||||
public LoadFilesTask(List<File> files) {
|
public LoadFilesTask(List<File> files) {
|
||||||
@ -107,76 +129,21 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||||||
|
|
||||||
private class ProcessChunksTask implements Runnable {
|
private class ProcessChunksTask implements Runnable {
|
||||||
|
|
||||||
private V[] chunks;
|
private final V[] chunks;
|
||||||
private Thread publisher;
|
|
||||||
|
|
||||||
|
|
||||||
public ProcessChunksTask(V[] chunks, Thread publisher) {
|
public ProcessChunksTask(V[] chunks) {
|
||||||
this.chunks = chunks;
|
this.chunks = chunks;
|
||||||
this.publisher = publisher;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!publisher.isInterrupted() && publisher.isAlive()) {
|
process(Arrays.asList(chunks));
|
||||||
process(Arrays.asList(chunks));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
||||||
private class SingleThreadExecutor extends ThreadPoolExecutor {
|
|
||||||
|
|
||||||
private final AtomicInteger count = new AtomicInteger(0);
|
|
||||||
|
|
||||||
|
|
||||||
public SingleThreadExecutor() {
|
|
||||||
super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isActive() {
|
|
||||||
return count.get() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Runnable command) {
|
|
||||||
|
|
||||||
if (count.getAndIncrement() <= 0) {
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, false, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
super.execute(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void afterExecute(Runnable r, Throwable t) {
|
|
||||||
super.afterExecute(r, t);
|
|
||||||
|
|
||||||
if (count.decrementAndGet() <= 0) {
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, true, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
|
||||||
|
|
||||||
|
|
||||||
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
|
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
|
||||||
@ -188,4 +155,36 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||||||
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
|
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class SingleThreadExecutor extends ThreadPoolExecutor {
|
||||||
|
|
||||||
|
public SingleThreadExecutor() {
|
||||||
|
super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), backgroundTransferThreadFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Runnable command) {
|
||||||
|
|
||||||
|
if (count.getAndIncrement() <= 0) {
|
||||||
|
setActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.execute(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterExecute(Runnable r, Throwable t) {
|
||||||
|
super.afterExecute(r, t);
|
||||||
|
|
||||||
|
if (count.decrementAndGet() <= 0) {
|
||||||
|
// shutdown executor
|
||||||
|
deactivate(false);
|
||||||
|
setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import java.nio.ByteBuffer;
|
|||||||
|
|
||||||
public class ByteBufferInputStream extends InputStream {
|
public class ByteBufferInputStream extends InputStream {
|
||||||
|
|
||||||
private ByteBuffer buffer;
|
private final ByteBuffer buffer;
|
||||||
|
|
||||||
|
|
||||||
public ByteBufferInputStream(ByteBuffer buffer) {
|
public ByteBufferInputStream(ByteBuffer buffer) {
|
||||||
|
41
source/net/sourceforge/tuned/DefaultThreadFactory.java
Normal file
41
source/net/sourceforge/tuned/DefaultThreadFactory.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.tuned;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
|
||||||
|
public class DefaultThreadFactory implements ThreadFactory {
|
||||||
|
|
||||||
|
private final AtomicInteger threadNumber = new AtomicInteger(0);
|
||||||
|
private final ThreadGroup group;
|
||||||
|
|
||||||
|
private final int priority;
|
||||||
|
private final boolean daemon;
|
||||||
|
|
||||||
|
|
||||||
|
public DefaultThreadFactory(String name, int priority) {
|
||||||
|
this(name, priority, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public DefaultThreadFactory(String groupName, int priority, boolean daemon) {
|
||||||
|
group = new ThreadGroup(groupName);
|
||||||
|
group.setDaemon(daemon);
|
||||||
|
|
||||||
|
this.daemon = daemon;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread t = new Thread(group, r, String.format("%s-thread-%d", group.getName(), threadNumber.incrementAndGet()));
|
||||||
|
|
||||||
|
t.setDaemon(daemon);
|
||||||
|
t.setPriority(priority);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user