Change-Id: I1bc200afa9f4a4f3c5e469eb0b2f93278cca97a7tags/7.0.0.beta3
@@ -0,0 +1,108 @@ | |||
/* | |||
* Copyright 2011 Vaadin Ltd. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||
* use this file except in compliance with the License. You may obtain a copy of | |||
* the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
* License for the specific language governing permissions and limitations under | |||
* the License. | |||
*/ | |||
package com.vaadin.client.ui; | |||
import com.vaadin.client.ApplicationConnection; | |||
import com.vaadin.server.KeyMapper; | |||
public class ShortcutAction { | |||
private final ShortcutKeyCombination sc; | |||
private final String caption; | |||
private final String key; | |||
private String targetCID; | |||
private String targetAction; | |||
/** | |||
* Constructor | |||
* | |||
* @param key | |||
* The @link {@link KeyMapper} key of the action. | |||
* @param sc | |||
* The key combination that triggers the action | |||
* @param caption | |||
* The caption of the action | |||
*/ | |||
public ShortcutAction(String key, ShortcutKeyCombination sc, String caption) { | |||
this(key, sc, caption, null, null); | |||
} | |||
/** | |||
* Constructor | |||
* | |||
* @param key | |||
* The @link {@link KeyMapper} key of the action. | |||
* @param sc | |||
* The key combination that triggers the action | |||
* @param caption | |||
* The caption of the action | |||
* @param targetPID | |||
* The pid of the component the action is targeting. We use the | |||
* pid, instead of the actual Paintable here, so we can delay the | |||
* fetching of the Paintable in cases where the Paintable does | |||
* not yet exist when the action is painted. | |||
* @param targetAction | |||
* The target string of the action. The target string is given to | |||
* the targeted Paintable if the paintable implements the | |||
* {@link ShortcutActionTarget} interface. | |||
*/ | |||
public ShortcutAction(String key, ShortcutKeyCombination sc, | |||
String caption, String targetCID, String targetAction) { | |||
this.sc = sc; | |||
this.key = key; | |||
this.caption = caption; | |||
this.targetCID = targetCID; | |||
this.targetAction = targetAction; | |||
} | |||
/** | |||
* Get the key combination that triggers the action | |||
*/ | |||
public ShortcutKeyCombination getShortcutCombination() { | |||
return sc; | |||
} | |||
/** | |||
* Get the caption of the action | |||
*/ | |||
public String getCaption() { | |||
return caption; | |||
} | |||
/** | |||
* Get the {@link KeyMapper} key for the action | |||
*/ | |||
public String getKey() { | |||
return key; | |||
} | |||
/** | |||
* Get the pid of the target of the action. Use | |||
* {@link ApplicationConnection#getPaintable(String)} to get the actual | |||
* Paintable | |||
*/ | |||
public String getTargetCID() { | |||
return targetCID; | |||
} | |||
/** | |||
* Get the target string of the action | |||
*/ | |||
public String getTargetAction() { | |||
return targetAction; | |||
} | |||
} |
@@ -30,9 +30,11 @@ import com.google.gwt.user.client.ui.KeyboardListenerCollection; | |||
import com.vaadin.client.ApplicationConnection; | |||
import com.vaadin.client.BrowserInfo; | |||
import com.vaadin.client.ComponentConnector; | |||
import com.vaadin.client.ConnectorMap; | |||
import com.vaadin.client.UIDL; | |||
import com.vaadin.client.Util; | |||
import com.vaadin.client.ui.richtextarea.VRichTextArea; | |||
import com.vaadin.shared.Connector; | |||
/** | |||
* A helper class to implement keyboard shorcut handling. Keeps a list of owners | |||
@@ -43,6 +45,15 @@ import com.vaadin.client.ui.richtextarea.VRichTextArea; | |||
*/ | |||
public class ShortcutActionHandler { | |||
public static final String ACTION_TARGET_ATTRIBUTE = "sat"; | |||
public static final String ACTION_TARGET_ACTION_ATTRIBUTE = "sata"; | |||
public static final String ACTION_CAPTION_ATTRIBUTE = "caption"; | |||
public static final String ACTION_KEY_ATTRIBUTE = "key"; | |||
public static final String ACTION_SHORTCUT_KEY_ATTRIBUTE = "kc"; | |||
public static final String ACTION_MODIFIER_KEYS_ATTRIBUTE = "mk"; | |||
public static final String ACTION_TARGET_VARIABLE = "actiontarget"; | |||
public static final String ACTION_TARGET_ACTION_VARIABLE = "action"; | |||
/** | |||
* An interface implemented by those users of this helper class that want to | |||
* support special components like {@link VRichTextArea} that don't properly | |||
@@ -108,15 +119,23 @@ public class ShortcutActionHandler { | |||
final UIDL action = (UIDL) it.next(); | |||
int[] modifiers = null; | |||
if (action.hasAttribute("mk")) { | |||
modifiers = action.getIntArrayAttribute("mk"); | |||
if (action.hasAttribute(ACTION_MODIFIER_KEYS_ATTRIBUTE)) { | |||
modifiers = action | |||
.getIntArrayAttribute(ACTION_MODIFIER_KEYS_ATTRIBUTE); | |||
} | |||
final ShortcutKeyCombination kc = new ShortcutKeyCombination( | |||
action.getIntAttribute("kc"), modifiers); | |||
final String key = action.getStringAttribute("key"); | |||
final String caption = action.getStringAttribute("caption"); | |||
actions.add(new ShortcutAction(key, kc, caption)); | |||
action.getIntAttribute(ACTION_SHORTCUT_KEY_ATTRIBUTE), | |||
modifiers); | |||
final String key = action.getStringAttribute(ACTION_KEY_ATTRIBUTE); | |||
final String caption = action | |||
.getStringAttribute(ACTION_CAPTION_ATTRIBUTE); | |||
final String targetPID = action | |||
.getStringAttribute(ACTION_TARGET_ATTRIBUTE); | |||
final String targetAction = action | |||
.getStringAttribute(ACTION_TARGET_ACTION_ATTRIBUTE); | |||
actions.add(new ShortcutAction(key, kc, caption, targetPID, | |||
targetAction)); | |||
} | |||
} | |||
@@ -171,11 +190,22 @@ public class ShortcutActionHandler { | |||
Scheduler.get().scheduleDeferred(new Command() { | |||
@Override | |||
public void execute() { | |||
if (finalTarget != null) { | |||
client.updateVariable(paintableId, "actiontarget", | |||
finalTarget, false); | |||
Connector shortcutTarget = ConnectorMap.get(client) | |||
.getConnector(a.getTargetCID()); | |||
boolean handledClientSide = false; | |||
if (shortcutTarget instanceof ShortcutActionTarget) { | |||
handledClientSide = ((ShortcutActionTarget) shortcutTarget) | |||
.handleAction(a); | |||
} | |||
if (!handledClientSide) { | |||
if (finalTarget != null) { | |||
client.updateVariable(paintableId, | |||
ACTION_TARGET_VARIABLE, finalTarget, false); | |||
} | |||
client.updateVariable(paintableId, | |||
ACTION_TARGET_ACTION_VARIABLE, a.getKey(), true); | |||
} | |||
client.updateVariable(paintableId, "action", a.getKey(), true); | |||
} | |||
}); | |||
} | |||
@@ -282,29 +312,3 @@ class ShortcutKeyCombination { | |||
return false; | |||
} | |||
} | |||
class ShortcutAction { | |||
private final ShortcutKeyCombination sc; | |||
private final String caption; | |||
private final String key; | |||
public ShortcutAction(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; | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
/* | |||
@VaadinApache2LicenseForJavaFiles@ | |||
*/ | |||
package com.vaadin.client.ui; | |||
/** | |||
* Widgets who wish to be notificed when a shortcut action has been triggered | |||
* with the widget as a target should implement this interface. The | |||
* {@link #handleAction(ShortcutAction)} method will be called just before the | |||
* action is communicated to the server | |||
* | |||
*/ | |||
public interface ShortcutActionTarget { | |||
/** | |||
* Called by the {@link ShortcutActionHandler} just before the shortcut | |||
* action is sent to the server side | |||
* | |||
* @param action | |||
* The action which will be performed on the server side | |||
* @return Returns true if the shortcut was handled | |||
*/ | |||
boolean handleAction(ShortcutAction action); | |||
} |
@@ -33,6 +33,8 @@ import com.vaadin.client.communication.StateChangeEvent; | |||
import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler; | |||
import com.vaadin.client.ui.AbstractComponentConnector; | |||
import com.vaadin.client.ui.Icon; | |||
import com.vaadin.client.ui.ShortcutAction; | |||
import com.vaadin.client.ui.ShortcutActionTarget; | |||
import com.vaadin.shared.MouseEventDetails; | |||
import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; | |||
import com.vaadin.shared.ui.Connect; | |||
@@ -43,7 +45,7 @@ import com.vaadin.ui.Button; | |||
@Connect(value = Button.class, loadStyle = LoadStyle.EAGER) | |||
public class ButtonConnector extends AbstractComponentConnector implements | |||
BlurHandler, FocusHandler, ClickHandler { | |||
BlurHandler, FocusHandler, ClickHandler, ShortcutActionTarget { | |||
private ButtonServerRpc rpc = RpcProxy.create(ButtonServerRpc.class, this); | |||
private FocusAndBlurServerRpc focusBlurProxy = RpcProxy.create( | |||
@@ -165,4 +167,20 @@ public class ButtonConnector extends AbstractComponentConnector implements | |||
rpc.click(details); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see | |||
* com.vaadin.terminal.gwt.client.ui.ShortcutActionTarget#handleAction(com | |||
* .vaadin.terminal.gwt.client.ui.ShortcutAction) | |||
*/ | |||
public boolean handleAction(ShortcutAction action) { | |||
if ("click".equals(action.getTargetAction())) { | |||
getWidget().onClick(); | |||
return true; | |||
} | |||
return false; | |||
} | |||
} |
@@ -18,6 +18,7 @@ package com.vaadin.event; | |||
import java.util.HashSet; | |||
import java.util.Map; | |||
import com.vaadin.client.ui.ShortcutActionHandler; | |||
import com.vaadin.event.Action.Container; | |||
import com.vaadin.event.Action.Handler; | |||
import com.vaadin.server.KeyMapper; | |||
@@ -187,14 +188,29 @@ public class ActionManager implements Action.Container, Action.Handler, | |||
} | |||
if (a instanceof ShortcutAction) { | |||
final ShortcutAction sa = (ShortcutAction) a; | |||
paintTarget.addAttribute("kc", sa.getKeyCode()); | |||
paintTarget | |||
.addAttribute( | |||
ShortcutActionHandler.ACTION_SHORTCUT_KEY_ATTRIBUTE, | |||
sa.getKeyCode()); | |||
final int[] modifiers = sa.getModifiers(); | |||
if (modifiers != null) { | |||
final String[] smodifiers = new String[modifiers.length]; | |||
for (int i = 0; i < modifiers.length; i++) { | |||
smodifiers[i] = String.valueOf(modifiers[i]); | |||
} | |||
paintTarget.addAttribute("mk", smodifiers); | |||
paintTarget | |||
.addAttribute( | |||
ShortcutActionHandler.ACTION_MODIFIER_KEYS_ATTRIBUTE, | |||
smodifiers); | |||
} | |||
if (sa.getTarget() != null) { | |||
paintTarget.addAttribute( | |||
ShortcutActionHandler.ACTION_TARGET_ATTRIBUTE, | |||
sa.getTarget()); | |||
paintTarget | |||
.addAttribute( | |||
ShortcutActionHandler.ACTION_TARGET_ACTION_ATTRIBUTE, | |||
sa.getTargetAction()); | |||
} | |||
} | |||
paintTarget.endTag("action"); | |||
@@ -212,10 +228,14 @@ public class ActionManager implements Action.Container, Action.Handler, | |||
} | |||
public void handleActions(Map<String, Object> variables, Container sender) { | |||
if (variables.containsKey("action") && actionMapper != null) { | |||
final String key = (String) variables.get("action"); | |||
if (variables | |||
.containsKey(ShortcutActionHandler.ACTION_TARGET_ACTION_VARIABLE) | |||
&& actionMapper != null) { | |||
final String key = (String) variables | |||
.get(ShortcutActionHandler.ACTION_TARGET_ACTION_VARIABLE); | |||
final Action action = actionMapper.get(key); | |||
final Object target = variables.get("actiontarget"); | |||
final Object target = variables | |||
.get(ShortcutActionHandler.ACTION_TARGET_VARIABLE); | |||
if (action != null) { | |||
handleAction(action, sender, target); | |||
} |
@@ -21,6 +21,7 @@ import java.util.regex.Matcher; | |||
import java.util.regex.Pattern; | |||
import com.vaadin.server.Resource; | |||
import com.vaadin.ui.Component; | |||
import com.vaadin.ui.ComponentContainer; | |||
import com.vaadin.ui.Panel; | |||
import com.vaadin.ui.Window; | |||
@@ -57,6 +58,10 @@ public class ShortcutAction extends Action { | |||
private final int[] modifiers; | |||
private Component target; | |||
private String targetAction; | |||
/** | |||
* Creates a shortcut that reacts to the given {@link KeyCode} and | |||
* (optionally) {@link ModifierKey}s. <br/> | |||
@@ -236,6 +241,46 @@ public class ShortcutAction extends Action { | |||
return modifiers; | |||
} | |||
/** | |||
* Set the target for the shortcut action. If the target widget on the | |||
* client side implements {@link ShortcutActionTarget} it will be notified | |||
* of the action before the action is communicated to the server side | |||
* | |||
* @param target | |||
* The component which will be thet target of the action | |||
*/ | |||
public void setTarget(Component target) { | |||
this.target = target; | |||
} | |||
/** | |||
* Get the target of the shortcut action | |||
*/ | |||
public Component getTarget() { | |||
return target; | |||
} | |||
/** | |||
* Get the action string that is given to the {@link ShortcutActionTarget} | |||
* on the client side | |||
* | |||
* @return | |||
*/ | |||
public String getTargetAction() { | |||
return targetAction; | |||
} | |||
/** | |||
* Set the action string that is give to the {@link ShortcutActionTarget} on | |||
* the client side | |||
* | |||
* @param targetAction | |||
* The target action string | |||
*/ | |||
public void setTargetAction(String targetAction) { | |||
this.targetAction = targetAction; | |||
} | |||
/** | |||
* Key codes that can be used for shortcuts | |||
* |
@@ -463,7 +463,6 @@ public class Button extends AbstractComponent implements | |||
* | |||
*/ | |||
public static class ClickShortcut extends ShortcutListener { | |||
protected Button button; | |||
/** | |||
* Creates a keyboard shortcut for clicking the given button using the | |||
@@ -476,7 +475,8 @@ public class Button extends AbstractComponent implements | |||
*/ | |||
public ClickShortcut(Button button, String shorthandCaption) { | |||
super(shorthandCaption); | |||
this.button = button; | |||
setTarget(button); | |||
setTargetAction("click"); | |||
} | |||
/** | |||
@@ -492,7 +492,8 @@ public class Button extends AbstractComponent implements | |||
*/ | |||
public ClickShortcut(Button button, int keyCode, int... modifiers) { | |||
super(null, keyCode, modifiers); | |||
this.button = button; | |||
setTarget(button); | |||
setTargetAction("click"); | |||
} | |||
/** | |||
@@ -510,7 +511,7 @@ public class Button extends AbstractComponent implements | |||
@Override | |||
public void handleAction(Object sender, Object target) { | |||
button.click(); | |||
// Action handled on the client side | |||
} | |||
} | |||