added cmd+, shortcut to macOS menubar

This commit is contained in:
Sebastian Stenzel
2017-05-27 01:20:44 +02:00
parent 96c2272b03
commit f4265e1d73
3 changed files with 132 additions and 51 deletions
@@ -37,6 +37,7 @@ import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.model.VaultFactory;
import org.cryptomator.ui.model.VaultList;
import org.cryptomator.ui.util.DialogBuilderUtil;
import org.cryptomator.ui.util.EawtApplicationWrapper;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
import org.fxmisc.easybind.monadic.MonadicBinding;
@@ -119,6 +120,12 @@ public class MainController implements ViewController {
EasyBind.subscribe(areAllVaultsLocked, Platform::setImplicitExit);
autoUnlocker.unlockAllSilently();
EawtApplicationWrapper.getApplication().ifPresent(app -> {
app.setPreferencesHandler(() -> {
Platform.runLater(this::toggleShowSettings);
});
});
}
@FXML
@@ -328,10 +335,14 @@ public class MainController implements ViewController {
@FXML
private void didClickShowSettings(ActionEvent e) {
toggleShowSettings();
}
private void toggleShowSettings() {
if (isShowingSettings.get()) {
activeController.set(viewControllerLoader.load("/fxml/welcome.fxml"));
showWelcomeView();
} else {
activeController.set(viewControllerLoader.load("/fxml/settings.fxml"));
showPreferencesView();
}
vaultList.getSelectionModel().clearSelection();
}
@@ -375,6 +386,14 @@ public class MainController implements ViewController {
// Subcontroller for right panel
// ****************************************
private void showWelcomeView() {
activeController.set(viewControllerLoader.load("/fxml/welcome.fxml"));
}
private void showPreferencesView() {
activeController.set(viewControllerLoader.load("/fxml/settings.fxml"));
}
private void showNotFoundView() {
activeController.set(viewControllerLoader.load("/fxml/notfound.fxml"));
}
@@ -0,0 +1,105 @@
/*******************************************************************************
* 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.util;
import java.io.File;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Reflection-based wrapper for com.apple.eawt.Application.
*/
public class EawtApplicationWrapper {
private static final Logger LOG = LoggerFactory.getLogger(EawtApplicationWrapper.class);
private final Class<?> applicationClass;
private final Object application;
private EawtApplicationWrapper() throws ReflectiveOperationException {
this.applicationClass = Class.forName("com.apple.eawt.Application");
this.application = applicationClass.getMethod("getApplication").invoke(null);
}
public static Optional<EawtApplicationWrapper> getApplication() {
try {
return Optional.of(new EawtApplicationWrapper());
} catch (ReflectiveOperationException e) {
return Optional.empty();
}
}
private void setOpenFileHandler(InvocationHandler handler) throws ReflectiveOperationException {
Class<?> handlerClass = Class.forName("com.apple.eawt.OpenFilesHandler");
Method setter = applicationClass.getMethod("setOpenFileHandler", handlerClass);
Object proxy = Proxy.newProxyInstance(applicationClass.getClassLoader(), new Class<?>[] {handlerClass}, handler);
setter.invoke(application, proxy);
}
public void setOpenFileHandler(Consumer<List<File>> handler) {
try {
Class<?> openFilesEventClass = Class.forName("com.apple.eawt.AppEvent$OpenFilesEvent");
Method getFiles = openFilesEventClass.getMethod("getFiles");
setOpenFileHandler(newMethodSpecificInvocationHandler("openFiles", args -> {
try {
Object openFilesEvent = args[0];
@SuppressWarnings("unchecked")
List<File> files = (List<File>) getFiles.invoke(openFilesEvent);
handler.accept(files);
} catch (ReflectiveOperationException e) {
LOG.error("Error invoking openFileHandler.", e);
}
return null;
}));
} catch (ReflectiveOperationException e) {
LOG.error("Exception setting openFileHandler.", e);
}
}
private void setPreferencesHandler(InvocationHandler handler) throws ReflectiveOperationException {
Class<?> handlerClass = Class.forName("com.apple.eawt.PreferencesHandler");
Method setter = applicationClass.getMethod("setPreferencesHandler", handlerClass);
Object proxy = Proxy.newProxyInstance(applicationClass.getClassLoader(), new Class<?>[] {handlerClass}, handler);
setter.invoke(application, proxy);
}
public void setPreferencesHandler(Runnable handler) {
try {
setPreferencesHandler(newMethodSpecificInvocationHandler("handlePreferences", args -> {
handler.run();
return null;
}));
} catch (ReflectiveOperationException e) {
LOG.error("Exception setting preferencesHandler.", e);
}
}
@FunctionalInterface
private static interface MethodSpecificInvocationHandler {
Object invoke(Object[] args);
}
private static InvocationHandler newMethodSpecificInvocationHandler(String methodName, MethodSpecificInvocationHandler handler) {
return new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals(methodName)) {
return handler.invoke(args);
} else {
return null;
}
}
};
}
}