I added an interesting hack to JComponent.processKeyBinding(). I now store the action command (from the InputMap) with which an Actions is going to be called in the Action instance as undocumented property __command__.

This allows for an optimization in the UI classes. Usually we have a couple of Action instances, each one handles one InputMap binding. The design of the InputMap/ActionMap is a little unfortunate, because the Action doesn't know for which InputMap binding it is called. This is why we need many instances of Action to do the keyboard work. Now if I store the action command in the Action before calling its actionPerformed() method, the Action can determine which keybinding is activated and execute different methods, which allows to have only one Action instance to do the work for all InputMap bindings for one type of component (the one instance is ususally shared between all components of that type, via a UI ActionMap). This should improve startup time of Swing significantly, when we changed all the UI classes to use this.

I think Sun has seen similar problems. AFAICS they use a LazyActionMap which presumably defers creation of the ActionMap to later when it is really used. I don't think we need to do this when we create only one Action instance per UI class. It only makes sense when a whole bunch of Action instances has to be created.

Here is a plan for how to handle Actions in UI classes:
- All the private Actions in a given UI should be crunched into one Action which multiplexes between different methods depending on the __command__ property. - For public and protected Action classes (there are a couple) we should also do this, and use one private Action class for everything, and let the public/protected classes delegate to this private class for compatibility.

2006-07-26  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/JComponent.java
        (processKeyBinding): Store the action command as property
        in the Action instance that we call. This allows for
        improvement on the side of the Action.


/Roman
Index: javax/swing/JComponent.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JComponent.java,v
retrieving revision 1.140
diff -u -1 -2 -r1.140 JComponent.java
--- javax/swing/JComponent.java	19 Jul 2006 19:37:18 -0000	1.140
+++ javax/swing/JComponent.java	26 Jul 2006 09:32:24 -0000
@@ -2572,38 +2572,55 @@
     if (KeyboardManager.getManager().processKeyStroke(current, keyStroke, e))
       e.consume();
   }
 
   protected boolean processKeyBinding(KeyStroke ks,
                                       KeyEvent e,
                                       int condition,
                                       boolean pressed)
   { 
     if (isEnabled())
       {
         Action act = null;
+        Object cmd = null;
         InputMap map = getInputMap(condition);
         if (map != null)
           {
-            Object cmd = map.get(ks);
+            cmd = map.get(ks);
             if (cmd != null)
               {
                 if (cmd instanceof ActionListenerProxy)
                   act = (Action) cmd;
                 else 
                   act = (Action) getActionMap().get(cmd);
               }
           }
         if (act != null && act.isEnabled())
-          return SwingUtilities.notifyAction(act, ks, e, this, e.getModifiers());
+          {
+            // Need to synchronize here so we don't get in trouble with
+            // our __command__ hack.
+            synchronized (act)
+              {
+                // We add the command as value to the action, so that
+                // the action can later determine the command with which it
+                // was called. This is undocumented, but shouldn't affect
+                // compatibility. It allows us to use only one Action instance
+                // to do the work for all components of one type, instead of
+                // having loads of small Actions. This effectivly saves startup
+                // time of Swing.
+                act.putValue("__command__", cmd);
+                return SwingUtilities.notifyAction(act, ks, e, this,
+                                                   e.getModifiers());
+              }
+          }
       }
     return false;
   }
   
   /**
    * Remove a keyboard action registry.
    *
    * @param aKeyStroke The keystroke to unregister
    *
    * @see #registerKeyboardAction(ActionListener, KeyStroke, int)
    * @see #getConditionForKeyStroke
    * @see #resetKeyboardActions

Reply via email to