package net.filebot.ui.filter;
import static java.util.Collections.*;
import static net.filebot.util.FileUtilities.*;
import java.awt.Color;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CancellationException;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import net.filebot.ui.filter.FileTree.FolderNode;
import net.filebot.ui.transfer.DefaultTransferHandler;
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> {
private FileTree tree = new FileTree();
private SpinnerNumberModel spinnerModel = new SpinnerNumberModel(4480, 0, Integer.MAX_VALUE, 100);
public SplitTool() {
super("Parts");
JScrollPane treeScrollPane = new JScrollPane(tree);
treeScrollPane.setBorder(new SeparatorBorder(2, new Color(0, 0, 0, 90), GradientStyle.TOP_TO_BOTTOM, SeparatorBorder.Position.BOTTOM));
JSpinner spinner = new JSpinner(spinnerModel);
spinner.setEditor(new JSpinner.NumberEditor(spinner, "#"));
setLayout(new MigLayout("insets 0, nogrid, fill", "align center", "[fill][pref!]"));
add(new LoadingOverlayPane(treeScrollPane, this), "grow, wrap");
add(new JLabel("Split every"));
add(spinner, "wmax 80, gap top rel, gap bottom unrel");
add(new JLabel("MB"));
tree.setTransferHandler(new DefaultTransferHandler(null, new FileTreeExportHandler()));
tree.setDragEnabled(true);
// update model in foreground, will be much faster than the initial load because length() is cached now
spinnerModel.addChangeListener(evt -> {
List<File> root = getRoot();
if (root.size() > 0) {
setRoot(root);
}
});
}
private long getSplitSize() {
return spinnerModel.getNumber().intValue() * ONE_MEGABYTE;
}
@Override
protected TreeModel createModelInBackground(List<File> root) {
if (root.isEmpty()) {
return new DefaultTreeModel(new FolderNode("Volumes", emptyList()));
}
int nextPart = 1;
long splitSize = getSplitSize();
List<File> files = listFiles(root, FILES, HUMAN_NAME_ORDER);
List<TreeNode> rootGroup = new ArrayList<TreeNode>();
List<File> currentPart = new ArrayList<File>();
List<File> remainder = new ArrayList<File>();
long totalSize = 0;
for (File f : files) {
long fileSize = f.length();
if (fileSize > splitSize) {
remainder.add(f);
continue;
}
if (totalSize + fileSize > splitSize) {
// part is full, add node and start with next one
rootGroup.add(createStatisticsNode(nextPart++, currentPart));
// reset total size and file list
totalSize = 0;
currentPart.clear();
}
totalSize += fileSize;
currentPart.add(f);
if (Thread.interrupted()) {
throw new CancellationException();
}
}
if (!currentPart.isEmpty()) {
// add last part
rootGroup.add(createStatisticsNode(nextPart++, currentPart));
}
if (!remainder.isEmpty()) {
rootGroup.add(createStatisticsNode("Remainder", remainder));
}
return new DefaultTreeModel(new FolderNode("Volumes", rootGroup));
}
protected FolderNode createStatisticsNode(int disk, List<File> files) {
return createStatisticsNode(String.format("Disk %,d", disk), files);
}
@Override
protected void setModel(TreeModel model) {
tree.setModel(model);
}
}