|
@@ -1,15 +1,13 @@
|
|
|
package org.cryptomator.ui.vaultoptions;
|
|
|
|
|
|
-import com.google.common.base.Strings;
|
|
|
import org.cryptomator.common.Environment;
|
|
|
-import org.cryptomator.common.vaults.Vault;
|
|
|
import org.cryptomator.common.mount.WindowsDriveLetters;
|
|
|
+import org.cryptomator.common.vaults.Vault;
|
|
|
import org.cryptomator.integrations.mount.MountCapability;
|
|
|
import org.cryptomator.integrations.mount.MountService;
|
|
|
import org.cryptomator.ui.common.FxController;
|
|
|
|
|
|
import javax.inject.Inject;
|
|
|
-import javafx.beans.binding.Bindings;
|
|
|
import javafx.beans.value.ObservableValue;
|
|
|
import javafx.fxml.FXML;
|
|
|
import javafx.scene.control.CheckBox;
|
|
@@ -38,10 +36,13 @@ public class MountOptionsController implements FxController {
|
|
|
|
|
|
private final ObservableValue<Boolean> mountpointDirSupported;
|
|
|
private final ObservableValue<Boolean> mountpointDriveLetterSupported;
|
|
|
- private final ObservableValue<Boolean> mountpointParentSupported; //TODO: use it in GUI
|
|
|
private final ObservableValue<Boolean> readOnlySupported;
|
|
|
private final ObservableValue<Boolean> mountFlagsSupported;
|
|
|
+ private final ObservableValue<Path> driveLetter;
|
|
|
+ private final ObservableValue<String> directoryPath;
|
|
|
+
|
|
|
|
|
|
+ //-- FXML objects --
|
|
|
public CheckBox readOnlyCheckbox;
|
|
|
public CheckBox customMountFlagsCheckbox;
|
|
|
public TextField mountFlagsField;
|
|
@@ -49,7 +50,8 @@ public class MountOptionsController implements FxController {
|
|
|
public RadioButton mountPointAutoBtn;
|
|
|
public RadioButton mountPointDriveLetterBtn;
|
|
|
public RadioButton mountPointDirBtn;
|
|
|
- public ChoiceBox<String> driveLetterSelection;
|
|
|
+ public TextField directoryPathField;
|
|
|
+ public ChoiceBox<Path> driveLetterSelection;
|
|
|
|
|
|
@Inject
|
|
|
MountOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, ObservableValue<MountService> mountService, WindowsDriveLetters windowsDriveLetters, ResourceBundle resourceBundle, Environment environment) {
|
|
@@ -57,11 +59,12 @@ public class MountOptionsController implements FxController {
|
|
|
this.vault = vault;
|
|
|
this.windowsDriveLetters = windowsDriveLetters;
|
|
|
this.resourceBundle = resourceBundle;
|
|
|
- this.mountpointDirSupported = mountService.map(s -> s.hasCapability(MountCapability.MOUNT_TO_EXISTING_DIR));
|
|
|
+ this.mountpointDirSupported = mountService.map(s -> s.hasCapability(MountCapability.MOUNT_TO_EXISTING_DIR) || s.hasCapability(MountCapability.MOUNT_WITHIN_EXISTING_PARENT));
|
|
|
this.mountpointDriveLetterSupported = mountService.map(s -> s.hasCapability(MountCapability.MOUNT_AS_DRIVE_LETTER));
|
|
|
- this.mountpointParentSupported = mountService.map(s -> s.hasCapability(MountCapability.MOUNT_WITHIN_EXISTING_PARENT));
|
|
|
this.mountFlagsSupported = mountService.map(s -> s.hasCapability(MountCapability.MOUNT_FLAGS));
|
|
|
this.readOnlySupported = mountService.map(s -> s.hasCapability(MountCapability.READ_ONLY));
|
|
|
+ this.driveLetter = vault.getVaultSettings().mountPoint().map(p -> isDriveLetter(p) ? p : null);
|
|
|
+ this.directoryPath = vault.getVaultSettings().mountPoint().map(p -> isDriveLetter(p) ? null : p.toString());
|
|
|
}
|
|
|
|
|
|
@FXML
|
|
@@ -73,26 +76,24 @@ public class MountOptionsController implements FxController {
|
|
|
mountFlagsField.disableProperty().bind(customMountFlagsCheckbox.selectedProperty().not());
|
|
|
customMountFlagsCheckbox.setSelected(vault.isHavingCustomMountFlags());
|
|
|
|
|
|
- // mount point options:
|
|
|
- mountPointToggleGroup.selectedToggleProperty().addListener(this::toggleMountPoint);
|
|
|
- driveLetterSelection.getItems().addAll(windowsDriveLetters.getAllDriveLetters());
|
|
|
+ //driveLetter choice box
|
|
|
+ driveLetterSelection.getItems().addAll(windowsDriveLetters.getAll());
|
|
|
driveLetterSelection.setConverter(new WinDriveLetterLabelConverter(windowsDriveLetters, resourceBundle));
|
|
|
- driveLetterSelection.setValue(vault.getVaultSettings().winDriveLetter().get());
|
|
|
+ driveLetterSelection.setOnShowing(event -> driveLetterSelection.setConverter(new WinDriveLetterLabelConverter(windowsDriveLetters, resourceBundle))); //TODO: does this work?
|
|
|
|
|
|
- if (vault.getVaultSettings().useCustomMountPath().get() && vault.getVaultSettings().getCustomMountPath().isPresent()) {
|
|
|
- mountPointToggleGroup.selectToggle(mountPointDirBtn);
|
|
|
- } else if (!Strings.isNullOrEmpty(vault.getVaultSettings().winDriveLetter().get())) {
|
|
|
- mountPointToggleGroup.selectToggle(mountPointDriveLetterBtn);
|
|
|
- } else {
|
|
|
+ //mountPoint toggle group
|
|
|
+ var mountPoint = vault.getVaultSettings().getMountPoint();
|
|
|
+ if (mountPoint == null) {
|
|
|
+ //prepare and select auto
|
|
|
mountPointToggleGroup.selectToggle(mountPointAutoBtn);
|
|
|
+ } else if (mountPoint.getParent() == null && isDriveLetter(mountPoint)) {
|
|
|
+ //prepare and select drive letter
|
|
|
+ mountPointToggleGroup.selectToggle(mountPointDriveLetterBtn);
|
|
|
+ } else if (driveLetterSelection.getValue() == null) {
|
|
|
+ //prepare and select dir
|
|
|
+ mountPointToggleGroup.selectToggle(mountPointDirBtn);
|
|
|
}
|
|
|
-
|
|
|
- vault.getVaultSettings().useCustomMountPath().bind(mountPointToggleGroup.selectedToggleProperty().isEqualTo(mountPointDirBtn));
|
|
|
- vault.getVaultSettings().winDriveLetter().bind( //
|
|
|
- Bindings.when(mountPointToggleGroup.selectedToggleProperty().isEqualTo(mountPointDriveLetterBtn)) //
|
|
|
- .then(driveLetterSelection.getSelectionModel().selectedItemProperty()) //
|
|
|
- .otherwise((String) null) //
|
|
|
- );
|
|
|
+ mountPointToggleGroup.selectedToggleProperty().addListener(this::selectedToggleChanged);
|
|
|
}
|
|
|
|
|
|
@FXML
|
|
@@ -111,16 +112,29 @@ public class MountOptionsController implements FxController {
|
|
|
|
|
|
@FXML
|
|
|
public void chooseCustomMountPoint() {
|
|
|
- chooseCustomMountPointOrReset(mountPointDirBtn);
|
|
|
+ try {
|
|
|
+ Path chosenPath = chooseCustomMountPointInternal();
|
|
|
+ vault.getVaultSettings().mountPoint().set(chosenPath);
|
|
|
+ } catch (NoDirSelectedException e) {
|
|
|
+ //no-op
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private void chooseCustomMountPointOrReset(Toggle previousMountToggle) {
|
|
|
+ /**
|
|
|
+ * Prepares and opens a directory chooser dialog.
|
|
|
+ * This method blocks until the dialog is closed.
|
|
|
+ *
|
|
|
+ * @return the absolute path to the chosen directory
|
|
|
+ * @throws NoDirSelectedException if dialog is closed without choosing a directory
|
|
|
+ */
|
|
|
+ private Path chooseCustomMountPointInternal() throws NoDirSelectedException {
|
|
|
DirectoryChooser directoryChooser = new DirectoryChooser();
|
|
|
directoryChooser.setTitle(resourceBundle.getString("vaultOptions.mount.mountPoint.directoryPickerTitle"));
|
|
|
try {
|
|
|
- var initialDir = Path.of(vault.getVaultSettings().getCustomMountPath().orElse(System.getProperty("user.home")));
|
|
|
+ var mp = vault.getVaultSettings().mountPoint().get();
|
|
|
+ var initialDir = mp != null && !isDriveLetter(mp) ? mp : Path.of(System.getProperty("user.home"));
|
|
|
|
|
|
- if (Files.exists(initialDir)) {
|
|
|
+ if (Files.isDirectory(initialDir)) {
|
|
|
directoryChooser.setInitialDirectory(initialDir.toFile());
|
|
|
}
|
|
|
} catch (InvalidPathException e) {
|
|
@@ -128,49 +142,74 @@ public class MountOptionsController implements FxController {
|
|
|
}
|
|
|
File file = directoryChooser.showDialog(window);
|
|
|
if (file != null) {
|
|
|
- vault.getVaultSettings().customMountPath().set(file.getAbsolutePath());
|
|
|
+ return file.toPath();
|
|
|
} else {
|
|
|
- mountPointToggleGroup.selectToggle(previousMountToggle);
|
|
|
+ throw new NoDirSelectedException();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void selectedToggleChanged(ObservableValue<? extends Toggle> observable, Toggle oldToggle, Toggle newToggle) {
|
|
|
+ Path mountPointToBe = null;
|
|
|
+ try {
|
|
|
+ //Remark: the mountpoint corresponding to the newToggle must be null, otherwise it would not be new!
|
|
|
+ if (mountPointDriveLetterBtn.equals(newToggle)) {
|
|
|
+ mountPointToBe = driveLetterSelection.getItems().get(0);
|
|
|
+ } else if (mountPointDirBtn.equals(newToggle)) {
|
|
|
+ mountPointToBe = chooseCustomMountPointInternal();
|
|
|
+ }
|
|
|
+ vault.getVaultSettings().mountPoint().set(mountPointToBe);
|
|
|
+ } catch (NoDirSelectedException e) {
|
|
|
+ if (!mountPointDirBtn.equals(oldToggle)) {
|
|
|
+ mountPointToggleGroup.selectToggle(oldToggle);
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void toggleMountPoint(@SuppressWarnings("unused") ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) {
|
|
|
- if (mountPointDirBtn.equals(newValue) && Strings.isNullOrEmpty(vault.getVaultSettings().customMountPath().get())) {
|
|
|
- chooseCustomMountPointOrReset(oldValue);
|
|
|
+ private boolean isDriveLetter(Path mountPoint) {
|
|
|
+ if (mountPoint != null) {
|
|
|
+ var s = mountPoint.toString();
|
|
|
+ return s.length() == 3 && mountPoint.toString().endsWith(":\\");
|
|
|
}
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Converts 'C' to "C:" to translate between model and GUI.
|
|
|
- */
|
|
|
- private static class WinDriveLetterLabelConverter extends StringConverter<String> {
|
|
|
+ private static class WinDriveLetterLabelConverter extends StringConverter<Path> {
|
|
|
|
|
|
- private final Set<String> occupiedDriveLetters;
|
|
|
+ private final Set<Path> occupiedDriveLetters;
|
|
|
private final ResourceBundle resourceBundle;
|
|
|
|
|
|
WinDriveLetterLabelConverter(WindowsDriveLetters windowsDriveLetters, ResourceBundle resourceBundle) {
|
|
|
- this.occupiedDriveLetters = windowsDriveLetters.getOccupiedDriveLetters();
|
|
|
+ this.occupiedDriveLetters = windowsDriveLetters.getOccupied();
|
|
|
this.resourceBundle = resourceBundle;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public String toString(String driveLetter) {
|
|
|
- if (Strings.isNullOrEmpty(driveLetter)) {
|
|
|
+ public String toString(Path driveLetter) {
|
|
|
+ if (driveLetter == null) {
|
|
|
return "";
|
|
|
} else if (occupiedDriveLetters.contains(driveLetter)) {
|
|
|
- return driveLetter + ": (" + resourceBundle.getString("vaultOptions.mount.winDriveLetterOccupied") + ")";
|
|
|
+ return driveLetter.toString().substring(0, 2) + " (" + resourceBundle.getString("vaultOptions.mount.winDriveLetterOccupied") + ")";
|
|
|
} else {
|
|
|
- return driveLetter + ":";
|
|
|
+ return driveLetter.toString().substring(0, 2);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public String fromString(String string) {
|
|
|
- throw new UnsupportedOperationException();
|
|
|
+ public Path fromString(String string) {
|
|
|
+ if (string.isEmpty()) {
|
|
|
+ return null;
|
|
|
+ } else {
|
|
|
+ return Path.of(string + "\\");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
+ //@formatter:off
|
|
|
+ private static class NoDirSelectedException extends Exception {}
|
|
|
+ //@formatter:on
|
|
|
+
|
|
|
// Getter & Setter
|
|
|
|
|
|
public ObservableValue<Boolean> mountFlagsSupportedProperty() {
|
|
@@ -189,14 +228,6 @@ public class MountOptionsController implements FxController {
|
|
|
return mountpointDirSupported.getValue();
|
|
|
}
|
|
|
|
|
|
- public ObservableValue<Boolean> mountpointParentSupportedProperty() {
|
|
|
- return mountpointParentSupported;
|
|
|
- }
|
|
|
-
|
|
|
- public boolean isMountpointParentSupported() {
|
|
|
- return mountpointParentSupported.getValue();
|
|
|
- }
|
|
|
-
|
|
|
public ObservableValue<Boolean> mountpointDriveLetterSupportedProperty() {
|
|
|
return mountpointDriveLetterSupported;
|
|
|
}
|
|
@@ -213,9 +244,20 @@ public class MountOptionsController implements FxController {
|
|
|
return readOnlySupported.getValue();
|
|
|
}
|
|
|
|
|
|
+ public ObservableValue<Path> driveLetterProperty() {
|
|
|
+ return driveLetter;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Path getDriveLetter() {
|
|
|
+ return driveLetter.getValue();
|
|
|
+ }
|
|
|
+
|
|
|
+ public ObservableValue<String> directoryPathProperty() {
|
|
|
+ return directoryPath;
|
|
|
+ }
|
|
|
|
|
|
- public String getCustomMountPath() {
|
|
|
- return vault.getVaultSettings().customMountPath().get();
|
|
|
+ public String getDirectoryPath() {
|
|
|
+ return directoryPath.getValue();
|
|
|
}
|
|
|
|
|
|
}
|