From a7dfe3619fc4aff77e06ff48ffd8502545d34005 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov Date: Sat, 25 Oct 2008 21:23:06 +0000 Subject: [PATCH] Provides optimizations to the keybindings with respect to execution time and garbage creation no matter how minor because the keybindings are used in MainFrame and ChatWindow which are in turn always in use. --- .../impl/gui/customcontrols/SIPCommFrame.java | 29 ++-- .../keybindings/KeybindingsActivator.java | 19 ++- .../keybindings/KeybindingsServiceImpl.java | 141 +++++++++--------- .../service/keybindings/KeybindingSet.java | 4 +- 4 files changed, 103 insertions(+), 90 deletions(-) diff --git a/src/net/java/sip/communicator/impl/gui/customcontrols/SIPCommFrame.java b/src/net/java/sip/communicator/impl/gui/customcontrols/SIPCommFrame.java index 0d92c1ec7..6974c4f92 100644 --- a/src/net/java/sip/communicator/impl/gui/customcontrols/SIPCommFrame.java +++ b/src/net/java/sip/communicator/impl/gui/customcontrols/SIPCommFrame.java @@ -8,15 +8,15 @@ import java.awt.*; import java.awt.event.*; +import java.util.*; import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.keybindings.*; import net.java.sip.communicator.service.configuration.*; import net.java.sip.communicator.util.*; -import net.java.sip.communicator.service.keybindings.*; -import java.util.*; /** * A custom frame that remembers its size and location and could have a @@ -79,6 +79,7 @@ public void actionPerformed(ActionEvent e) * Sets the input map to utilize a given category of keybindings. The frame * is updated to reflect the new bindings when they change. This replaces * any previous bindings that have been added. + * * @param category set of keybindings to be utilized */ protected void setKeybindingInput(KeybindingSet.Category category) @@ -91,17 +92,16 @@ protected void setKeybindingInput(KeybindingSet.Category category) } // Adds new bindings to input map - KeybindingsService service = GuiActivator.getKeybindingsService(); - this.bindings = service.getBindings(category); + this.bindings = + GuiActivator.getKeybindingsService().getBindings(category); - for (KeyStroke key : this.bindings.getBindings().keySet()) + for (Map.Entry key2action : this.bindings + .getBindings().entrySet()) { - String action = this.bindings.getBindings().get(key); - imap.put(key, action); + imap.put(key2action.getKey(), key2action.getValue()); } this.bindings.addObserver(this); - } /** @@ -382,18 +382,21 @@ private void resetInputMap() imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close"); } - // Listens for changes in binding sets so they can be reflected in the input - // map + /** + * Listens for changes in binding sets so they can be reflected in the input + * map + */ public void update(Observable obs, Object arg) { if (obs instanceof KeybindingSet) { KeybindingSet changedBindings = (KeybindingSet) obs; + resetInputMap(); - for (KeyStroke binding : changedBindings.getBindings().keySet()) + for (Map.Entry key2action : changedBindings + .getBindings().entrySet()) { - String action = changedBindings.getBindings().get(binding); - imap.put(binding, action); + imap.put(key2action.getKey(), key2action.getValue()); } } } diff --git a/src/net/java/sip/communicator/impl/keybindings/KeybindingsActivator.java b/src/net/java/sip/communicator/impl/keybindings/KeybindingsActivator.java index 4e6c62154..ed072ffa0 100644 --- a/src/net/java/sip/communicator/impl/keybindings/KeybindingsActivator.java +++ b/src/net/java/sip/communicator/impl/keybindings/KeybindingsActivator.java @@ -6,25 +6,27 @@ */ package net.java.sip.communicator.impl.keybindings; -import net.java.sip.communicator.service.keybindings.KeybindingsService; -import net.java.sip.communicator.util.Logger; +import net.java.sip.communicator.service.keybindings.*; +import net.java.sip.communicator.util.*; import org.osgi.framework.*; /** * Enabling and disabling osgi functionality for keybindings. + * * @author Damian Johnson */ public class KeybindingsActivator implements BundleActivator { private static final Logger logger = - Logger.getLogger(KeybindingsActivator.class); - + Logger.getLogger(KeybindingsActivator.class); + private KeybindingsServiceImpl keybindingsService = null; - + /** * Called when this bundle is started. + * * @param context The execution context of the bundle being started. */ public void start(BundleContext context) @@ -32,17 +34,18 @@ public void start(BundleContext context) if (this.keybindingsService == null) { logger.debug("Service Impl: " + getClass().getName() - + " [ STARTED ]"); + + " [ STARTED ]"); this.keybindingsService = new KeybindingsServiceImpl(); this.keybindingsService.start(context); context.registerService(KeybindingsService.class.getName(), - this.keybindingsService, null); + this.keybindingsService, null); } } /** * Called when this bundle is stopped so the Framework can perform the * bundle-specific activities necessary to stop the bundle. + * * @param context The execution context of the bundle being stopped. */ public void stop(BundleContext context) @@ -53,4 +56,4 @@ public void stop(BundleContext context) this.keybindingsService = null; } } -} \ No newline at end of file +} diff --git a/src/net/java/sip/communicator/impl/keybindings/KeybindingsServiceImpl.java b/src/net/java/sip/communicator/impl/keybindings/KeybindingsServiceImpl.java index 9e6315159..16e5f3eed 100644 --- a/src/net/java/sip/communicator/impl/keybindings/KeybindingsServiceImpl.java +++ b/src/net/java/sip/communicator/impl/keybindings/KeybindingsServiceImpl.java @@ -7,18 +7,18 @@ package net.java.sip.communicator.impl.keybindings; import java.io.*; -import java.text.ParseException; +import java.text.*; import java.util.*; -import javax.swing.KeyStroke; +import javax.swing.*; import org.osgi.framework.*; -import chooser.Persistence; +import chooser.*; -import net.java.sip.communicator.service.fileaccess.FileAccessService; +import net.java.sip.communicator.service.fileaccess.*; import net.java.sip.communicator.service.keybindings.*; -import net.java.sip.communicator.util.Logger; +import net.java.sip.communicator.util.*; /** * Service that concerns keybinding mappings used by various parts of the UI. @@ -31,83 +31,86 @@ * * Custom bindings attempt to be written again whenever they're changed if the * service is running. Each category of keybindings are stored in its own file. + * * @author Damian Johnson */ class KeybindingsServiceImpl implements KeybindingsService, Observer { private static final Logger logger = - Logger.getLogger(KeybindingsServiceImpl.class); - + Logger.getLogger(KeybindingsServiceImpl.class); + // Name of the relative directory that holds default bindings private static final String DEFAULT_KEYBINDING_DIR = - "/resources/config/defaultkeybindings"; - + "/resources/config/defaultkeybindings"; + // Name of the directory that holds custom bindings private static final String CUSTOM_KEYBINDING_DIR = "keybindings"; - + // Flag indicating if service is running private boolean isRunning = false; - + // Loaded keybinding mappings, maps to null if defaults failed to be loaded - private final HashMap bindings = - new HashMap (); - + private final HashMap bindings = + new HashMap(); + /** * Starts the KeybindingService, for each keybinding category retrieving the * default bindings then overwriting them with any custom bindings that can * be retrieved. This writes the merged copy back if it differs from the * custom bindings. This is a no-op if the service has already been started. + * * @param bc the currently valid OSGI bundle context. */ synchronized void start(BundleContext bc) { - if (this.isRunning) return; + if (this.isRunning) + return; for (KeybindingSet.Category category : KeybindingSet.Category.values()) { // Retrieves default bindings Persistence format = category.getFormat(); - LinkedHashMap defaultBindings; + LinkedHashMap defaultBindings; try { String defaultPath = - DEFAULT_KEYBINDING_DIR + "/" + category.getResource(); + DEFAULT_KEYBINDING_DIR + "/" + category.getResource(); InputStream in = getClass().getResourceAsStream(defaultPath); defaultBindings = format.load(in); } catch (IOException exc) { logger.error("default bindings set missing: " - + category.getResource(), exc); + + category.getResource(), exc); this.bindings.put(category, null); continue; } catch (ParseException exc) { logger.error("unable to parse default bindings set: " - + category.getResource(), exc); + + category.getResource(), exc); this.bindings.put(category, null); continue; } - + // Attempts to retrieve custom bindings String customPath = - CUSTOM_KEYBINDING_DIR + "/" + category.getResource(); + CUSTOM_KEYBINDING_DIR + "/" + category.getResource(); File customFile; try { ServiceReference faServiceReference = - bc.getServiceReference(FileAccessService.class - .getName()); + bc.getServiceReference(FileAccessService.class.getName()); FileAccessService faService = - (FileAccessService) bc.getService(faServiceReference); - + (FileAccessService) bc.getService(faServiceReference); + // Makes directory for custom bindings if it doesn't exist File customDir = - faService - .getPrivatePersistentDirectory(CUSTOM_KEYBINDING_DIR); - if (!customDir.exists()) customDir.mkdir(); - + faService + .getPrivatePersistentDirectory(CUSTOM_KEYBINDING_DIR); + if (!customDir.exists()) + customDir.mkdir(); + // Gets file access service to reference persistent storage // of the user customFile = faService.getPrivatePersistentFile(customPath); @@ -115,18 +118,17 @@ synchronized void start(BundleContext bc) catch (Exception exc) { String msg = - "unable to secure file for custom bindings (" - + customPath - + "), using defaults but won't be able to save changes"; + "unable to secure file for custom bindings (" + customPath + + "), using defaults but won't be able to save changes"; logger.error(msg, exc); KeybindingSetImpl newSet = - new KeybindingSetImpl(defaultBindings, category, null); + new KeybindingSetImpl(defaultBindings, category, null); this.bindings.put(category, newSet); newSet.addObserver(this); continue; } - - LinkedHashMap customBindings = null; + + LinkedHashMap customBindings = null; if (customFile.exists()) { try @@ -141,38 +143,40 @@ synchronized void start(BundleContext bc) // loading custom bindings } } - + // Merges custom bindings - LinkedHashMap merged = - new LinkedHashMap (); + LinkedHashMap merged = + new LinkedHashMap(); if (customBindings != null) { - LinkedHashMap customTmp = - new LinkedHashMap (customBindings); - - for (KeyStroke shortcut : defaultBindings.keySet()) + Map customTmp = + new LinkedHashMap(customBindings); + + for (Map.Entry shortcut2action : defaultBindings + .entrySet()) { - String action = defaultBindings.get(shortcut); - + String action = shortcut2action.getValue(); + if (customTmp.containsValue(action)) { KeyStroke custom = null; - for (KeyStroke customShortcut : customTmp.keySet()) + for (Map.Entry customShortcut2action : customTmp + .entrySet()) { - if (customTmp.get(customShortcut).equals(action)) + if (customShortcut2action.getValue().equals(action)) { - custom = customShortcut; + custom = customShortcut2action.getKey(); break; } } - + assert custom != null; customTmp.remove(custom); merged.put(custom, action); } else { - merged.put(shortcut, action); + merged.put(shortcut2action.getKey(), action); } } } @@ -180,7 +184,7 @@ synchronized void start(BundleContext bc) { merged = defaultBindings; } - + // Writes merged result if (!merged.equals(customBindings)) { @@ -193,25 +197,26 @@ synchronized void start(BundleContext bc) catch (IOException exc) { logger.error("unable to write to: " - + customFile.getAbsolutePath(), exc); + + customFile.getAbsolutePath(), exc); } } - + KeybindingSetImpl newSet = - new KeybindingSetImpl(merged, category, customFile); + new KeybindingSetImpl(merged, category, customFile); this.bindings.put(category, newSet); newSet.addObserver(this); } - + this.isRunning = true; } - + /** * Invalidates references to custom bindings, preventing further writes. */ synchronized void stop() { - if (!this.isRunning) return; + if (!this.isRunning) + return; for (KeybindingSetImpl bindingSet : this.bindings.values()) { bindingSet.invalidate(); @@ -219,32 +224,34 @@ synchronized void stop() this.bindings.clear(); this.isRunning = false; } - + /** * Provides the bindings associated with a given category. This may be null * if the default bindings failed to be loaded. + * * @param category segment of the UI for which bindings should be retrieved * @return mappings of keystrokes to the string representation of their * actions * @throws UnsupportedOperationException if the service isn't running */ public synchronized KeybindingSet getBindings( - KeybindingSet.Category category) + KeybindingSet.Category category) { - if (!this.isRunning) throw new UnsupportedOperationException(); - + if (!this.isRunning) + throw new UnsupportedOperationException(); + // Started services should have all categories assert this.bindings.containsKey(category); return this.bindings.get(category); } - + // Listens for changes in binding sets so changes can be written public void update(Observable obs, Object arg) { if (obs instanceof KeybindingSetImpl) { KeybindingSetImpl changedBindings = (KeybindingSetImpl) obs; - + // Attempts to avoid lock if unwritable (this works since bindings // can't become re-writable) if (changedBindings.isWritable()) @@ -255,24 +262,24 @@ public void update(Observable obs, Object arg) { // Writes new bindings to custom file File customFile = changedBindings.getCustomFile(); - + try { FileOutputStream out = - new FileOutputStream(customFile); + new FileOutputStream(customFile); Persistence format = - changedBindings.getCategory().getFormat(); + changedBindings.getCategory().getFormat(); format.save(out, changedBindings.getBindings()); out.close(); } catch (IOException exc) { logger.error("unable to write to: " - + customFile.getAbsolutePath(), exc); + + customFile.getAbsolutePath(), exc); } } } } } } -} \ No newline at end of file +} diff --git a/src/net/java/sip/communicator/service/keybindings/KeybindingSet.java b/src/net/java/sip/communicator/service/keybindings/KeybindingSet.java index 0df1d1396..9174f9f21 100644 --- a/src/net/java/sip/communicator/service/keybindings/KeybindingSet.java +++ b/src/net/java/sip/communicator/service/keybindings/KeybindingSet.java @@ -8,9 +8,9 @@ import java.util.*; -import javax.swing.KeyStroke; +import javax.swing.*; -import chooser.Persistence; +import chooser.*; /** * Wrapper for keybinding sets. Observers are notified when there's a change.