further improving windows mount options

This commit is contained in:
Armin Schrenk
2019-10-16 16:41:28 +02:00
parent ca73c3ad90
commit 57d3f788e6
2 changed files with 125 additions and 17 deletions

View File

@@ -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<Path> 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<Path> 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<Path> {
@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 <code>null</code> always on first, as this is "auto-assign".
*/
private static class WinDriveLetterComparator implements Comparator<Path> {
@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

View File

@@ -3,14 +3,13 @@
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<?import org.cryptomator.ui.controls.AlphanumericTextField?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.cryptomator.ui.vaultoptions.MountOptionsController"
@@ -37,17 +36,16 @@
</HBox>
<!-- TODO windows drive letter, see https://github.com/cryptomator/cryptomator/blob/1.4.16/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java#L283-L298 -->
<!-- TODO maybe change label to text because you cannot interact with the hbox -->
<Label text="Mount Point"/>
<RadioButton fx:id="automaticDriveLetter" text="Automatically pick free drive letter" visible="${controller.osIsWindows}" managed="${controller.adapterIsDokan}" onAction="#changeMountPointForWindows"/>
<Text text="TODO Mount Point"/>
<RadioButton fx:id="automaticDriveLetter" text="TODO Automatically pick free drive letter" visible="${controller.osIsWindows}" managed="${controller.adapterIsDokan}" onAction="#changeMountPointForWindows"/>
<HBox spacing="6">
<children>
<RadioButton fx:id="specificDriveLetter" text="Choose specific drive letter" visible="${controller.osIsWindows}" managed="${controller.adapterIsDokan}" onAction="#changeMountPointForWindows"/>
<ChoiceBox fx:id="DriveLetterSelection" disable="${!specificDriveLetter.selected}"/>
<RadioButton fx:id="specificDriveLetter" text="TODO Choose specific drive letter" visible="${controller.osIsWindows}" managed="${controller.adapterIsDokan}" onAction="#changeMountPointForWindows"/>
<ChoiceBox fx:id="driveLetterSelection" disable="${!specificDriveLetter.selected}"/>
</children>
</HBox>
<RadioButton fx:id="specificDirectory" text="Choose empty directory" visible="${controller.adapterIsDokan}" managed="${controller.adapterIsDokan}" onAction="#changeMountPointForWindows"/>
<HBox visible="${specificDirectory.selected}" >
<RadioButton fx:id="specificDirectory" text="TODO Choose empty directory" visible="${controller.adapterIsDokan}" managed="${controller.adapterIsDokan}" onAction="#changeMountPointForWindows"/>
<HBox visible="${specificDirectory.selected}">
<padding>
<Insets left="25"/>
</padding>