浏览代码

get rid of some legacy code with too much if/else

Sebastian Stenzel 5 年之前
父节点
当前提交
7fb5c741ad

+ 1 - 1
main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java

@@ -69,7 +69,7 @@ public class DokanyVolume implements Volume {
 		} else {
 			//auto assign drive letter
 			if (!windowsDriveLetters.getAvailableDriveLetters().isEmpty()) {
-				return windowsDriveLetters.getAvailableDriveLetters().iterator().next();
+				return Path.of(windowsDriveLetters.getAvailableDriveLetters().iterator().next() + ":\\");
 			} else {
 				//TODO: Error Handling
 				throw new VolumeException("No free drive letter available.");

+ 11 - 9
main/commons/src/main/java/org/cryptomator/common/vaults/WindowsDriveLetters.java

@@ -5,6 +5,7 @@
  *******************************************************************************/
 package org.cryptomator.common.vaults;
 
+import com.google.common.collect.Sets;
 import org.apache.commons.lang3.SystemUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -14,7 +15,6 @@ import javax.inject.Singleton;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
 import java.util.Set;
-import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 import java.util.stream.StreamSupport;
@@ -23,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<Path> A_TO_Z;
+	private static final Set<String> A_TO_Z;
 
 	static {
 		try (IntStream stream = IntStream.rangeClosed('A', 'Z')) {
-			A_TO_Z = stream.mapToObj(i -> Path.of(((char) i)+":\\")).collect(Collectors.toSet());
+			A_TO_Z = stream.mapToObj(i -> String.valueOf((char) i)).collect(Collectors.toSet());
 		}
 	}
 
@@ -35,20 +35,22 @@ public final class WindowsDriveLetters {
 	public WindowsDriveLetters() {
 	}
 
-	public Set<Path> getOccupiedDriveLetters() {
+	public Set<String> getAllDriveLetters() {
+		return A_TO_Z;
+	}
+
+	public Set<String> 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).collect(Collectors.toSet());
+			return StreamSupport.stream(rootDirs.spliterator(), false).map(Path::toString).collect(Collectors.toSet());
 		}
 	}
 
-	public Set<Path> getAvailableDriveLetters() {
-		Set<Path> occupiedDriveLetters = getOccupiedDriveLetters();
-		Predicate<Path> isOccupiedDriveLetter = occupiedDriveLetters::contains;
-		return A_TO_Z.stream().filter(isOccupiedDriveLetter.negate()).collect(Collectors.toSet());
+	public Set<String> getAvailableDriveLetters() {
+		return Sets.difference(A_TO_Z, getOccupiedDriveLetters());
 	}
 
 }

+ 57 - 99
main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java

@@ -1,14 +1,18 @@
 package org.cryptomator.ui.vaultoptions;
 
+import com.google.common.base.Strings;
+import javafx.beans.binding.Bindings;
 import javafx.beans.binding.BooleanBinding;
 import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.SimpleBooleanProperty;
 import javafx.beans.property.StringProperty;
+import javafx.beans.value.ObservableValue;
 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.Toggle;
 import javafx.scene.control.ToggleGroup;
 import javafx.stage.DirectoryChooser;
 import javafx.stage.Stage;
@@ -23,7 +27,6 @@ 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;
 
@@ -36,15 +39,15 @@ public class MountOptionsController implements FxController {
 	private final BooleanBinding adapterIsDokan;
 	private final WindowsDriveLetters windowsDriveLetters;
 	private final ResourceBundle resourceBundle;
-	private final ToggleGroup toggleGroup;
 	public TextField driveName;
 	public CheckBox readOnlyCheckbox;
 	public CheckBox customMountFlagsCheckbox;
 	public TextField mountFlags;
-	public RadioButton automaticDriveLetter;
-	public RadioButton specificDriveLetter;
-	public RadioButton specificDirectory;
-	public ChoiceBox<Path> driveLetterSelection;
+	public ToggleGroup mountPoint;
+	public RadioButton mountPointAuto;
+	public RadioButton mountPointWinDriveLetter;
+	public RadioButton mountPointCustomDir;
+	public ChoiceBox<String> driveLetterSelection;
 
 	@Inject
 	MountOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, Settings settings, WindowsDriveLetters windowsDriveLetters, ResourceBundle resourceBundle) {
@@ -53,16 +56,18 @@ public class MountOptionsController implements FxController {
 		this.adapterIsDokan = settings.preferredVolumeImpl().isEqualTo(VolumeImpl.DOKANY);
 		this.windowsDriveLetters = windowsDriveLetters;
 		this.resourceBundle = resourceBundle;
-		this.toggleGroup = new ToggleGroup();
 	}
 
 	@FXML
 	public void initialize() {
 		driveName.textProperty().bindBidirectional(vault.getVaultSettings().mountName());
+
+		// readonly:
 		readOnlyCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().usesReadOnlyMode());
-		mountFlags.disableProperty().bind(customMountFlagsCheckbox.selectedProperty().not());
 		readOnlyCheckbox.disableProperty().bind(customMountFlagsCheckbox.selectedProperty());
 
+		// custom mount flags:
+		mountFlags.disableProperty().bind(customMountFlagsCheckbox.selectedProperty().not());
 		customMountFlagsCheckbox.setSelected(vault.isHavingCustomMountFlags());
 		if (vault.isHavingCustomMountFlags()) {
 			mountFlags.textProperty().bindBidirectional(vault.getVaultSettings().mountFlags());
@@ -71,20 +76,24 @@ public class MountOptionsController implements FxController {
 			mountFlags.textProperty().bind(vault.defaultMountFlagsProperty());
 		}
 
-		toggleGroup.getToggles().addAll(automaticDriveLetter, specificDriveLetter, specificDirectory);
-		initDriveLetterSelection();
-
-		//TODO: set the toggleGroup correctly at init
-	}
-
-	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()));
+		// mount point options:
+		mountPoint.selectedToggleProperty().addListener(this::toggleMountPoint);
+		driveLetterSelection.getItems().addAll(windowsDriveLetters.getAllDriveLetters());
+		driveLetterSelection.setConverter(new WinDriveLetterLabelConverter(windowsDriveLetters));
+		driveLetterSelection.setValue(vault.getVaultSettings().winDriveLetter().get());
+		vault.getVaultSettings().usesIndividualMountPath().bind(mountPoint.selectedToggleProperty().isEqualTo(mountPointCustomDir));
+		vault.getVaultSettings().winDriveLetter().bind( //
+				Bindings.when(mountPoint.selectedToggleProperty().isEqualTo(mountPointWinDriveLetter)) //
+						.then(driveLetterSelection.getSelectionModel().selectedItemProperty()) //
+						.otherwise((String) null) //
+		);
+		if (vault.getVaultSettings().usesIndividualMountPath().get()) {
+			mountPoint.selectToggle(mountPointCustomDir);
+		} else if (!Strings.isNullOrEmpty(vault.getVaultSettings().winDriveLetter().get())) {
+			mountPoint.selectToggle(mountPointWinDriveLetter);
+		} else {
+			mountPoint.selectToggle(mountPointAuto);
+		}
 	}
 
 	@FXML
@@ -102,36 +111,7 @@ public class MountOptionsController implements FxController {
 	}
 
 	@FXML
-	public void changeMountPointForWindows() {
-		assert osIsWindows.get();
-		if (specificDriveLetter.isSelected()) {
-			vault.getVaultSettings().usesIndividualMountPath().set(true);
-			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);
-			vault.getVaultSettings().winDriveLetter().set(null);
-			vault.getVaultSettings().individualMountPath().set(null);
-		}
-	}
-
-	private File chooseDirectory() {
+	private void chooseCustomMountPoint() {
 		DirectoryChooser directoryChooser = new DirectoryChooser();
 		directoryChooser.setTitle(resourceBundle.getString("vaultOptions.mount.winDirChooser"));
 		try {
@@ -139,65 +119,43 @@ public class MountOptionsController implements FxController {
 		} catch (Exception e) {
 			//NO-OP
 		}
-		return directoryChooser.showDialog(window);
+		File file = directoryChooser.showDialog(window);
+		if (file != null) {
+			vault.getVaultSettings().individualMountPath().set(file.getAbsolutePath());
+		} else {
+			vault.getVaultSettings().individualMountPath().set(null);
+		}
+	}
+
+	private void toggleMountPoint(@SuppressWarnings("unused") ObservableValue<? extends Toggle> observable, @SuppressWarnings("unused") Toggle oldValue, Toggle newValue) {
+		if (mountPointCustomDir.equals(newValue) && Strings.isNullOrEmpty(vault.getVaultSettings().individualMountPath().get())) {
+			chooseCustomMountPoint();
+		}
 	}
 
 	/**
 	 * Converts 'C' to "C:" to translate between model and GUI.
 	 */
-	private class WinDriveLetterLabelConverter extends StringConverter<Path> {
+	private static class WinDriveLetterLabelConverter extends StringConverter<String> {
 
-		@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("vaultOptions.mount.winDriveLetterOccupied") + ")";
-			} else {
-				return root.toString().substring(0, 1);
-			}
-		}
+		private final Set<String> occupiedDriveLetters;
 
-		@Override
-		public Path fromString(String string) {
-			return Path.of(string);
+		WinDriveLetterLabelConverter(WindowsDriveLetters windowsDriveLetters) {
+			this.occupiedDriveLetters = windowsDriveLetters.getOccupiedDriveLetters();
 		}
 
-	}
-
-	/**
-	 * 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;
+		public String toString(String driveLetter) {
+			if (occupiedDriveLetters.contains(driveLetter)) {
+				return driveLetter + ": (occupied)"; // TODO localize?
 			} else {
-				return c1.compareTo(c2);
+				return driveLetter + ":";
 			}
 		}
-	}
 
-	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();
+		@Override
+		public String fromString(String string) {
+			throw new UnsupportedOperationException();
 		}
 
 	}
@@ -220,11 +178,11 @@ public class MountOptionsController implements FxController {
 		return adapterIsDokan.get();
 	}
 
-	public StringProperty customMountPathProperty(){
+	public StringProperty customMountPathProperty() {
 		return vault.getVaultSettings().individualMountPath();
 	}
 
-	public String getCustomMountPath(){
+	public String getCustomMountPath() {
 		return vault.getVaultSettings().individualMountPath().get();
 	}
 

+ 20 - 12
main/ui/src/main/resources/fxml/vault_options_mount.fxml

@@ -1,19 +1,25 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Button?>
 <?import javafx.scene.control.CheckBox?>
 <?import javafx.scene.control.ChoiceBox?>
 <?import javafx.scene.control.Label?>
 <?import javafx.scene.control.RadioButton?>
 <?import javafx.scene.control.TextField?>
+<?import javafx.scene.control.ToggleGroup?>
 <?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"
 	  spacing="6">
+	<fx:define>
+		<ToggleGroup fx:id="mountPoint"/>
+	</fx:define>
 	<padding>
 		<Insets topRightBottomLeft="12"/>
 	</padding>
@@ -34,23 +40,25 @@
 				<TextField fx:id="mountFlags" HBox.hgrow="ALWAYS" maxWidth="Infinity"/>
 			</children>
 		</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 -->
+		
 		<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="TODO Choose specific drive letter" visible="${controller.osIsWindows}" managed="${controller.adapterIsDokan}" onAction="#changeMountPointForWindows"/>
-				<ChoiceBox fx:id="driveLetterSelection" disable="${!specificDriveLetter.selected}"/>
-			</children>
+		<RadioButton toggleGroup="${mountPoint}" fx:id="mountPointAuto" text="TODO Automatically pick free drive letter"/>
+		<HBox spacing="6" visible="${controller.osIsWindows}" managed="${controller.osIsWindows}">
+			<RadioButton toggleGroup="${mountPoint}" fx:id="mountPointWinDriveLetter" text="TODO Choose specific drive letter"/>
+			<ChoiceBox fx:id="driveLetterSelection" disable="${!mountPointWinDriveLetter.selected}"/>
 		</HBox>
-		<RadioButton fx:id="specificDirectory" text="TODO Choose empty directory" visible="${controller.adapterIsDokan}" managed="${controller.adapterIsDokan}" onAction="#changeMountPointForWindows"/>
-		<HBox visible="${specificDirectory.selected}">
+		<RadioButton toggleGroup="${mountPoint}" fx:id="mountPointCustomDir" text="TODO Choose empty directory"/>
+		<HBox visible="${mountPointCustomDir.selected}">
 			<padding>
-				<Insets left="25"/>
+				<Insets left="24"/>
 			</padding>
 			<children>
-				<TextField fx:id="mntDir" text="${controller.customMountPath}" HBox.hgrow="ALWAYS" maxWidth="Infinity" disable="true"/>
+				<TextField text="${controller.customMountPath}" HBox.hgrow="ALWAYS" maxWidth="Infinity" disable="true"/>
+				<Button text="TODO select" onAction="#chooseCustomMountPoint" contentDisplay="LEFT">
+					<graphic>
+						<FontAwesome5IconView glyph="FOLDER_OPEN" glyphSize="15"/>
+					</graphic>
+				</Button>
 			</children>
 		</HBox>
 	</children>