From 57d3f788e60e6c5be75b0db88bc81822f4a87abb Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 16 Oct 2019 16:41:28 +0200 Subject: [PATCH] further improving windows mount options --- .../vaultoptions/MountOptionsController.java | 126 ++++++++++++++++-- .../resources/fxml/vault_options_mount.fxml | 16 +-- 2 files changed, 125 insertions(+), 17 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java index a78d3921d..dcd14d9bb 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java @@ -3,26 +3,38 @@ package org.cryptomator.ui.vaultoptions; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; -import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.CheckBox; +import javafx.scene.control.ChoiceBox; import javafx.scene.control.RadioButton; import javafx.scene.control.TextField; import javafx.scene.control.ToggleGroup; +import javafx.stage.DirectoryChooser; +import javafx.stage.Stage; +import javafx.util.StringConverter; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VolumeImpl; import org.cryptomator.common.vaults.Vault; +import org.cryptomator.common.vaults.WindowsDriveLetters; import org.cryptomator.ui.common.FxController; import javax.inject.Inject; +import java.io.File; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.ResourceBundle; +import java.util.Set; @VaultOptionsScoped public class MountOptionsController implements FxController { + private final Stage window; private final Vault vault; private final BooleanProperty osIsWindows = new SimpleBooleanProperty(SystemUtils.IS_OS_WINDOWS); private final BooleanBinding adapterIsDokan; + private final WindowsDriveLetters windowsDriveLetters; + private final ResourceBundle resourceBundle; private final ToggleGroup toggleGroup; public TextField driveName; public CheckBox readOnlyCheckbox; @@ -31,11 +43,15 @@ public class MountOptionsController implements FxController { public RadioButton automaticDriveLetter; public RadioButton specificDriveLetter; public RadioButton specificDirectory; + public ChoiceBox driveLetterSelection; @Inject - MountOptionsController(@VaultOptionsWindow Vault vault, Settings settings) { + MountOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, Settings settings, WindowsDriveLetters windowsDriveLetters, ResourceBundle resourceBundle) { + this.window = window; this.vault = vault; this.adapterIsDokan = settings.preferredVolumeImpl().isEqualTo(VolumeImpl.DOKANY); + this.windowsDriveLetters = windowsDriveLetters; + this.resourceBundle = resourceBundle; this.toggleGroup = new ToggleGroup(); } @@ -55,7 +71,17 @@ public class MountOptionsController implements FxController { } toggleGroup.getToggles().addAll(automaticDriveLetter, specificDriveLetter, specificDirectory); + initDriveLetterSelection(); + } + private void initDriveLetterSelection() { + driveLetterSelection.setConverter(new WinDriveLetterLabelConverter()); + Set freeLetters = windowsDriveLetters.getAvailableDriveLetters(); + driveLetterSelection.getItems().addAll(freeLetters); + driveLetterSelection.getItems().sort(new WinDriveLetterComparator()); + chooseSelectedDriveLetter(); + //TODO: check if we should write only the letter or the path to the settings!! + driveLetterSelection.getSelectionModel().selectedItemProperty().addListener(p -> vault.getVaultSettings().winDriveLetter().set(p.toString())); } @FXML @@ -76,11 +102,24 @@ public class MountOptionsController implements FxController { public void changeMountPointForWindows() { assert osIsWindows.get(); if (specificDriveLetter.isSelected()) { - //TODO: set any default free drive letter - } else if (specificDirectory.isSelected()) { vault.getVaultSettings().usesIndividualMountPath().set(true); - //TODO: open directory picker - + vault.getVaultSettings().winDriveLetter().set(driveLetterSelection.getSelectionModel().getSelectedItem().toString()); + vault.getVaultSettings().individualMountPath().set(null); + } else if (specificDirectory.isSelected()) { + final File file = chooseDirectory(); + if (file != null) { + //TODO: should we check wether the directory is empty or not? + vault.getVaultSettings().usesIndividualMountPath().set(true); + vault.getVaultSettings().individualMountPath().set(file.getAbsolutePath()); + vault.getVaultSettings().winDriveLetter().set(null); + } else { + //NO-OP + //TODO: deduplicate code + toggleGroup.selectToggle(automaticDriveLetter); + vault.getVaultSettings().usesIndividualMountPath().set(false); + vault.getVaultSettings().winDriveLetter().set(null); + vault.getVaultSettings().individualMountPath().set(null); + } } else { //set property vault.getVaultSettings().usesIndividualMountPath().set(false); @@ -89,8 +128,79 @@ public class MountOptionsController implements FxController { } } - @FXML - public void selectEmptyDirectory(ActionEvent actionEvent) { + private File chooseDirectory() { + DirectoryChooser directoryChooser = new DirectoryChooser(); + directoryChooser.setTitle(resourceBundle.getString("TODO")); + try { + directoryChooser.setInitialDirectory(Path.of(System.getProperty("user.home")).toFile()); + } catch (Exception e) { + //NO-OP + } + return directoryChooser.showDialog(window); + } + + /** + * Converts 'C' to "C:" to translate between model and GUI. + */ + private class WinDriveLetterLabelConverter extends StringConverter { + + @Override + public String toString(Path root) { + if (root == null) { + //TODO: none drive letter is selected + return ""; + } else if (root.endsWith("occupied")) { + return root.getRoot().toString().substring(0, 1) + " (" + resourceBundle.getString("TODO") + ")"; + } else { + return root.toString().substring(0, 1); + } + } + + @Override + public Path fromString(String string) { + if (resourceBundle.getString("TODO").equals(string)) { + return null; + } else { + return Path.of(string); + } + } + + } + + /** + * Natural sorting of ASCII letters, but null always on first, as this is "auto-assign". + */ + private static class WinDriveLetterComparator implements Comparator { + + @Override + public int compare(Path c1, Path c2) { + if (c1 == null) { + return -1; + } else if (c2 == null) { + return 1; + } else { + return c1.compareTo(c2); + } + } + } + + private void chooseSelectedDriveLetter() { + assert SystemUtils.IS_OS_WINDOWS; + // if the vault prefers a drive letter, that is currently occupied, this is our last chance to reset this: + if (vault.getVaultSettings().winDriveLetter().isNotEmpty().get()) { + final Path pickedRoot = Path.of(vault.getVaultSettings().winDriveLetter().get()); + if (windowsDriveLetters.getOccupiedDriveLetters().contains(pickedRoot)) { + Path alteredPath = pickedRoot.resolve("occupied"); + driveLetterSelection.getItems().add(alteredPath); + driveLetterSelection.getSelectionModel().select(alteredPath); + } else { + driveLetterSelection.getSelectionModel().select(pickedRoot); + } + } else { + // first option is known to be 'auto-assign' due to #WinDriveLetterComparator. + driveLetterSelection.getSelectionModel().selectFirst(); + } + } // Getter & Setter diff --git a/main/ui/src/main/resources/fxml/vault_options_mount.fxml b/main/ui/src/main/resources/fxml/vault_options_mount.fxml index 772065f14..56479297e 100644 --- a/main/ui/src/main/resources/fxml/vault_options_mount.fxml +++ b/main/ui/src/main/resources/fxml/vault_options_mount.fxml @@ -3,14 +3,13 @@ - + - - -