Browse Source

Merge branch 'develop' into feature/#1228-forcedUnmountDialog

Sebastian Stenzel 4 years ago
parent
commit
1cd4da0796

+ 13 - 3
.github/ISSUE_TEMPLATE/bug.md

@@ -5,8 +5,11 @@ labels: type:bug
 ---
 
 <!--
-⚠️⚠️⚠️ READ CAREFULLY ⚠️⚠️⚠️
-
+**************************************
+*                                    *
+*   ⚠️⚠️⚠️ READ CAREFULLY ⚠️⚠️⚠️   *
+*                                    *
+**************************************
 Do you want to ask a QUESTION? Are you looking for SUPPORT?
 We're happy to help you via our support channels! Please read: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md
 
@@ -14,7 +17,14 @@ By filing an issue, you are expected to comply with our code of conduct: https:/
 
 Of course, we also expect you to search for existing similar issues first! ;) https://github.com/cryptomator/cryptomator/issues?q=
 
-⚠️ IMPORTANT: If you don't stick to this template, the issue will get closed. To proof that you read this, please remove the X from the following line:
+
+⚠️ IMPORTANT: If you don't stick to this template, the issue will get closed.
+
+*****************************************************************************
+*                                                                           *
+*   To proof that you read this, please remove the X from the line below:   *
+*                                                                           *
+*****************************************************************************
 -->
 <!-- oooXooo -->
 

+ 1 - 1
main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java

@@ -28,7 +28,7 @@ class MacVolumeMountChooser implements MountPointChooser {
 
 	@Override
 	public Optional<Path> chooseMountPoint(Volume caller) {
-		return Optional.of(VOLUME_PATH).map(dir -> this.helper.chooseTemporaryMountPoint(this.vaultSettings, dir));
+		return Optional.of(helper.chooseTemporaryMountPoint(vaultSettings, VOLUME_PATH));
 	}
 
 	@Override

+ 5 - 6
main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java

@@ -20,11 +20,10 @@ import java.util.Optional;
 class MountPointHelper {
 
 	public static Logger LOG = LoggerFactory.getLogger(MountPointHelper.class);
-
 	private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10;
 
 	private final Optional<Path> tmpMountPointDir;
-	private volatile boolean alreadyChecked = false;
+	private volatile boolean unmountDebrisCleared = false;
 
 	@Inject
 	public MountPointHelper(Environment env) {
@@ -55,13 +54,13 @@ class MountPointHelper {
 	}
 
 	public synchronized void clearIrregularUnmountDebrisIfNeeded() {
-		if (alreadyChecked || tmpMountPointDir.isEmpty()) {
-			return; //nuthin to do
+		if (unmountDebrisCleared || tmpMountPointDir.isEmpty()) {
+			return; // nothing to do
 		}
 		if (Files.exists(tmpMountPointDir.get(), LinkOption.NOFOLLOW_LINKS)) {
 			clearIrregularUnmountDebris(tmpMountPointDir.get());
 		}
-		alreadyChecked = true;
+		unmountDebrisCleared = true;
 	}
 
 	private void clearIrregularUnmountDebris(Path dirContainingMountPoints) {
@@ -92,7 +91,7 @@ class MountPointHelper {
 		} catch (IOException e) {
 			LOG.warn("Unable to perform cleanup of mountpoint dir {}.", dirContainingMountPoints, e);
 		} finally {
-			alreadyChecked = true;
+			unmountDebrisCleared = true;
 		}
 	}
 

+ 3 - 2
main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java

@@ -20,7 +20,8 @@ public abstract class AbstractVolume implements Volume {
 	}
 
 	protected Path determineMountPoint() throws InvalidMountPointException {
-		for (var chooser : Iterables.filter(choosers, c -> c.isApplicable(this))) {
+		var applicableChoosers = Iterables.filter(choosers, c -> c.isApplicable(this));
+		for (var chooser : applicableChoosers) {
 			Optional<Path> chosenPath = chooser.chooseMountPoint(this);
 			if (chosenPath.isEmpty()) { // chooser couldn't find a feasible mountpoint
 				continue;
@@ -29,7 +30,7 @@ public abstract class AbstractVolume implements Volume {
 			this.usedChooser = chooser;
 			return chosenPath.get();
 		}
-		throw new InvalidMountPointException("No feasible MountPoint found!");
+		throw new InvalidMountPointException(String.format("No feasible MountPoint found by choosers: %s", applicableChoosers));
 	}
 
 	protected void cleanupMountPoint() {

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

@@ -13,7 +13,6 @@ import org.slf4j.LoggerFactory;
 
 import javax.inject.Inject;
 import javax.inject.Named;
-import java.util.SortedSet;
 import java.util.concurrent.ExecutorService;
 
 public class DokanyVolume extends AbstractVolume {
@@ -42,7 +41,6 @@ public class DokanyVolume extends AbstractVolume {
 	@Override
 	public void mount(CryptoFileSystem fs, String mountFlags) throws InvalidMountPointException, VolumeException {
 		this.mountPoint = determineMountPoint();
-		String mountName = vaultSettings.mountName().get();
 		try {
 			this.mount = mountFactory.mount(fs.getPath("/"), mountPoint, vaultSettings.mountName().get(), FS_TYPE_NAME, mountFlags.strip());
 		} catch (MountFailedException e) {
@@ -62,8 +60,18 @@ public class DokanyVolume extends AbstractVolume {
 	}
 
 	@Override
-	public void unmount() {
-		mount.close();
+	public void unmount() throws VolumeException {
+		try {
+			mount.unmount();
+		} catch (IllegalStateException e) {
+			throw new VolumeException("Unmount Failed.", e);
+		}
+		cleanupMountPoint();
+	}
+
+	@Override
+	public void unmountForced() {
+		mount.close(); //TODO: with next dokany-nio-release, change this to unmountForced()
 		cleanupMountPoint();
 	}
 

+ 3 - 4
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java

@@ -1,6 +1,5 @@
 package org.cryptomator.ui.addvaultwizard;
 
-import com.tobiasdiez.easybind.EasyBind;
 import dagger.Lazy;
 import org.cryptomator.ui.common.ErrorComponent;
 import org.cryptomator.ui.common.FxController;
@@ -84,11 +83,11 @@ public class CreateNewVaultLocationController implements FxController {
 	public void initialize() {
 		predefinedLocationToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
 		usePresetPath.bind(predefinedLocationToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
-		EasyBind.subscribe(vaultPath, this::vaultPathDidChange);
+		vaultPath.addListener(this::vaultPathDidChange);
 	}
 
-	private void vaultPathDidChange(Path newValue) {
-		if (newValue != null && !Files.notExists(newValue)) {
+	private void vaultPathDidChange(@SuppressWarnings("unused") ObservableValue<? extends Path> observable, @SuppressWarnings("unused") Path oldValue, Path newValue) {
+		if (!Files.notExists(newValue)) {
 			warningText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists"));
 		} else {
 			warningText.set(null);

+ 6 - 7
main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java

@@ -1,6 +1,5 @@
 package org.cryptomator.ui.fxapp;
 
-import com.tobiasdiez.easybind.EasyBind;
 import dagger.Lazy;
 import org.cryptomator.common.LicenseHolder;
 import org.cryptomator.common.settings.Settings;
@@ -41,9 +40,9 @@ public class FxApplication extends Application {
 	private final Settings settings;
 	private final Lazy<MainWindowComponent> mainWindow;
 	private final Lazy<PreferencesComponent> preferencesWindow;
+	private final Lazy<QuitComponent> quitWindow;
 	private final Provider<UnlockComponent.Builder> unlockWindowBuilderProvider;
 	private final Provider<LockComponent.Builder> lockWindowBuilderProvider;
-	private final Provider<QuitComponent.Builder> quitWindowBuilderProvider;
 	private final Optional<TrayIntegrationProvider> trayIntegration;
 	private final Optional<UiAppearanceProvider> appearanceProvider;
 	private final VaultService vaultService;
@@ -52,13 +51,13 @@ public class FxApplication extends Application {
 	private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged;
 
 	@Inject
-	FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<LockComponent.Builder> lockWindowBuilderProvider, Provider<QuitComponent.Builder> quitWindowBuilderProvider, Optional<TrayIntegrationProvider> trayIntegration, Optional<UiAppearanceProvider> appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet<Stage> visibleStages) {
+	FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<LockComponent.Builder> lockWindowBuilderProvider, Lazy<QuitComponent> quitWindow, Optional<TrayIntegrationProvider> trayIntegration, Optional<UiAppearanceProvider> appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet<Stage> visibleStages) {
 		this.settings = settings;
 		this.mainWindow = mainWindow;
 		this.preferencesWindow = preferencesWindow;
 		this.unlockWindowBuilderProvider = unlockWindowBuilderProvider;
 		this.lockWindowBuilderProvider = lockWindowBuilderProvider;
-		this.quitWindowBuilderProvider = quitWindowBuilderProvider;
+		this.quitWindow = quitWindow;
 		this.trayIntegration = trayIntegration;
 		this.appearanceProvider = appearanceProvider;
 		this.vaultService = vaultService;
@@ -70,7 +69,7 @@ public class FxApplication extends Application {
 		LOG.trace("FxApplication.start()");
 		Platform.setImplicitExit(false);
 
-		EasyBind.subscribe(hasVisibleStages, this::hasVisibleStagesChanged);
+		hasVisibleStages.addListener(this::hasVisibleStagesChanged);
 
 		settings.theme().addListener(this::appThemeChanged);
 		loadSelectedStyleSheet(settings.theme().get());
@@ -81,7 +80,7 @@ public class FxApplication extends Application {
 		throw new UnsupportedOperationException("Use start() instead.");
 	}
 
-	private void hasVisibleStagesChanged(boolean newValue) {
+	private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue<? extends Boolean> observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) {
 		if (newValue) {
 			trayIntegration.ifPresent(TrayIntegrationProvider::restoredFromTray);
 		} else {
@@ -119,7 +118,7 @@ public class FxApplication extends Application {
 
 	public void showQuitWindow(QuitResponse response) {
 		Platform.runLater(() -> {
-			quitWindowBuilderProvider.get().quitResponse(response).build().showQuitWindow();
+			quitWindow.get().showQuitWindow(response);
 			LOG.debug("Showing QuitWindow");
 		});
 	}

+ 4 - 0
main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java

@@ -89,4 +89,8 @@ abstract class FxApplicationModule {
 		return builder.build();
 	}
 
+	@Provides
+	static QuitComponent provideQuitComponent(QuitComponent.Builder builder) {
+		return builder.build();
+	}
 }

+ 6 - 5
main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java

@@ -1,6 +1,5 @@
 package org.cryptomator.ui.mainwindow;
 
-import com.tobiasdiez.easybind.EasyBind;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.common.vaults.VaultListManager;
 import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
@@ -13,6 +12,7 @@ import javax.inject.Inject;
 import javafx.beans.binding.Bindings;
 import javafx.beans.binding.BooleanBinding;
 import javafx.beans.property.ObjectProperty;
+import javafx.beans.value.ObservableValue;
 import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
 import javafx.fxml.FXML;
@@ -41,7 +41,7 @@ public class VaultListController implements FxController {
 		this.removeVault = removeVault;
 		this.noVaultSelected = selectedVault.isNull();
 		this.emptyVaultList = Bindings.isEmpty(vaults);
-		EasyBind.subscribe(selectedVault, this::selectedVaultDidChange);
+		selectedVault.addListener(this::selectedVaultDidChange);
 	}
 
 	public void initialize() {
@@ -58,10 +58,11 @@ public class VaultListController implements FxController {
 		});
 	}
 
-	private void selectedVaultDidChange(Vault newValue) {
-		if (newValue != null) {
-			VaultListManager.redetermineVaultState(newValue);
+	private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue<? extends Vault> observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) {
+		if (newValue == null) {
+			return;
 		}
+		VaultListManager.redetermineVaultState(newValue);
 	}
 
 	@FXML

+ 11 - 0
main/ui/src/main/java/org/cryptomator/ui/preferences/DonationKeyPreferencesController.java

@@ -1,5 +1,6 @@
 package org.cryptomator.ui.preferences;
 
+import com.google.common.base.CharMatcher;
 import org.cryptomator.common.LicenseHolder;
 import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.settings.UiTheme;
@@ -10,6 +11,7 @@ import javafx.application.Application;
 import javafx.beans.value.ObservableValue;
 import javafx.fxml.FXML;
 import javafx.scene.control.TextArea;
+import javafx.scene.control.TextFormatter;
 
 @PreferencesScoped
 public class DonationKeyPreferencesController implements FxController {
@@ -32,6 +34,15 @@ public class DonationKeyPreferencesController implements FxController {
 	public void initialize() {
 		donationKeyField.setText(licenseHolder.getLicenseKey().orElse(null));
 		donationKeyField.textProperty().addListener(this::registrationKeyChanged);
+		donationKeyField.setTextFormatter(new TextFormatter<>(this::checkVaultNameLength));
+	}
+
+	private TextFormatter.Change checkVaultNameLength(TextFormatter.Change change) {
+		if (change.isContentChange()) {
+			var strippedText = CharMatcher.whitespace().removeFrom(change.getText());
+			change.setText(strippedText);
+		}
+		return change;
 	}
 
 	private void registrationKeyChanged(@SuppressWarnings("unused") ObservableValue<? extends String> observable, @SuppressWarnings("unused") String oldValue, String newValue) {

+ 4 - 5
main/ui/src/main/java/org/cryptomator/ui/quit/QuitComponent.java

@@ -5,7 +5,6 @@
  *******************************************************************************/
 package org.cryptomator.ui.quit;
 
-import dagger.BindsInstance;
 import dagger.Lazy;
 import dagger.Subcomponent;
 import org.cryptomator.ui.common.FxmlFile;
@@ -25,7 +24,10 @@ public interface QuitComponent {
 	@FxmlScene(FxmlFile.QUIT)
 	Lazy<Scene> scene();
 
-	default Stage showQuitWindow() {
+	QuitController controller();
+
+	default Stage showQuitWindow(QuitResponse response) {
+		controller().updateQuitRequest(response);
 		Stage stage = window();
 		stage.setScene(scene().get());
 		stage.show();
@@ -36,9 +38,6 @@ public interface QuitComponent {
 	@Subcomponent.Builder
 	interface Builder {
 
-		@BindsInstance
-		Builder quitResponse(QuitResponse response);
-
 		QuitComponent build();
 	}
 

+ 24 - 8
main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java

@@ -16,6 +16,8 @@ import javafx.stage.Stage;
 import java.awt.desktop.QuitResponse;
 import java.util.Collection;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 @QuitScoped
@@ -24,26 +26,40 @@ public class QuitController implements FxController {
 	private static final Logger LOG = LoggerFactory.getLogger(QuitController.class);
 
 	private final Stage window;
-	private final QuitResponse response;
 	private final ObservableList<Vault> unlockedVaults;
 	private final ExecutorService executorService;
 	private final VaultService vaultService;
+	private final AtomicReference<QuitResponse> quitResponse = new AtomicReference<>();
 	public Button lockAndQuitButton;
 
 	@Inject
-	QuitController(@QuitWindow Stage window, QuitResponse response, ObservableList<Vault> vaults, ExecutorService executorService, VaultService vaultService) {
+	QuitController(@QuitWindow Stage window, ObservableList<Vault> vaults, ExecutorService executorService, VaultService vaultService) {
 		this.window = window;
-		this.response = response;
 		this.unlockedVaults = vaults.filtered(Vault::isUnlocked);
 		this.executorService = executorService;
 		this.vaultService = vaultService;
+		window.setOnCloseRequest(windowEvent -> cancel());
+	}
+
+	public void updateQuitRequest(QuitResponse newResponse) {
+		var oldResponse = quitResponse.getAndSet(newResponse);
+		if (oldResponse != null) {
+			oldResponse.cancelQuit();
+		}
+	}
+
+	private void respondToQuitRequest(Consumer<QuitResponse> action) {
+		var response = quitResponse.getAndSet(null);
+		if (response != null) {
+			action.accept(response);
+		}
 	}
 
 	@FXML
 	public void cancel() {
 		LOG.info("Quitting application canceled by user.");
 		window.close();
-		response.cancelQuit();
+		respondToQuitRequest(QuitResponse::cancelQuit);
 	}
 
 	@FXML
@@ -56,16 +72,16 @@ public class QuitController implements FxController {
 			LOG.info("Locked {}", lockAllTask.getValue().stream().map(Vault::getDisplayName).collect(Collectors.joining(", ")));
 			if (unlockedVaults.isEmpty()) {
 				window.close();
-				response.performQuit();
+				respondToQuitRequest(QuitResponse::performQuit);
 			}
 		});
 		lockAllTask.setOnFailed(evt -> {
 			LOG.warn("Locking failed", lockAllTask.getException());
 			lockAndQuitButton.setDisable(false);
 			lockAndQuitButton.setContentDisplay(ContentDisplay.TEXT_ONLY);
-			// TODO: show force lock or force quit scene (and DO NOT cancelQuit() here!)
-			// see https://github.com/cryptomator/cryptomator/blob/1.4.16/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java#L151-L163
-			response.cancelQuit();
+			// TODO: show force lock or force quit scene (and DO NOT cancelQuit() here!) (see https://github.com/cryptomator/cryptomator/pull/1416)
+			window.close();
+			respondToQuitRequest(QuitResponse::cancelQuit);
 		});
 		executorService.execute(lockAllTask);
 	}

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java

@@ -43,7 +43,7 @@ abstract class QuitModule {
 	@Provides
 	@FxmlScene(FxmlFile.QUIT)
 	@QuitScoped
-	static Scene provideUnlockScene(@QuitWindow FXMLLoaderFactory fxmlLoaders) {
+	static Scene provideQuitScene(@QuitWindow FXMLLoaderFactory fxmlLoaders) {
 		return fxmlLoaders.createScene("/fxml/quit.fxml");
 	}
 

+ 2 - 2
main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java

@@ -39,7 +39,7 @@ public class GeneralVaultOptionsController implements FxController {
 	public void initialize() {
 		vaultName.textProperty().set(vault.getVaultSettings().displayName().get());
 		vaultName.focusedProperty().addListener(this::trimVaultNameOnFocusLoss);
-		vaultName.setTextFormatter(new TextFormatter<>(this::checkVaultNameLength));
+		vaultName.setTextFormatter(new TextFormatter<>(this::removeWhitespaces));
 		unlockOnStartupCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().unlockAfterStartup());
 		actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values());
 		actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock());
@@ -53,7 +53,7 @@ public class GeneralVaultOptionsController implements FxController {
 		}
 	}
 
-	private TextFormatter.Change checkVaultNameLength(TextFormatter.Change change) {
+	private TextFormatter.Change removeWhitespaces(TextFormatter.Change change) {
 		if (change.isContentChange() && change.getControlNewText().length() > VAULTNAME_TRUNCATE_THRESHOLD) {
 			return null; // reject any change that would lead to a text exceeding threshold
 		} else {