Przeglądaj źródła

fixes #4175 and partly #5373 (TextField and RichTextArea now work properly)

svn changeset:14289/svn branch:6.4
tags/6.7.0.beta1
Matti Tahvonen 14 lat temu
rodzic
commit
14f0506bf3

+ 98
- 26
src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java Wyświetl plik

@@ -12,12 +12,17 @@ import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
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.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea;

/**
* A helper class to implement keyboard shorcut handling. Keeps a list of owners
@@ -27,7 +32,45 @@ import com.vaadin.terminal.gwt.client.UIDL;
* @author IT Mill ltd
*/
public class ShortcutActionHandler {
private final ArrayList actions = new ArrayList();

/**
* An interface implemented by those users (most often {@link Container}s,
* but HasWidgets at least) of this helper class that want to support
* special components like {@link 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
*/
ShortcutActionHandler getShortcutActionHandler();
}

/**
* A focusable {@link Paintable} implementing this interface will be
* notified before shortcut actions are handled if it will be the target of
* the action (most commonly means it is the focused component during the
* keyboard combination is triggered by the user).
*/
public interface BeforeShortcutActionListener extends Paintable {
/**
* This method is called by ShortcutActionHandler before firing the
* shortcut if the Paintable is currently focused (aka the target of the
* shortcut action). Eg. a field can update its possibly changed value
* to the server before shortcut action is fired.
*
* @param e
* the event that triggered the shortcut action
*/
public void onBeforeShortcutAction(Event e);
}

private final ArrayList<ShortcutAction> actions = new ArrayList<ShortcutAction>();
private ApplicationConnection client;
private String paintableId;

@@ -68,38 +111,66 @@ public class ShortcutActionHandler {
}
}

public void handleKeyboardEvent(final Event event) {
public void handleKeyboardEvent(final Event event, Paintable target) {
final int modifiers = KeyboardListenerCollection
.getKeyboardModifiers(event);
final char keyCode = (char) DOM.eventGetKeyCode(event);
final ShortcutKeyCombination kc = new ShortcutKeyCombination(keyCode,
modifiers);
final Iterator it = actions.iterator();
final Iterator<ShortcutAction> it = actions.iterator();
while (it.hasNext()) {
final ShortcutAction a = (ShortcutAction) it.next();
final ShortcutAction a = it.next();
if (a.getShortcutCombination().equals(kc)) {
final Element et = DOM.eventGetTarget(event);
final Paintable target = client.getPaintable(et);
DOM.eventPreventDefault(event);
shakeTarget(et);
DeferredCommand.addCommand(new Command() {
public void execute() {
shakeTarget(et);
}
});
DeferredCommand.addCommand(new Command() {
public void execute() {
if (target != null) {
client.updateVariable(paintableId, "actiontarget",
target, false);
}
client.updateVariable(paintableId, "action",
a.getKey(), true);
}
});
fireAction(event, a, target);
break;
}
}

}

public void handleKeyboardEvent(final Event event) {
handleKeyboardEvent(event, null);
}

private void fireAction(final Event event, final ShortcutAction a,
Paintable target) {
final Element et = DOM.eventGetTarget(event);
if (target == null) {
Widget w = Util.findWidget(et, null);
while (w != null && !(w instanceof Paintable)) {
w = w.getParent();
}
target = (Paintable) w;
}
final Paintable finalTarget = target;

event.preventDefault();

/*
* The target component might have unpublished changes, try to
* synchronize them before firing shortcut action.
*/
if (finalTarget instanceof BeforeShortcutActionListener) {
((BeforeShortcutActionListener) finalTarget)
.onBeforeShortcutAction(event);
} else {
shakeTarget(et);
DeferredCommand.addCommand(new Command() {
public void execute() {
shakeTarget(et);
}
});
}

DeferredCommand.addCommand(new Command() {
public void execute() {
if (finalTarget != null) {
client.updateVariable(paintableId, "actiontarget",
finalTarget, false);
}
client.updateVariable(paintableId, "action", a.getKey(), true);
}
});
}

/**
@@ -108,9 +179,10 @@ public class ShortcutActionHandler {
* sent to server. This is done by removing focus and then returning it
* immediately back to target element.
* <p>
* This is practically a hack and should be replaced with an interface via
* widgets could be notified when they should fire value change. Big task
* for TextFields, DateFields and various selects.
* This is practically a hack and should be replaced with an interface
* {@link BeforeShortcutActionListener} via widgets could be notified when
* they should fire value change. Big task for TextFields, DateFields and
* various selects.
*
* <p>
* TODO separate opera impl with generator

+ 7
- 1
src/com/vaadin/terminal/gwt/client/ui/VPanel.java Wyświetl plik

@@ -24,8 +24,10 @@ import com.vaadin.terminal.gwt.client.RenderInformation;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;

public class VPanel extends SimplePanel implements Container {
public class VPanel extends SimplePanel implements Container,
ShortcutActionHandlerOwner {

public static final String CLICK_EVENT_IDENTIFIER = "click";
public static final String CLASSNAME = "v-panel";
@@ -548,4 +550,8 @@ public class VPanel extends SimplePanel implements Container {
detectContainerBorders();
}

public ShortcutActionHandler getShortcutActionHandler() {
return shortcutHandler;
}

}

+ 6
- 1
src/com/vaadin/terminal/gwt/client/ui/VTextField.java Wyświetl plik

@@ -23,6 +23,7 @@ import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener;

/**
* This class represents a basic text input field with one row.
@@ -31,7 +32,7 @@ import com.vaadin.terminal.gwt.client.VTooltip;
*
*/
public class VTextField extends TextBoxBase implements Paintable, Field,
ChangeHandler, FocusHandler, BlurHandler {
ChangeHandler, FocusHandler, BlurHandler, BeforeShortcutActionListener {

/**
* The input node CSS classname.
@@ -381,4 +382,8 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
}
}

public void onBeforeShortcutAction(Event e) {
valueChange(false);
}

}

+ 6
- 1
src/com/vaadin/terminal/gwt/client/ui/VView.java Wyświetl plik

@@ -35,12 +35,13 @@ import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;

/**
*
*/
public class VView extends SimplePanel implements Container, ResizeHandler,
Window.ClosingHandler {
Window.ClosingHandler, ShortcutActionHandlerOwner {

private static final String CLASSNAME = "v-view";

@@ -693,4 +694,8 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
parentFrame = getParentFrame();
}

public ShortcutActionHandler getShortcutActionHandler() {
return actionHandler;
}

}

+ 7
- 1
src/com/vaadin/terminal/gwt/client/ui/VWindow.java Wyświetl plik

@@ -32,6 +32,7 @@ import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VDebugConsole;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;

/**
* "Sub window" component.
@@ -40,7 +41,8 @@ import com.vaadin.terminal.gwt.client.VDebugConsole;
*
* @author IT Mill Ltd
*/
public class VWindow extends VOverlay implements Container, ScrollListener {
public class VWindow extends VOverlay implements Container, ScrollListener,
ShortcutActionHandlerOwner {

/**
* Minimum allowed height of a window. This refers to the content area, not
@@ -1201,4 +1203,8 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
// NOP, window has own caption, layout captio not rendered
}

public ShortcutActionHandler getShortcutActionHandler() {
return shortcutHandler;
}

}

+ 51
- 4
src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java Wyświetl plik

@@ -8,6 +8,8 @@ import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.shared.HandlerRegistration;
@@ -15,15 +17,20 @@ import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.ui.Field;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;

/**
* This class implements a basic client side rich text editor component.
@@ -32,7 +39,8 @@ import com.vaadin.terminal.gwt.client.ui.Field;
*
*/
public class VRichTextArea extends Composite implements Paintable, Field,
ChangeHandler, BlurHandler, KeyPressHandler {
ChangeHandler, BlurHandler, KeyPressHandler, KeyDownHandler,
BeforeShortcutActionListener {

/**
* The input node CSS classname.
@@ -64,11 +72,16 @@ public class VRichTextArea extends Composite implements Paintable, Field,

private HandlerRegistration keyPressHandler;

private ShortcutActionHandlerOwner hasShortcutActionHandler;

private String currentValue = "";

public VRichTextArea() {
fp.add(formatter);

rta.setWidth("100%");
rta.addBlurHandler(this);
rta.addKeyDownHandler(this);

fp.add(rta);

@@ -97,7 +110,8 @@ public class VRichTextArea extends Composite implements Paintable, Field,
id = uidl.getId();

if (uidl.hasVariable("text")) {
rta.setHTML(uidl.getStringVariable("text"));
currentValue = uidl.getStringVariable("text");
rta.setHTML(currentValue);

}
setEnabled(!uidl.getBooleanAttribute("disabled"));
@@ -130,9 +144,12 @@ public class VRichTextArea extends Composite implements Paintable, Field,
* Method is public to let popupview force synchronization on close.
*/
public void synchronizeContentToServer() {
final String html = rta.getHTML();
if (client != null && id != null) {
client.updateVariable(id, "text", html, immediate);
final String html = rta.getHTML();
if (!html.equals(currentValue)) {
client.updateVariable(id, "text", html, immediate);
currentValue = html;
}
}
}

@@ -251,4 +268,34 @@ public class VRichTextArea extends Composite implements Paintable, Field,
}
}

public void onKeyDown(KeyDownEvent event) {
// delegate to closest shortcut action handler
// throw event from the iframe forward to the shortcuthandler
ShortcutActionHandler shortcutHandler = getShortcutHandlerOwner()
.getShortcutActionHandler();
if (shortcutHandler != null) {
shortcutHandler
.handleKeyboardEvent(com.google.gwt.user.client.Event
.as(event.getNativeEvent()), this);
}
}

private ShortcutActionHandlerOwner getShortcutHandlerOwner() {
if (hasShortcutActionHandler == null) {
Widget parent = getParent();
while (parent != null) {
if (parent instanceof ShortcutActionHandlerOwner) {
break;
}
parent = parent.getParent();
}
hasShortcutActionHandler = (ShortcutActionHandlerOwner) parent;
}
return hasShortcutActionHandler;
}

public void onBeforeShortcutAction(Event e) {
synchronizeContentToServer();
}

}

Ładowanie…
Anuluj
Zapisz