
com.vaadin.client.ui.ShortcutActionHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jvxvaadin-server Show documentation
Show all versions of jvxvaadin-server Show documentation
Vaadin UI implementation for JVx
The newest version!
/*
* Copyright 2000-2016 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 java.util.ArrayList;
import java.util.Iterator;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.KeyboardListenerCollection;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
import com.vaadin.client.ui.combobox.ComboBoxConnector;
import com.vaadin.client.ui.datefield.DateTimeFieldConnector;
import com.vaadin.client.ui.textfield.AbstractTextFieldConnector;
/**
* A helper class to implement keyboard shorcut handling. Keeps a list of owners
* actions and fires actions to server. User class needs to delegate keyboard
* events to handleKeyboardEvents function.
*
* @author Vaadin Ltd
*/
@SuppressWarnings("deprecation")
public class ShortcutActionHandler {
/**
* An interface implemented by those users of this helper class that want to
* support special components like {@code VRichTextArea} that don't properly
* propagate key down events. Those components can build support for
* shortcut actions by traversing the closest
* {@link ShortcutActionHandlerOwner} from the component hierarchy an
* passing keydown events to {@link ShortcutActionHandler}.
*/
public interface ShortcutActionHandlerOwner extends HasWidgets {
/**
* Returns the ShortCutActionHandler currently used or null if there is
* currently no shortcutactionhandler
*
* @return the shortcut action handler
*/
ShortcutActionHandler getShortcutActionHandler();
}
private final ArrayList actions = new ArrayList<>();
private ApplicationConnection client;
private String paintableId;
/**
*
* @param pid
* Paintable id
* @param c
* reference to application connections
*/
public ShortcutActionHandler(String pid, ApplicationConnection c) {
paintableId = pid;
client = c;
}
/**
* Updates list of actions this handler listens to.
*
* @param c
* UIDL snippet containing actions
*/
public void updateActionMap(UIDL c) {
actions.clear();
final Iterator> it = c.getChildIterator();
while (it.hasNext()) {
final UIDL action = (UIDL) it.next();
int[] modifiers = null;
if (action.hasAttribute("mk")) {
modifiers = action.getIntArrayAttribute("mk");
}
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));
}
}
public void handleKeyboardEvent(final Event event,
ComponentConnector target) {
final int modifiers = KeyboardListenerCollection
.getKeyboardModifiers(event);
final char keyCode = (char) DOM.eventGetKeyCode(event);
if (keyCode == 0) {
return;
}
final ShortcutKeyCombination kc = new ShortcutKeyCombination(keyCode,
modifiers);
final Iterator it = actions.iterator();
while (it.hasNext()) {
final ShortcutAction a = it.next();
if (a.getShortcutCombination().equals(kc)) {
fireAction(event, a, target);
break;
}
}
}
public void handleKeyboardEvent(final Event event) {
handleKeyboardEvent(event, null);
}
private void fireAction(final Event event, final ShortcutAction a,
ComponentConnector target) {
final Element et = DOM.eventGetTarget(event);
if (target == null) {
target = Util.findPaintable(client, et);
}
final ComponentConnector finalTarget = target;
event.preventDefault();
/*
* The focused component might have unpublished changes, try to
* synchronize them before firing shortcut action.
*/
client.flushActiveConnector();
// Performance tuning. Enter and Shift-Enter are handled on client, and server gets only focus lost.
// This will only work, in case of jumping from one simple editor to the next simple editor.
if (et.hasTagName("input") && target.getWidget().getElement().getClassName().contains(" editor ") && event.getKeyCode() == 13)
{
Element next = getNextFocusElement(Document.get(), et, event.getShiftKey());
ComponentConnector nextTarget = Util.findPaintable(client, next);
if (nextTarget instanceof AbstractTextFieldConnector)
{
AbstractTextFieldWidget widget = (AbstractTextFieldWidget)((AbstractTextFieldConnector)nextTarget).getWidget();
widget.selectAll();
next.focus();
return;
}
else if (nextTarget instanceof ComboBoxConnector)
{
VComboBox widget = ((ComboBoxConnector)nextTarget).getWidget();
widget.tb.selectAll();
next.focus();
return;
}
else if (nextTarget instanceof DateTimeFieldConnector)
{
VPopupTimeCalendar widget = ((DateTimeFieldConnector)nextTarget).getWidget();
widget.text.selectAll();
next.focus();
return;
}
}
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
if (finalTarget != null) {
client.updateVariable(paintableId, "actiontarget",
finalTarget, false);
}
client.updateVariable(paintableId, "action", a.getKey(), true);
}
});
}
private static native void blur(Element e)
/*-{
if(e.blur) {
e.blur();
}
}-*/;
private static native void focus(Element e)
/*-{
if(e.blur) {
e.focus();
}
}-*/;
/**
* Find the next or previous focusable component. (For simulation of tab / shift tab).
* @param doc the document
* @param elem the current element
* @param previous search previous or next otherwise
* @return next or previous focusable component
*/
private static native Element getNextFocusElement(Document doc, Element elem, boolean previous)
/*-{
var focusable = Array.prototype.filter.call(
doc.querySelectorAll('a:not([disabled]), button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"]:not([tabindex="-2"])'),
function (element) {
return (element.offsetWidth > 0 || element.offsetHeight > 0) && element.tabIndex >= 0;
}
);
var index = focusable.indexOf(elem);
if (index < 0)
{
return null;
}
else if (previous)
{
if (index == 0)
{
return focusable[focusable.length - 1];
}
else
{
return focusable[index - 1];
}
}
else
{
if (index < focusable.length - 1)
{
return focusable[index + 1];
}
else
{
return focusable[0];
}
}
}-*/;
}
class ShortcutKeyCombination {
public static final int SHIFT = 16;
public static final int CTRL = 17;
public static final int ALT = 18;
public static final int META = 91;
char keyCode = 0;
private int modifiersMask;
public ShortcutKeyCombination() {
}
ShortcutKeyCombination(char kc, int modifierMask) {
keyCode = kc;
modifiersMask = modifierMask;
}
@SuppressWarnings("deprecation")
ShortcutKeyCombination(int kc, int[] modifiers) {
keyCode = (char) kc;
modifiersMask = 0;
if (modifiers != null) {
for (int i = 0; i < modifiers.length; i++) {
switch (modifiers[i]) {
case ALT:
modifiersMask = modifiersMask
| KeyboardListener.MODIFIER_ALT;
break;
case CTRL:
modifiersMask = modifiersMask
| KeyboardListener.MODIFIER_CTRL;
break;
case SHIFT:
modifiersMask = modifiersMask
| KeyboardListener.MODIFIER_SHIFT;
break;
case META:
modifiersMask = modifiersMask
| KeyboardListener.MODIFIER_META;
break;
default:
break;
}
}
}
}
public boolean equals(ShortcutKeyCombination other) {
if (keyCode == other.keyCode && modifiersMask == other.modifiersMask) {
return true;
}
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;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy