From 42be5330fe3e88971c462f8174f5b0358a933022 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 19 Apr 2017 00:06:46 +0200 Subject: [PATCH] Refactored FXML loading --- .../launcher/LauncherComponent.java | 4 +- .../cryptomator/launcher/MainApplication.java | 2 +- .../java/org/cryptomator/ui/UiModule.java | 3 +- .../AbstractFXMLViewController.java | 101 ------------------ .../controllers/ChangePasswordController.java | 15 ++- .../ui/controllers/InitializeController.java | 15 ++- .../LocalizedFXMLViewController.java | 23 ---- .../ui/controllers/MainController.java | 85 ++++++--------- .../ui/controllers/NotFoundController.java | 19 ++-- .../ui/controllers/SettingsController.java | 26 +++-- .../ui/controllers/UnlockController.java | 14 ++- .../ui/controllers/UnlockedController.java | 15 ++- .../ui/controllers/UpgradeController.java | 15 +-- .../ui/controllers/ViewController.java | 22 ++++ .../ui/controllers/ViewControllerKey.java | 18 ++++ .../ui/controllers/ViewControllerLoader.java | 44 ++++++++ .../ui/controllers/ViewControllerModule.java | 73 +++++++++++++ .../ui/controllers/WelcomeController.java | 17 ++- .../main/resources/fxml/change_password.fxml | 2 +- .../src/main/resources/fxml/initialize.fxml | 2 +- main/ui/src/main/resources/fxml/main.fxml | 2 +- main/ui/src/main/resources/fxml/notfound.fxml | 2 +- main/ui/src/main/resources/fxml/settings.fxml | 2 +- main/ui/src/main/resources/fxml/unlock.fxml | 2 +- main/ui/src/main/resources/fxml/unlocked.fxml | 2 +- main/ui/src/main/resources/fxml/upgrade.fxml | 2 +- main/ui/src/main/resources/fxml/welcome.fxml | 2 +- 27 files changed, 288 insertions(+), 241 deletions(-) delete mode 100644 main/ui/src/main/java/org/cryptomator/ui/controllers/AbstractFXMLViewController.java delete mode 100644 main/ui/src/main/java/org/cryptomator/ui/controllers/LocalizedFXMLViewController.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/controllers/ViewController.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerKey.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerLoader.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerModule.java diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/LauncherComponent.java b/main/launcher/src/main/java/org/cryptomator/launcher/LauncherComponent.java index 06a50b024..4b574811b 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/LauncherComponent.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/LauncherComponent.java @@ -3,7 +3,7 @@ package org.cryptomator.launcher; import javax.inject.Singleton; import org.cryptomator.logging.DebugMode; -import org.cryptomator.ui.controllers.MainController; +import org.cryptomator.ui.controllers.ViewControllerLoader; import dagger.Component; @@ -11,7 +11,7 @@ import dagger.Component; @Component(modules = LauncherModule.class) interface LauncherComponent { - MainController mainController(); + ViewControllerLoader fxmlLoader(); DebugMode debugMode(); diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/MainApplication.java b/main/launcher/src/main/java/org/cryptomator/launcher/MainApplication.java index 5cdc4e6ae..731320c93 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/MainApplication.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/MainApplication.java @@ -27,7 +27,7 @@ public class MainApplication extends Application { launcherComponent.debugMode().initialize(); - MainController mainCtrl = launcherComponent.mainController(); + MainController mainCtrl = launcherComponent.fxmlLoader().load("/fxml/main.fxml"); mainCtrl.initStage(primaryStage); primaryStage.show(); diff --git a/main/ui/src/main/java/org/cryptomator/ui/UiModule.java b/main/ui/src/main/java/org/cryptomator/ui/UiModule.java index 9b4671162..cecf183f1 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/UiModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/UiModule.java @@ -22,6 +22,7 @@ import org.cryptomator.common.settings.SettingsProvider; import org.cryptomator.frontend.webdav.WebDavServer; import org.cryptomator.jni.JniModule; import org.cryptomator.keychain.KeychainModule; +import org.cryptomator.ui.controllers.ViewControllerModule; import org.cryptomator.ui.model.VaultComponent; import org.cryptomator.ui.util.DeferredCloser; import org.fxmisc.easybind.EasyBind; @@ -32,7 +33,7 @@ import dagger.Module; import dagger.Provides; import javafx.beans.binding.Binding; -@Module(includes = {CommonsModule.class, KeychainModule.class, JniModule.class}, subcomponents = {VaultComponent.class}) +@Module(includes = {ViewControllerModule.class, CommonsModule.class, KeychainModule.class, JniModule.class}, subcomponents = {VaultComponent.class}) public class UiModule { private static final Logger LOG = LoggerFactory.getLogger(UiModule.class); diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/AbstractFXMLViewController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/AbstractFXMLViewController.java deleted file mode 100644 index d013cc63f..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/AbstractFXMLViewController.java +++ /dev/null @@ -1,101 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. - * This file is licensed under the terms of the MIT license. - * See the LICENSE.txt file for more info. - * - * Contributors: - * Sebastian Stenzel - initial API and implementation - *******************************************************************************/ -package org.cryptomator.ui.controllers; - -import java.io.IOException; -import java.net.URL; -import java.util.ResourceBundle; -import java.util.concurrent.atomic.AtomicReference; - -import org.cryptomator.common.LazyInitializer; - -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 final AtomicReference fxmlRoot = new AtomicReference<>(); - - /** - * Gets the URL to the FXML file describing the view presented by this controller.
- * - * A default implementation would look like this:
- * - * return getClass().getResource("/myView.fxml"); - * - * - * @return FXML resource URL - */ - protected abstract URL getFxmlResourceUrl(); - - /** - * @return Localization bundle for the FXML labels or null. - */ - protected abstract ResourceBundle getFxmlResourceBundle(); - - @Override - public final void initialize(URL location, 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 Parent loadFxml() { - final FXMLLoader loader = createFxmlLoader(); - try { - return LazyInitializer.initializeLazily(fxmlRoot, loader::load, IOException.class); - } catch (IOException e) { - throw new IllegalStateException("Could not load FXML file from location: " + loader.getLocation(), e); - } - } - - /** - * 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; - } - -} diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java index ba23bfdd1..45b652ce5 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java @@ -11,7 +11,6 @@ package org.cryptomator.ui.controllers; import java.io.IOException; import java.io.UncheckedIOException; -import java.net.URL; import java.util.Objects; import java.util.Optional; @@ -35,28 +34,31 @@ import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.Parent; import javafx.scene.control.Button; import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; import javafx.scene.layout.Region; import javafx.scene.text.Text; @Singleton -public class ChangePasswordController extends LocalizedFXMLViewController { +public class ChangePasswordController implements ViewController { private static final Logger LOG = LoggerFactory.getLogger(ChangePasswordController.class); private final Application app; private final PasswordStrengthUtil strengthRater; + private final Localization localization; private final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4 private Optional listener = Optional.empty(); private Vault vault; @Inject public ChangePasswordController(Application app, PasswordStrengthUtil strengthRater, Localization localization) { - super(localization); this.app = app; this.strengthRater = strengthRater; + this.localization = localization; } @FXML @@ -95,6 +97,9 @@ public class ChangePasswordController extends LocalizedFXMLViewController { @FXML private Region passwordStrengthLevel4; + @FXML + private GridPane root; + @Override public void initialize() { BooleanBinding oldPasswordIsEmpty = oldPasswordField.textProperty().isEmpty(); @@ -112,8 +117,8 @@ public class ChangePasswordController extends LocalizedFXMLViewController { } @Override - protected URL getFxmlResourceUrl() { - return getClass().getResource("/fxml/change_password.fxml"); + public Parent getRoot() { + return root; } void setVault(Vault vault) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java index d45cce37a..5a21eba91 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java @@ -10,7 +10,6 @@ package org.cryptomator.ui.controllers; import java.io.IOException; -import java.net.URL; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.FileAlreadyExistsException; import java.util.Objects; @@ -33,15 +32,18 @@ import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.Parent; import javafx.scene.control.Button; import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; import javafx.scene.layout.Region; @Singleton -public class InitializeController extends LocalizedFXMLViewController { +public class InitializeController implements ViewController { private static final Logger LOG = LoggerFactory.getLogger(InitializeController.class); + private final Localization localization; private final PasswordStrengthUtil strengthRater; private final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4 private Optional listener = Optional.empty(); @@ -49,7 +51,7 @@ public class InitializeController extends LocalizedFXMLViewController { @Inject public InitializeController(Localization localization, PasswordStrengthUtil strengthRater) { - super(localization); + this.localization = localization; this.strengthRater = strengthRater; } @@ -83,6 +85,9 @@ public class InitializeController extends LocalizedFXMLViewController { @FXML private Region passwordStrengthLevel4; + @FXML + private GridPane root; + @Override public void initialize() { BooleanBinding passwordIsEmpty = passwordField.textProperty().isEmpty(); @@ -99,8 +104,8 @@ public class InitializeController extends LocalizedFXMLViewController { } @Override - protected URL getFxmlResourceUrl() { - return getClass().getResource("/fxml/initialize.fxml"); + public Parent getRoot() { + return root; } void setVault(Vault vault) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/LocalizedFXMLViewController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/LocalizedFXMLViewController.java deleted file mode 100644 index de1496fbb..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/LocalizedFXMLViewController.java +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the accompanying LICENSE file. - *******************************************************************************/ -package org.cryptomator.ui.controllers; - -import org.cryptomator.ui.settings.Localization; - -abstract class LocalizedFXMLViewController extends AbstractFXMLViewController { - - protected final Localization localization; - - public LocalizedFXMLViewController(Localization localization) { - this.localization = localization; - } - - @Override - protected Localization getFxmlResourceBundle() { - return localization; - } - -} diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java index 7b0de1f51..e8490a71d 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java @@ -12,7 +12,6 @@ package org.cryptomator.ui.controllers; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; @@ -24,7 +23,6 @@ import java.util.concurrent.ExecutorService; import javax.inject.Inject; import javax.inject.Named; -import javax.inject.Provider; import javax.inject.Singleton; import org.apache.commons.lang3.SystemUtils; @@ -45,7 +43,6 @@ import org.fxmisc.easybind.monadic.MonadicBinding; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dagger.Lazy; import javafx.application.Application; import javafx.application.Platform; import javafx.beans.binding.Binding; @@ -58,6 +55,7 @@ import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.geometry.Side; import javafx.scene.Parent; +import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; @@ -74,7 +72,7 @@ import javafx.stage.FileChooser; import javafx.stage.Stage; @Singleton -public class MainController extends LocalizedFXMLViewController { +public class MainController implements ViewController { private static final Logger LOG = LoggerFactory.getLogger(MainController.class); private static final String ACTIVE_WINDOW_STYLE_CLASS = "active-window"; @@ -82,23 +80,17 @@ public class MainController extends LocalizedFXMLViewController { private final Stage mainWindow; private final ExitUtil exitUtil; + private final Localization localization; private final ExecutorService executorService; private final BlockingQueue fileOpenRequests; private final Settings settings; private final VaultFactory vaultFactoy; - private final Lazy welcomeController; - private final Lazy initializeController; - private final Lazy notFoundController; - private final Lazy upgradeController; - private final Lazy unlockController; - private final Provider unlockedControllerProvider; - private final Lazy changePasswordController; - private final Lazy settingsController; - private final ObjectProperty activeController = new SimpleObjectProperty<>(); + private final ViewControllerLoader fxmlLoader; + private final ObjectProperty activeController = new SimpleObjectProperty<>(); private final VaultList vaults; private final ObjectProperty selectedVault = new SimpleObjectProperty<>(); - private final BooleanExpression isSelectedVaultUnlocked = BooleanBinding.booleanExpression(EasyBind.select(selectedVault).selectObject(Vault::unlockedProperty).orElse(false)); - private final BooleanExpression isSelectedVaultValid = BooleanBinding.booleanExpression(EasyBind.monadic(selectedVault).map(Vault::isValidVaultDirectory).orElse(false)); + private final BooleanExpression isSelectedVaultUnlocked = BooleanExpression.booleanExpression(EasyBind.select(selectedVault).selectObject(Vault::unlockedProperty).orElse(false)); + private final BooleanExpression isSelectedVaultValid = BooleanExpression.booleanExpression(EasyBind.monadic(selectedVault).map(Vault::isValidVaultDirectory).orElse(false)); private final BooleanExpression canEditSelectedVault = selectedVault.isNotNull().and(isSelectedVaultUnlocked.not()); private final MonadicBinding upgradeStrategyForSelectedVault; private final BooleanBinding isShowingSettings; @@ -108,28 +100,19 @@ public class MainController extends LocalizedFXMLViewController { @Inject public MainController(@Named("mainWindow") Stage mainWindow, ExecutorService executorService, @Named("fileOpenRequests") BlockingQueue fileOpenRequests, ExitUtil exitUtil, Localization localization, - Settings settings, VaultFactory vaultFactoy, Lazy welcomeController, Lazy initializeController, Lazy notFoundController, - Lazy upgradeController, Lazy unlockController, Provider unlockedControllerProvider, Lazy changePasswordController, - Lazy settingsController, UpgradeStrategies upgradeStrategies, VaultList vaults) { - super(localization); + Settings settings, VaultFactory vaultFactoy, ViewControllerLoader fxmlLoader, UpgradeStrategies upgradeStrategies, VaultList vaults) { this.mainWindow = mainWindow; this.executorService = executorService; this.fileOpenRequests = fileOpenRequests; this.exitUtil = exitUtil; + this.localization = localization; this.settings = settings; this.vaultFactoy = vaultFactoy; - this.welcomeController = welcomeController; - this.initializeController = initializeController; - this.notFoundController = notFoundController; - this.upgradeController = upgradeController; - this.unlockController = unlockController; - this.unlockedControllerProvider = unlockedControllerProvider; - this.changePasswordController = changePasswordController; - this.settingsController = settingsController; + this.fxmlLoader = fxmlLoader; this.vaults = vaults; // derived bindings: - this.isShowingSettings = activeController.isEqualTo(settingsController.get()); + this.isShowingSettings = Bindings.equal(SettingsController.class, EasyBind.monadic(activeController).map(ViewController::getClass)); this.upgradeStrategyForSelectedVault = EasyBind.monadic(selectedVault).map(upgradeStrategies::getUpgradeStrategy); } @@ -143,7 +126,7 @@ public class MainController extends LocalizedFXMLViewController { private ContextMenu addVaultContextMenu; @FXML - private HBox rootPane; + private HBox root; @FXML private ListView vaultList; @@ -167,7 +150,7 @@ public class MainController extends LocalizedFXMLViewController { public void initialize() { vaultList.setItems(vaults); vaultList.setCellFactory(this::createDirecoryListCell); - activeController.set(welcomeController.get()); + activeController.set(fxmlLoader.load("/fxml/welcome.fxml")); selectedVault.bind(vaultList.getSelectionModel().selectedItemProperty()); removeVaultButton.disableProperty().bind(canEditSelectedVault.not()); emptyListInstructions.visibleProperty().bind(Bindings.isEmpty(vaults)); @@ -180,8 +163,13 @@ public class MainController extends LocalizedFXMLViewController { } @Override + public Parent getRoot() { + return root; + } + public void initStage(Stage stage) { - super.initStage(stage); + stage.setScene(new Scene(getRoot())); + stage.sizeToScene(); stage.titleProperty().bind(windowTitle()); stage.setResizable(false); loadFont("/css/ionicons.ttf"); @@ -227,11 +215,6 @@ public class MainController extends LocalizedFXMLViewController { }); } - @Override - protected URL getFxmlResourceUrl() { - return getClass().getResource("/fxml/main.fxml"); - } - private ListCell createDirecoryListCell(ListView param) { final DirectoryListCell cell = new DirectoryListCell(); cell.setVaultContextMenu(vaultListCellContextMenu); @@ -323,7 +306,7 @@ public class MainController extends LocalizedFXMLViewController { if (ButtonType.OK.equals(choice.get())) { vaults.remove(selectedVault.get()); if (vaults.isEmpty()) { - activeController.set(welcomeController.get()); + activeController.set(fxmlLoader.load("/fxml/welcome.fxml")); } } } @@ -335,10 +318,10 @@ public class MainController extends LocalizedFXMLViewController { @FXML private void didClickShowSettings(ActionEvent e) { - if (settingsController.get().equals(activeController.get())) { - activeController.set(welcomeController.get()); + if (isShowingSettings.get()) { + activeController.set(fxmlLoader.load("/fxml/welcome.fxml")); } else { - activeController.set(settingsController.get()); + activeController.set(fxmlLoader.load("/fxml/settings.fxml")); } vaultList.getSelectionModel().clearSelection(); } @@ -347,8 +330,8 @@ public class MainController extends LocalizedFXMLViewController { // Binding Listeners // **************************************** - private void activeControllerDidChange(AbstractFXMLViewController newValue) { - final Parent root = newValue.loadFxml(); + private void activeControllerDidChange(ViewController newValue) { + final Parent root = newValue.getRoot(); contentPane.getChildren().clear(); contentPane.getChildren().add(root); } @@ -383,13 +366,11 @@ public class MainController extends LocalizedFXMLViewController { // **************************************** private void showNotFoundView() { - final NotFoundController ctrl = notFoundController.get(); - activeController.set(ctrl); + activeController.set(fxmlLoader.load("/fxml/notfound.fxml")); } private void showInitializeView() { - final InitializeController ctrl = initializeController.get(); - ctrl.loadFxml(); + final InitializeController ctrl = fxmlLoader.load("/fxml/initialize.fxml"); ctrl.setVault(selectedVault.get()); ctrl.setListener(this::didInitialize); activeController.set(ctrl); @@ -400,8 +381,7 @@ public class MainController extends LocalizedFXMLViewController { } private void showUpgradeView() { - final UpgradeController ctrl = upgradeController.get(); - ctrl.loadFxml(); + final UpgradeController ctrl = fxmlLoader.load("/fxml/upgrade.fxml"); ctrl.setVault(selectedVault.get()); ctrl.setListener(this::didUpgrade); activeController.set(ctrl); @@ -412,8 +392,7 @@ public class MainController extends LocalizedFXMLViewController { } private void showUnlockView() { - final UnlockController ctrl = unlockController.get(); - ctrl.loadFxml(); + final UnlockController ctrl = fxmlLoader.load("/fxml/unlock.fxml"); ctrl.setVault(selectedVault.get()); ctrl.setListener(this::didUnlock); activeController.set(ctrl); @@ -428,9 +407,8 @@ public class MainController extends LocalizedFXMLViewController { private void showUnlockedView(Vault vault) { final UnlockedController ctrl = unlockedVaults.computeIfAbsent(vault, k -> { - return unlockedControllerProvider.get(); + return fxmlLoader.load("/fxml/unlocked.fxml"); }); - ctrl.loadFxml(); ctrl.setVault(vault); ctrl.setListener(this::didLock); activeController.set(ctrl); @@ -445,8 +423,7 @@ public class MainController extends LocalizedFXMLViewController { } private void showChangePasswordView() { - final ChangePasswordController ctrl = changePasswordController.get(); - ctrl.loadFxml(); + final ChangePasswordController ctrl = fxmlLoader.load("/fxml/change_password.fxml"); ctrl.setVault(selectedVault.get()); ctrl.setListener(this::didChangePassword); activeController.set(ctrl); diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/NotFoundController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/NotFoundController.java index 84388e51d..ef2e44a07 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/NotFoundController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/NotFoundController.java @@ -5,24 +5,27 @@ *******************************************************************************/ package org.cryptomator.ui.controllers; -import java.net.URL; - import javax.inject.Inject; import javax.inject.Singleton; -import org.cryptomator.ui.settings.Localization; +import javafx.fxml.FXML; +import javafx.scene.Parent; +import javafx.scene.layout.VBox; @Singleton -public class NotFoundController extends LocalizedFXMLViewController { +public class NotFoundController implements ViewController { @Inject - public NotFoundController(Localization localization) { - super(localization); + public NotFoundController() { + // no-op } + @FXML + VBox root; + @Override - protected URL getFxmlResourceUrl() { - return getClass().getResource("/fxml/notfound.fxml"); + public Parent getRoot() { + return root; } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java index 1cf66d10f..a2984623b 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java @@ -8,10 +8,10 @@ ******************************************************************************/ package org.cryptomator.ui.controllers; -import java.net.URL; import java.util.Optional; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; import org.apache.commons.lang3.CharUtils; @@ -22,22 +22,27 @@ import org.cryptomator.ui.settings.Localization; import javafx.beans.binding.Bindings; import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.Parent; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ChoiceBox; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.input.KeyEvent; +import javafx.scene.layout.VBox; @Singleton -public class SettingsController extends LocalizedFXMLViewController { +public class SettingsController implements ViewController { + private final Localization localization; private final Settings settings; + private final Optional applicationVersion; @Inject - public SettingsController(Localization localization, Settings settings) { - super(localization); + public SettingsController(Localization localization, Settings settings, @Named("applicationVersion") Optional applicationVersion) { + this.localization = localization; this.settings = settings; + this.applicationVersion = applicationVersion; } @FXML @@ -67,6 +72,9 @@ public class SettingsController extends LocalizedFXMLViewController { @FXML private CheckBox debugModeCheckbox; + @FXML + private VBox root; + @Override public void initialize() { checkForUpdatesCheckbox.setDisable(areUpdatesManagedExternally()); @@ -78,7 +86,7 @@ public class SettingsController extends LocalizedFXMLViewController { useIpv6Label.setVisible(SystemUtils.IS_OS_WINDOWS); useIpv6Checkbox.setVisible(SystemUtils.IS_OS_WINDOWS); useIpv6Checkbox.setSelected(SystemUtils.IS_OS_WINDOWS && settings.useIpv6().get()); - versionLabel.setText(String.format(localization.getString("settings.version.label"), applicationVersion().orElse("SNAPSHOT"))); + versionLabel.setText(String.format(localization.getString("settings.version.label"), applicationVersion.orElse("SNAPSHOT"))); prefGvfsSchemeLabel.setVisible(SystemUtils.IS_OS_LINUX); prefGvfsScheme.setVisible(SystemUtils.IS_OS_LINUX); prefGvfsScheme.getItems().add("dav"); @@ -93,12 +101,8 @@ public class SettingsController extends LocalizedFXMLViewController { } @Override - protected URL getFxmlResourceUrl() { - return getClass().getResource("/fxml/settings.fxml"); - } - - private Optional applicationVersion() { - return Optional.ofNullable(getClass().getPackage().getImplementationVersion()); + public Parent getRoot() { + return root; } @FXML diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java index 2c46cc7e6..a3b624c82 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java @@ -8,7 +8,6 @@ ******************************************************************************/ package org.cryptomator.ui.controllers; -import java.net.URL; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; @@ -38,6 +37,7 @@ import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.Parent; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; @@ -52,11 +52,12 @@ import javafx.scene.layout.GridPane; import javafx.scene.text.Text; import javafx.util.StringConverter; -public class UnlockController extends LocalizedFXMLViewController { +public class UnlockController implements ViewController { private static final Logger LOG = LoggerFactory.getLogger(UnlockController.class); private final Application app; + private final Localization localization; private final AsyncTaskService asyncTaskService; private final WindowsDriveLetters driveLetters; private final ChangeListener driveLetterChangeListener = this::winDriveLetterDidChange; @@ -66,8 +67,8 @@ public class UnlockController extends LocalizedFXMLViewController { @Inject public UnlockController(Application app, Localization localization, AsyncTaskService asyncTaskService, WindowsDriveLetters driveLetters, Optional keychainAccess) { - super(localization); this.app = app; + this.localization = localization; this.asyncTaskService = asyncTaskService; this.driveLetters = driveLetters; this.keychainAccess = keychainAccess; @@ -112,6 +113,9 @@ public class UnlockController extends LocalizedFXMLViewController { @FXML private GridPane advancedOptions; + @FXML + private GridPane root; + @Override public void initialize() { advancedOptions.managedProperty().bind(advancedOptions.visibleProperty()); @@ -132,8 +136,8 @@ public class UnlockController extends LocalizedFXMLViewController { } @Override - protected URL getFxmlResourceUrl() { - return getClass().getResource("/fxml/unlock.fxml"); + public Parent getRoot() { + return root; } void setVault(Vault vault) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java index 015a46998..c0efa6fdf 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java @@ -8,7 +8,6 @@ ******************************************************************************/ package org.cryptomator.ui.controllers; -import java.net.URL; import java.util.Optional; import javax.inject.Inject; @@ -27,6 +26,7 @@ import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.geometry.Side; +import javafx.scene.Parent; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart.Data; @@ -37,14 +37,16 @@ import javafx.scene.control.MenuItem; import javafx.scene.control.ToggleButton; import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; +import javafx.scene.layout.VBox; import javafx.stage.PopupWindow.AnchorLocation; import javafx.util.Duration; -public class UnlockedController extends LocalizedFXMLViewController { +public class UnlockedController implements ViewController { private static final int IO_SAMPLING_STEPS = 100; private static final double IO_SAMPLING_INTERVAL = 0.25; + private final Localization localization; private final AsyncTaskService asyncTaskService; private final ObjectProperty vault = new SimpleObjectProperty<>(); private Optional listener = Optional.empty(); @@ -68,9 +70,12 @@ public class UnlockedController extends LocalizedFXMLViewController { @FXML private MenuItem revealVaultMenuItem; + @FXML + private VBox root; + @Inject public UnlockedController(Localization localization, AsyncTaskService asyncTaskService) { - super(localization); + this.localization = localization; this.asyncTaskService = asyncTaskService; } @@ -83,8 +88,8 @@ public class UnlockedController extends LocalizedFXMLViewController { } @Override - protected URL getFxmlResourceUrl() { - return getClass().getResource("/fxml/unlocked.fxml"); + public Parent getRoot() { + return root; } private void vaultChanged(Vault newVault) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java index 700e7a920..63eacdbda 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java @@ -5,7 +5,6 @@ *******************************************************************************/ package org.cryptomator.ui.controllers; -import java.net.URL; import java.util.Objects; import java.util.Optional; @@ -25,12 +24,14 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.Parent; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.Label; import javafx.scene.control.ProgressIndicator; +import javafx.scene.layout.GridPane; -public class UpgradeController extends LocalizedFXMLViewController { +public class UpgradeController implements ViewController { private final ObjectProperty strategy = new SimpleObjectProperty<>(); private final UpgradeStrategies strategies; @@ -40,7 +41,6 @@ public class UpgradeController extends LocalizedFXMLViewController { @Inject public UpgradeController(Localization localization, UpgradeStrategies strategies, AsyncTaskService asyncTaskService) { - super(localization); this.strategies = strategies; this.asyncTaskService = asyncTaskService; } @@ -66,8 +66,11 @@ public class UpgradeController extends LocalizedFXMLViewController { @FXML private Label errorLabel; + @FXML + private GridPane root; + @Override - protected void initialize() { + public void initialize() { upgradeTitleLabel.textProperty().bind(EasyBind.monadic(strategy).map(this::upgradeTitle).orElse("")); upgradeMsgLabel.textProperty().bind(EasyBind.monadic(strategy).map(this::upgradeMessage).orElse("")); @@ -77,8 +80,8 @@ public class UpgradeController extends LocalizedFXMLViewController { } @Override - protected URL getFxmlResourceUrl() { - return getClass().getResource("/fxml/upgrade.fxml"); + public Parent getRoot() { + return root; } void setVault(Vault vault) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewController.java new file mode 100644 index 000000000..ba6a641b7 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewController.java @@ -0,0 +1,22 @@ +package org.cryptomator.ui.controllers; + +import java.net.URL; +import java.util.ResourceBundle; + +import javafx.fxml.Initializable; +import javafx.scene.Parent; + +public interface ViewController extends Initializable { + + Parent getRoot(); + + @Override + default void initialize(URL location, ResourceBundle resources) { + initialize(); + } + + default void initialize() { + // no-op + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerKey.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerKey.java new file mode 100644 index 000000000..6c47cee49 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerKey.java @@ -0,0 +1,18 @@ +package org.cryptomator.ui.controllers; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import dagger.MapKey; + +@Documented +@Target(METHOD) +@Retention(RUNTIME) +@MapKey +public @interface ViewControllerKey { + Class value(); +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerLoader.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerLoader.java new file mode 100644 index 000000000..b16c4f0d0 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerLoader.java @@ -0,0 +1,44 @@ +package org.cryptomator.ui.controllers; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.cryptomator.ui.settings.Localization; + +import javafx.fxml.FXMLLoader; + +@Singleton +public class ViewControllerLoader { + + private final Map, Provider> controllerProviders; + private final Localization localization; + + @Inject + public ViewControllerLoader(Map, Provider> controllerProviders, Localization localization) { + this.controllerProviders = controllerProviders; + this.localization = localization; + } + + public T load(String resourceName) { + FXMLLoader loader = new FXMLLoader(); + loader.setControllerFactory(this::constructController); + loader.setResources(localization); + try (InputStream in = getClass().getResourceAsStream(resourceName)) { + loader.load(in); + } catch (IOException e) { + throw new UncheckedIOException("Error loading FXML: " + resourceName, e); + } + return loader.getController(); + } + + private ViewController constructController(Class clazz) { + return controllerProviders.get(clazz).get(); + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerModule.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerModule.java new file mode 100644 index 000000000..b8f4a019f --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerModule.java @@ -0,0 +1,73 @@ +package org.cryptomator.ui.controllers; + +import dagger.Module; +import dagger.Provides; +import dagger.multibindings.IntoMap; + +@Module +public class ViewControllerModule { + + @Provides + @IntoMap + @ViewControllerKey(ChangePasswordController.class) + ViewController provideChangePasswordController(ChangePasswordController controller) { + return controller; + } + + @Provides + @IntoMap + @ViewControllerKey(InitializeController.class) + ViewController provideInitializeController(InitializeController controller) { + return controller; + } + + @Provides + @IntoMap + @ViewControllerKey(MainController.class) + ViewController provideMainController(MainController controller) { + return controller; + } + + @Provides + @IntoMap + @ViewControllerKey(NotFoundController.class) + ViewController provideNotFoundController(NotFoundController controller) { + return controller; + } + + @Provides + @IntoMap + @ViewControllerKey(SettingsController.class) + ViewController provideSettingsController(SettingsController controller) { + return controller; + } + + @Provides + @IntoMap + @ViewControllerKey(UnlockController.class) + ViewController provideUnlockController(UnlockController controller) { + return controller; + } + + @Provides + @IntoMap + @ViewControllerKey(UnlockedController.class) + ViewController provideUnlockedController(UnlockedController controller) { + return controller; + } + + @Provides + @IntoMap + @ViewControllerKey(UpgradeController.class) + ViewController provideUpgradeController(UpgradeController controller) { + return controller; + } + + @Provides + @IntoMap + @ViewControllerKey(WelcomeController.class) + ViewController provideWelcomeController(WelcomeController controller) { + return controller; + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java index b635fdaf6..adc2da623 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java @@ -16,6 +16,7 @@ import java.nio.charset.StandardCharsets; import java.util.Comparator; import java.util.Map; import java.util.Optional; +import java.util.ResourceBundle; import javax.inject.Inject; import javax.inject.Named; @@ -43,17 +44,20 @@ import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.Node; +import javafx.scene.Parent; import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; import javafx.scene.control.ProgressIndicator; +import javafx.scene.layout.VBox; @Singleton -public class WelcomeController extends LocalizedFXMLViewController { +public class WelcomeController implements ViewController { private static final Logger LOG = LoggerFactory.getLogger(WelcomeController.class); private final Application app; private final Optional applicationVersion; + private final Localization localization; private final Settings settings; private final Comparator semVerComparator; private final AsyncTaskService asyncTaskService; @@ -61,9 +65,9 @@ public class WelcomeController extends LocalizedFXMLViewController { @Inject public WelcomeController(Application app, @Named("applicationVersion") Optional applicationVersion, Localization localization, Settings settings, @Named("SemVer") Comparator semVerComparator, AsyncTaskService asyncTaskService) { - super(localization); this.app = app; this.applicationVersion = applicationVersion; + this.localization = localization; this.settings = settings; this.semVerComparator = semVerComparator; this.asyncTaskService = asyncTaskService; @@ -81,8 +85,11 @@ public class WelcomeController extends LocalizedFXMLViewController { @FXML private Hyperlink updateLink; + @FXML + private VBox root; + @Override - public void initialize() { + public void initialize(URL location, ResourceBundle resources) { if (areUpdatesManagedExternally()) { checkForUpdatesContainer.setVisible(false); } else if (settings.checkForUpdates().get()) { @@ -91,8 +98,8 @@ public class WelcomeController extends LocalizedFXMLViewController { } @Override - protected URL getFxmlResourceUrl() { - return getClass().getResource("/fxml/welcome.fxml"); + public Parent getRoot() { + return root; } // **************************************** diff --git a/main/ui/src/main/resources/fxml/change_password.fxml b/main/ui/src/main/resources/fxml/change_password.fxml index 723bcb5bd..9232e7f10 100644 --- a/main/ui/src/main/resources/fxml/change_password.fxml +++ b/main/ui/src/main/resources/fxml/change_password.fxml @@ -25,7 +25,7 @@ - + diff --git a/main/ui/src/main/resources/fxml/initialize.fxml b/main/ui/src/main/resources/fxml/initialize.fxml index 40e8521ee..649d36f43 100644 --- a/main/ui/src/main/resources/fxml/initialize.fxml +++ b/main/ui/src/main/resources/fxml/initialize.fxml @@ -23,7 +23,7 @@ - + diff --git a/main/ui/src/main/resources/fxml/main.fxml b/main/ui/src/main/resources/fxml/main.fxml index 61f03c97e..afc023ea2 100644 --- a/main/ui/src/main/resources/fxml/main.fxml +++ b/main/ui/src/main/resources/fxml/main.fxml @@ -24,7 +24,7 @@ - + diff --git a/main/ui/src/main/resources/fxml/notfound.fxml b/main/ui/src/main/resources/fxml/notfound.fxml index c4f8208f7..b890d10e8 100644 --- a/main/ui/src/main/resources/fxml/notfound.fxml +++ b/main/ui/src/main/resources/fxml/notfound.fxml @@ -11,7 +11,7 @@ - +