package org.peerbox.presenter.settings.synchronization;
import java.io.IOException;
import java.nio.file.Path;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tooltip;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import org.peerbox.filerecovery.IFileRecoveryHandler;
import org.peerbox.forcesync.IForceSyncHandler;
import org.peerbox.share.IShareFolderHandler;
import org.peerbox.utils.DialogUtils;
import org.peerbox.view.ViewNames;
import org.peerbox.watchservice.IFileEventManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Provider;
/**
* This class is used as a template to produce the context menu of
* the {@link javafx.scene.control.CheckBoxTreeItem CheckBoxTreeItem}s
* for the {@link org.peerbox.presenter.settings.synchronization.
* Synchronization Synchronization} class.
* @author Claudio
*
*/
public class CustomizedTreeCell extends CheckBoxTreeCell<PathItem> {
private static final Logger logger = LoggerFactory.getLogger(CustomizedTreeCell.class);
private ContextMenu menu;
private IFileEventManager fileEventManager;
private Provider<IFileRecoveryHandler> recoverFileHandlerProvider;
private Provider<IShareFolderHandler> shareFolderHandlerProvider;
private Provider<IForceSyncHandler> forceSyncHandlerProvider;
private Stage stage;
private MenuItem recoverMenuItem;
private CustomMenuItem deleteItem;
private CustomMenuItem shareItem;
private MenuItem propertiesItem;
private MenuItem forceSyncItem;
public CustomizedTreeCell(IFileEventManager fileEventManager,
Provider<IFileRecoveryHandler> recoverFileHandlerProvider,
Provider<IShareFolderHandler> shareFolderHandlerProvider,
Provider<IForceSyncHandler> forceSyncHandlerProvider){
this.fileEventManager = fileEventManager;
this.shareFolderHandlerProvider = shareFolderHandlerProvider;
this.recoverFileHandlerProvider = recoverFileHandlerProvider;
this.forceSyncHandlerProvider = forceSyncHandlerProvider;
menu = new ContextMenu();
deleteItem = new CustomMenuItem(new Label("Delete from network"));
deleteItem.setOnAction(new DeleteAction());
menu.getItems().add(deleteItem);
shareItem = new CustomMenuItem(new Label("Share"));
shareItem.setOnAction(new ShareFolderAction());
menu.getItems().add(shareItem);
propertiesItem = new MenuItem("Properties");
propertiesItem.setOnAction(new ShowPropertiesAction());
menu.getItems().add(propertiesItem);
forceSyncItem = new MenuItem("Force synchronization");
forceSyncItem.setOnAction(new ForceSyncAction());
menu.getItems().add(forceSyncItem);
recoverMenuItem = createRecoveMenuItem();
menu.getItems().add(recoverMenuItem);
menu.setOnShowing(new ShowMenuHandler());
setContextMenu(menu);
}
private MenuItem createRecoveMenuItem() {
Label label = new Label("Recover File");
MenuItem menuItem = new CustomMenuItem(label);
menuItem.setOnAction(new RecoverFileAction());
return menuItem;
}
private class ShowMenuHandler implements EventHandler<WindowEvent> {
@Override
public void handle(WindowEvent arg0) {
if(getItem() != null) {
// first enable all and then decide depending on file/folder
enableAllMenuItems();
if (getItem().isFile()) {
shareItem.setVisible(false);
propertiesItem.setVisible(true);
} else if (!getItem().getPath().toFile().exists()) {
shareItem.setDisable(true);
Label label = (Label) shareItem.getContent();
label.setTooltip(new Tooltip("You cannot share this folder as it is not synchronized."));
} else {
shareItem.setDisable(false);
shareItem.setVisible(true);
Label label = (Label) shareItem.getContent();
label.setTooltip(new Tooltip("Right-click to share this folder with a friend."));
}
boolean disableRecoverMenu = getItem().isFolder();
recoverMenuItem.setDisable(disableRecoverMenu);
} else {
// disable menu
disableAllMenuItems();
}
}
private void disableAllMenuItems() {
menu.getItems().forEach(item -> item.setDisable(true));
}
private void enableAllMenuItems() {
menu.getItems().forEach(item -> item.setDisable(false));
}
}
private class ShowPropertiesAction implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent arg0) {
if (getItem() != null) {
showProperties(getItem());
}
}
private void showProperties(PathItem item) {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource(ViewNames.PROPERTIES_VIEW));
loader.setController(new Properties(getItem()));
Parent root = loader.load();
// load UI on Application thread and show window
Runnable showStage = new Runnable() {
@Override
public void run() {
Scene scene = new Scene(root);
stage = new Stage();
stage.setTitle("Properties of "
+ getItem().getPath().getFileName());
stage.setScene(scene);
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
stage = null;
}
});
stage.show();
}
};
if (Platform.isFxApplicationThread()) {
showStage.run();
} else {
Platform.runLater(showStage);
}
} catch (IOException e) {
logger.warn("Exception while showing properties.", e);
}
}
}
private class DeleteAction implements EventHandler<ActionEvent> {
public void handle(ActionEvent t) {
if (getItem() != null) {
Alert hardDelete = DialogUtils.createAlert(AlertType.WARNING);
hardDelete.setTitle("Irreversibly delete file?");
hardDelete.setHeaderText("You're about to hard-delete " + getItem().getPath().getFileName());
hardDelete.setContentText("The file will be removed completely from the network and cannot be recovered."
+ " Proceed?");
hardDelete.getButtonTypes().clear();
hardDelete.getButtonTypes().addAll(ButtonType.YES, ButtonType.NO);
hardDelete.showAndWait();
if(hardDelete.getResult() == ButtonType.YES){
fileEventManager.onLocalFileHardDelete(getItem().getPath());
Alert confirm = DialogUtils.createAlert(AlertType.INFORMATION);
confirm.setTitle("Hard-delete confirmation");
confirm.setContentText(getItem().getPath() + " has been hard-deleted.");
confirm.showAndWait();
}
}
}
}
private class RecoverFileAction implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent event) {
if (getItem() != null && getItem().getPath() != null) {
IFileRecoveryHandler handler = recoverFileHandlerProvider.get();
Path toRecover = getItem().getPath();
handler.recoverFile(toRecover);
}
}
}
private class ShareFolderAction implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent event) {
if (getItem() != null && getItem().getPath() != null) {
IShareFolderHandler handler = shareFolderHandlerProvider.get();
Path toShare = getItem().getPath();
handler.shareFolder(toShare);
}
}
}
private class ForceSyncAction implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent arg0) {
IForceSyncHandler handler = forceSyncHandlerProvider.get();
handler.forceSync();
}
}
}