moved from guice to dagger

This commit is contained in:
Sebastian Stenzel
2015-08-08 19:13:16 +02:00
parent 48b319ec99
commit af9deffa6d
30 changed files with 579 additions and 447 deletions

View File

@@ -7,7 +7,6 @@ Cryptomator is licensed under the MIT license. The details can be found in the a
Cryptomator uses third party softwares that may be licensed under different licenses.
### Jackson
Jackson is a high-performance, Free/Open Source JSON processing library.
It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has
@@ -24,7 +23,6 @@ FasterXML.com (http://fasterxml.com).
in some artifacts (usually source distributions); but is always available
from the source code management (SCM) system project uses.
### Jetty
Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
@@ -39,7 +37,6 @@ Permission to use, copy, modify and distribute UnixCrypt
for non-commercial or commercial purposes and without fee is
granted provided that the copyright notice appears in all copies.
### Jackrabbit WebDAV Library
Copyright 2004-2014 The Apache Software Foundation
@@ -83,6 +80,12 @@ Copyright (c) 2013, ControlsFX
Licensed under the accompanying BSD license file.
### Dagger 2
Copyright 2014 Google, Inc.
Copyright 2012 Square, Inc.
Licensed under the Apache License, Version 2.0
### Apache Log4j
Copyright 1999-2012 Apache Software Foundation
@@ -93,4 +96,4 @@ ResolverUtil.java Copyright 2005-2006 Tim Fennell
### JUnit
Copyright (c) 2000-2006, www.hamcrest.org
Licensed under the accompanying BSD license file.
Licensed under the accompanying BSD license file.

View File

@@ -112,7 +112,7 @@
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<!-- org.apache.httpcomponents:httpclient is newer, but jackrabbit uses this version. We don't have a reason to upgrade -->
<!-- org.apache.httpcomponents:httpclient is newer, but jackrabbit uses this version. We don't have a reason to upgrade -->
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>${commons-httpclient.version}</version>
@@ -127,9 +127,9 @@
<!-- DI -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>2.0</version>
</dependency>
<!-- JSON -->

View File

@@ -55,8 +55,35 @@
<!-- DI -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<dependencies>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
<configuration>
<!-- workaround for http://jira.codehaus.org/browse/MCOMPILER-202 -->
<forceJavacCompilerUse>true</forceJavacCompilerUse>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,20 @@
package org.cryptomator.ui;
import java.util.concurrent.ExecutorService;
import javax.inject.Singleton;
import org.cryptomator.ui.controllers.MainController;
import org.cryptomator.ui.util.DeferredCloser;
import dagger.Component;
@Singleton
@Component(modules = CryptomatorModule.class)
interface CryptomatorComponent {
ExecutorService executorService();
DeferredCloser deferredCloser();
MainController mainController();
}

View File

@@ -0,0 +1,120 @@
package org.cryptomator.ui;
import java.util.Comparator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.cryptomator.crypto.Cryptor;
import org.cryptomator.crypto.SamplingCryptorDecorator;
import org.cryptomator.crypto.aes256.Aes256Cryptor;
import org.cryptomator.ui.model.VaultFactory;
import org.cryptomator.ui.model.VaultObjectMapperProvider;
import org.cryptomator.ui.settings.Settings;
import org.cryptomator.ui.settings.SettingsProvider;
import org.cryptomator.ui.util.DeferredCloser;
import org.cryptomator.ui.util.DeferredCloser.Closer;
import org.cryptomator.ui.util.SemVerComparator;
import org.cryptomator.ui.util.mount.WebDavMounter;
import org.cryptomator.ui.util.mount.WebDavMounterProvider;
import org.cryptomator.webdav.WebDavServer;
import com.fasterxml.jackson.databind.ObjectMapper;
import dagger.Module;
import dagger.Provides;
import javafx.application.Application;
@Module
class CryptomatorModule {
private final Application application;
private final DeferredCloser deferredCloser;
public CryptomatorModule(Application application) {
this.application = application;
this.deferredCloser = new DeferredCloser();
}
@Provides
@Singleton
Application provideApplication() {
return application;
}
@Provides
@Singleton
DeferredCloser provideDeferredCloser() {
return deferredCloser;
}
@Provides
@Singleton
@Named("SemVer")
Comparator<String> provideSemVerComparator() {
return new SemVerComparator();
}
@Provides
@Singleton
VaultObjectMapperProvider provideVaultObjectMapperProvider(VaultFactory vaultFactory) {
return new VaultObjectMapperProvider(vaultFactory);
}
@Provides
@Singleton
@Named("VaultJsonMapper")
ObjectMapper provideVaultObjectMapper(VaultObjectMapperProvider vaultObjectMapperProvider) {
return vaultObjectMapperProvider.get();
}
@Provides
@Singleton
SettingsProvider provideSettingsProvider(DeferredCloser closer, @Named("VaultJsonMapper") Provider<ObjectMapper> objectMapper) {
return new SettingsProvider(closer, objectMapper.get());
}
@Provides
Settings provideSettings(SettingsProvider settingsProvider) {
return settingsProvider.get();
}
@Provides
@Singleton
ExecutorService provideExecutorService() {
return closeLater(Executors.newCachedThreadPool(), ExecutorService::shutdown);
}
@Provides
@Singleton
VaultFactory provideVaultFactory(WebDavServer server, Provider<Cryptor> cryptorProvider, WebDavMounter mounter, DeferredCloser closer) {
return new VaultFactory(server, cryptorProvider, mounter, closer);
}
@Provides
@Singleton
WebDavMounter provideWebDavMounterProvider(WebDavServer server, ExecutorService executorService) {
return new WebDavMounterProvider(server, executorService).get();
}
@Provides
@Singleton
WebDavServer provideWebDavServer() {
final WebDavServer webDavServer = new WebDavServer();
webDavServer.start();
return closeLater(webDavServer, WebDavServer::stop);
}
@Provides
Cryptor provideCryptor() {
return SamplingCryptorDecorator.decorate(new Aes256Cryptor());
}
private <T> T closeLater(T object, Closer<T> closer) {
return deferredCloser.closeLater(object, closer).get().get();
}
}

View File

@@ -15,15 +15,7 @@ import java.nio.file.Path;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.ui.MainModule.ControllerFactory;
import org.cryptomator.ui.controllers.MainController;
import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.util.ActiveWindowStyleSupport;
@@ -34,8 +26,10 @@ import org.cryptomator.ui.util.TrayIconUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Guice;
import com.google.inject.Injector;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
public class MainApplication extends Application {
@@ -44,28 +38,15 @@ public class MainApplication extends Application {
private static final Logger LOG = LoggerFactory.getLogger(MainApplication.class);
private final ExecutorService executorService;
private final ControllerFactory controllerFactory;
private final DeferredCloser closer;
private final MainController mainCtrl;
public MainApplication() {
this(getInjector());
}
private static Injector getInjector() {
return Guice.createInjector(new MainModule());
}
public MainApplication(Injector injector) {
this(injector.getInstance(ExecutorService.class), injector.getInstance(ControllerFactory.class), injector.getInstance(DeferredCloser.class), injector.getInstance(MainApplicationReference.class));
}
public MainApplication(ExecutorService executorService, ControllerFactory controllerFactory, DeferredCloser closer, MainApplicationReference appRef) {
super();
this.executorService = executorService;
this.controllerFactory = controllerFactory;
this.closer = closer;
final CryptomatorComponent comp = DaggerCryptomatorComponent.builder().cryptomatorModule(new CryptomatorModule(this)).build();
this.executorService = comp.executorService();
this.closer = comp.deferredCloser();
this.mainCtrl = comp.mainController();
Cryptomator.addShutdownTask(closer::close);
appRef.set(this);
}
@Override
@@ -83,34 +64,29 @@ public class MainApplication extends Application {
});
chooseNativeStylesheet();
mainCtrl.initStage(primaryStage);
final ResourceBundle rb = ResourceBundle.getBundle("localization");
final FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/main.fxml"), rb);
loader.setControllerFactory(controllerFactory);
final Parent root = loader.load();
final MainController ctrl = loader.getController();
ctrl.setStage(primaryStage);
final Scene scene = new Scene(root);
primaryStage.setTitle(rb.getString("app.name"));
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.setResizable(false);
primaryStage.show();
ActiveWindowStyleSupport.startObservingFocus(primaryStage);
TrayIconUtil.init(primaryStage, rb, () -> {
quit();
});
for (String arg : getParameters().getUnnamed()) {
handleCommandLineArg(ctrl, arg);
handleCommandLineArg(mainCtrl, arg);
}
if (SystemUtils.IS_OS_MAC_OSX) {
Cryptomator.OPEN_FILE_HANDLER.complete(file -> handleCommandLineArg(ctrl, file.getAbsolutePath()));
Cryptomator.OPEN_FILE_HANDLER.complete(file -> handleCommandLineArg(mainCtrl, file.getAbsolutePath()));
}
LocalInstance cryptomatorGuiInstance = closer.closeLater(SingleInstanceManager.startLocalInstance(APPLICATION_KEY, executorService), LocalInstance::close).get().get();
cryptomatorGuiInstance.registerListener(arg -> handleCommandLineArg(ctrl, arg));
cryptomatorGuiInstance.registerListener(arg -> handleCommandLineArg(mainCtrl, arg));
}
void handleCommandLineArg(final MainController ctrl, String arg) {
@@ -162,25 +138,4 @@ public class MainApplication extends Application {
closer.close();
}
/**
* Needed to inject MainApplication. Problem: Application needs to be set asap after injector creation.
*/
static class MainApplicationReference {
private Application application;
private void set(Application application) {
this.application = application;
}
public Application get() {
if (application == null) {
throw new IllegalStateException("not yet ready.");
} else {
return application;
}
}
}
}

View File

@@ -1,111 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 cryptomator.org
* This file is licensed under the terms of the MIT license.
* See the LICENSE.txt file for more info.
*
* Contributors:
* Tillmann Gaida - initial implementation
******************************************************************************/
package org.cryptomator.ui;
import java.util.Comparator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javafx.application.Application;
import javafx.util.Callback;
import javax.inject.Named;
import javax.inject.Singleton;
import org.cryptomator.crypto.Cryptor;
import org.cryptomator.crypto.SamplingCryptorDecorator;
import org.cryptomator.crypto.aes256.Aes256Cryptor;
import org.cryptomator.ui.MainApplication.MainApplicationReference;
import org.cryptomator.ui.model.VaultFactory;
import org.cryptomator.ui.model.VaultObjectMapperProvider;
import org.cryptomator.ui.settings.Settings;
import org.cryptomator.ui.settings.SettingsProvider;
import org.cryptomator.ui.util.DeferredCloser;
import org.cryptomator.ui.util.DeferredCloser.Closer;
import org.cryptomator.ui.util.SemVerComparator;
import org.cryptomator.ui.util.mount.WebDavMounter;
import org.cryptomator.ui.util.mount.WebDavMounterProvider;
import org.cryptomator.webdav.WebDavServer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.Provides;
import com.google.inject.name.Names;
public class MainModule extends AbstractModule {
private final DeferredCloser deferredCloser = new DeferredCloser();
public static interface ControllerFactory extends Callback<Class<?>, Object> {
}
@Override
protected void configure() {
bind(DeferredCloser.class).toInstance(deferredCloser);
bind(ObjectMapper.class).annotatedWith(Names.named("VaultJsonMapper")).toProvider(VaultObjectMapperProvider.class);
bind(Settings.class).toProvider(SettingsProvider.class);
bind(WebDavMounter.class).toProvider(WebDavMounterProvider.class).asEagerSingleton();
}
@Provides
@Singleton
ControllerFactory getControllerFactory(Injector injector) {
return cls -> injector.getInstance(cls);
}
@Provides
@Singleton
MainApplicationReference getApplicationBinding() {
return new MainApplicationReference();
}
@Provides
Application getApplication(MainApplicationReference ref) {
return ref.get();
}
@Provides
@Named("SemVer")
@Singleton
Comparator<String> getSemVerComparator() {
return new SemVerComparator();
}
@Provides
@Singleton
ExecutorService getExec() {
return closeLater(Executors.newCachedThreadPool(), ExecutorService::shutdown);
}
@Provides
Cryptor getCryptor() {
return SamplingCryptorDecorator.decorate(new Aes256Cryptor());
}
@Provides
@Singleton
VaultFactory getVaultFactory(WebDavServer server, Provider<Cryptor> cryptorProvider, WebDavMounter mounter, DeferredCloser closer) {
return new VaultFactory(server, cryptorProvider, mounter, closer);
}
@Provides
@Singleton
WebDavServer getServer() {
final WebDavServer webDavServer = new WebDavServer();
webDavServer.start();
return closeLater(webDavServer, WebDavServer::stop);
}
<T> T closeLater(T object, Closer<T> closer) {
return deferredCloser.closeLater(object, closer).get().get();
}
}

View File

@@ -0,0 +1,105 @@
package org.cryptomator.ui.controllers;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
* Controller presenting a single view.
*/
abstract class AbstractFXMLViewController implements Initializable {
private Parent fxmlRoot;
/**
* URL from #initialize(URL, ResourceBundle)
*/
protected URL rootUrl;
/**
* ResourceBundle from #initialize(URL, ResourceBundle)
*/
protected ResourceBundle resourceBundle;
/**
* Gets the URL to the FXML file describing the view presented by this controller.<br/>
*
* A default implementation would look like this:<br/>
* <code>
* return getClass().getResource("/myView.fxml");
* </code>
*
* @return FXML resource URL
*/
protected abstract URL getFxmlResourceUrl();
/**
* @return Localization bundle for the FXML labels or <code>null</code>.
*/
protected abstract ResourceBundle getFxmlResourceBundle();
@Override
public final void initialize(URL location, ResourceBundle resources) {
this.rootUrl = location;
this.resourceBundle = resources;
this.initialize();
}
protected void initialize() {
}
/**
* Creates a FXML loader used in {@link #loadFxml()}. This method can be overwritten for further loader customization.
*
* @return Configured loader ready to load.
*/
protected FXMLLoader createFxmlLoader() {
final URL fxmlUrl = getFxmlResourceUrl();
final ResourceBundle rb = getFxmlResourceBundle();
final FXMLLoader loader = new FXMLLoader(fxmlUrl, rb);
loader.setController(this);
return loader;
}
/**
* Loads the view presented by this controller from the FXML file return by {@link #getFxmlResourceUrl()}. This method can only be invoked once.
*
* @return Parent view element.
*/
protected final synchronized Parent loadFxml() {
if (fxmlRoot == null) {
final FXMLLoader loader = createFxmlLoader();
try {
fxmlRoot = loader.load();
} catch (IOException e) {
throw new IllegalStateException("Could not load FXML file from location: " + loader.getLocation(), e);
}
}
return fxmlRoot;
}
/**
* Creates a new scene with the root node from the FXML file and applies it to the given stage.
*/
public void initStage(Stage stage) {
final Parent root = loadFxml();
stage.setScene(new Scene(root));
stage.sizeToScene();
}
/**
* @return Creates a new stage and calls {@link #initStage(Stage)}.
*/
public Stage createStage() {
final Stage stage = new Stage();
initStage(stage);
return stage;
}
}

View File

@@ -10,15 +10,8 @@ import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.text.Text;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.cryptomator.crypto.exceptions.UnsupportedKeyLengthException;
import org.cryptomator.crypto.exceptions.UnsupportedVaultException;
@@ -28,13 +21,20 @@ import org.cryptomator.ui.model.Vault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.text.Text;
public class ChangePasswordController implements Initializable {
@Singleton
public class ChangePasswordController extends AbstractFXMLViewController {
private static final Logger LOG = LoggerFactory.getLogger(ChangePasswordController.class);
private ResourceBundle rb;
private ChangePasswordListener listener;
private Vault vault;
@@ -65,9 +65,17 @@ public class ChangePasswordController implements Initializable {
}
@Override
public void initialize(URL location, ResourceBundle rb) {
this.rb = rb;
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/change_password.fxml");
}
@Override
protected ResourceBundle getFxmlResourceBundle() {
return ResourceBundle.getBundle("localization");
}
@Override
public void initialize() {
oldPasswordField.textProperty().addListener(this::passwordFieldsDidChange);
newPasswordField.textProperty().addListener(this::passwordFieldsDidChange);
retypePasswordField.textProperty().addListener(this::passwordFieldsDidChange);
@@ -109,19 +117,19 @@ public class ChangePasswordController implements Initializable {
vault.getCryptor().decryptMasterKey(masterKeyInputStream, oldPassword);
Files.copy(masterKeyPath, masterKeyBackupPath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
messageText.setText(rb.getString("changePassword.errorMessage.decryptionFailed"));
messageText.setText(resourceBundle.getString("changePassword.errorMessage.decryptionFailed"));
LOG.error("Decryption failed for technical reasons.", ex);
newPasswordField.swipe();
retypePasswordField.swipe();
return;
} catch (WrongPasswordException e) {
messageText.setText(rb.getString("changePassword.errorMessage.wrongPassword"));
messageText.setText(resourceBundle.getString("changePassword.errorMessage.wrongPassword"));
newPasswordField.swipe();
retypePasswordField.swipe();
Platform.runLater(oldPasswordField::requestFocus);
return;
} catch (UnsupportedKeyLengthException ex) {
messageText.setText(rb.getString("changePassword.errorMessage.unsupportedKeyLengthInstallJCE"));
messageText.setText(resourceBundle.getString("changePassword.errorMessage.unsupportedKeyLengthInstallJCE"));
LOG.warn("Unsupported Key-Length. Please install Oracle Java Cryptography Extension (JCE).", ex);
newPasswordField.swipe();
retypePasswordField.swipe();
@@ -129,9 +137,9 @@ public class ChangePasswordController implements Initializable {
} catch (UnsupportedVaultException e) {
downloadsPageLink.setVisible(true);
if (e.isVaultOlderThanSoftware()) {
messageText.setText(rb.getString("changePassword.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
messageText.setText(resourceBundle.getString("changePassword.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
} else if (e.isSoftwareOlderThanVault()) {
messageText.setText(rb.getString("changePassword.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
messageText.setText(resourceBundle.getString("changePassword.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
}
newPasswordField.swipe();
retypePasswordField.swipe();
@@ -146,7 +154,7 @@ public class ChangePasswordController implements Initializable {
final CharSequence newPassword = newPasswordField.getCharacters();
try (final OutputStream masterKeyOutputStream = Files.newOutputStream(masterKeyPath, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC)) {
vault.getCryptor().encryptMasterKey(masterKeyOutputStream, newPassword);
messageText.setText(rb.getString("changePassword.infoMessage.success"));
messageText.setText(resourceBundle.getString("changePassword.infoMessage.success"));
Platform.runLater(this::didChangePassword);
// At this point the backup is still using the old password.
// It will be changed as soon as the user unlocks the vault the next time.

View File

@@ -19,23 +19,25 @@ import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ResourceBundle;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.model.Vault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InitializeController implements Initializable {
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
@Singleton
public class InitializeController extends AbstractFXMLViewController {
private static final Logger LOG = LoggerFactory.getLogger(InitializeController.class);
private ResourceBundle localization;
private Vault vault;
private InitializationListener listener;
@@ -51,9 +53,22 @@ public class InitializeController implements Initializable {
@FXML
private Label messageLabel;
@Inject
public InitializeController() {
}
@Override
public void initialize(URL url, ResourceBundle rb) {
this.localization = rb;
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/initialize.fxml");
}
@Override
protected ResourceBundle getFxmlResourceBundle() {
return ResourceBundle.getBundle("localization");
}
@Override
public void initialize() {
passwordField.textProperty().addListener(this::passwordFieldsDidChange);
retypePasswordField.textProperty().addListener(this::passwordFieldsDidChange);
}
@@ -88,9 +103,9 @@ public class InitializeController implements Initializable {
listener.didInitialize(this);
}
} catch (FileAlreadyExistsException ex) {
messageLabel.setText(localization.getString("initialize.messageLabel.alreadyInitialized"));
messageLabel.setText(resourceBundle.getString("initialize.messageLabel.alreadyInitialized"));
} catch (InvalidPathException ex) {
messageLabel.setText(localization.getString("initialize.messageLabel.invalidPath"));
messageLabel.setText(resourceBundle.getString("initialize.messageLabel.invalidPath"));
} catch (IOException ex) {
LOG.error("I/O Exception", ex);
} finally {

View File

@@ -4,6 +4,10 @@ import java.net.URL;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.cryptomator.ui.model.Vault;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
@@ -18,18 +22,13 @@ import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.CheckBoxListCell;
import javafx.stage.Stage;
import javafx.util.StringConverter;
import javax.inject.Inject;
import org.cryptomator.ui.model.Vault;
public class MacWarningsController implements Initializable {
public class MacWarningsController extends AbstractFXMLViewController {
@FXML
private ListView<Warning> warningsList;
@@ -43,7 +42,6 @@ public class MacWarningsController implements Initializable {
private final ChangeListener<Boolean> stageVisibilityChangeListener = this::windowVisibilityDidChange;
private Stage stage;
private Vault vault;
private ResourceBundle rb;
@Inject
public MacWarningsController(Application application) {
@@ -51,8 +49,17 @@ public class MacWarningsController implements Initializable {
}
@Override
public void initialize(URL location, ResourceBundle rb) {
this.rb = rb;
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/mac_warnings.fxml");
}
@Override
protected ResourceBundle getFxmlResourceBundle() {
return ResourceBundle.getBundle("localization");
}
@Override
public void initialize() {
warnings.addListener(this::warningsDidInvalidate);
warningsList.setItems(warnings);
warningsList.setCellFactory(CheckBoxListCell.forListView(Warning::selectedProperty, new StringConverter<Warning>() {
@@ -70,6 +77,13 @@ public class MacWarningsController implements Initializable {
}));
}
@Override
public void initStage(Stage stage) {
super.initStage(stage);
this.stage = stage;
stage.showingProperty().addListener(new WeakChangeListener<>(stageVisibilityChangeListener));
}
@FXML
private void didClickWhitelistButton(ActionEvent event) {
warnings.filtered(w -> w.isSelected()).stream().forEach(w -> {
@@ -103,7 +117,7 @@ public class MacWarningsController implements Initializable {
private void windowVisibilityDidChange(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (Boolean.TRUE.equals(newValue)) {
stage.setTitle(String.format(rb.getString("macWarnings.windowTitle"), vault.getName()));
stage.setTitle(String.format(resourceBundle.getString("macWarnings.windowTitle"), vault.getName()));
warnings.addAll(vault.getNamesOfResourcesWithInvalidMac().stream().map(Warning::new).collect(Collectors.toList()));
vault.getNamesOfResourcesWithInvalidMac().addListener(this.unauthenticatedResourcesChangeListener);
} else {
@@ -116,11 +130,6 @@ public class MacWarningsController implements Initializable {
whitelistButton.setDisable(warnings.filtered(w -> w.isSelected()).isEmpty());
}
public void setStage(Stage stage) {
this.stage = stage;
stage.showingProperty().addListener(new WeakChangeListener<>(stageVisibilityChangeListener));
}
public void setVault(Vault vault) {
this.vault = vault;
}

View File

@@ -18,14 +18,28 @@ import java.util.List;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.cryptomator.ui.controllers.ChangePasswordController.ChangePasswordListener;
import org.cryptomator.ui.controllers.InitializeController.InitializationListener;
import org.cryptomator.ui.controllers.UnlockController.UnlockListener;
import org.cryptomator.ui.controllers.UnlockedController.LockListener;
import org.cryptomator.ui.controls.DirectoryListCell;
import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.model.VaultFactory;
import org.cryptomator.ui.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dagger.Lazy;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Side;
import javafx.scene.Parent;
import javafx.scene.control.ContextMenu;
@@ -38,21 +52,8 @@ import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import org.cryptomator.ui.MainModule.ControllerFactory;
import org.cryptomator.ui.controllers.ChangePasswordController.ChangePasswordListener;
import org.cryptomator.ui.controllers.InitializeController.InitializationListener;
import org.cryptomator.ui.controllers.UnlockController.UnlockListener;
import org.cryptomator.ui.controllers.UnlockedController.LockListener;
import org.cryptomator.ui.controls.DirectoryListCell;
import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.model.VaultFactory;
import org.cryptomator.ui.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
public class MainController implements Initializable, InitializationListener, UnlockListener, LockListener, ChangePasswordListener {
@Singleton
public class MainController extends AbstractFXMLViewController implements InitializationListener, UnlockListener, LockListener, ChangePasswordListener {
private static final Logger LOG = LoggerFactory.getLogger(MainController.class);
@@ -76,28 +77,50 @@ public class MainController implements Initializable, InitializationListener, Un
@FXML
private Pane contentPane;
private final ControllerFactory controllerFactory;
private final Settings settings;
private final VaultFactory vaultFactoy;
private ResourceBundle rb;
private final Lazy<WelcomeController> welcomeController;
private final Lazy<InitializeController> initializeController;
private final Lazy<UnlockController> unlockController;
private final Provider<UnlockedController> unlockedController;
private final Lazy<ChangePasswordController> changePasswordController;
@Inject
public MainController(ControllerFactory controllerFactory, Settings settings, VaultFactory vaultFactoy) {
public MainController(Settings settings, VaultFactory vaultFactoy, Lazy<WelcomeController> welcomeController, Lazy<InitializeController> initializeController, Lazy<UnlockController> unlockController,
Provider<UnlockedController> unlockedController, Lazy<ChangePasswordController> changePasswordController) {
super();
this.controllerFactory = controllerFactory;
this.settings = settings;
this.vaultFactoy = vaultFactoy;
this.welcomeController = welcomeController;
this.initializeController = initializeController;
this.unlockController = unlockController;
this.unlockedController = unlockedController;
this.changePasswordController = changePasswordController;
}
@Override
public void initialize(URL url, ResourceBundle rb) {
this.rb = rb;
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/main.fxml");
}
@Override
protected ResourceBundle getFxmlResourceBundle() {
return ResourceBundle.getBundle("localization");
}
@Override
public void initialize() {
final ObservableList<Vault> items = FXCollections.observableList(settings.getDirectories());
vaultList.setItems(items);
vaultList.setCellFactory(this::createDirecoryListCell);
vaultList.getSelectionModel().getSelectedItems().addListener(this::selectedVaultDidChange);
this.showWelcomeView();
}
@Override
public void initStage(Stage stage) {
super.initStage(stage);
this.stage = stage;
}
@FXML
@@ -191,14 +214,14 @@ public class MainController implements Initializable, InitializationListener, Un
private void selectedVaultDidChange(ListChangeListener.Change<? extends Vault> change) {
final Vault selectedVault = vaultList.getSelectionModel().getSelectedItem();
if (selectedVault == null) {
stage.setTitle(rb.getString("app.name"));
stage.setTitle(resourceBundle.getString("app.name"));
showWelcomeView();
} else if (!Files.isDirectory(selectedVault.getPath())) {
Platform.runLater(() -> {
vaultList.getItems().remove(selectedVault);
vaultList.getSelectionModel().clearSelection();
});
stage.setTitle(rb.getString("app.name"));
stage.setTitle(resourceBundle.getString("app.name"));
showWelcomeView();
} else {
stage.setTitle(selectedVault.getName());
@@ -237,25 +260,17 @@ public class MainController implements Initializable, InitializationListener, Un
}
}
private <T> T showView(String fxml) {
try {
final FXMLLoader loader = new FXMLLoader(getClass().getResource(fxml), rb);
loader.setControllerFactory(controllerFactory);
final Parent root = loader.load();
contentPane.getChildren().clear();
contentPane.getChildren().add(root);
return loader.getController();
} catch (IOException e) {
throw new IllegalStateException("Failed to load fxml file.", e);
}
}
private void showWelcomeView() {
this.showView("/fxml/welcome.fxml");
final Parent root = welcomeController.get().loadFxml();
contentPane.getChildren().clear();
contentPane.getChildren().add(root);
}
private void showInitializeView(Vault vault) {
final InitializeController ctrl = showView("/fxml/initialize.fxml");
final InitializeController ctrl = initializeController.get();
final Parent root = ctrl.loadFxml();
contentPane.getChildren().clear();
contentPane.getChildren().add(root);
ctrl.setVault(vault);
ctrl.setListener(this);
}
@@ -266,7 +281,10 @@ public class MainController implements Initializable, InitializationListener, Un
}
private void showUnlockView(Vault vault) {
final UnlockController ctrl = showView("/fxml/unlock.fxml");
final UnlockController ctrl = unlockController.get();
final Parent root = ctrl.loadFxml();
contentPane.getChildren().clear();
contentPane.getChildren().add(root);
ctrl.setVault(vault);
ctrl.setListener(this);
}
@@ -278,7 +296,10 @@ public class MainController implements Initializable, InitializationListener, Un
}
private void showUnlockedView(Vault vault) {
final UnlockedController ctrl = showView("/fxml/unlocked.fxml");
final UnlockedController ctrl = unlockedController.get();
final Parent root = ctrl.loadFxml();
contentPane.getChildren().clear();
contentPane.getChildren().add(root);
ctrl.setVault(vault);
ctrl.setListener(this);
}
@@ -292,7 +313,10 @@ public class MainController implements Initializable, InitializationListener, Un
}
private void showChangePasswordView(Vault vault) {
final ChangePasswordController ctrl = showView("/fxml/change_password.fxml");
final ChangePasswordController ctrl = changePasswordController.get();
final Parent root = ctrl.loadFxml();
contentPane.getChildren().clear();
contentPane.getChildren().add(root);
ctrl.setVault(vault);
ctrl.setListener(this);
}

View File

@@ -19,19 +19,7 @@ import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.text.Text;
import javax.inject.Inject;
import javax.security.auth.DestroyFailedException;
import org.apache.commons.lang3.CharUtils;
@@ -44,13 +32,22 @@ import org.cryptomator.ui.util.FXThreads;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.text.Text;
public class UnlockController implements Initializable {
public class UnlockController extends AbstractFXMLViewController {
private static final Logger LOG = LoggerFactory.getLogger(UnlockController.class);
private ResourceBundle rb;
private UnlockListener listener;
private Vault vault;
@@ -77,15 +74,22 @@ public class UnlockController implements Initializable {
@Inject
public UnlockController(Application app, ExecutorService exec) {
super();
this.app = app;
this.exec = exec;
}
@Override
public void initialize(URL url, ResourceBundle rb) {
this.rb = rb;
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/unlock.fxml");
}
@Override
protected ResourceBundle getFxmlResourceBundle() {
return ResourceBundle.getBundle("localization");
}
@Override
public void initialize() {
passwordField.textProperty().addListener(this::passwordFieldsDidChange);
mountName.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents);
mountName.textProperty().addListener(this::mountNameDidChange);
@@ -124,7 +128,7 @@ public class UnlockController implements Initializable {
try (final InputStream masterKeyInputStream = Files.newInputStream(masterKeyPath, StandardOpenOption.READ)) {
vault.getCryptor().decryptMasterKey(masterKeyInputStream, password);
if (!vault.startServer()) {
messageText.setText(rb.getString("unlock.messageLabel.startServerFailed"));
messageText.setText(resourceBundle.getString("unlock.messageLabel.startServerFailed"));
vault.getCryptor().destroy();
return;
}
@@ -136,26 +140,26 @@ public class UnlockController implements Initializable {
} catch (IOException ex) {
setControlsDisabled(false);
progressIndicator.setVisible(false);
messageText.setText(rb.getString("unlock.errorMessage.decryptionFailed"));
messageText.setText(resourceBundle.getString("unlock.errorMessage.decryptionFailed"));
LOG.error("Decryption failed for technical reasons.", ex);
} catch (WrongPasswordException e) {
setControlsDisabled(false);
progressIndicator.setVisible(false);
messageText.setText(rb.getString("unlock.errorMessage.wrongPassword"));
messageText.setText(resourceBundle.getString("unlock.errorMessage.wrongPassword"));
Platform.runLater(passwordField::requestFocus);
} catch (UnsupportedKeyLengthException ex) {
setControlsDisabled(false);
progressIndicator.setVisible(false);
messageText.setText(rb.getString("unlock.errorMessage.unsupportedKeyLengthInstallJCE"));
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedKeyLengthInstallJCE"));
LOG.warn("Unsupported Key-Length. Please install Oracle Java Cryptography Extension (JCE).", ex);
} catch (UnsupportedVaultException e) {
setControlsDisabled(false);
progressIndicator.setVisible(false);
downloadsPageLink.setVisible(true);
if (e.isVaultOlderThanSoftware()) {
messageText.setText(rb.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
} else if (e.isSoftwareOlderThanVault()) {
messageText.setText(rb.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
}
} catch (DestroyFailedException e) {
setControlsDisabled(false);

View File

@@ -8,10 +8,17 @@
******************************************************************************/
package org.cryptomator.ui.controllers;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javax.inject.Inject;
import javax.inject.Provider;
import org.cryptomator.crypto.CryptorIOSampling;
import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.util.ActiveWindowStyleSupport;
import org.cryptomator.ui.util.mount.CommandFailedException;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
@@ -20,10 +27,6 @@ import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
@@ -32,21 +35,10 @@ import javafx.scene.control.Label;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.cryptomator.crypto.CryptorIOSampling;
import org.cryptomator.ui.MainModule.ControllerFactory;
import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.util.ActiveWindowStyleSupport;
import org.cryptomator.ui.util.mount.CommandFailedException;
import com.google.inject.Inject;
public class UnlockedController implements Initializable {
public class UnlockedController extends AbstractFXMLViewController {
private static final int IO_SAMPLING_STEPS = 100;
private static final double IO_SAMPLING_INTERVAL = 0.25;
private final ControllerFactory controllerFactory;
private final Stage macWarningWindow = new Stage();
private MacWarningsController macWarningCtrl;
private LockListener listener;
private Vault vault;
private Timeline ioAnimation;
@@ -60,32 +52,28 @@ public class UnlockedController implements Initializable {
@FXML
private NumberAxis xAxis;
private ResourceBundle rb;
private final Stage macWarningsWindow = new Stage();
private final MacWarningsController macWarningsController;
@Inject
public UnlockedController(ControllerFactory controllerFactory) {
this.controllerFactory = controllerFactory;
public UnlockedController(Provider<MacWarningsController> macWarningsControllerProvider) {
this.macWarningsController = macWarningsControllerProvider.get();
}
@Override
public void initialize(URL url, ResourceBundle rb) {
this.rb = rb;
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/unlocked.fxml");
}
try {
final FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/mac_warnings.fxml"), rb);
loader.setControllerFactory(controllerFactory);
@Override
protected ResourceBundle getFxmlResourceBundle() {
return ResourceBundle.getBundle("localization");
}
final Parent root = loader.load();
macWarningWindow.setScene(new Scene(root));
macWarningWindow.sizeToScene();
macWarningWindow.setResizable(false);
ActiveWindowStyleSupport.startObservingFocus(macWarningWindow);
macWarningCtrl = loader.getController();
macWarningCtrl.setStage(macWarningWindow);
} catch (IOException e) {
throw new IllegalStateException("Failed to load fxml file.", e);
}
@Override
public void initialize() {
macWarningsController.initStage(macWarningsWindow);
ActiveWindowStyleSupport.startObservingFocus(macWarningsWindow);
}
@FXML
@@ -93,7 +81,7 @@ public class UnlockedController implements Initializable {
try {
vault.unmount();
} catch (CommandFailedException e) {
messageLabel.setText(rb.getString("unlocked.label.unmountFailed"));
messageLabel.setText(resourceBundle.getString("unlocked.label.unmountFailed"));
return;
}
vault.stopServer();
@@ -110,11 +98,11 @@ public class UnlockedController implements Initializable {
private void macWarningsDidChange(ListChangeListener.Change<? extends String> change) {
if (change.getList().size() > 0) {
Platform.runLater(() -> {
macWarningWindow.show();
macWarningsWindow.show();
});
} else {
Platform.runLater(() -> {
macWarningWindow.hide();
macWarningsWindow.hide();
});
}
}
@@ -138,6 +126,13 @@ public class UnlockedController implements Initializable {
ioAnimation.play();
}
private void stopIoSampling() {
if (ioAnimation != null) {
ioGraph.getData().clear();
ioAnimation.stop();
}
}
private class IoSamplingAnimationHandler implements EventHandler<ActionEvent> {
private static final double BYTES_TO_MEGABYTES_FACTOR = 1.0 / IO_SAMPLING_INTERVAL / 1024.0 / 1024.0;
@@ -181,7 +176,7 @@ public class UnlockedController implements Initializable {
public void setVault(Vault vault) {
this.vault = vault;
macWarningCtrl.setVault(vault);
macWarningsController.setVault(vault);
// listen to MAC warnings as long as this vault is unlocked:
final ListChangeListener<String> macWarningsListener = this::macWarningsDidChange;
@@ -193,6 +188,7 @@ public class UnlockedController implements Initializable {
});
// sample crypto-throughput:
stopIoSampling();
if (vault.getCryptor() instanceof CryptorIOSampling) {
startIoSampling((CryptorIOSampling) vault.getCryptor());
} else {

View File

@@ -16,17 +16,9 @@ import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Hyperlink;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
@@ -40,7 +32,16 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
public class WelcomeController implements Initializable {
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Hyperlink;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
@Singleton
public class WelcomeController extends AbstractFXMLViewController {
private static final Logger LOG = LoggerFactory.getLogger(WelcomeController.class);
@@ -53,7 +54,6 @@ public class WelcomeController implements Initializable {
private final Application app;
private final Comparator<String> semVerComparator;
private final ExecutorService executor;
private ResourceBundle rb;
@Inject
public WelcomeController(Application app, @Named("SemVer") Comparator<String> semVerComparator, ExecutorService executor) {
@@ -63,8 +63,17 @@ public class WelcomeController implements Initializable {
}
@Override
public void initialize(URL url, ResourceBundle rb) {
this.rb = rb;
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/welcome.fxml");
}
@Override
protected ResourceBundle getFxmlResourceBundle() {
return ResourceBundle.getBundle("localization");
}
@Override
public void initialize() {
this.botImageView.setImage(new Image(WelcomeController.class.getResource("/bot_welcome.png").toString()));
executor.execute(this::checkForUpdates);
}
@@ -103,7 +112,7 @@ public class WelcomeController implements Initializable {
final String currentVersion = WelcomeController.class.getPackage().getImplementationVersion();
LOG.debug("Current version: {}, lastest version: {}", currentVersion, latestVersion);
if (currentVersion != null && semVerComparator.compare(currentVersion, latestVersion) < 0) {
final String msg = String.format(rb.getString("welcome.newVersionMessage"), latestVersion, currentVersion);
final String msg = String.format(resourceBundle.getString("welcome.newVersionMessage"), latestVersion, currentVersion);
Platform.runLater(() -> {
this.updateLink.setText(msg);
this.updateLink.setVisible(true);

View File

@@ -2,14 +2,14 @@ package org.cryptomator.ui.model;
import java.nio.file.Path;
import javax.inject.Inject;
import javax.inject.Provider;
import org.cryptomator.crypto.Cryptor;
import org.cryptomator.ui.util.DeferredCloser;
import org.cryptomator.ui.util.mount.WebDavMounter;
import org.cryptomator.webdav.WebDavServer;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class VaultFactory {
private final WebDavServer server;

View File

@@ -5,6 +5,7 @@ import java.nio.file.FileSystems;
import java.nio.file.Path;
import javax.inject.Inject;
import javax.inject.Provider;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
@@ -16,7 +17,6 @@ import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.google.inject.Provider;
public class VaultObjectMapperProvider implements Provider<ObjectMapper> {

View File

@@ -0,0 +1,20 @@
package org.cryptomator.ui.settings;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.cryptomator.ui.util.DeferredCloser;
import com.fasterxml.jackson.databind.ObjectMapper;
import dagger.Module;
@Module
public class SettingsModule {
@Singleton
Provider<Settings> provideSettingsProvider(Provider<ObjectMapper> objectMapper) {
return new SettingsProvider(new DeferredCloser(), objectMapper.get());
}
}

View File

@@ -11,6 +11,7 @@ import java.nio.file.StandardOpenOption;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.ui.util.DeferredCloser;
@@ -18,7 +19,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Provider;
public class SettingsProvider implements Provider<Settings> {
@@ -50,7 +50,7 @@ public class SettingsProvider implements Provider<Settings> {
this.deferredCloser = deferredCloser;
this.objectMapper = objectMapper;
}
private Path getSettingsPath() throws IOException {
String settingsPathProperty = System.getProperty("settingsPath");
if (settingsPathProperty == null) {

View File

@@ -20,6 +20,8 @@ import org.cryptomator.ui.controllers.MainController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
/**
* <p>
* Tries to bring open-close symmetry in contexts where the resource outlives
@@ -57,8 +59,10 @@ public class DeferredCloser implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(MainController.class);
@VisibleForTesting
final Map<Long, ManagedResource<?>> cleanups = new ConcurrentSkipListMap<>();
@VisibleForTesting
final AtomicLong counter = new AtomicLong();
public class ManagedResource<T> implements DeferredClosable<T> {
@@ -73,6 +77,7 @@ public class DeferredCloser implements AutoCloseable {
this.closer = closer;
}
@Override
public void close() {
final T oldObject = object.getAndSet(null);
if (oldObject != null) {
@@ -86,6 +91,7 @@ public class DeferredCloser implements AutoCloseable {
}
}
@Override
public Optional<T> get() throws IllegalStateException {
return Optional.ofNullable(object.get());
}
@@ -94,6 +100,7 @@ public class DeferredCloser implements AutoCloseable {
/**
* Closes all added objects which have not been closed before and releases references.
*/
@Override
public void close() {
for (Iterator<ManagedResource<?>> iterator = cleanups.values().iterator(); iterator.hasNext();) {
final ManagedResource<?> closableProvider = iterator.next();

View File

@@ -12,13 +12,12 @@ package org.cryptomator.ui.util.mount;
import java.util.concurrent.ExecutorService;
import javax.inject.Inject;
import javax.inject.Provider;
import org.cryptomator.webdav.WebDavServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Provider;
public class WebDavMounterProvider implements Provider<WebDavMounter> {
private static final Logger LOG = LoggerFactory.getLogger(WebDavMounterProvider.class);

View File

@@ -22,7 +22,7 @@
<?import javafx.scene.text.Text?>
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" fx:controller="org.cryptomator.ui.controllers.ChangePasswordController" xmlns:fx="http://javafx.com/fxml">
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets top="24.0" right="24.0" bottom="24.0" left="24.0" />
</padding>

View File

@@ -16,7 +16,7 @@
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.control.Label?>
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" fx:controller="org.cryptomator.ui.controllers.InitializeController" xmlns:fx="http://javafx.com/fxml">
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets top="24.0" right="24.0" bottom="24.0" left="24.0" />
</padding>

View File

@@ -15,7 +15,7 @@
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.HBox?>
<VBox styleClass="root" alignment="CENTER" prefHeight="225.0" prefWidth="525.0" spacing="12.0" fx:controller="org.cryptomator.ui.controllers.MacWarningsController" xmlns:fx="http://javafx.com/fxml">
<VBox styleClass="root" alignment="CENTER" prefHeight="225.0" prefWidth="525.0" spacing="12.0" xmlns:fx="http://javafx.com/fxml">
<padding><Insets top="12.0" right="12.0" bottom="12.0" left="12.0"/></padding>

View File

@@ -18,12 +18,11 @@
<?import javafx.scene.control.MenuItem?>
<?import javafx.geometry.Insets?>
<HBox fx:id="rootPane" prefHeight="440.0" prefWidth="640.0" fx:controller="org.cryptomator.ui.controllers.MainController" xmlns:fx="http://javafx.com/fxml">
<HBox fx:id="rootPane" prefHeight="440.0" prefWidth="640.0" xmlns:fx="http://javafx.com/fxml">
<padding><Insets top="20" right="20" bottom="20" left="20.0"/></padding>
<fx:define>
<fx:include fx:id="welcomeView" source="welcome.fxml" />
<ContextMenu fx:id="vaultListCellContextMenu">
<items>
<MenuItem text="%main.directoryList.contextMenu.remove" onAction="#didClickRemoveSelectedEntry" />
@@ -49,11 +48,7 @@
</ToolBar>
</children>
</VBox>
<Pane fx:id="contentPane">
<children>
<fx:reference source="welcomeView" />
</children>
</Pane>
<Pane fx:id="contentPane"/>
</children>
</HBox>

View File

@@ -22,7 +22,7 @@
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.text.Text?>
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" fx:controller="org.cryptomator.ui.controllers.UnlockController" xmlns:fx="http://javafx.com/fxml">
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets top="24.0" right="24.0" bottom="24.0" left="24.0" />
</padding>

View File

@@ -17,7 +17,7 @@
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.ColumnConstraints?>
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" fx:controller="org.cryptomator.ui.controllers.UnlockedController" xmlns:fx="http://javafx.com/fxml">
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets top="24.0" right="24.0" bottom="24.0" left="24.0" />
</padding>

View File

@@ -18,7 +18,7 @@
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.control.Hyperlink?>
<AnchorPane xmlns:fx="http://javafx.com/fxml" fx:controller="org.cryptomator.ui.controllers.WelcomeController">
<AnchorPane xmlns:fx="http://javafx.com/fxml">
<children>
<Label AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="20.0" prefWidth="400.0" alignment="CENTER" style="-fx-font-size: 1.5em;" text="%welcome.welcomeLabel"/>

View File

@@ -1,62 +0,0 @@
package org.cryptomator.ui.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* Taken from http://fabiostrozzi.eu/2011/03/27/junit-tests-easy-guice/
*/
public class GuiceJUnitRunner extends BlockJUnit4ClassRunner {
private final Injector injector;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface GuiceModules {
Class<?>[] value();
}
@Override
public Object createTest() throws Exception {
Object obj = super.createTest();
injector.injectMembers(obj);
return obj;
}
public GuiceJUnitRunner(Class<?> klass) throws InitializationError {
super(klass);
Class<?>[] classes = getModulesFor(klass);
injector = createInjectorFor(classes);
}
private Injector createInjectorFor(Class<?>[] classes) throws InitializationError {
Module[] modules = new Module[classes.length];
for (int i = 0; i < classes.length; i++) {
try {
modules[i] = (Module) (classes[i]).newInstance();
} catch (InstantiationException e) {
throw new InitializationError(e);
} catch (IllegalAccessException e) {
throw new InitializationError(e);
}
}
return Guice.createInjector(modules);
}
private Class<?>[] getModulesFor(Class<?> klass) throws InitializationError {
GuiceModules annotation = klass.getAnnotation(GuiceModules.class);
if (annotation == null)
throw new InitializationError("Missing @GuiceModules annotation for unit test '" + klass.getName() + "'");
return annotation.value();
}
}

View File

@@ -2,23 +2,12 @@ package org.cryptomator.ui.util;
import java.util.Comparator;
import javax.inject.Inject;
import javax.inject.Named;
import org.cryptomator.ui.MainModule;
import org.cryptomator.ui.test.GuiceJUnitRunner;
import org.cryptomator.ui.test.GuiceJUnitRunner.GuiceModules;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(GuiceJUnitRunner.class)
@GuiceModules(MainModule.class)
public class SemVerComparatorTest {
@Inject
@Named("SemVer")
private Comparator<String> semVerComparator;
private final Comparator<String> semVerComparator = new SemVerComparator();
// equal versions