]> source.dussan.org Git - vaadin-framework.git/commitdiff
added initial support for keyboard shortcuts. Now only Panel supports them on server...
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Wed, 29 Aug 2007 12:37:25 +0000 (12:37 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Wed, 29 Aug 2007 12:37:25 +0000 (12:37 +0000)
svn changeset:2150/svn branch:trunk

src/com/itmill/toolkit/demo/KeyboardShortcut.java
src/com/itmill/toolkit/terminal/gwt/client/UIDL.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IShortcutAction.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ShortcutKeyCombination.java [new file with mode: 0644]
src/com/itmill/toolkit/ui/Button.java
src/com/itmill/toolkit/ui/Panel.java

index 4bb1e6cff88de75adc7fd46b5fffed5db81345b7..76a3ba332179e7f564b1477dce07cb5a904e70eb 100644 (file)
@@ -12,7 +12,7 @@ import com.itmill.toolkit.ui.*;
  * 
  */
 public class KeyboardShortcut extends com.itmill.toolkit.Application implements
-               Handler {
+Handler {
        private Window main;
 
        private Button a;
@@ -25,6 +25,23 @@ public class KeyboardShortcut extends com.itmill.toolkit.Application implements
 
        private AbstractField f;
 
+       Action[] actions = new Action[] {
+                       new ShortcutAction("Button a action",
+                                       ShortcutAction.KeyCode.A, new int[] {
+                                       ShortcutAction.ModifierKey.CTRL,
+                                       ShortcutAction.ModifierKey.SHIFT }),
+                       new ShortcutAction("Button z action",
+                                       ShortcutAction.KeyCode.Z, new int[] {
+                                       ShortcutAction.ModifierKey.CTRL,
+                                       ShortcutAction.ModifierKey.SHIFT }),
+                       new ShortcutAction("Button x action",
+                                       ShortcutAction.KeyCode.X, new int[] {
+                                       ShortcutAction.ModifierKey.CTRL,
+                                       ShortcutAction.ModifierKey.SHIFT }),
+                       new ShortcutAction("Restart ",
+                               ShortcutAction.KeyCode.ESCAPE, null)
+       };
+
        public void init() {
 
                main = new Window("Keyboard shortcuts demo");
@@ -32,32 +49,29 @@ public class KeyboardShortcut extends com.itmill.toolkit.Application implements
                setTheme("corporate");
 
                main
-                               .addComponent(new Label(
-                                               "<h3>Test application for shortcut actions</h3>"
-                                                               + "<p><b>Notes:</b><br />"
-                                                               + "<b>This feature is under development and it's API may still change.</b><br />"
-                                                               + "<b>If events do not work, <b>set focus to Textfield first.</b><br />"
-                                                               + "<b>Browsers may have reserved the keyboard combinations used in "
-                                                               + "this demo for other purposes.</b><br /></p>",
-                                               Label.CONTENT_RAW));
+               .addComponent(new Label(
+                               "<h3>Test application for shortcut actions</h3>"
+                               + "<p><b>Notes:</b><br />"
+                               + "<b>This feature is under development and it's API may still change.</b><br />"
+                               + "<b>If events do not work, <b>set focus to Textfield first.</b><br />"
+                               + "<b>Browsers may have reserved the keyboard combinations used in "
+                               + "this demo for other purposes.</b><br /></p>",
+                               Label.CONTENT_XHTML));
                main
-                               .addComponent(new Label(
-                                               "ESC restarts program, ctrl-shift-a clicks A button, "
-                                                               + "ctrl-shift-z clicks Z button, ctrl-shift-x clicks X button"));
+               .addComponent(new Label(
+                               "ESC restarts program, ctrl-shift-a clicks A button, "
+                               + "ctrl-shift-z clicks Z button, ctrl-shift-x clicks X button"));
 
                // Restart button
                close = new Button("restart", this, "close");
-               close.addActionHandler(this);
+
                main.addComponent(close);
 
                a = new Button("Button A", this, "buttonAHandler");
-               a.addActionHandler(this);
 
                z = new Button("Button Z", this, "buttonZHandler");
-               z.addActionHandler(this);
 
                x = new Button("Button X", this, "buttonXHandler");
-               x.addActionHandler(this);
 
                f = new TextField("Textfield");
 
@@ -66,43 +80,23 @@ public class KeyboardShortcut extends com.itmill.toolkit.Application implements
                main.addComponent(x);
                main.addComponent(f);
 
+               main.addActionHandler(this);
+
                f.focus();
        }
 
        public Action[] getActions(Object target, Object sender) {
-               Action[] actions = new Action[1];
-               if (sender == a) {
-                       actions[0] = (Action) new ShortcutAction("Button a action",
-                                       ShortcutAction.KeyCode.A, new int[] {
-                                                       ShortcutAction.ModifierKey.CTRL,
-                                                       ShortcutAction.ModifierKey.SHIFT });
-               } else if (sender == z) {
-                       actions[0] = (Action) (new ShortcutAction("Button z action",
-                                       ShortcutAction.KeyCode.Z, new int[] {
-                                                       ShortcutAction.ModifierKey.CTRL,
-                                                       ShortcutAction.ModifierKey.SHIFT }));
-
-               } else if (sender == x) {
-                       actions[0] = (Action) new ShortcutAction("Button x action",
-                                       ShortcutAction.KeyCode.X, new int[] {
-                                                       ShortcutAction.ModifierKey.CTRL,
-                                                       ShortcutAction.ModifierKey.SHIFT });
-               } else {
-                       // restart button
-                       actions[0] = new ShortcutAction("Restart ",
-                                       ShortcutAction.KeyCode.ESCAPE, null);
-               }
                return actions;
        }
 
        public void handleAction(Action action, Object sender, Object target) {
-               if (target == a)
+               if (action == actions[0])
                        this.buttonAHandler();
-               if (target == z)
+               if (action == actions[1])
                        this.buttonZHandler();
-               if (target == x)
+               if (action == actions[2])
                        this.buttonXHandler();
-               if (target == close)
+               if (action == actions[3])
                        this.close();
        }
 
index 4cffdbcd35dd5c3f8f2d97e45e77369612396377..18ef9306a9c8f0653302a6d23ff8a63124693911 100644 (file)
@@ -93,6 +93,14 @@ public class UIDL {
                return s;
        }
 
+       public int[] getIntArrayAttribute(String name) {
+               JSONArray a = (JSONArray) ((JSONObject) json.get(1)).get(name);
+               int[] s = new int[a.size()];
+               for (int i = 0; i < a.size(); i++)
+                       s[i] = Integer.parseInt(((JSONString) a.get(i)).stringValue());
+               return s;
+       }
+
        public HashSet getStringArrayAttributeAsSet(String string) {
                JSONArray a = getArrayVariable(string);
                HashSet s = new HashSet();
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IShortcutAction.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IShortcutAction.java
new file mode 100644 (file)
index 0000000..73a1e7c
--- /dev/null
@@ -0,0 +1,27 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+public class IShortcutAction {
+
+       private ShortcutKeyCombination sc;
+       private String caption;
+       private String key;
+
+       public IShortcutAction(String key, ShortcutKeyCombination sc, String caption) {
+               this.sc = sc;
+               this.key = key;
+               this.caption = caption;
+       }
+       
+       public ShortcutKeyCombination getShortcutCombination() {
+               return sc;
+       }
+       
+       public String getCaption() {
+               return caption;
+       }
+       
+       public String getKey() {
+               return key;
+       }
+
+}
index 099ed630c5c6b3f57edf5e6b7d1052dabbb57310..445eb4b9670c21c26d9d75fb2d3beed2ccb79b86 100644 (file)
@@ -1,8 +1,11 @@
 package com.itmill.toolkit.terminal.gwt.client.ui;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
 
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.user.client.ui.SimplePanel;
@@ -19,13 +22,25 @@ public class IView extends SimplePanel implements Paintable {
        
        private HashSet subWindows = new HashSet();
 
+       private ArrayList actions = new ArrayList();
 
+       private ApplicationConnection client;
+
+       private String id;
+       
+       public IView() {
+               super();
+               sinkEvents(Event.KEYEVENTS);
+       }
        
        public String getTheme() {
                return theme;
        }
        
        public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+               this.client = client;
+               
+               this.id = uidl.getId();
                
                // Start drawing from scratch
                clear();
@@ -76,6 +91,8 @@ public class IView extends SimplePanel implements Paintable {
                                        subWindows.add(w);
                                }
                                ((Paintable)w).updateFromUIDL(childUidl, client);
+                       } else if ("actions".equals(childUidl.getTag())) {
+                               updateActionMap(childUidl);
                        }
                }
                
@@ -88,4 +105,49 @@ public class IView extends SimplePanel implements Paintable {
                }
        }
 
+       private void updateActionMap(UIDL c) {
+               actions.clear();
+               Iterator it = c.getChildIterator();
+               while(it.hasNext()) {
+                       UIDL action = (UIDL) it.next();
+                       
+                       int[] modifiers = null;
+                       if(action.hasAttribute("mk"))
+                               modifiers = action.getIntArrayAttribute("mk");
+                       
+                       ShortcutKeyCombination kc = new ShortcutKeyCombination(
+                                       action.getIntAttribute("kc"),
+                                       modifiers);
+                       String key = action.getStringAttribute("key");
+                       String caption = action.getStringAttribute("caption");
+                       actions.add(new IShortcutAction(key,kc, caption));
+               }
+       }
+
+       public void onBrowserEvent(Event event) {
+               if(DOM.eventGetType(event) == Event.ONKEYDOWN) {
+                       handleKeyEvent(event);
+               }
+               super.onBrowserEvent(event);
+       }
+
+       private void handleKeyEvent(Event event) {
+               client.console.log("keyEvent");
+               
+               ShortcutKeyCombination kc = new ShortcutKeyCombination();
+               kc.altKey = DOM.eventGetAltKey(event);
+               kc.ctrlKey = DOM.eventGetCtrlKey(event);
+               kc.shiftKey = DOM.eventGetShiftKey(event);
+               kc.keyCode = DOM.eventGetKeyCode(event);
+               Iterator it = actions.iterator();
+               while(it.hasNext()) {
+                       IShortcutAction a = (IShortcutAction) it.next();
+                       if(a.getShortcutCombination().equals(kc)) {
+                               client.updateVariable(id, "action", a.getKey(), true);
+                       }
+               }
+       }
+       
 }
+
+
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ShortcutKeyCombination.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ShortcutKeyCombination.java
new file mode 100644 (file)
index 0000000..2732859
--- /dev/null
@@ -0,0 +1,49 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+public class ShortcutKeyCombination {
+       
+       public static final int SHIFT = 16;
+       public static final int CTRL = 17;
+       public static final int ALT = 18;
+       
+       
+       
+       int keyCode = 0;
+       boolean altKey = false;
+       boolean ctrlKey = false;
+       boolean shiftKey = false;
+       boolean metaKey = false;
+       
+       public ShortcutKeyCombination() {
+       }
+       
+       ShortcutKeyCombination(int kc, int[] modifiers) {
+               keyCode = kc;
+               if(modifiers != null) {
+                       for (int i = 0; i < modifiers.length; i++) {
+                               switch (modifiers[i]) {
+                               case ALT:
+                                       altKey = true;
+                                       break;
+                               case CTRL:
+                                       ctrlKey = true;
+                                       break;
+                               case SHIFT:
+                                       shiftKey = true;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+       }
+       
+       public boolean equals(ShortcutKeyCombination other) {
+               if( this.keyCode == other.keyCode &&
+                               this.altKey == other.altKey &&
+                               this.ctrlKey == other.ctrlKey &&
+                               this.shiftKey == other.shiftKey)
+                       return true;
+               return false;
+       }
+}
\ No newline at end of file
index b15d3b2da35edd1a95cdedf158ef77d2c2b37f04..8968c229f2021bcf691e06fc127c2c54613dbb48 100644 (file)
@@ -52,17 +52,12 @@ import com.itmill.toolkit.terminal.PaintTarget;
  * @VERSION@
  * @since 3.0
  */
-public class Button extends AbstractField implements Action.Container {
+public class Button extends AbstractField {
 
        /* Private members ************************************************* */
 
        boolean switchMode = false;
 
-       /** List of action handlers */
-       private LinkedList actionHandlers = null;
-
-       /** Action mapper */
-       private KeyMapper actionMapper = null;
 
        /**
         * Creates a new push button. The value of the push button is allways false
@@ -176,44 +171,6 @@ public class Button extends AbstractField implements Action.Container {
                }
                target.addVariable(this, "state", state);
 
-               // Actions
-               if (actionHandlers != null) {
-                       Set actionSet = new LinkedHashSet();
-                       for (Iterator ahi = actionHandlers.iterator(); ahi.hasNext();) {
-                               Action[] aa = ((Action.Handler) ahi.next()).getActions(this,
-                                               this);
-                               if (aa != null)
-                                       for (int ai = 0; ai < aa.length; ai++) {
-                                               actionSet.add(aa[ai]);
-                                       }
-                       }
-
-                       target.startTag("actions");
-                       target.addVariable(this, "action", "");
-                       for (Iterator i = actionSet.iterator(); i.hasNext();) {
-                               try {
-                                       ShortcutAction a = (ShortcutAction) i.next();
-                                       target.startTag("action");
-                                       if (a.getCaption() != null)
-                                               target.addAttribute("caption", a.getCaption());
-                                       if (a.getIcon() != null)
-                                               target.addAttribute("icon", a.getIcon());
-                                       target.addAttribute("key", actionMapper.key(a));
-                                       target.addAttribute("keycode", a.getKeyCode());
-                                       if (a.getModifiers() != null) {
-                                               int[] modifiers = a.getModifiers();
-                                               target.addAttribute("modifiers", modifiers.length);
-                                               for (int j = 0; j < modifiers.length; j++) {
-                                                       target.addAttribute("modifier" + j, modifiers[j]);
-                                               }
-                                       }
-                                       target.endTag("action");
-                               } catch (Exception e) {
-                                       // ignore non-shorcut actions for button
-                               }
-                       }
-                       target.endTag("actions");
-               }
        }
 
        /**
@@ -249,21 +206,6 @@ public class Button extends AbstractField implements Action.Container {
                                        setValue(new Boolean(false));
                        }
                }
-               // Actions
-               // TODO this is pretty much copy-pasted from tree, may be simplified
-               if (variables.containsKey("action")) {
-
-                       StringTokenizer st = new StringTokenizer((String) variables
-                                       .get("action"), ",");
-                       if (st.countTokens() == 2) {
-                               Action action = (Action) actionMapper.get(st.nextToken());
-                               if (action != null && actionHandlers != null)
-                                       for (Iterator i = actionHandlers.iterator(); i.hasNext();)
-                                               ((Action.Handler) i.next()).handleAction(action, this,
-                                                               this);
-                       }
-               }
-
        }
 
        /**
@@ -403,44 +345,4 @@ public class Button extends AbstractField implements Action.Container {
                fireEvent(new Button.ClickEvent(this));
        }
 
-       /**
-        * Adds an action handler.
-        * 
-        * @see com.itmill.toolkit.event.Action.Container#addActionHandler(Action.Handler)
-        */
-       public void addActionHandler(Action.Handler actionHandler) {
-
-               if (actionHandler != null) {
-
-                       if (actionHandlers == null) {
-                               actionHandlers = new LinkedList();
-                               actionMapper = new KeyMapper();
-                       }
-
-                       if (!actionHandlers.contains(actionHandler)) {
-                               actionHandlers.add(actionHandler);
-                               requestRepaint();
-                       }
-               }
-       }
-
-       /**
-        * Removes an action handler.
-        * 
-        * @see com.itmill.toolkit.event.Action.Container#removeActionHandler(Action.Handler)
-        */
-       public void removeActionHandler(Action.Handler actionHandler) {
-
-               if (actionHandlers != null && actionHandlers.contains(actionHandler)) {
-
-                       actionHandlers.remove(actionHandler);
-
-                       if (actionHandlers.isEmpty()) {
-                               actionHandlers = null;
-                               actionMapper = null;
-                       }
-
-                       requestRepaint();
-               }
-       }
 }
index 6d0321f10b47c85ec4db4e2df62e1ceea9dcf66e..f55a7e3896d56492c81ec1af815e8f2d2af7f052 100644 (file)
 package com.itmill.toolkit.ui;
 
 import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
 
+import com.itmill.toolkit.event.Action;
+import com.itmill.toolkit.event.ShortcutAction;
+import com.itmill.toolkit.event.Action.Handler;
+import com.itmill.toolkit.terminal.KeyMapper;
 import com.itmill.toolkit.terminal.PaintException;
 import com.itmill.toolkit.terminal.PaintTarget;
 import com.itmill.toolkit.terminal.Scrollable;
@@ -46,7 +54,7 @@ import com.itmill.toolkit.terminal.Sizeable;
  */
 public class Panel extends AbstractComponentContainer implements Sizeable,
                Scrollable, ComponentContainer.ComponentAttachListener,
-               ComponentContainer.ComponentDetachListener {
+               ComponentContainer.ComponentDetachListener, Action.Container {
 
        /**
         * Layout of the panel.
@@ -87,6 +95,12 @@ public class Panel extends AbstractComponentContainer implements Sizeable,
         * Scrolling mode.
         */
        private boolean scrollable = false;
+       
+       /** List of action handlers */
+       private LinkedList actionHandlers = null;
+
+       /** Action mapper */
+       private KeyMapper actionMapper = null;
 
        /**
         * Creates a new empty panel. Ordered layout is used.
@@ -193,6 +207,41 @@ public class Panel extends AbstractComponentContainer implements Sizeable,
                        target.addVariable(this, "scrollleft", getScrollOffsetX());
                        target.addVariable(this, "scrolldown", getScrollOffsetY());
                }
+               
+
+               if (actionHandlers != null && !actionHandlers.isEmpty()) {
+                       target.addVariable(this, "action", "");
+                       target.startTag("actions");
+
+                       for (Iterator ahi = actionHandlers.iterator(); ahi.hasNext();) {
+                               Action[] aa = ((Action.Handler) ahi.next()).getActions(null, this);
+                               if (aa != null) {
+                                       for (int ai = 0; ai < aa.length; ai++) {
+                                               Action a = aa[ai];
+                                               target.startTag("action");
+                                               String akey = actionMapper.key(aa[ai]);
+                                               target.addAttribute("key", akey);
+                                               if (a.getCaption() != null)
+                                                       target.addAttribute("caption", a.getCaption());
+                                               if (a.getIcon() != null)
+                                                       target.addAttribute("icon", a.getIcon());
+                                               if (a instanceof ShortcutAction) {
+                                                       ShortcutAction sa = (ShortcutAction) a;
+                                                       target.addAttribute("kc", sa.getKeyCode());
+                                                       int[] modifiers = sa.getModifiers();
+                                                       if(modifiers != null) {
+                                                               String[] smodifiers = new String[modifiers.length];
+                                                               for (int i = 0; i < modifiers.length; i++)
+                                                                       smodifiers[i] = String.valueOf(modifiers[i]);
+                                                               target.addAttribute("mk", smodifiers);
+                                                       }
+                                               }
+                                               target.endTag("action");
+                                       }
+                               }
+                       }
+                       target.endTag("actions");
+               }
        }
 
        /**
@@ -312,6 +361,17 @@ public class Panel extends AbstractComponentContainer implements Sizeable,
                        setScrollOffsetX(newScrollX.intValue());
                if (newScrollY != null && newScrollY.intValue() != getScrollOffsetY())
                        setScrollOffsetY(newScrollY.intValue());
+               
+               // Actions
+               if (variables.containsKey("action")) {
+                       String key = (String) variables.get("action");
+                       Action action = (Action) actionMapper.get(key);
+                       if (action != null && actionHandlers != null)
+                               for (Iterator i = actionHandlers.iterator(); i.hasNext();)
+                                       ((Action.Handler) i.next()).handleAction(action, this,
+                                                       this);
+               }
+
        }
 
        /**
@@ -454,4 +514,40 @@ public class Panel extends AbstractComponentContainer implements Sizeable,
                layout.removeAllComponents();
        }
 
+       public void addActionHandler(Handler actionHandler) {
+               if (actionHandler != null) {
+
+                       if (actionHandlers == null) {
+                               actionHandlers = new LinkedList();
+                               actionMapper = new KeyMapper();
+                       }
+
+                       if (!actionHandlers.contains(actionHandler)) {
+                               actionHandlers.add(actionHandler);
+                               requestRepaint();
+                       }
+               }
+               
+       }
+
+       /**
+        * Removes an action handler.
+        * 
+        * @see com.itmill.toolkit.event.Action.Container#removeActionHandler(Action.Handler)
+        */
+       public void removeActionHandler(Action.Handler actionHandler) {
+
+               if (actionHandlers != null && actionHandlers.contains(actionHandler)) {
+
+                       actionHandlers.remove(actionHandler);
+
+                       if (actionHandlers.isEmpty()) {
+                               actionHandlers = null;
+                               actionMapper = null;
+                       }
+
+                       requestRepaint();
+               }
+       }
+
 }