package org.jftclient.tree;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.annotation.PreDestroy;
import org.apache.commons.io.FileUtils;
import org.jftclient.JFTText;
import org.jftclient.LocalFileUtils;
import org.jftclient.OutputPanel;
import org.jftclient.command.CommandCopy;
import org.jftclient.command.CommandCopyExecution;
import org.jftclient.command.CommandCopyFactory;
import org.jftclient.ssh.Connection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
/**
* @author sergei.malafeev
*/
@Component
public class CommonTree {
private static final Logger logger = LoggerFactory.getLogger(CommonTree.class);
private static DataFormat dataFormat = new DataFormat("tree");
@Autowired
private Connection connection;
private ExecutorService executorService = Executors.newCachedThreadPool();
private OutputPanel outputPanel = OutputPanel.getInstance();
public void expand(TreeView<Node> treeView) {
List<TreeItem<Node>> items = new ArrayList<>(treeView.getSelectionModel().getSelectedItems());
if (items.isEmpty() || items.size() > 1) {
return;
}
TreeItem<Node> item = items.get(0);
if (item.isExpanded()) {
item.setExpanded(false);
} else {
treeView.getSelectionModel().clearSelection();
item.setExpanded(true);
treeView.getSelectionModel().select(item);
}
}
public void refresh(TreeView<Node> treeView, Tree tree) {
List<TreeItem<Node>> items = new ArrayList<>(treeView.getSelectionModel().getSelectedItems());
if (items.isEmpty() || items.size() > 1) {
return;
}
treeView.getSelectionModel().clearSelection();
items.get(0).getChildren().setAll(tree.buildChildren(items.get(0)));
treeView.getSelectionModel().select(items.get(0));
}
public void deleteSelectedItems(TreeView<Node> treeView, Tree tree) {
List<TreeItem<Node>> items = new ArrayList<>(treeView.getSelectionModel().getSelectedItems());
if (items.isEmpty()) {
return;
}
treeView.getSelectionModel().clearSelection();
TreeItem<Node> parent = null;
Map<String, TreeItem<Node>> reducedItems = reduceByPaths(items);
for (Map.Entry<String, TreeItem<Node>> item : reducedItems.entrySet()) {
if (item.getValue().getParent() != null) {
if (parent == null) {
parent = item.getValue().getParent();
} else {
if (item.getValue().getParent().getValue().isParentOf(parent.getValue())) {
parent = item.getValue().getParent();
}
}
}
if (tree.isLocal()) {
File src = new File(item.getKey());
if (src.isFile()) {
if (!src.delete()) {
logger.warn("cannot delete file {}", src.getAbsolutePath());
outputPanel.println(JFTText.getLocalHost(), JFTText.textBlack("rm " +
src.getAbsolutePath() + " "), JFTText.failed());
} else {
outputPanel.println(JFTText.getLocalHost(), JFTText.textBlack("rm " +
src.getAbsolutePath()));
}
} else {
try {
FileUtils.deleteDirectory(src);
outputPanel.println(JFTText.getLocalHost(), JFTText.textBlack("rm -rf " +
src.getAbsolutePath()));
} catch (IOException e) {
logger.warn("failed to remove dir", e);
outputPanel.println(JFTText.getLocalHost(), JFTText.textBlack("rm -rf " +
src.getAbsolutePath() + " "), JFTText.failed());
}
}
} else {
connection.rm(item.getKey());
}
}
if (parent != null) {
parent.getChildren().setAll(tree.buildChildren(parent));
}
}
public void setDragDropEvent(NodeTreeCell cell, LocalTree localTree) {
//Source:
cell.setOnDragDetected(event -> {
Dragboard db = cell.startDragAndDrop(TransferMode.ANY);
db.setDragView(cell.getCurrentImage());
ClipboardContent content = new ClipboardContent();
List<Node> files = new ArrayList<>();
ObservableList<TreeItem<Node>> selectedItems = cell.getTreeView().getSelectionModel().getSelectedItems();
for (TreeItem<Node> node : selectedItems) {
files.add(node.getValue());
}
content.put(dataFormat, files);
db.setContent(content);
event.consume();
});
//Target:
cell.setOnDragOver(event -> {
NodeTreeCell source = (NodeTreeCell) event.getGestureSource();
//check that if target is file then source is not directory:
boolean validNodes = !(cell.getItem().isFile() && !source.getItem().isFile());
if (event.getGestureSource() != cell && validNodes) {
event.acceptTransferModes(TransferMode.COPY);
}
event.consume();
});
//Target:
cell.setOnDragEntered(event -> {
if (event.getGestureSource() != cell) {
cell.setStyle("-fx-background-color: green;");
}
event.consume();
});
//Target
cell.setOnDragExited(event -> {
cell.setStyle("");
event.consume();
});
//Target
cell.setOnDragDropped(event -> {
Dragboard db = event.getDragboard();
event.setDropCompleted(true);
NodeTreeCell source = (NodeTreeCell) event.getGestureSource();
NodeTreeCell target = (NodeTreeCell) event.getGestureTarget();
@SuppressWarnings({"unchecked"})
List<Node> files = (List<Node>) db.getContent(dataFormat);
String targetPath = cell.getItem().getPath();
OutputPanel outputPanel = OutputPanel.getInstance();
if (source.isLocalTree() && target.isLocalTree()) {
//Local to Local
for (Node file : files) {
File src = new File(file.getPath());
File dest = new File(targetPath);
if (src.getParentFile().equals(dest)) {
outputPanel.println(JFTText.getLocalHost(), JFTText.textBlack("cp " +
file.getPath() + " " + cell.getItem().getPath() + " "), JFTText.failed());
outputPanel.println(JFTText.textBlack("Source and destination are the same"));
continue;
}
if (LocalFileUtils.copy(src, dest)) {
outputPanel.println(JFTText.getLocalHost(), JFTText.textBlack("cp " +
file.getPath() + " " + cell.getItem().getPath()));
} else {
outputPanel.println(JFTText.getLocalHost(), JFTText.textBlack("cp " +
file.getPath() + " " + cell.getItem().getPath() + " "), JFTText.failed());
}
cell.getTreeItem().getChildren().clear();
cell.getTreeItem().getChildren().addAll(localTree.buildChildren(cell.getTreeItem()));
}
} else if (source.isLocalTree() && !target.isLocalTree()) {
//Local to Remote
List<CommandCopy> commandCopies = getCommands(files, source.isLocalTree(), target.isLocalTree(), targetPath);
for (CommandCopy commandCopy : commandCopies) {
CommandCopyExecution commandCopyExecution = new CommandCopyExecution(commandCopy, connection);
Future<Boolean> task = executorService.submit(commandCopyExecution);
}
} else if (!source.isLocalTree() && !target.isLocalTree()) {
//Remote to Remote
List<CommandCopy> commandCopies = getCommands(files, source.isLocalTree(), target.isLocalTree(), targetPath);
for (CommandCopy commandCopy : commandCopies) {
connection.sendCommand(commandCopy.toString());
}
} else if (!source.isLocalTree() && target.isLocalTree()) {
//Remote to Local
List<CommandCopy> commandCopies = getCommands(files, source.isLocalTree(), target.isLocalTree(), targetPath);
for (CommandCopy commandCopy : commandCopies) {
CommandCopyExecution commandCopyExecution = new CommandCopyExecution(commandCopy, connection);
Future<Boolean> task = executorService.submit(commandCopyExecution);
}
}
//cell.getTreeView().getSelectionModel().select(cell.getTreeItem());
event.consume();
});
//Source
cell.setOnDragDone(event -> {
event.consume();
});
}
private List<CommandCopy> getCommands(List<Node> files, boolean isSourceLocal, boolean isTargetLocal, String targetPath) {
List<String> sources = new ArrayList<>();
for (Node file : files) {
sources.add(file.getPath());
}
CommandCopyFactory commandCopyFactory = new CommandCopyFactory(connection);
return commandCopyFactory.buildCommands(isSourceLocal, isTargetLocal, targetPath, sources);
}
private Map<String, TreeItem<Node>> reduceByPaths(List<TreeItem<Node>> items) {
Map<String, TreeItem<Node>> map = new TreeMap<>();
for (TreeItem<Node> item : items) {
map.put(item.getValue().getPath(), item);
}
Map<String, TreeItem<Node>> found = new TreeMap<>();
for (Map.Entry<String, TreeItem<Node>> path : map.entrySet()) {
if (found.isEmpty()) {
found.put(path.getKey(), path.getValue());
} else {
boolean add = true;
for (String foundPath : found.keySet()) {
if (path.getKey().startsWith(foundPath)) {
add = false;
break;
}
}
if (add) {
found.put(path.getKey(), path.getValue());
}
}
}
return found;
}
@PreDestroy
public void destroy() {
executorService.shutdownNow();
}
}