mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-21 01:56:55 -04:00
Merge branch 'feature/issue-363' into develop
This commit is contained in:
@@ -40,9 +40,9 @@ class NormalizedNameFolder extends DelegatingFolder<NormalizedNameFolder, Normal
|
||||
NormalizedNameFile nfcFile = super.file(nfcName);
|
||||
NormalizedNameFile nfdFile = super.file(nfdName);
|
||||
if (!nfcName.equals(nfdName) && nfcFile.exists() && nfdFile.exists()) {
|
||||
LOG.warn("Ambiguous file names \"" + nfcName + "\" (NFC) vs. \"" + nfdName + "\" (NFD). Both files exist. Using \"" + nfcName + "\" (NFC).");
|
||||
LOG.debug("Ambiguous file names \"" + nfcName + "\" (NFC) vs. \"" + nfdName + "\" (NFD). Both files exist. Using \"" + nfcName + "\" (NFC).");
|
||||
} else if (!nfcName.equals(nfdName) && !nfcFile.exists() && nfdFile.exists()) {
|
||||
LOG.info("Moving file from \"" + nfcName + "\" (NFD) to \"" + nfdName + "\" (NFC).");
|
||||
LOG.debug("Moving file from \"" + nfcName + "\" (NFD) to \"" + nfdName + "\" (NFC).");
|
||||
nfdFile.moveTo(nfcFile);
|
||||
}
|
||||
return nfcFile;
|
||||
@@ -60,9 +60,9 @@ class NormalizedNameFolder extends DelegatingFolder<NormalizedNameFolder, Normal
|
||||
NormalizedNameFolder nfcFolder = super.folder(nfcName);
|
||||
NormalizedNameFolder nfdFolder = super.folder(nfdName);
|
||||
if (!nfcName.equals(nfdName) && nfcFolder.exists() && nfdFolder.exists()) {
|
||||
LOG.warn("Ambiguous folder names \"" + nfcName + "\" (NFC) vs. \"" + nfdName + "\" (NFD). Both files exist. Using \"" + nfcName + "\" (NFC).");
|
||||
LOG.debug("Ambiguous folder names \"" + nfcName + "\" (NFC) vs. \"" + nfdName + "\" (NFD). Both files exist. Using \"" + nfcName + "\" (NFC).");
|
||||
} else if (!nfcName.equals(nfdName) && !nfcFolder.exists() && nfdFolder.exists()) {
|
||||
LOG.info("Moving folder from \"" + nfcName + "\" (NFD) to \"" + nfdName + "\" (NFC).");
|
||||
LOG.debug("Moving folder from \"" + nfcName + "\" (NFD) to \"" + nfdName + "\" (NFC).");
|
||||
nfdFolder.moveTo(nfcFolder);
|
||||
}
|
||||
return nfcFolder;
|
||||
|
||||
@@ -68,7 +68,7 @@ final class ConflictResolver {
|
||||
String alternativeCiphertext = nameEncryptor.apply(alternativeCleartext).get();
|
||||
alternativeFile = folder.file(isDirectory ? DIR_PREFIX + alternativeCiphertext : alternativeCiphertext);
|
||||
} while (alternativeFile.exists());
|
||||
LOG.info("Detected conflict {}:\n{}\n{}", conflictId, canonicalFile, conflictingFile);
|
||||
LOG.debug("Detected conflict {}:\n{}\n{}", conflictId, canonicalFile, conflictingFile);
|
||||
conflictingFile.moveTo(alternativeFile);
|
||||
return alternativeFile;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ class ContextPaths {
|
||||
return format("/%s/%s", id, name);
|
||||
}
|
||||
|
||||
public static String removeFrontendId(String path) {
|
||||
return path.replaceAll("/" + FRONTEND_ID_PATTERN + "/", "/[...]/");
|
||||
}
|
||||
|
||||
public static Optional<FrontendId> extractFrontendId(String path) {
|
||||
Matcher matcher = SERVLET_PATH_WITH_FRONTEND_ID_PATTERN.matcher(path);
|
||||
if (matcher.matches()) {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.cryptomator.frontend.webdav;
|
||||
|
||||
import org.eclipse.jetty.server.HandlerContainer;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
|
||||
class FontendIdHidingServletContextHandler extends ServletContextHandler {
|
||||
|
||||
public FontendIdHidingServletContextHandler(HandlerContainer parent, String contextPath, int options) {
|
||||
super(parent, contextPath, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ContextPaths.removeFrontendId(super.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,8 +8,6 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.frontend.webdav;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collection;
|
||||
@@ -110,7 +108,7 @@ public class WebDavServer implements FrontendFactory {
|
||||
|
||||
@Override
|
||||
public Frontend create(Folder root, FrontendId id, String name) throws FrontendCreationFailedException {
|
||||
String contextPath = format("/%s/%s", id, name);
|
||||
String contextPath = ContextPaths.from(id, name);
|
||||
final URI uri;
|
||||
try {
|
||||
uri = new URI("http", null, "localhost", getPort(), contextPath, null, null);
|
||||
@@ -118,10 +116,10 @@ public class WebDavServer implements FrontendFactory {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
final ServletContextHandler handler = addServlet(root, uri);
|
||||
LOG.info("Servlet available under " + uri);
|
||||
LOG.info("Servlet available under " + ContextPaths.removeFrontendId(uri.toString()));
|
||||
return new WebDavFrontend(webdavMounterProvider, handler, uri);
|
||||
}
|
||||
|
||||
|
||||
public void setValidFrontendIds(Collection<FrontendId> validFrontendIds) {
|
||||
tarpit.setValidFrontendIds(validFrontendIds);
|
||||
}
|
||||
|
||||
@@ -35,9 +35,10 @@ import org.eclipse.jetty.servlet.ServletHolder;
|
||||
class WebDavServletContextFactory {
|
||||
|
||||
private static final String WILDCARD = "/*";
|
||||
|
||||
|
||||
@Inject
|
||||
public WebDavServletContextFactory() {}
|
||||
public WebDavServletContextFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Jetty ServletContextHandler, that can be be added to a servletCollection as follows:
|
||||
@@ -63,7 +64,7 @@ class WebDavServletContextFactory {
|
||||
}
|
||||
};
|
||||
final String contextPath = StringUtils.removeEnd(contextRoot.getPath(), "/");
|
||||
final ServletContextHandler servletContext = new ServletContextHandler(null, contextPath, ServletContextHandler.SESSIONS);
|
||||
final ServletContextHandler servletContext = new FontendIdHidingServletContextHandler(null, contextPath, ServletContextHandler.SESSIONS);
|
||||
final ServletHolder servletHolder = new ServletHolder(contextPath, new WebDavServlet(contextRoot, root));
|
||||
servletContext.addServlet(servletHolder, WILDCARD);
|
||||
servletContext.addFilter(LoopbackFilter.class, WILDCARD, EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.util.ApplicationVersion;
|
||||
import org.cryptomator.ui.util.SingleInstanceManager;
|
||||
import org.cryptomator.ui.util.SingleInstanceManager.RemoteInstance;
|
||||
import org.eclipse.jetty.util.ConcurrentHashSet;
|
||||
@@ -33,63 +34,62 @@ public class Cryptomator {
|
||||
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();
|
||||
|
||||
public static void main(String[] args) {
|
||||
String cryptomatorVersion = Optional.ofNullable(Cryptomator.class.getPackage().getImplementationVersion()).orElse("SNAPSHOT");
|
||||
LOG.info("Starting Cryptomator {} on {} {} ({})", cryptomatorVersion, SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
|
||||
LOG.info("Starting Cryptomator {} on {} {} ({})", ApplicationVersion.orElse("SNAPSHOT"), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
|
||||
|
||||
if (SystemUtils.IS_OS_MAC_OSX) {
|
||||
/*
|
||||
* On OSX we're in an awkward position. We need to register a handler in the main thread of this application. However, we can't
|
||||
* even pass objects to the application, so we're forced to use a static CompletableFuture for the handler, which actually opens
|
||||
* the file in the application.
|
||||
*
|
||||
* Code taken from https://github.com/axet/desktop/blob/master/src/main/java/com/github/axet/desktop/os/mac/AppleHandlers.java
|
||||
*/
|
||||
try {
|
||||
final Class<?> applicationClass = Class.forName("com.apple.eawt.Application");
|
||||
final Class<?> openFilesHandlerClass = Class.forName("com.apple.eawt.OpenFilesHandler");
|
||||
final Method getApplication = applicationClass.getMethod("getApplication");
|
||||
final Object application = getApplication.invoke(null);
|
||||
final Method setOpenFileHandler = applicationClass.getMethod("setOpenFileHandler", openFilesHandlerClass);
|
||||
|
||||
final ClassLoader openFilesHandlerClassLoader = openFilesHandlerClass.getClassLoader();
|
||||
final OpenFilesHandlerClassHandler openFilesHandlerHandler = new OpenFilesHandlerClassHandler();
|
||||
final Object openFilesHandlerObject = Proxy.newProxyInstance(openFilesHandlerClassLoader, new Class<?>[] {openFilesHandlerClass}, openFilesHandlerHandler);
|
||||
|
||||
setOpenFileHandler.invoke(application, openFilesHandlerObject);
|
||||
} catch (ReflectiveOperationException | RuntimeException e) {
|
||||
// Since we're trying to call OS-specific code, we'll just have
|
||||
// to hope for the best.
|
||||
LOG.error("exception adding OSX file open handler", e);
|
||||
}
|
||||
addOsxFileOpenHandler();
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform certain things on VM termination.
|
||||
*/
|
||||
Runtime.getRuntime().addShutdownHook(CLEAN_SHUTDOWN_PERFORMER);
|
||||
new CleanShutdownPerformer().registerShutdownHook();
|
||||
|
||||
/*
|
||||
* Before starting the application, we check if there is already an instance running on this computer. If so, we send our command
|
||||
* line arguments to that instance and quit.
|
||||
*/
|
||||
final Optional<RemoteInstance> remoteInstance = SingleInstanceManager.getRemoteInstance(MainApplication.APPLICATION_KEY);
|
||||
|
||||
if (remoteInstance.isPresent()) {
|
||||
try (RemoteInstance instance = remoteInstance.get()) {
|
||||
LOG.info("An instance of Cryptomator is already running at {}.", instance.getRemotePort());
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
remoteInstance.get().sendMessage(args[i], 100);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error forwarding arguments to remote instance", e);
|
||||
}
|
||||
final Optional<RemoteInstance> runningInstance = SingleInstanceManager.getRemoteInstance(MainApplication.APPLICATION_KEY);
|
||||
if (runningInstance.isPresent()) {
|
||||
sendArgsToRunningInstance(args, runningInstance);
|
||||
} else {
|
||||
Application.launch(MainApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addOsxFileOpenHandler() {
|
||||
/*
|
||||
* On OSX we're in an awkward position. We need to register a handler in the main thread of this application. However, we can't
|
||||
* even pass objects to the application, so we're forced to use a static CompletableFuture for the handler, which actually opens
|
||||
* the file in the application.
|
||||
*
|
||||
* Code taken from https://github.com/axet/desktop/blob/master/src/main/java/com/github/axet/desktop/os/mac/AppleHandlers.java
|
||||
*/
|
||||
try {
|
||||
final Class<?> applicationClass = Class.forName("com.apple.eawt.Application");
|
||||
final Class<?> openFilesHandlerClass = Class.forName("com.apple.eawt.OpenFilesHandler");
|
||||
final Method getApplication = applicationClass.getMethod("getApplication");
|
||||
final Object application = getApplication.invoke(null);
|
||||
final Method setOpenFileHandler = applicationClass.getMethod("setOpenFileHandler", openFilesHandlerClass);
|
||||
|
||||
final ClassLoader openFilesHandlerClassLoader = openFilesHandlerClass.getClassLoader();
|
||||
final OpenFilesHandlerClassHandler openFilesHandlerHandler = new OpenFilesHandlerClassHandler();
|
||||
final Object openFilesHandlerObject = Proxy.newProxyInstance(openFilesHandlerClassLoader, new Class<?>[] {openFilesHandlerClass}, openFilesHandlerHandler);
|
||||
|
||||
setOpenFileHandler.invoke(application, openFilesHandlerObject);
|
||||
} catch (ReflectiveOperationException | RuntimeException e) {
|
||||
// Since we're trying to call OS-specific code, we'll just have
|
||||
// to hope for the best.
|
||||
LOG.error("exception adding OSX file open handler", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendArgsToRunningInstance(String[] args, final Optional<RemoteInstance> remoteInstance) {
|
||||
try (RemoteInstance instance = remoteInstance.get()) {
|
||||
LOG.info("An instance of Cryptomator is already running at {}.", instance.getRemotePort());
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
remoteInstance.get().sendMessage(args[i], 100);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error forwarding arguments to remote instance", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addShutdownTask(Runnable r) {
|
||||
SHUTDOWN_TASKS.add(r);
|
||||
}
|
||||
@@ -111,6 +111,10 @@ public class Cryptomator {
|
||||
});
|
||||
SHUTDOWN_TASKS.clear();
|
||||
}
|
||||
|
||||
public void registerShutdownHook() {
|
||||
Runtime.getRuntime().addShutdownHook(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleOpenFileRequest(File file) {
|
||||
|
||||
@@ -37,6 +37,8 @@ interface CryptomatorComponent {
|
||||
|
||||
ExitUtil exitUtil();
|
||||
|
||||
DebugMode debugMode();
|
||||
|
||||
Optional<MacFunctions> nativeMacFunctions();
|
||||
|
||||
}
|
||||
|
||||
75
main/ui/src/main/java/org/cryptomator/ui/DebugMode.java
Normal file
75
main/ui/src/main/java/org/cryptomator/ui/DebugMode.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package org.cryptomator.ui;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.apache.logging.log4j.LogManager.ROOT_LOGGER_NAME;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.apache.logging.log4j.core.config.Configuration;
|
||||
import org.apache.logging.log4j.core.config.LoggerConfig;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Singleton
|
||||
public class DebugMode {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DebugMode.class);
|
||||
|
||||
private static final Collection<LoggerUpgrade> LOGGER_UPGRADES = asList( //
|
||||
loggerUpgrade(ROOT_LOGGER_NAME, Level.INFO), //
|
||||
loggerUpgrade("org.cryptomator", Level.TRACE), //
|
||||
loggerUpgrade("org.eclipse.jetty.server.Server", Level.DEBUG) //
|
||||
);
|
||||
|
||||
private final Settings settings;
|
||||
|
||||
@Inject
|
||||
public DebugMode(Settings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
if (settings.getDebugMode()) {
|
||||
enable();
|
||||
LOG.debug("Debug mode initialized");
|
||||
}
|
||||
}
|
||||
|
||||
private void enable() {
|
||||
LoggerContext context = (LoggerContext) LogManager.getContext(false);
|
||||
Configuration config = context.getConfiguration();
|
||||
LOGGER_UPGRADES.forEach(loggerUpgrade -> loggerUpgrade.execute(config));
|
||||
context.updateLoggers();
|
||||
}
|
||||
|
||||
private static LoggerUpgrade loggerUpgrade(String loggerName, Level minLevel) {
|
||||
return new LoggerUpgrade(loggerName, minLevel);
|
||||
}
|
||||
|
||||
private static class LoggerUpgrade {
|
||||
|
||||
private final Level level;
|
||||
private final String loggerName;
|
||||
|
||||
public LoggerUpgrade(String loggerName, Level minLevel) {
|
||||
this.loggerName = loggerName;
|
||||
this.level = minLevel;
|
||||
}
|
||||
|
||||
public void execute(Configuration config) {
|
||||
LoggerConfig loggerConfig = config.getLoggerConfig(loggerName);
|
||||
if (loggerConfig.getLevel().isMoreSpecificThan(level)) {
|
||||
loggerConfig.setLevel(level);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,18 +43,46 @@ public class MainApplication extends Application {
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException {
|
||||
LOG.info("JavaFX application started");
|
||||
final CryptomatorComponent comp;
|
||||
|
||||
CryptomatorComponent comp = createCryptomatorComponent(primaryStage);
|
||||
MainController mainCtrl = comp.mainController();
|
||||
closer = comp.deferredCloser();
|
||||
|
||||
comp.debugMode().initialize();
|
||||
|
||||
setupFXMLClassLoader();
|
||||
setupStylesheets();
|
||||
|
||||
initializeStage(primaryStage, mainCtrl);
|
||||
showWindow(primaryStage);
|
||||
|
||||
registerExitHandler(comp);
|
||||
|
||||
openFilesRequestedDuringStartup(primaryStage, mainCtrl);
|
||||
registerApplicationToProcessOpenFileRequests(primaryStage, comp, mainCtrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
try {
|
||||
comp = DaggerCryptomatorComponent.builder() //
|
||||
closer.close();
|
||||
} catch (ExecutionException e) {
|
||||
LOG.error("Error closing ressources", e);
|
||||
}
|
||||
}
|
||||
|
||||
private CryptomatorComponent createCryptomatorComponent(Stage primaryStage) {
|
||||
try {
|
||||
return DaggerCryptomatorComponent.builder() //
|
||||
.cryptomatorModule(new CryptomatorModule(this, primaryStage)) //
|
||||
.secureRandomModule(new SecureRandomModule(SecureRandom.getInstanceStrong())) //
|
||||
.build();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("Every implementation of the Java platform is required to support at least one strong SecureRandom implementation.", e);
|
||||
}
|
||||
final MainController mainCtrl = comp.mainController();
|
||||
closer = comp.deferredCloser();
|
||||
}
|
||||
|
||||
private void setupFXMLClassLoader() {
|
||||
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
FXMLLoader.setDefaultClassLoader(contextClassLoader);
|
||||
Platform.runLater(() -> {
|
||||
@@ -66,35 +94,55 @@ public class MainApplication extends Application {
|
||||
Thread.currentThread().setContextClassLoader(contextClassLoader);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Set stylesheets and initialize stage:
|
||||
private void setupStylesheets() {
|
||||
Font.loadFont(getClass().getResourceAsStream("/css/ionicons.ttf"), 12.0);
|
||||
chooseNativeStylesheet();
|
||||
}
|
||||
|
||||
private void initializeStage(Stage primaryStage, MainController mainCtrl) {
|
||||
mainCtrl.initStage(primaryStage);
|
||||
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:
|
||||
private void showWindow(Stage primaryStage) {
|
||||
primaryStage.show();
|
||||
ActiveWindowStyleSupport.startObservingFocus(primaryStage);
|
||||
comp.exitUtil().initExitHandler(this::quit);
|
||||
}
|
||||
|
||||
// open files, if requested during startup:
|
||||
private void registerExitHandler(CryptomatorComponent comp) {
|
||||
comp.exitUtil().initExitHandler(this::quit);
|
||||
}
|
||||
|
||||
private void openFilesRequestedDuringStartup(Stage primaryStage, final MainController mainCtrl) {
|
||||
for (String arg : getParameters().getUnnamed()) {
|
||||
handleCommandLineArg(arg, primaryStage, mainCtrl);
|
||||
}
|
||||
if (SystemUtils.IS_OS_MAC_OSX) {
|
||||
Cryptomator.OPEN_FILE_HANDLER.complete(file -> handleCommandLineArg(file.getAbsolutePath(), primaryStage, mainCtrl));
|
||||
}
|
||||
}
|
||||
|
||||
// register this application instance as primary application, that other instances can send open file requests to:
|
||||
private void registerApplicationToProcessOpenFileRequests(Stage primaryStage, final CryptomatorComponent comp, final MainController mainCtrl) throws IOException {
|
||||
LocalInstance cryptomatorGuiInstance = closer.closeLater(SingleInstanceManager.startLocalInstance(APPLICATION_KEY, comp.executorService()), LocalInstance::close).get().get();
|
||||
cryptomatorGuiInstance.registerListener(arg -> handleCommandLineArg(arg, primaryStage, mainCtrl));
|
||||
}
|
||||
|
||||
private void chooseNativeStylesheet() {
|
||||
if (SystemUtils.IS_OS_MAC_OSX) {
|
||||
setUserAgentStylesheet(getClass().getResource("/css/mac_theme.css").toString());
|
||||
} else if (SystemUtils.IS_OS_LINUX) {
|
||||
setUserAgentStylesheet(getClass().getResource("/css/linux_theme.css").toString());
|
||||
} else if (SystemUtils.IS_OS_WINDOWS) {
|
||||
setUserAgentStylesheet(getClass().getResource("/css/win_theme.css").toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCommandLineArg(String arg, Stage primaryStage, MainController mainCtrl) {
|
||||
// find correct location:
|
||||
final Path path = FileSystems.getDefault().getPath(arg);
|
||||
@@ -118,16 +166,6 @@ public class MainApplication extends Application {
|
||||
});
|
||||
}
|
||||
|
||||
private void chooseNativeStylesheet() {
|
||||
if (SystemUtils.IS_OS_MAC_OSX) {
|
||||
setUserAgentStylesheet(getClass().getResource("/css/mac_theme.css").toString());
|
||||
} else if (SystemUtils.IS_OS_LINUX) {
|
||||
setUserAgentStylesheet(getClass().getResource("/css/linux_theme.css").toString());
|
||||
} else if (SystemUtils.IS_OS_WINDOWS) {
|
||||
setUserAgentStylesheet(getClass().getResource("/css/win_theme.css").toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void quit() {
|
||||
Platform.runLater(() -> {
|
||||
stop();
|
||||
@@ -136,13 +174,4 @@ public class MainApplication extends Application {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
try {
|
||||
closer.close();
|
||||
} catch (ExecutionException e) {
|
||||
LOG.error("Error closing ressources", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,6 +59,9 @@ public class SettingsController extends LocalizedFXMLViewController {
|
||||
@FXML
|
||||
private ChoiceBox<String> prefGvfsScheme;
|
||||
|
||||
@FXML
|
||||
private CheckBox debugModeCheckbox;
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
checkForUpdatesCheckbox.setDisable(areUpdatesManagedExternally());
|
||||
@@ -74,11 +77,13 @@ public class SettingsController extends LocalizedFXMLViewController {
|
||||
prefGvfsScheme.getItems().add("dav");
|
||||
prefGvfsScheme.getItems().add("webdav");
|
||||
prefGvfsScheme.setValue(settings.getPreferredGvfsScheme());
|
||||
debugModeCheckbox.setSelected(settings.getDebugMode());
|
||||
|
||||
EasyBind.subscribe(checkForUpdatesCheckbox.selectedProperty(), this::checkForUpdateDidChange);
|
||||
EasyBind.subscribe(portField.textProperty(), this::portDidChange);
|
||||
EasyBind.subscribe(useIpv6Checkbox.selectedProperty(), this::useIpv6DidChange);
|
||||
EasyBind.subscribe(prefGvfsScheme.valueProperty(), this::prefGvfsSchemeDidChange);
|
||||
EasyBind.subscribe(debugModeCheckbox.selectedProperty(), this::debugModeDidChange);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,6 +119,11 @@ public class SettingsController extends LocalizedFXMLViewController {
|
||||
settings.save();
|
||||
}
|
||||
|
||||
private void debugModeDidChange(Boolean newValue) {
|
||||
settings.setDebugMode(newValue);
|
||||
settings.save();
|
||||
}
|
||||
|
||||
private void prefGvfsSchemeDidChange(String newValue) {
|
||||
settings.setPreferredGvfsScheme(newValue);
|
||||
settings.save();
|
||||
|
||||
@@ -58,15 +58,6 @@ public class UnlockedController extends LocalizedFXMLViewController {
|
||||
private Optional<LockListener> listener = Optional.empty();
|
||||
private Timeline ioAnimation;
|
||||
|
||||
@Inject
|
||||
public UnlockedController(Localization localization, Provider<MacWarningsController> macWarningsControllerProvider, AsyncTaskService asyncTaskService) {
|
||||
super(localization);
|
||||
this.macWarningsController = macWarningsControllerProvider.get();
|
||||
this.asyncTaskService = asyncTaskService;
|
||||
|
||||
macWarningsController.vault.bind(this.vault);
|
||||
}
|
||||
|
||||
@FXML
|
||||
private Label messageLabel;
|
||||
|
||||
@@ -85,6 +76,15 @@ public class UnlockedController extends LocalizedFXMLViewController {
|
||||
@FXML
|
||||
private MenuItem revealVaultMenuItem;
|
||||
|
||||
@Inject
|
||||
public UnlockedController(Localization localization, Provider<MacWarningsController> macWarningsControllerProvider, AsyncTaskService asyncTaskService) {
|
||||
super(localization);
|
||||
this.macWarningsController = macWarningsControllerProvider.get();
|
||||
this.asyncTaskService = asyncTaskService;
|
||||
|
||||
macWarningsController.vault.bind(this.vault);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
macWarningsController.initStage(macWarningsWindow);
|
||||
|
||||
@@ -13,7 +13,6 @@ import java.net.URL;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
@@ -29,6 +28,7 @@ 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.cryptomator.ui.util.ApplicationVersion;
|
||||
import org.cryptomator.ui.util.AsyncTaskService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -104,7 +104,7 @@ public class WelcomeController extends LocalizedFXMLViewController {
|
||||
asyncTaskService.asyncTaskOf(() -> {
|
||||
final HttpClient client = new HttpClient();
|
||||
final HttpMethod method = new GetMethod("https://cryptomator.org/downloads/latestVersion.json");
|
||||
client.getParams().setParameter(HttpClientParams.USER_AGENT, "Cryptomator VersionChecker/" + applicationVersion().orElse("SNAPSHOT"));
|
||||
client.getParams().setParameter(HttpClientParams.USER_AGENT, "Cryptomator VersionChecker/" + ApplicationVersion.orElse("SNAPSHOT"));
|
||||
client.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
|
||||
client.getParams().setConnectionManagerTimeout(5000);
|
||||
client.executeMethod(method);
|
||||
@@ -124,10 +124,6 @@ public class WelcomeController extends LocalizedFXMLViewController {
|
||||
}).run();
|
||||
}
|
||||
|
||||
private Optional<String> applicationVersion() {
|
||||
return Optional.ofNullable(getClass().getPackage().getImplementationVersion());
|
||||
}
|
||||
|
||||
private void compareVersions(final Map<String, String> latestVersions) {
|
||||
final String latestVersion;
|
||||
if (SystemUtils.IS_OS_MAC_OSX) {
|
||||
@@ -140,7 +136,7 @@ public class WelcomeController extends LocalizedFXMLViewController {
|
||||
// no version check possible on unsupported OS
|
||||
return;
|
||||
}
|
||||
final String currentVersion = applicationVersion().orElse(null);
|
||||
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(localization.getString("welcome.newVersionMessage"), latestVersion, currentVersion);
|
||||
|
||||
@@ -28,6 +28,7 @@ public class Settings implements Serializable {
|
||||
public static final boolean DEFAULT_USE_IPV6 = false;
|
||||
public static final Integer DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
||||
public static final String DEFAULT_GVFS_SCHEME = "dav";
|
||||
public static final boolean DEFAULT_DEBUG_MODE = false;
|
||||
|
||||
private final Consumer<Settings> saveCmd;
|
||||
|
||||
@@ -49,6 +50,9 @@ public class Settings implements Serializable {
|
||||
@JsonProperty("preferredGvfsScheme")
|
||||
private String preferredGvfsScheme;
|
||||
|
||||
@JsonProperty("debugMode")
|
||||
private Boolean debugMode;
|
||||
|
||||
/**
|
||||
* Package-private constructor; use {@link SettingsProvider}.
|
||||
*/
|
||||
@@ -125,4 +129,12 @@ public class Settings implements Serializable {
|
||||
this.preferredGvfsScheme = preferredGvfsScheme;
|
||||
}
|
||||
|
||||
public boolean getDebugMode() {
|
||||
return debugMode == null ? DEFAULT_DEBUG_MODE : debugMode;
|
||||
}
|
||||
|
||||
public void setDebugMode(boolean debugMode) {
|
||||
this.debugMode = debugMode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.cryptomator.ui.util;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.cryptomator.ui.Cryptomator;
|
||||
|
||||
public class ApplicationVersion {
|
||||
|
||||
public static String orElse(String other) {
|
||||
return get().orElse(other);
|
||||
}
|
||||
|
||||
public static Optional<String> get() {
|
||||
return Optional.ofNullable(Cryptomator.class.getPackage().getImplementationVersion());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,6 +46,10 @@
|
||||
<Label GridPane.rowIndex="3" GridPane.columnIndex="0" fx:id="prefGvfsSchemeLabel" text="%settings.prefGvfsScheme.label" cacheShape="true" cache="true" />
|
||||
<ChoiceBox GridPane.rowIndex="3" GridPane.columnIndex="1" fx:id="prefGvfsScheme" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 4 -->
|
||||
<Label GridPane.rowIndex="4" GridPane.columnIndex="0" fx:id="debugModeLabel" text="%settings.debugMode.label" cacheShape="true" cache="true" />
|
||||
<CheckBox GridPane.rowIndex="4" GridPane.columnIndex="1" fx:id="debugModeCheckbox" cacheShape="true" cache="true" />
|
||||
|
||||
</children>
|
||||
</GridPane>
|
||||
<Label VBox.vgrow="NEVER" text="%settings.requiresRestartLabel" alignment="CENTER" cacheShape="true" cache="true" />
|
||||
|
||||
@@ -66,6 +66,7 @@ settings.checkForUpdates.label = Auf Updates prüfen
|
||||
settings.port.label = WebDAV Port *
|
||||
settings.port.prompt = 0 \= Automatisch wählen
|
||||
settings.useipv6.label = IPv6-Literal nutzen
|
||||
settings.debugMode.label= Debug Modus *
|
||||
settings.requiresRestartLabel = * benötigt Neustart von Cryptomator
|
||||
# tray icon
|
||||
tray.menu.open = Öffnen
|
||||
|
||||
@@ -102,6 +102,7 @@ settings.port.label=WebDAV Port *
|
||||
settings.port.prompt=0 = Choose automatically
|
||||
settings.useipv6.label=Use IPv6 literal
|
||||
settings.prefGvfsScheme.label=WebDAV scheme
|
||||
settings.debugMode.label=Debug mode *
|
||||
settings.requiresRestartLabel=* Cryptomator needs to restart
|
||||
|
||||
# tray icon
|
||||
|
||||
@@ -27,9 +27,13 @@
|
||||
</Appenders>
|
||||
|
||||
<Loggers>
|
||||
<!-- package-specific config: -->
|
||||
<Logger name="org.cryptomator" level="DEBUG" />
|
||||
<Logger name="org.eclipse.jetty.server.Server" level="DEBUG" />
|
||||
<!--
|
||||
= NOTE =
|
||||
All loggers below are set to info.
|
||||
This is required to allow changing the levels of the loggers programmatically.
|
||||
-->
|
||||
<Logger name="org.cryptomator" level="INFO" />
|
||||
<Logger name="org.eclipse.jetty.server.Server" level="INFO" />
|
||||
<Logger name="org.cryptomator.ui.model" level="INFO">
|
||||
<AppenderRef ref="UpgradeLog" />
|
||||
</Logger>
|
||||
|
||||
Reference in New Issue
Block a user