mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 10:11:27 +00:00
UI code cleanup
This commit is contained in:
@@ -19,8 +19,6 @@ import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javafx.application.Application;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.util.SingleInstanceManager;
|
||||
import org.cryptomator.ui.util.SingleInstanceManager.RemoteInstance;
|
||||
@@ -28,11 +26,12 @@ import org.eclipse.jetty.util.ConcurrentHashSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javafx.application.Application;
|
||||
|
||||
public class Cryptomator {
|
||||
public static final Logger LOG = LoggerFactory.getLogger(MainApplication.class);
|
||||
|
||||
public static final CompletableFuture<Consumer<File>> OPEN_FILE_HANDLER = new CompletableFuture<>();
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Cryptomator.class);
|
||||
private static final Set<Runnable> SHUTDOWN_TASKS = new ConcurrentHashSet<>();
|
||||
private static final CleanShutdownPerformer CLEAN_SHUTDOWN_PERFORMER = new CleanShutdownPerformer();
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@ import java.util.concurrent.ExecutorService;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.ui.controllers.MainController;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.util.DeferredCloser;
|
||||
import org.cryptomator.ui.util.TrayIconUtil;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
@@ -25,4 +27,8 @@ interface CryptomatorComponent {
|
||||
DeferredCloser deferredCloser();
|
||||
|
||||
MainController mainController();
|
||||
|
||||
Localization localization();
|
||||
|
||||
TrayIconUtil trayIconUtil();
|
||||
}
|
||||
@@ -24,7 +24,6 @@ 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 com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -32,16 +31,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import javafx.application.Application;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Module(includes = CryptoEngineModule.class)
|
||||
class CryptomatorModule {
|
||||
|
||||
private final Application application;
|
||||
private final DeferredCloser deferredCloser;
|
||||
private final Stage mainWindow;
|
||||
|
||||
public CryptomatorModule(Application application) {
|
||||
public CryptomatorModule(Application application, Stage mainWindow) {
|
||||
this.application = application;
|
||||
this.deferredCloser = new DeferredCloser();
|
||||
this.mainWindow = mainWindow;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -50,10 +50,19 @@ class CryptomatorModule {
|
||||
return application;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("mainWindow")
|
||||
Stage provideMainWindow() {
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
DeferredCloser provideDeferredCloser() {
|
||||
return deferredCloser;
|
||||
DeferredCloser closer = new DeferredCloser();
|
||||
Cryptomator.addShutdownTask(closer::close);
|
||||
return closer;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -78,8 +87,8 @@ class CryptomatorModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ExecutorService provideExecutorService() {
|
||||
return closeLater(Executors.newCachedThreadPool(), ExecutorService::shutdown);
|
||||
ExecutorService provideExecutorService(DeferredCloser closer) {
|
||||
return closer.closeLater(Executors.newCachedThreadPool(), ExecutorService::shutdown).get().orElseThrow(IllegalStateException::new);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -90,14 +99,10 @@ class CryptomatorModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
FrontendFactory provideFrontendFactory(WebDavServer webDavServer, Settings settings) {
|
||||
FrontendFactory provideFrontendFactory(DeferredCloser closer, WebDavServer webDavServer, Settings settings) {
|
||||
webDavServer.setPort(settings.getPort());
|
||||
webDavServer.start();
|
||||
return closeLater(webDavServer, WebDavServer::stop);
|
||||
}
|
||||
|
||||
private <T> T closeLater(T object, Closer<T> closer) {
|
||||
return deferredCloser.closeLater(object, closer).get().get();
|
||||
return closer.closeLater(webDavServer, WebDavServer::stop).get().orElseThrow(IllegalStateException::new);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.controllers.MainController;
|
||||
@@ -21,7 +19,6 @@ import org.cryptomator.ui.util.ActiveWindowStyleSupport;
|
||||
import org.cryptomator.ui.util.DeferredCloser;
|
||||
import org.cryptomator.ui.util.SingleInstanceManager;
|
||||
import org.cryptomator.ui.util.SingleInstanceManager.LocalInstance;
|
||||
import org.cryptomator.ui.util.TrayIconUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -35,24 +32,16 @@ import javafx.stage.Stage;
|
||||
public class MainApplication extends Application {
|
||||
|
||||
public static final String APPLICATION_KEY = "CryptomatorGUI";
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MainApplication.class);
|
||||
|
||||
private final ExecutorService executorService;
|
||||
private final DeferredCloser closer;
|
||||
private final MainController mainCtrl;
|
||||
|
||||
public MainApplication() {
|
||||
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);
|
||||
}
|
||||
private DeferredCloser closer;
|
||||
|
||||
@Override
|
||||
public void start(final Stage primaryStage) throws IOException {
|
||||
Font.loadFont(getClass().getResourceAsStream("/css/ionicons.ttf"), 12.0);
|
||||
public void start(Stage primaryStage) throws IOException {
|
||||
final CryptomatorComponent comp = DaggerCryptomatorComponent.builder().cryptomatorModule(new CryptomatorModule(this, primaryStage)).build();
|
||||
final MainController mainCtrl = comp.mainController();
|
||||
closer = comp.deferredCloser();
|
||||
|
||||
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
FXMLLoader.setDefaultClassLoader(contextClassLoader);
|
||||
Platform.runLater(() -> {
|
||||
@@ -65,36 +54,35 @@ public class MainApplication extends Application {
|
||||
}
|
||||
});
|
||||
|
||||
// Set stylesheets and initialize stage:
|
||||
Font.loadFont(getClass().getResourceAsStream("/css/ionicons.ttf"), 12.0);
|
||||
chooseNativeStylesheet();
|
||||
|
||||
mainCtrl.initStage(primaryStage);
|
||||
|
||||
final ResourceBundle rb = ResourceBundle.getBundle("localization");
|
||||
primaryStage.titleProperty().bind(mainCtrl.windowTitle());
|
||||
primaryStage.setResizable(false);
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
primaryStage.getIcons().add(new Image(MainApplication.class.getResourceAsStream("/window_icon.png")));
|
||||
}
|
||||
|
||||
// show window and start observing its focus:
|
||||
primaryStage.show();
|
||||
|
||||
ActiveWindowStyleSupport.startObservingFocus(primaryStage);
|
||||
TrayIconUtil.init(primaryStage, rb, () -> {
|
||||
quit();
|
||||
});
|
||||
comp.trayIconUtil().initTrayIcon(this::quit);
|
||||
|
||||
// open files, if requested during startup:
|
||||
for (String arg : getParameters().getUnnamed()) {
|
||||
handleCommandLineArg(arg);
|
||||
handleCommandLineArg(arg, primaryStage, mainCtrl);
|
||||
}
|
||||
|
||||
if (SystemUtils.IS_OS_MAC_OSX) {
|
||||
Cryptomator.OPEN_FILE_HANDLER.complete(file -> handleCommandLineArg(file.getAbsolutePath()));
|
||||
Cryptomator.OPEN_FILE_HANDLER.complete(file -> handleCommandLineArg(file.getAbsolutePath(), primaryStage, mainCtrl));
|
||||
}
|
||||
|
||||
LocalInstance cryptomatorGuiInstance = closer.closeLater(SingleInstanceManager.startLocalInstance(APPLICATION_KEY, executorService), LocalInstance::close).get().get();
|
||||
cryptomatorGuiInstance.registerListener(arg -> handleCommandLineArg(arg));
|
||||
// register this application instance as primary application, that other instances can send open file requests to:
|
||||
LocalInstance cryptomatorGuiInstance = closer.closeLater(SingleInstanceManager.startLocalInstance(APPLICATION_KEY, comp.executorService()), LocalInstance::close).get().get();
|
||||
cryptomatorGuiInstance.registerListener(arg -> handleCommandLineArg(arg, primaryStage, mainCtrl));
|
||||
}
|
||||
|
||||
private void handleCommandLineArg(String arg) {
|
||||
private void handleCommandLineArg(String arg, Stage primaryStage, MainController mainCtrl) {
|
||||
// find correct location:
|
||||
final Path path = FileSystems.getDefault().getPath(arg);
|
||||
final Path vaultPath;
|
||||
@@ -110,7 +98,10 @@ public class MainApplication extends Application {
|
||||
// add vault to ctrl:
|
||||
Platform.runLater(() -> {
|
||||
mainCtrl.addVault(vaultPath, true);
|
||||
mainCtrl.toFront();
|
||||
primaryStage.setIconified(false);
|
||||
primaryStage.show();
|
||||
primaryStage.toFront();
|
||||
primaryStage.requestFocus();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -28,16 +28,6 @@ abstract class AbstractFXMLViewController implements Initializable {
|
||||
|
||||
private final AtomicReference<Parent> fxmlRoot = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* 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/>
|
||||
*
|
||||
@@ -57,8 +47,6 @@ abstract class AbstractFXMLViewController implements Initializable {
|
||||
|
||||
@Override
|
||||
public final void initialize(URL location, ResourceBundle resources) {
|
||||
this.rootUrl = location;
|
||||
this.resourceBundle = resources;
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.cryptomator.crypto.engine.InvalidPassphraseException;
|
||||
import org.cryptomator.crypto.engine.UnsupportedVaultFormatException;
|
||||
import org.cryptomator.ui.controls.SecPasswordField;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -41,12 +42,14 @@ public class ChangePasswordController extends AbstractFXMLViewController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ChangePasswordController.class);
|
||||
|
||||
private final Application app;
|
||||
private final Localization localization;
|
||||
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
|
||||
private Optional<ChangePasswordListener> listener = Optional.empty();
|
||||
|
||||
@Inject
|
||||
public ChangePasswordController(Application app) {
|
||||
public ChangePasswordController(Application app, Localization localization) {
|
||||
this.app = app;
|
||||
this.localization = localization;
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -82,7 +85,7 @@ public class ChangePasswordController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
protected ResourceBundle getFxmlResourceBundle() {
|
||||
return ResourceBundle.getBundle("localization");
|
||||
return localization;
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -103,21 +106,21 @@ public class ChangePasswordController extends AbstractFXMLViewController {
|
||||
downloadsPageLink.setVisible(false);
|
||||
try {
|
||||
vault.get().changePassphrase(oldPasswordField.getCharacters(), newPasswordField.getCharacters());
|
||||
messageText.setText(resourceBundle.getString("changePassword.infoMessage.success"));
|
||||
messageText.setText(localization.getString("changePassword.infoMessage.success"));
|
||||
listener.ifPresent(this::invokeListenerLater);
|
||||
} catch (InvalidPassphraseException e) {
|
||||
messageText.setText(resourceBundle.getString("changePassword.errorMessage.wrongPassword"));
|
||||
messageText.setText(localization.getString("changePassword.errorMessage.wrongPassword"));
|
||||
Platform.runLater(oldPasswordField::requestFocus);
|
||||
} catch (UncheckedIOException | IOException ex) {
|
||||
messageText.setText(resourceBundle.getString("changePassword.errorMessage.decryptionFailed"));
|
||||
messageText.setText(localization.getString("changePassword.errorMessage.decryptionFailed"));
|
||||
LOG.error("Decryption failed for technical reasons.", ex);
|
||||
} catch (UnsupportedVaultFormatException e) {
|
||||
downloadsPageLink.setVisible(true);
|
||||
LOG.warn("Unable to unlock vault: " + e.getMessage());
|
||||
if (e.isVaultOlderThanSoftware()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
} else if (e.isSoftwareOlderThanVault()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
}
|
||||
} finally {
|
||||
oldPasswordField.swipe();
|
||||
|
||||
@@ -20,6 +20,7 @@ import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.ui.controls.SecPasswordField;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -37,11 +38,13 @@ public class InitializeController extends AbstractFXMLViewController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(InitializeController.class);
|
||||
|
||||
private final Localization localization;
|
||||
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
|
||||
private Optional<InitializationListener> listener = Optional.empty();
|
||||
|
||||
@Inject
|
||||
public InitializeController() {
|
||||
public InitializeController(Localization localization) {
|
||||
this.localization = localization;
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -70,7 +73,7 @@ public class InitializeController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
protected ResourceBundle getFxmlResourceBundle() {
|
||||
return ResourceBundle.getBundle("localization");
|
||||
return localization;
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -84,10 +87,10 @@ public class InitializeController extends AbstractFXMLViewController {
|
||||
vault.get().create(passphrase);
|
||||
listener.ifPresent(this::invokeListenerLater);
|
||||
} catch (FileAlreadyExistsException ex) {
|
||||
messageLabel.setText(resourceBundle.getString("initialize.messageLabel.alreadyInitialized"));
|
||||
messageLabel.setText(localization.getString("initialize.messageLabel.alreadyInitialized"));
|
||||
} catch (UncheckedIOException | IOException ex) {
|
||||
LOG.error("I/O Exception", ex);
|
||||
messageLabel.setText(resourceBundle.getString("initialize.messageLabel.initializationFailed"));
|
||||
messageLabel.setText(localization.getString("initialize.messageLabel.initializationFailed"));
|
||||
} finally {
|
||||
passwordField.swipe();
|
||||
retypePasswordField.swipe();
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.beans.Observable;
|
||||
@@ -41,6 +42,7 @@ import javafx.util.StringConverter;
|
||||
public class MacWarningsController extends AbstractFXMLViewController {
|
||||
|
||||
private final Application application;
|
||||
private final Localization localization;
|
||||
private final ObservableList<Warning> warnings = FXCollections.observableArrayList();
|
||||
private final ListChangeListener<String> unauthenticatedResourcesChangeListener = this::unauthenticatedResourcesDidChange;
|
||||
private final ChangeListener<Boolean> stageVisibilityChangeListener = this::windowVisibilityDidChange;
|
||||
@@ -48,8 +50,9 @@ public class MacWarningsController extends AbstractFXMLViewController {
|
||||
private Stage stage;
|
||||
|
||||
@Inject
|
||||
public MacWarningsController(Application application) {
|
||||
public MacWarningsController(Application application, Localization localization) {
|
||||
this.application = application;
|
||||
this.localization = localization;
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -84,7 +87,7 @@ public class MacWarningsController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
protected ResourceBundle getFxmlResourceBundle() {
|
||||
return ResourceBundle.getBundle("localization");
|
||||
return localization;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,7 +130,7 @@ public class MacWarningsController extends AbstractFXMLViewController {
|
||||
|
||||
private void windowVisibilityDidChange(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
|
||||
if (Boolean.TRUE.equals(newValue)) {
|
||||
stage.setTitle(String.format(resourceBundle.getString("macWarnings.windowTitle"), vault.get().getName()));
|
||||
stage.setTitle(String.format(localization.getString("macWarnings.windowTitle"), vault.get().getName()));
|
||||
warnings.addAll(vault.get().getNamesOfResourcesWithInvalidMac().stream().map(Warning::new).collect(Collectors.toList()));
|
||||
vault.get().getNamesOfResourcesWithInvalidMac().addListener(this.unauthenticatedResourcesChangeListener);
|
||||
} else {
|
||||
|
||||
@@ -19,12 +19,14 @@ import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.ui.controls.DirectoryListCell;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.model.VaultFactory;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.fxmisc.easybind.monadic.MonadicBinding;
|
||||
@@ -58,6 +60,8 @@ public class MainController extends AbstractFXMLViewController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MainController.class);
|
||||
|
||||
private final Stage mainWindow;
|
||||
private final Localization localization;
|
||||
private final VaultFactory vaultFactoy;
|
||||
private final Lazy<WelcomeController> welcomeController;
|
||||
private final Lazy<InitializeController> initializeController;
|
||||
@@ -74,8 +78,11 @@ public class MainController extends AbstractFXMLViewController {
|
||||
private final Map<Vault, UnlockedController> unlockedVaults = new HashMap<>();
|
||||
|
||||
@Inject
|
||||
public MainController(Settings settings, VaultFactory vaultFactoy, Lazy<WelcomeController> welcomeController, Lazy<InitializeController> initializeController, Lazy<UnlockController> unlockController,
|
||||
Provider<UnlockedController> unlockedControllerProvider, Lazy<ChangePasswordController> changePasswordController, Lazy<SettingsController> settingsController) {
|
||||
public MainController(@Named("mainWindow") Stage mainWindow, Localization localization, Settings settings, VaultFactory vaultFactoy, Lazy<WelcomeController> welcomeController,
|
||||
Lazy<InitializeController> initializeController, Lazy<UnlockController> unlockController, Provider<UnlockedController> unlockedControllerProvider, Lazy<ChangePasswordController> changePasswordController,
|
||||
Lazy<SettingsController> settingsController) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.localization = localization;
|
||||
this.vaultFactoy = vaultFactoy;
|
||||
this.welcomeController = welcomeController;
|
||||
this.initializeController = initializeController;
|
||||
@@ -89,8 +96,6 @@ public class MainController extends AbstractFXMLViewController {
|
||||
this.isShowingSettings = activeController.isEqualTo(settingsController.get());
|
||||
}
|
||||
|
||||
private Stage stage;
|
||||
|
||||
@FXML
|
||||
private ContextMenu vaultListCellContextMenu;
|
||||
|
||||
@@ -137,7 +142,7 @@ public class MainController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
protected ResourceBundle getFxmlResourceBundle() {
|
||||
return ResourceBundle.getBundle("localization");
|
||||
return localization;
|
||||
}
|
||||
|
||||
private ListCell<Vault> createDirecoryListCell(ListView<Vault> param) {
|
||||
@@ -146,12 +151,6 @@ public class MainController extends AbstractFXMLViewController {
|
||||
return cell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initStage(Stage stage) {
|
||||
super.initStage(stage);
|
||||
this.stage = stage;
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// UI Events
|
||||
// ****************************************
|
||||
@@ -169,7 +168,7 @@ public class MainController extends AbstractFXMLViewController {
|
||||
private void didClickCreateNewVault(ActionEvent event) {
|
||||
final FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Cryptomator vault", "*" + Vault.VAULT_FILE_EXTENSION));
|
||||
final File file = fileChooser.showSaveDialog(stage);
|
||||
final File file = fileChooser.showSaveDialog(mainWindow);
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
@@ -194,7 +193,7 @@ public class MainController extends AbstractFXMLViewController {
|
||||
private void didClickAddExistingVaults(ActionEvent event) {
|
||||
final FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Cryptomator vault", "*" + Vault.VAULT_FILE_EXTENSION));
|
||||
final List<File> files = fileChooser.showOpenMultipleDialog(stage);
|
||||
final List<File> files = fileChooser.showOpenMultipleDialog(mainWindow);
|
||||
if (files != null) {
|
||||
for (final File file : files) {
|
||||
addVault(file.toPath(), false);
|
||||
@@ -288,7 +287,7 @@ public class MainController extends AbstractFXMLViewController {
|
||||
// ****************************************
|
||||
|
||||
public Binding<String> windowTitle() {
|
||||
return EasyBind.monadic(selectedVault).map(Vault::getName).orElse(resourceBundle.getString("app.name"));
|
||||
return EasyBind.monadic(selectedVault).map(Vault::getName).orElse(localization.getString("app.name"));
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -340,13 +339,4 @@ public class MainController extends AbstractFXMLViewController {
|
||||
showUnlockView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to make the application window visible.
|
||||
*/
|
||||
public void toFront() {
|
||||
stage.setIconified(false);
|
||||
stage.show();
|
||||
stage.toFront();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang3.CharUtils;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
@@ -26,10 +27,12 @@ import javafx.scene.input.KeyEvent;
|
||||
@Singleton
|
||||
public class SettingsController extends AbstractFXMLViewController {
|
||||
|
||||
private final Localization localization;
|
||||
private final Settings settings;
|
||||
|
||||
@Inject
|
||||
public SettingsController(Settings settings) {
|
||||
public SettingsController(Localization localization, Settings settings) {
|
||||
this.localization = localization;
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@@ -57,7 +60,7 @@ public class SettingsController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
protected ResourceBundle getFxmlResourceBundle() {
|
||||
return ResourceBundle.getBundle("localization");
|
||||
return localization;
|
||||
}
|
||||
|
||||
private void portDidChange(String newValue) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.cryptomator.frontend.FrontendFactory;
|
||||
import org.cryptomator.frontend.webdav.mount.WindowsDriveLetters;
|
||||
import org.cryptomator.ui.controls.SecPasswordField;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -54,6 +55,7 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UnlockController.class);
|
||||
|
||||
private final Application app;
|
||||
private final Localization localization;
|
||||
private final ExecutorService exec;
|
||||
private final Lazy<FrontendFactory> frontendFactory;
|
||||
private final WindowsDriveLetters driveLetters;
|
||||
@@ -61,8 +63,9 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
|
||||
|
||||
@Inject
|
||||
public UnlockController(Application app, ExecutorService exec, Lazy<FrontendFactory> frontendFactory, WindowsDriveLetters driveLetters) {
|
||||
public UnlockController(Application app, Localization localization, ExecutorService exec, Lazy<FrontendFactory> frontendFactory, WindowsDriveLetters driveLetters) {
|
||||
this.app = app;
|
||||
this.localization = localization;
|
||||
this.exec = exec;
|
||||
this.frontendFactory = frontendFactory;
|
||||
this.driveLetters = driveLetters;
|
||||
@@ -123,7 +126,7 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
protected ResourceBundle getFxmlResourceBundle() {
|
||||
return ResourceBundle.getBundle("localization");
|
||||
return localization;
|
||||
}
|
||||
|
||||
private void vaultChanged(Vault newVault) {
|
||||
@@ -132,7 +135,7 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
}
|
||||
passwordField.clear();
|
||||
advancedOptions.setVisible(false);
|
||||
advancedOptionsButton.setText(resourceBundle.getString("unlock.button.advancedOptions.show"));
|
||||
advancedOptionsButton.setText(localization.getString("unlock.button.advancedOptions.show"));
|
||||
progressIndicator.setVisible(false);
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
winDriveLetter.valueProperty().removeListener(driveLetterChangeListener);
|
||||
@@ -167,9 +170,9 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
private void didClickAdvancedOptionsButton(ActionEvent event) {
|
||||
advancedOptions.setVisible(!advancedOptions.isVisible());
|
||||
if (advancedOptions.isVisible()) {
|
||||
advancedOptionsButton.setText(resourceBundle.getString("unlock.button.advancedOptions.hide"));
|
||||
advancedOptionsButton.setText(localization.getString("unlock.button.advancedOptions.hide"));
|
||||
} else {
|
||||
advancedOptionsButton.setText(resourceBundle.getString("unlock.button.advancedOptions.show"));
|
||||
advancedOptionsButton.setText(localization.getString("unlock.button.advancedOptions.show"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +206,7 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
@Override
|
||||
public String toString(Character letter) {
|
||||
if (letter == null) {
|
||||
return resourceBundle.getString("unlock.choicebox.winDriveLetter.auto");
|
||||
return localization.getString("unlock.choicebox.winDriveLetter.auto");
|
||||
} else {
|
||||
return Character.toString(letter) + ":";
|
||||
}
|
||||
@@ -211,7 +214,7 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
public Character fromString(String string) {
|
||||
if (resourceBundle.getString("unlock.choicebox.winDriveLetter.auto").equals(string)) {
|
||||
if (localization.getString("unlock.choicebox.winDriveLetter.auto").equals(string)) {
|
||||
return null;
|
||||
} else {
|
||||
return CharUtils.toCharacterObject(string);
|
||||
@@ -280,7 +283,7 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
vault.get().reveal();
|
||||
} catch (InvalidPassphraseException e) {
|
||||
Platform.runLater(() -> {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.wrongPassword"));
|
||||
messageText.setText(localization.getString("unlock.errorMessage.wrongPassword"));
|
||||
passwordField.requestFocus();
|
||||
});
|
||||
} catch (UnsupportedVaultFormatException e) {
|
||||
@@ -288,15 +291,15 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
Platform.runLater(() -> {
|
||||
downloadsPageLink.setVisible(true);
|
||||
if (e.isVaultOlderThanSoftware()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
} else if (e.isSoftwareOlderThanVault()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
}
|
||||
});
|
||||
} catch (FrontendCreationFailedException | CommandFailedException e) {
|
||||
LOG.error("Decryption failed for technical reasons.", e);
|
||||
Platform.runLater(() -> {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.mountingFailed"));
|
||||
messageText.setText(localization.getString("unlock.errorMessage.mountingFailed"));
|
||||
});
|
||||
} finally {
|
||||
Platform.runLater(() -> {
|
||||
|
||||
@@ -18,6 +18,7 @@ import javax.inject.Provider;
|
||||
|
||||
import org.cryptomator.frontend.CommandFailedException;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.util.ActiveWindowStyleSupport;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
@@ -50,6 +51,7 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
private static final int IO_SAMPLING_STEPS = 100;
|
||||
private static final double IO_SAMPLING_INTERVAL = 0.25;
|
||||
|
||||
private final Localization localization;
|
||||
private final Stage macWarningsWindow = new Stage();
|
||||
private final MacWarningsController macWarningsController;
|
||||
private final ExecutorService exec;
|
||||
@@ -58,7 +60,8 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
private Timeline ioAnimation;
|
||||
|
||||
@Inject
|
||||
public UnlockedController(Provider<MacWarningsController> macWarningsControllerProvider, ExecutorService exec) {
|
||||
public UnlockedController(Localization localization, Provider<MacWarningsController> macWarningsControllerProvider, ExecutorService exec) {
|
||||
this.localization = localization;
|
||||
this.macWarningsController = macWarningsControllerProvider.get();
|
||||
this.exec = exec;
|
||||
|
||||
@@ -96,7 +99,7 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
protected ResourceBundle getFxmlResourceBundle() {
|
||||
return ResourceBundle.getBundle("localization");
|
||||
return localization;
|
||||
}
|
||||
|
||||
private void vaultChanged(Vault newVault) {
|
||||
@@ -125,7 +128,7 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
vault.get().unmount();
|
||||
} catch (CommandFailedException e) {
|
||||
Platform.runLater(() -> {
|
||||
messageLabel.setText(resourceBundle.getString("unlocked.label.unmountFailed"));
|
||||
messageLabel.setText(localization.getString("unlocked.label.unmountFailed"));
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -151,7 +154,7 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
vault.get().reveal();
|
||||
} catch (CommandFailedException e) {
|
||||
Platform.runLater(() -> {
|
||||
messageLabel.setText(resourceBundle.getString("unlocked.label.revealFailed"));
|
||||
messageLabel.setText(localization.getString("unlocked.label.revealFailed"));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.apache.commons.httpclient.methods.GetMethod;
|
||||
import org.apache.commons.httpclient.params.HttpClientParams;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -54,13 +55,15 @@ public class WelcomeController extends AbstractFXMLViewController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WelcomeController.class);
|
||||
|
||||
private final Application app;
|
||||
private final Localization localization;
|
||||
private final Settings settings;
|
||||
private final Comparator<String> semVerComparator;
|
||||
private final ExecutorService executor;
|
||||
|
||||
@Inject
|
||||
public WelcomeController(Application app, Settings settings, @Named("SemVer") Comparator<String> semVerComparator, ExecutorService executor) {
|
||||
public WelcomeController(Application app, Localization localization, Settings settings, @Named("SemVer") Comparator<String> semVerComparator, ExecutorService executor) {
|
||||
this.app = app;
|
||||
this.localization = localization;
|
||||
this.settings = settings;
|
||||
this.semVerComparator = semVerComparator;
|
||||
this.executor = executor;
|
||||
@@ -99,7 +102,7 @@ public class WelcomeController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
protected ResourceBundle getFxmlResourceBundle() {
|
||||
return ResourceBundle.getBundle("localization");
|
||||
return localization;
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -115,7 +118,7 @@ public class WelcomeController extends AbstractFXMLViewController {
|
||||
return;
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
checkForUpdatesStatus.setText(resourceBundle.getString("welcome.checkForUpdates.label.currentlyChecking"));
|
||||
checkForUpdatesStatus.setText(localization.getString("welcome.checkForUpdates.label.currentlyChecking"));
|
||||
checkForUpdatesIndicator.setVisible(true);
|
||||
});
|
||||
final HttpClient client = new HttpClient();
|
||||
@@ -162,7 +165,7 @@ public class WelcomeController extends AbstractFXMLViewController {
|
||||
final String currentVersion = applicationVersion().orElse(null);
|
||||
LOG.debug("Current version: {}, lastest version: {}", currentVersion, latestVersion);
|
||||
if (currentVersion != null && semVerComparator.compare(currentVersion, latestVersion) < 0) {
|
||||
final String msg = String.format(resourceBundle.getString("welcome.newVersionMessage"), latestVersion, currentVersion);
|
||||
final String msg = String.format(localization.getString("welcome.newVersionMessage"), latestVersion, currentVersion);
|
||||
Platform.runLater(() -> {
|
||||
this.updateLink.setText(msg);
|
||||
this.updateLink.setVisible(true);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.cryptomator.ui.settings;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class Localization extends ResourceBundle {
|
||||
|
||||
@Inject
|
||||
public Localization() {
|
||||
this.parent = ResourceBundle.getBundle("localization");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object handleGetObject(String key) {
|
||||
return parent.getObject(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getKeys() {
|
||||
return parent.getKeys();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,13 +17,14 @@ import org.cryptomator.ui.model.Vault;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
|
||||
@JsonPropertyOrder(value = {"directories", "checkForUpdatesEnabled", "port"})
|
||||
@JsonPropertyOrder(value = {"directories", "checkForUpdatesEnabled", "port", "numTrayNotifications"})
|
||||
public class Settings implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7609959894417878744L;
|
||||
public static final int MIN_PORT = 1024;
|
||||
public static final int MAX_PORT = 65535;
|
||||
public static final int DEFAULT_PORT = 0;
|
||||
public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
||||
|
||||
@JsonProperty("directories")
|
||||
private List<Vault> directories;
|
||||
@@ -34,6 +35,9 @@ public class Settings implements Serializable {
|
||||
@JsonProperty("port")
|
||||
private Integer port;
|
||||
|
||||
@JsonProperty("numTrayNotifications")
|
||||
private Integer numTrayNotifications;
|
||||
|
||||
/**
|
||||
* Package-private constructor; use {@link SettingsProvider}.
|
||||
*/
|
||||
@@ -82,4 +86,12 @@ public class Settings implements Serializable {
|
||||
return port == DEFAULT_PORT || port >= MIN_PORT && port <= MAX_PORT;
|
||||
}
|
||||
|
||||
public Integer getNumTrayNotifications() {
|
||||
return numTrayNotifications == null ? DEFAULT_NUM_TRAY_NOTIFICATIONS : numTrayNotifications;
|
||||
}
|
||||
|
||||
public void setNumTrayNotifications(Integer numTrayNotifications) {
|
||||
this.numTrayNotifications = numTrayNotifications;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.cryptomator.ui.controllers.MainController;
|
||||
import org.cryptomator.common.ConsumerThrowingException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -41,23 +41,8 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
* @author Tillmann Gaida
|
||||
*/
|
||||
public class DeferredCloser implements AutoCloseable {
|
||||
public static interface Closer<T> {
|
||||
void close(T object) throws Exception;
|
||||
}
|
||||
|
||||
static class EmptyResource<T> implements DeferredClosable<T> {
|
||||
@Override
|
||||
public Optional<T> get() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MainController.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DeferredCloser.class);
|
||||
|
||||
@VisibleForTesting
|
||||
final Map<Long, ManagedResource<?>> cleanups = new ConcurrentSkipListMap<>();
|
||||
@@ -65,13 +50,13 @@ public class DeferredCloser implements AutoCloseable {
|
||||
@VisibleForTesting
|
||||
final AtomicLong counter = new AtomicLong();
|
||||
|
||||
public class ManagedResource<T> implements DeferredClosable<T> {
|
||||
private class ManagedResource<T> implements DeferredClosable<T> {
|
||||
private final long number = counter.incrementAndGet();
|
||||
|
||||
private final AtomicReference<T> object = new AtomicReference<>();
|
||||
private final Closer<T> closer;
|
||||
private final ConsumerThrowingException<T, Exception> closer;
|
||||
|
||||
ManagedResource(T object, Closer<T> closer) {
|
||||
public ManagedResource(T object, ConsumerThrowingException<T, Exception> closer) {
|
||||
super();
|
||||
this.object.set(object);
|
||||
this.closer = closer;
|
||||
@@ -82,11 +67,10 @@ public class DeferredCloser implements AutoCloseable {
|
||||
final T oldObject = object.getAndSet(null);
|
||||
if (oldObject != null) {
|
||||
cleanups.remove(number);
|
||||
|
||||
try {
|
||||
closer.close(oldObject);
|
||||
closer.accept(oldObject);
|
||||
} catch (Exception e) {
|
||||
LOG.error("exception closing resource", e);
|
||||
LOG.error("Closing resource failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +93,7 @@ public class DeferredCloser implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
public <T> DeferredClosable<T> closeLater(T object, Closer<T> closer) {
|
||||
public <T> DeferredClosable<T> closeLater(T object, ConsumerThrowingException<T, Exception> closer) {
|
||||
Objects.requireNonNull(object);
|
||||
Objects.requireNonNull(closer);
|
||||
final ManagedResource<T> resource = new ManagedResource<T>(object, closer);
|
||||
@@ -130,4 +114,16 @@ public class DeferredCloser implements AutoCloseable {
|
||||
public static <T> DeferredClosable<T> empty() {
|
||||
return (DeferredClosable<T>) EMPTY_RESOURCE;
|
||||
}
|
||||
|
||||
static class EmptyResource<T> implements DeferredClosable<T> {
|
||||
@Override
|
||||
public Optional<T> get() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,77 +18,67 @@ import java.awt.TrayIcon;
|
||||
import java.awt.TrayIcon.MessageType;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Singleton
|
||||
public final class TrayIconUtil {
|
||||
|
||||
private static TrayIconUtil INSTANCE;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TrayIconUtil.class);
|
||||
|
||||
private final Stage mainApplicationWindow;
|
||||
private final ResourceBundle rb;
|
||||
private final Runnable exitCommand;
|
||||
private final Stage mainWindow;
|
||||
private final Localization localization;
|
||||
|
||||
/**
|
||||
* This will add an icon to the system tray and modify the application shutdown procedure. Depending on
|
||||
* {@link Platform#isImplicitExit()} the application may still be running, allowing shutdown using the tray menu.
|
||||
*/
|
||||
public synchronized static void init(Stage mainApplicationWindow, ResourceBundle rb, Runnable exitCommand) {
|
||||
if (INSTANCE == null && SystemTray.isSupported()) {
|
||||
INSTANCE = new TrayIconUtil(mainApplicationWindow, rb, exitCommand);
|
||||
}
|
||||
@Inject
|
||||
public TrayIconUtil(@Named("mainWindow") Stage mainWindow, Localization localization) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.localization = localization;
|
||||
}
|
||||
|
||||
private TrayIconUtil(Stage mainApplicationWindow, ResourceBundle rb, Runnable exitCommand) {
|
||||
this.mainApplicationWindow = mainApplicationWindow;
|
||||
this.rb = rb;
|
||||
this.exitCommand = exitCommand;
|
||||
|
||||
initTrayIcon();
|
||||
}
|
||||
|
||||
private void initTrayIcon() {
|
||||
final TrayIcon trayIcon = createTrayIcon();
|
||||
public void initTrayIcon(Runnable exitCommand) {
|
||||
final TrayIcon trayIcon = createTrayIcon(exitCommand);
|
||||
try {
|
||||
SystemTray.getSystemTray().add(trayIcon);
|
||||
mainApplicationWindow.setOnCloseRequest((e) -> {
|
||||
mainWindow.setOnCloseRequest((e) -> {
|
||||
if (Platform.isImplicitExit()) {
|
||||
exitCommand.run();
|
||||
} else {
|
||||
mainApplicationWindow.close();
|
||||
mainWindow.close();
|
||||
this.showTrayNotification(trayIcon);
|
||||
}
|
||||
});
|
||||
} catch (SecurityException | AWTException ex) {
|
||||
// not working? then just go ahead and close the app
|
||||
mainApplicationWindow.setOnCloseRequest((ev) -> {
|
||||
mainWindow.setOnCloseRequest((ev) -> {
|
||||
exitCommand.run();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private TrayIcon createTrayIcon() {
|
||||
private TrayIcon createTrayIcon(Runnable exitCommand) {
|
||||
final PopupMenu popup = new PopupMenu();
|
||||
|
||||
final MenuItem showItem = new MenuItem(rb.getString("tray.menu.open"));
|
||||
final MenuItem showItem = new MenuItem(localization.getString("tray.menu.open"));
|
||||
showItem.addActionListener(this::restoreFromTray);
|
||||
popup.add(showItem);
|
||||
|
||||
final MenuItem exitItem = new MenuItem(rb.getString("tray.menu.quit"));
|
||||
exitItem.addActionListener(this::quitFromTray);
|
||||
final MenuItem exitItem = new MenuItem(localization.getString("tray.menu.quit"));
|
||||
exitItem.addActionListener(e -> exitCommand.run());
|
||||
popup.add(exitItem);
|
||||
|
||||
final Image image;
|
||||
@@ -98,7 +88,7 @@ public final class TrayIconUtil {
|
||||
image = Toolkit.getDefaultToolkit().getImage(TrayIconUtil.class.getResource("/tray_icon.png"));
|
||||
}
|
||||
|
||||
return new TrayIcon(image, rb.getString("app.name"), popup);
|
||||
return new TrayIcon(image, localization.getString("app.name"), popup);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,8 +110,8 @@ public final class TrayIconUtil {
|
||||
private void showTrayNotification(TrayIcon trayIcon) {
|
||||
final Runnable notificationCmd;
|
||||
if (SystemUtils.IS_OS_MAC_OSX) {
|
||||
final String title = rb.getString("tray.infoMsg.title");
|
||||
final String msg = rb.getString("tray.infoMsg.msg.osx");
|
||||
final String title = localization.getString("tray.infoMsg.title");
|
||||
final String msg = localization.getString("tray.infoMsg.msg.osx");
|
||||
final String notificationCenterAppleScript = String.format("display notification \"%s\" with title \"%s\"", msg, title);
|
||||
notificationCmd = () -> {
|
||||
try {
|
||||
@@ -137,8 +127,8 @@ public final class TrayIconUtil {
|
||||
}
|
||||
};
|
||||
} else {
|
||||
final String title = rb.getString("tray.infoMsg.title");
|
||||
final String msg = rb.getString("tray.infoMsg.msg");
|
||||
final String title = localization.getString("tray.infoMsg.title");
|
||||
final String msg = localization.getString("tray.infoMsg.msg");
|
||||
notificationCmd = () -> {
|
||||
trayIcon.displayMessage(title, msg, MessageType.INFO);
|
||||
};
|
||||
@@ -150,13 +140,9 @@ public final class TrayIconUtil {
|
||||
|
||||
private void restoreFromTray(ActionEvent event) {
|
||||
Platform.runLater(() -> {
|
||||
mainApplicationWindow.show();
|
||||
mainApplicationWindow.requestFocus();
|
||||
mainWindow.show();
|
||||
mainWindow.requestFocus();
|
||||
});
|
||||
}
|
||||
|
||||
private void quitFromTray(ActionEvent event) {
|
||||
exitCommand.run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user