From cf2e7ec472459b621f9d75828aa037300fb499c1 Mon Sep 17 00:00:00 2001 From: Joacim Breiler Date: Sun, 26 Feb 2023 15:43:06 +0100 Subject: [PATCH] Fix problem with the shortcut service that only read default key mappings. It will now listen to the key map settings and update a local cache. --- .../ContinuousActionShortcutListener.java | 12 +- .../ugs/nbp/lib/services/ShortcutService.java | 117 +++++++++++++++--- 2 files changed, 101 insertions(+), 28 deletions(-) diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/services/ContinuousActionShortcutListener.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/services/ContinuousActionShortcutListener.java index 1055f7d6f2..5ec88324ab 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/services/ContinuousActionShortcutListener.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/services/ContinuousActionShortcutListener.java @@ -91,17 +91,13 @@ protected void registerListener() { private String getKeyAsString(KeyEvent e) { KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiersEx()); - return Utilities.keyToString(keyStroke, false); + return Utilities.keyToString(keyStroke, true); } private Optional getContinuousActionByShortcut(String keyAsString) { - Optional actionId = shortcutService.getActionIdForShortcut(keyAsString); - if (!actionId.isPresent()) { - return Optional.empty(); - } - - Optional actionById = actionRegistrationService.getActionById(actionId.get()); - return actionById.filter(action -> actionById.get().getAction() instanceof ContinuousAction); + return shortcutService.getActionIdForShortcut(keyAsString) + .flatMap(actionRegistrationService::getActionById) + .filter(action -> action.getAction() instanceof ContinuousAction); } @Override diff --git a/ugs-platform/ugs-platform-ugslib/src/main/java/com/willwinder/ugs/nbp/lib/services/ShortcutService.java b/ugs-platform/ugs-platform-ugslib/src/main/java/com/willwinder/ugs/nbp/lib/services/ShortcutService.java index 520510ecf9..fab6a84c3f 100644 --- a/ugs-platform/ugs-platform-ugslib/src/main/java/com/willwinder/ugs/nbp/lib/services/ShortcutService.java +++ b/ugs-platform/ugs-platform-ugslib/src/main/java/com/willwinder/ugs/nbp/lib/services/ShortcutService.java @@ -18,31 +18,49 @@ This file is part of Universal Gcode Sender (UGS). */ package com.willwinder.ugs.nbp.lib.services; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import org.apache.commons.lang3.StringUtils; -import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileAttributeEvent; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileRenameEvent; import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataFolder; +import org.openide.loaders.DataShadow; +import org.openide.loaders.InstanceDataObject; import org.openide.util.lookup.ServiceProvider; +import javax.swing.KeyStroke; +import java.util.Collections; +import java.util.Map; import java.util.Optional; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; /** * A service that can be used to find actions using their shortcut key mapping - * in the format defined in {@link org.openide.util.Utilities#stringToKey(String)} + * in the format defined in {@link org.openide.util.Utilities#keyToString(KeyStroke, boolean)} + * (remember to use portable format) * * @author Joacim Breiler */ @ServiceProvider(service = ShortcutService.class) -public class ShortcutService { +public class ShortcutService implements FileChangeListener { + + private static final Logger LOGGER = Logger.getLogger(ShortcutService.class.getSimpleName()); /** * Cache the found shortcuts to speed things up using the shortcut as key and the actionId as value. */ - private final Cache shortcutCache = CacheBuilder.newBuilder() - .expireAfterWrite(20, TimeUnit.SECONDS) - .build(); + private final Map shortcutMap = new ConcurrentHashMap<>(); + + /** + * The current keymap used + */ + private String currentKeymap; + + public ShortcutService() { + reloadShortcuts(); + FileUtil.getSystemConfigRoot().addRecursiveListener(this); + } /** * Finds a shortcut in format defined in {@link org.openide.util.Utilities#stringToKey(String)} @@ -51,19 +69,78 @@ public class ShortcutService { * @return a shortcut reference */ public Optional getActionIdForShortcut(String keyAsString) { - String actionId = shortcutCache.getIfPresent(keyAsString); - if (StringUtils.isNotEmpty(actionId)) { - return Optional.of(actionId); + return Optional.ofNullable(shortcutMap.get(keyAsString)); + } + + + @Override + public void fileFolderCreated(FileEvent fileEvent) { + // Not used + } + + @Override + public void fileDataCreated(FileEvent fileEvent) { + if (!fileEvent.getFile().getPath().startsWith(getKeymapConfigRoot())) { + return; + } + + DataFolder folder = DataFolder.findFolder(FileUtil.getSystemConfigFile(getKeymapConfigRoot())); + String keyAsString = fileEvent.getFile().getName(); + Collections.list(folder.children()).stream() + .filter(DataShadow.class::isInstance).map(DataShadow.class::cast) + .filter(f -> f.getName().equals(keyAsString)) + .findFirst() + .ifPresent(ShortcutService.this::setShortcut); + } + + @Override + public void fileChanged(FileEvent fileEvent) { + fileDataCreated(fileEvent); + } + + @Override + public void fileDeleted(FileEvent fileEvent) { + if (!fileEvent.getFile().getPath().startsWith("Keymaps/" + currentKeymap + "/")) { + return; } - FileObject rootFileObject = FileUtil.getConfigFile("Shortcuts/" + keyAsString + ".shadow"); - if (rootFileObject == null) { - return Optional.empty(); + shortcutMap.remove(fileEvent.getFile().getName()); + LOGGER.fine(() -> String.format("Removed shortcut: %s", fileEvent.getFile().getName())); + } + + @Override + public void fileRenamed(FileRenameEvent fileRenameEvent) { + // Not used + } + + @Override + public void fileAttributeChanged(FileAttributeEvent fileAttributeEvent) { + if (!fileAttributeEvent.getFile().getPath().equals("Keymaps") && fileAttributeEvent.getName().equals("currentKeymap")) { + return; } - String name = rootFileObject.getName(); - actionId = rootFileObject.getAttribute("originalFile").toString(); - shortcutCache.put(name, actionId); - return Optional.of(actionId); + reloadShortcuts(); + } + + private String getKeymapConfigRoot() { + return "Keymaps/" + currentKeymap; + } + + private void setShortcut(DataShadow file) { + InstanceDataObject cookie = file.getCookie(InstanceDataObject.class); + String actionId = cookie.getPrimaryFile().getPath(); + shortcutMap.put(file.getName(), actionId); + LOGGER.fine(() -> String.format("Set shortcut: %s -> %s", file.getName(), actionId)); + } + + private void reloadShortcuts() { + currentKeymap = FileUtil.getConfigFile("Keymaps").getAttribute("currentKeymap").toString(); + LOGGER.fine(() -> String.format("Reloading shortcuts using keymap %s", currentKeymap)); + + shortcutMap.clear(); + DataFolder folder = DataFolder.findFolder(FileUtil.getSystemConfigFile(getKeymapConfigRoot())); + Collections.list(folder.children()).stream() + .filter(DataShadow.class::isInstance).map(DataShadow.class::cast) + .forEach(this::setShortcut); } }