Hatena::ブログ(Diary)

tomoTakaの日記

2013-12-05

File Tree View Sample(Part3) Drag and Drop

This is the 2nd day of the JavaFX Advent calendar.no title
The 1st day is 曲線のアニメーション - JavaFX in the Box by Mr.@
The 3rd day is caffeineswitch - TOP by Mr.
@

I added the following one function to the previous sample application.File Tree View Sample(Part 2) - tomoTakaの日記

  1. Copying a file by a drag-and-drop operation on TreeView.

Thanks to this article Drag-and-Drop Feature in JavaFX Applications | JavaFX 2 Tutorials and Documentation ,it is not difficult to implement this function.

I used JavaSE8 for this sample application.
f:id:tomoTaka:20131130204615p:image:w360

  • Screen1(select the source file)

f:id:tomoTaka:20131130202841p:image:w360

  • Screen2(When the mouse pointer hovers over a target that fits the given drag-and-drop gesture, the target changes its background color)

f:id:tomoTaka:20131130204247p:image:w280

  • Screen3(The dialog shows up when the target has the item same as the sources)

f:id:tomoTaka:20131204074304p:image:w360

  • Screen4(when the mouse pointer hovers over the sources parent directory, the background color does not change.)

f:id:tomoTaka:20131201110225p:image:w360

  • code1(Starting the Drag-and-Drop Gesture on a Source)
  • Define a file(isLead) as a source
  • Pass the transfer mode only COPY, because MOVE event does not happen MAX OS X 10.7?(I will try this after get a new MAC)
  • Put a file on a dragboard, since there is no method about Path.
        cell.setOnDragDetected(event -> {
            TreeItem<PathItem> item = cell.getTreeItem();
            if (item != null && item.isLeaf()) {
                Dragboard db = cell.startDragAndDrop(TransferMode.COPY);
                ClipboardContent content = new ClipboardContent();
                List<File> files = Arrays.asList(cell.getTreeItem().getValue().getPath().toFile());
                content.putFiles(files);
                db.setContent(content);
                event.consume();
            }
        });

  • code2(Handling a DRAG_OVER Event on a Target)
  • Define a directory(!isLead) as a target
  • Accept it only if it is not dragged from the same item nor the same parent(see Screen4)
  • Allow only copying
        cell.setOnDragOver(event -> {
            TreeItem<PathItem> item = cell.getTreeItem();
            if ((item != null && !item.isLeaf()) &&
                    event.getGestureSource() != cell &&
                    event.getDragboard().hasFiles()) {
                Path targetPath = cell.getTreeItem().getValue().getPath();
                PathTreeCell sourceCell = (PathTreeCell) event.getGestureSource();
                final Path sourceParentPath = sourceCell.getTreeItem().getValue().getPath().getParent();
                if (sourceParentPath.compareTo(targetPath) != 0) {
                    event.acceptTransferModes(TransferMode.COPY);
                }
            }
            event.consume();
        });

  • code3(Providing Visual Feedback by a Gesture Target)
  • Set the condition like the code2
  • The target changes its backgound color here(see Screen2)
        cell.setOnDragEntered(event -> {
            TreeItem<PathItem> item = cell.getTreeItem();
            if ((item != null && !item.isLeaf()) &&
                    event.getGestureSource() != cell &&
                    event.getDragboard().hasFiles()) {
                Path targetPath = cell.getTreeItem().getValue().getPath();
                PathTreeCell sourceCell = (PathTreeCell) event.getGestureSource();
                final Path sourceParentPath = sourceCell.getTreeItem().getValue().getPath().getParent();
                if (sourceParentPath.compareTo(targetPath) != 0) {
                    cell.setStyle("-fx-background-color: powderblue;");
                }                
            }
            event.consume();
        });

  • code4(Handling a DRAG_EXIT Event on a Target)
  • The target restore its original color here
        cell.setOnDragExited(event -> {
            cell.setStyle("-fx-background-color: white");
            event.consume();
        });

  • code5(Handling a DRAG_DROPPED Event on a Target)
  • The dialog shows up when the target has the item same as the sources.(see Screen 3, code 7)
  • If OK button is clicked, copying of files starts
  • Add the source item to the target directory as a leaf, if the item does not exist on the target
        cell.setOnDragDropped(event -> {
            Dragboard db = event.getDragboard();
            boolean success = false;
            if (db.hasFiles()) {
                final Path source = db.getFiles().get(0).toPath();
                final Path target = Paths.get(
                        cell.getTreeItem().getValue().getPath().toAbsolutePath().toString(),
                        source.getFileName().toString());
                if (Files.exists(target, LinkOption.NOFOLLOW_LINKS)) {                    
                    Platform.runLater(() -> {
                        BooleanProperty replaceProp = new SimpleBooleanProperty();
                        // the dialog shows up here
                        CopyModalDialog dialog = new CopyModalDialog(stage, replaceProp);
                        replaceProp.addListener((ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) -> {
                            if (newValue) {
                                // if OK button is clicked, copying of files starts
                                FileCopyTask task = new FileCopyTask(source, target);
                                service.submit(task);
                            }
                        });
                    });
                } else {
                    // Copying of files starts
                    FileCopyTask task = new FileCopyTask(source, target);
                    service.submit(task);
                    task.setOnSucceeded(value -> {
                        Platform.runLater(() -> {
                            // add the source item to the target directory as a leaf
                            TreeItem<PathItem> item = PathTreeItem.createNode(new PathItem(target));
                            cell.getTreeItem().getChildren().add(item);
                        });
                    });
                }
                success = true;
            }
            event.setDropCompleted(success);
            event.consume();
        });
  • code6(FileCopyTask.java)
  • This class extends the Task class for running in the background.
public class FileCopyTask extends Task<Void> {
    private Path source;
    private Path target;

    public FileCopyTask(Path source, Path target) {
        this.source = source;
        this.target = target;
    }    
    @Override
    protected Void call() throws Exception {
        Files.copy(this.source, this.target, StandardCopyOption.REPLACE_EXISTING);
        return null;
    }
}
  • code7(CopyModalDialog.java)
  • This code shows you how to create the dialog
  • replaceProp has the true value, if you click OK button
public class CopyModalDialog {    
    public CopyModalDialog(Stage owner, final BooleanProperty replaceProp) {
        final Stage dialog = new Stage(StageStyle.UTILITY);
        dialog.initOwner(owner);
        dialog.initModality(Modality.APPLICATION_MODAL);
        GridPane root = new GridPane();
        root.setPadding(new Insets(30));
        root.setHgap(5);
        root.setVgap(10);
        Label label = new Label("The item already exists in this location. Do you want to replace it?");
        Button okButton = new Button("OK");
        okButton.setOnAction(event -> {
            replaceProp.set(true);
            dialog.hide();
        });
        Button cancelButton = new Button("Cancel");
        cancelButton.setOnAction(event -> {
            replaceProp.set(false);
            dialog.hide();
        });
        root.add(label, 0, 0, 2, 1);
        root.addRow(1, okButton, cancelButton);
        dialog.setScene(new Scene(root));
        dialog.show();
    }
}

The whole code is hereno title
I learned JavaFX a lot from the articleJavaFX 2ではじめる、GUI開発 第14回 非同期処理 | 日経 xTECH(クロステック) written by Mr.@
keep coding...