瀏覽代碼

Merge branch 'bugfix/872-vaultLetterChangesAutomatically' into develop

infeo 5 年之前
父節點
當前提交
66d7621bc9

+ 5 - 1
main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsJsonAdapterTest.java

@@ -51,7 +51,11 @@ public class VaultSettingsJsonAdapterTest {
 		String result = buf.toString();
 
 		MatcherAssert.assertThat(result, CoreMatchers.containsString("\"id\":\"test\""));
-		MatcherAssert.assertThat(result, CoreMatchers.containsString("\"path\":\"/foo/bar\""));
+		if(System.getProperty("os.name").contains("Windows")){
+			MatcherAssert.assertThat(result, CoreMatchers.containsString("\"path\":\"\\\\foo\\\\bar\""));
+		} else {
+			MatcherAssert.assertThat(result, CoreMatchers.containsString("\"path\":\"/foo/bar\""));
+		}
 		MatcherAssert.assertThat(result, CoreMatchers.containsString("\"mountName\":\"mountyMcMountFace\""));
 		MatcherAssert.assertThat(result, CoreMatchers.containsString("\"mountFlags\":\"--foo --bar\""));
 	}

+ 35 - 24
main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java

@@ -33,7 +33,6 @@ import javafx.scene.text.Text;
 import javafx.stage.DirectoryChooser;
 import javafx.stage.Stage;
 import javafx.util.StringConverter;
-import org.apache.commons.lang3.CharUtils;
 import org.apache.commons.lang3.SystemUtils;
 import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.settings.VaultSettings;
@@ -78,7 +77,7 @@ public class UnlockController implements ViewController {
 	private final Stage mainWindow;
 	private final Localization localization;
 	private final WindowsDriveLetters driveLetters;
-	private final ChangeListener<Character> driveLetterChangeListener = this::winDriveLetterDidChange;
+	private final ChangeListener<Path> driveLetterChangeListener = this::winDriveLetterDidChange;
 	private final Optional<KeychainAccess> keychainAccess;
 	private final Settings settings;
 	private final ExecutorService executor;
@@ -129,7 +128,7 @@ public class UnlockController implements ViewController {
 	private CheckBox useCustomWinDriveLetter;
 
 	@FXML
-	private ChoiceBox<Character> winDriveLetter;
+	private ChoiceBox<Path> winDriveLetter;
 
 	@FXML
 	private CheckBox useCustomMountPoint;
@@ -256,6 +255,7 @@ public class UnlockController implements ViewController {
 			
 			winDriveLetter.visibleProperty().bind(useCustomMountPoint.selectedProperty().not());
 			winDriveLetter.managedProperty().bind(useCustomMountPoint.selectedProperty().not());
+			useCustomWinDriveLetter.setSelected(!vaultSettings.usesIndividualMountPath().get());
 			useCustomWinDriveLetter.visibleProperty().bind(useCustomMountPoint.selectedProperty().not());
 			useCustomWinDriveLetter.managedProperty().bind(useCustomMountPoint.selectedProperty().not());
 		}
@@ -309,7 +309,7 @@ public class UnlockController implements ViewController {
 		}
 	}
 
-	private void mountNameDidChange(@SuppressWarnings("unused") ObservableValue<? extends String> property, @SuppressWarnings("unused")String oldValue, String newValue) {
+	private void mountNameDidChange(@SuppressWarnings("unused") ObservableValue<? extends String> property, @SuppressWarnings("unused") String oldValue, String newValue) {
 		// newValue is guaranteed to be a-z0-9_, see #filterAlphanumericKeyEvents
 		if (newValue.isEmpty()) {
 			mountName.setText(vault.getMountName());
@@ -321,7 +321,7 @@ public class UnlockController implements ViewController {
 		}
 	}
 
-	private void useReadOnlyDidChange(@SuppressWarnings("unused") ObservableValue<? extends Boolean> property, @SuppressWarnings("unused")Boolean oldValue, Boolean newValue) {
+	private void useReadOnlyDidChange(@SuppressWarnings("unused") ObservableValue<? extends Boolean> property, @SuppressWarnings("unused") Boolean oldValue, Boolean newValue) {
 		vault.getVaultSettings().usesReadOnlyMode().setValue(newValue);
 		if (!useCustomMountFlags.isSelected()) {
 			mountFlags.setText(vault.getMountFlags()); // update default flags
@@ -329,14 +329,14 @@ public class UnlockController implements ViewController {
 	}
 
 
-	private void useCustomMountFlagsDidChange(@SuppressWarnings("unused") ObservableValue<? extends Boolean> property, @SuppressWarnings("unused")Boolean oldValue, Boolean newValue) {
+	private void useCustomMountFlagsDidChange(@SuppressWarnings("unused") ObservableValue<? extends Boolean> property, @SuppressWarnings("unused") Boolean oldValue, Boolean newValue) {
 		if (!newValue) {
 			vault.setMountFlags(VaultSettings.DEFAULT_MOUNT_FLAGS);
 			mountFlags.setText(vault.getMountFlags());
 		}
 	}
 
-	private void mountFlagsDidChange(@SuppressWarnings("unused") ObservableValue<? extends String> property, @SuppressWarnings("unused")String oldValue, String newValue) {
+	private void mountFlagsDidChange(@SuppressWarnings("unused") ObservableValue<? extends String> property, @SuppressWarnings("unused") String oldValue, String newValue) {
 		if (useCustomMountFlags.isSelected()) {
 			vault.setMountFlags(newValue);
 		}
@@ -359,26 +359,33 @@ public class UnlockController implements ViewController {
 		}
 	}
 
+	@FXML
+	public void didClickCustomMountPointCheckbox() {
+		useCustomWinDriveLetter.setSelected(vault.getWinDriveLetter() != null);
+	}
+
 	/**
 	 * Converts 'C' to "C:" to translate between model and GUI.
 	 */
-	private class WinDriveLetterLabelConverter extends StringConverter<Character> {
+	private class WinDriveLetterLabelConverter extends StringConverter<Path> {
 
 		@Override
-		public String toString(Character letter) {
-			if (letter == null) {
+		public String toString(Path root) {
+			if (root == null) {
 				return localization.getString("unlock.choicebox.winDriveLetter.auto");
+			} else if (root.endsWith("occupied")) {
+				return root.getRoot().toString().substring(0, 1) + " (" + localization.getString("unlock.choicebox.winDriveLetter.occupied") + ")";
 			} else {
-				return letter + ":";
+				return root.toString().substring(0, 1);
 			}
 		}
 
 		@Override
-		public Character fromString(String string) {
+		public Path fromString(String string) {
 			if (localization.getString("unlock.choicebox.winDriveLetter.auto").equals(string)) {
 				return null;
 			} else {
-				return CharUtils.toCharacterObject(string);
+				return Path.of(string);
 			}
 		}
 
@@ -387,37 +394,41 @@ public class UnlockController implements ViewController {
 	/**
 	 * Natural sorting of ASCII letters, but <code>null</code> always on first, as this is "auto-assign".
 	 */
-	private static class WinDriveLetterComparator implements Comparator<Character> {
+	private static class WinDriveLetterComparator implements Comparator<Path> {
 
 		@Override
-		public int compare(Character c1, Character c2) {
+		public int compare(Path c1, Path c2) {
 			if (c1 == null) {
 				return -1;
 			} else if (c2 == null) {
 				return 1;
 			} else {
-				return c1 - c2;
+				return c1.compareTo(c2);
 			}
 		}
 	}
 
-	private void winDriveLetterDidChange(@SuppressWarnings("unused") ObservableValue<? extends Character> property, @SuppressWarnings("unused") Character oldValue, Character newValue) {
+	private void winDriveLetterDidChange(@SuppressWarnings("unused") ObservableValue<? extends Path> property, @SuppressWarnings("unused") Path oldValue, Path newValue) {
 		vault.setWinDriveLetter(newValue);
 	}
 
 	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.getWinDriveLetter() != null && driveLetters.getOccupiedDriveLetters().contains(vault.getWinDriveLetter())) {
-			vault.setWinDriveLetter(null);
-		}
-		final Character letter = vault.getWinDriveLetter();
-		if (letter == null) {
+		if (vault.getWinDriveLetter() != null) {
+			final Path pickedRoot = Path.of(vault.getWinDriveLetter() + ":\\");
+			if (driveLetters.getOccupiedDriveLetters().contains(pickedRoot)) {
+				Path alteredPath = pickedRoot.resolve("occupied");
+				this.winDriveLetter.getItems().add(alteredPath);
+				this.winDriveLetter.getSelectionModel().select(alteredPath);
+			} else {
+				this.winDriveLetter.getSelectionModel().select(pickedRoot);
+			}
+		} else {
 			// first option is known to be 'auto-assign' due to #WinDriveLetterComparator.
 			this.winDriveLetter.getSelectionModel().selectFirst();
-		} else {
-			this.winDriveLetter.getSelectionModel().select(letter);
 		}
+
 	}
 
 	// ****************************************

+ 3 - 2
main/ui/src/main/java/org/cryptomator/ui/model/Vault.java

@@ -288,10 +288,11 @@ public class Vault {
 		}
 	}
 
-	public void setWinDriveLetter(Character winDriveLetter) {
-		if (winDriveLetter == null) {
+	public void setWinDriveLetter(Path root) {
+		if (root == null) {
 			vaultSettings.winDriveLetter().set(null);
 		} else {
+			char winDriveLetter = root.toString().charAt(0);
 			vaultSettings.winDriveLetter().set(String.valueOf(winDriveLetter));
 		}
 	}

+ 7 - 8
main/ui/src/main/java/org/cryptomator/ui/model/WindowsDriveLetters.java

@@ -5,7 +5,6 @@
  *******************************************************************************/
 package org.cryptomator.ui.model;
 
-import org.apache.commons.lang3.CharUtils;
 import org.apache.commons.lang3.SystemUtils;
 import org.cryptomator.common.FxApplicationScoped;
 import org.slf4j.Logger;
@@ -24,11 +23,11 @@ import java.util.stream.StreamSupport;
 public final class WindowsDriveLetters {
 
 	private static final Logger LOG = LoggerFactory.getLogger(WindowsDriveLetters.class);
-	private static final Set<Character> D_TO_Z;
+	private static final Set<Path> D_TO_Z;
 
 	static {
 		try (IntStream stream = IntStream.rangeClosed('D', 'Z')) {
-			D_TO_Z = stream.mapToObj(i -> (char) i).collect(Collectors.toSet());
+			D_TO_Z = stream.mapToObj(i -> Path.of(((char) i)+":\\")).collect(Collectors.toSet());
 		}
 	}
 
@@ -36,19 +35,19 @@ public final class WindowsDriveLetters {
 	public WindowsDriveLetters() {
 	}
 
-	public Set<Character> getOccupiedDriveLetters() {
+	public Set<Path> getOccupiedDriveLetters() {
 		if (!SystemUtils.IS_OS_WINDOWS) {
 			LOG.warn("Attempted to get occupied drive letters on non-Windows machine.");
 			return Set.of();
 		} else {
 			Iterable<Path> rootDirs = FileSystems.getDefault().getRootDirectories();
-			return StreamSupport.stream(rootDirs.spliterator(), false).map(Path::toString).map(CharUtils::toChar).map(Character::toUpperCase).collect(Collectors.toSet());
+			return StreamSupport.stream(rootDirs.spliterator(), false).collect(Collectors.toSet());
 		}
 	}
 
-	public Set<Character> getAvailableDriveLetters() {
-		Set<Character> occupiedDriveLetters = getOccupiedDriveLetters();
-		Predicate<Character> isOccupiedDriveLetter = occupiedDriveLetters::contains;
+	public Set<Path> getAvailableDriveLetters() {
+		Set<Path> occupiedDriveLetters = getOccupiedDriveLetters();
+		Predicate<Path> isOccupiedDriveLetter = occupiedDriveLetters::contains;
 		return D_TO_Z.stream().filter(isOccupiedDriveLetter.negate()).collect(Collectors.toSet());
 	}
 

+ 9 - 7
main/ui/src/main/resources/fxml/unlock.fxml

@@ -76,26 +76,28 @@
 		<CheckBox fx:id="useReadOnlyMode" text="%unlock.label.useReadOnlyMode"/>
 
 		<!-- Custom Mount Point -->
-		<CheckBox fx:id="useCustomMountPoint" text="%unlock.label.useOwnMountPath"/>
-		<HBox fx:id="customMountPoint" spacing="6" alignment="BASELINE_LEFT">
+		<CheckBox fx:id="useCustomMountPoint" text="%unlock.label.useOwnMountPath" onAction="#didClickCustomMountPointCheckbox"/>
+		<HBox fx:id="customMountPoint" spacing="6" alignment="BASELINE_LEFT" >
 			<padding>
 				<Insets left="20.0"/>
+				<Insets bottom="-19.0"/>
 			</padding>
 			<Label HBox.hgrow="ALWAYS" fx:id="customMountPointLabel" textOverrun="LEADING_ELLIPSIS"/>
 			<Button HBox.hgrow="NEVER" minWidth="-Infinity" text="&#xf434;" styleClass="ionicons" onAction="#didClickChooseCustomMountPoint" focusTraversable="true"/>
 		</HBox>
 
+		<!-- Windows Drive Letter -->
+		<HBox spacing="12" alignment="BASELINE_LEFT">
+			<CheckBox fx:id="useCustomWinDriveLetter" text="%unlock.label.winDriveLetter" onAction="#didClickCustomWinDriveLetterCheckbox"/>
+			<ChoiceBox fx:id="winDriveLetter" HBox.hgrow="NEVER" maxWidth="Infinity"/>
+		</HBox>
+
 		<!-- Mount Flags -->
 		<HBox spacing="12" alignment="BASELINE_LEFT">
 			<CheckBox fx:id="useCustomMountFlags" text="%unlock.label.useCustomMountFlags"/>
 			<TextField fx:id="mountFlags" HBox.hgrow="ALWAYS" maxWidth="Infinity"/>
 		</HBox>
 
-		<!-- Windows Drive Letter -->
-		<HBox spacing="12" alignment="BASELINE_LEFT">
-			<CheckBox fx:id="useCustomWinDriveLetter" text="%unlock.label.winDriveLetter" onAction="#didClickCustomWinDriveLetterCheckbox"/>
-			<ChoiceBox fx:id="winDriveLetter" HBox.hgrow="NEVER" maxWidth="Infinity"/>
-		</HBox>
 	</VBox>
 
 </VBox>

+ 2 - 1
main/ui/src/main/resources/localization/en.txt

@@ -78,7 +78,7 @@ unlock.label.useCustomMountFlags=Custom Mount Flags
 unlock.label.unlockAfterStartup=Auto-Unlock on Start (Experimental)
 unlock.label.revealAfterMount=Reveal Drive
 unlock.label.useReadOnlyMode=Read-Only
-unlock.label.winDriveLetter=Drive Letter
+unlock.label.winDriveLetter=Custom Drive Letter
 unlock.label.useOwnMountPath=Custom Mount Point
 unlock.label.chooseMountPath=Choose empty directory…
 unlock.label.downloadsPageLink=All Cryptomator versions
@@ -89,6 +89,7 @@ unlock.savePassword.delete.confirmation.title=Delete Saved Password
 unlock.savePassword.delete.confirmation.header=Do you really want to delete the saved password of this vault?
 unlock.savePassword.delete.confirmation.content=The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save Password" option enabled.
 unlock.choicebox.winDriveLetter.auto=Assign automatically
+unlock.choicebox.winDriveLetter.occupied=occupied
 unlock.errorMessage.wrongPassword=Wrong password
 unlock.errorMessage.unlockFailed=Unlock failed. See log file for details.
 unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware=Unsupported vault. This vault has been created with an older version of Cryptomator.