From de46b1116a959129b630c6866e6e7322fe55fd07 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Fri, 17 Dec 2010 09:11:43 +0000 Subject: [PATCH] #5039: introduced focus/blur events for (sub)window, client side support and some necessary refactoring svn changeset:16556/svn branch:6.5 --- .../terminal/gwt/client/ui/VWindow.java | 97 +++++++++++++------ src/com/vaadin/ui/Window.java | 57 ++++++++++- 2 files changed, 121 insertions(+), 33 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java index 9691acc31c..18c41d2e4a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java @@ -10,7 +10,15 @@ import java.util.Set; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.DomEvent.Type; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.dom.client.ScrollEvent; +import com.google.gwt.event.dom.client.ScrollHandler; import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; @@ -21,28 +29,27 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Frame; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.RootPanel; -import com.google.gwt.user.client.ui.ScrollListener; -import com.google.gwt.user.client.ui.ScrollPanel; 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.EventId; 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.VDebugConsole; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener; import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; /** * "Sub window" component. * - * TODO update position / scroll position / size to client - * * @author IT Mill Ltd */ -public class VWindow extends VOverlay implements Container, ScrollListener, - ShortcutActionHandlerOwner { +public class VWindow extends VOverlay implements Container, + ShortcutActionHandlerOwner, ScrollHandler, KeyDownHandler, + FocusHandler, BlurHandler, BeforeShortcutActionListener { /** * Minimum allowed height of a window. This refers to the content area, not @@ -87,7 +94,7 @@ public class VWindow extends VOverlay implements Container, ScrollListener, private Element resizeBox; - private final ScrollPanel contentPanel = new ScrollPanel(); + private final FocusableScrollPanel contentPanel = new FocusableScrollPanel(); private boolean dragging; @@ -176,10 +183,10 @@ public class VWindow extends VOverlay implements Container, ScrollListener, constructDOM(); setPopupPosition(order * STACKING_OFFSET_PIXELS, order * STACKING_OFFSET_PIXELS); - contentPanel.addScrollListener(this); - - // make it focusable, but last in focus chain - DOM.setElementProperty(contentPanel.getElement(), "tabIndex", "0"); + contentPanel.addScrollHandler(this); + contentPanel.addKeyDownHandler(this); + contentPanel.addFocusHandler(this); + contentPanel.addBlurHandler(this); } private void bringToFront() { @@ -241,8 +248,6 @@ public class VWindow extends VOverlay implements Container, ScrollListener, wrapper2 = DOM.createDiv(); DOM.setElementProperty(wrapper2, "className", CLASSNAME + "-wrap2"); - DOM.sinkEvents(wrapper, Event.ONKEYDOWN); - DOM.appendChild(wrapper2, closeBox); DOM.appendChild(wrapper2, header); DOM.appendChild(header, headerText); @@ -495,6 +500,12 @@ public class VWindow extends VOverlay implements Container, ScrollListener, client.getView().scrollIntoView(uidl); if (uidl.hasAttribute("bringToFront")) { + /* + * Focus as a side-efect. Will be overridden by + * ApplicationConnection if another component was focused by the + * server side. + */ + contentPanel.focus(); /* * Modal windows bring them self the front with scheduleFinally(), * deferred is used here so possible (additional) bringToFront @@ -585,13 +596,6 @@ public class VWindow extends VOverlay implements Container, ScrollListener, return contentAreaToRootDifference; } - private int getContentAreaBorderPadding() { - if (contentAreaBorderPadding < 0) { - measure(); - } - return contentAreaBorderPadding; - } - private void measure() { if (!isAttached()) { return; @@ -832,11 +836,6 @@ public class VWindow extends VOverlay implements Container, ScrollListener, if (event != null) { final int type = event.getTypeInt(); - if (type == Event.ONKEYDOWN && shortcutHandler != null) { - shortcutHandler.handleKeyboardEvent(event); - return; - } - final Element target = DOM.eventGetTarget(event); // Handle window caption tooltips @@ -863,14 +862,18 @@ public class VWindow extends VOverlay implements Container, ScrollListener, } } + /* + * If clicking on other than the content, move focus to the window. + * After that this windows e.g. gets all keyboard shortcuts. + */ if (type == Event.ONMOUSEDOWN && !DOM.isOrHasChild(contentPanel.getElement(), target)) { - Util.focus(contentPanel.getElement()); + contentPanel.focus(); } } if (!bubble) { - event.cancelBubble(true); + event.stopPropagation(); } else { // Super.onBrowserEvent takes care of Handlers added by the // ClickEventHandler @@ -1082,6 +1085,8 @@ public class VWindow extends VOverlay implements Container, ScrollListener, private int extraH = 0; + private boolean hasFocus; + private int getExtraHeight() { extraH = header.getOffsetHeight() + footer.getOffsetHeight(); return extraH; @@ -1164,11 +1169,6 @@ public class VWindow extends VOverlay implements Container, ScrollListener, return true; } - public void onScroll(Widget widget, int scrollLeft, int scrollTop) { - client.updateVariable(id, "scrollTop", scrollTop, false); - client.updateVariable(id, "scrollLeft", scrollLeft, false); - } - @Override public void addStyleDependentName(String styleSuffix) { // VWindow's getStyleElement() does not return the same element as @@ -1227,4 +1227,37 @@ public class VWindow extends VOverlay implements Container, ScrollListener, return shortcutHandler; } + public void onScroll(ScrollEvent event) { + client.updateVariable(id, "scrollTop", + contentPanel.getScrollPosition(), false); + client.updateVariable(id, "scrollLeft", + contentPanel.getHorizontalScrollPosition(), false); + + } + + public void onKeyDown(KeyDownEvent event) { + if (shortcutHandler != null) { + shortcutHandler + .handleKeyboardEvent(Event.as(event.getNativeEvent())); + return; + } + } + + public void onBlur(BlurEvent event) { + if (client.hasEventListeners(this, EventId.BLUR)) { + client.updateVariable(id, EventId.BLUR, "", true); + } + } + + public void onFocus(FocusEvent event) { + if (client.hasEventListeners(this, EventId.FOCUS)) { + client.updateVariable(id, EventId.FOCUS, "", true); + } + } + + public void onBeforeShortcutAction(Event e) { + // NOP, nothing to update just avoid workaround ( causes excess + // blur/focus ) + } + } diff --git a/src/com/vaadin/ui/Window.java b/src/com/vaadin/ui/Window.java index 37f5f8390e..57dd4fd82b 100644 --- a/src/com/vaadin/ui/Window.java +++ b/src/com/vaadin/ui/Window.java @@ -17,6 +17,12 @@ import java.util.Map; import java.util.Set; import com.vaadin.Application; +import com.vaadin.event.FieldEvents.BlurEvent; +import com.vaadin.event.FieldEvents.BlurListener; +import com.vaadin.event.FieldEvents.BlurNotifier; +import com.vaadin.event.FieldEvents.FocusEvent; +import com.vaadin.event.FieldEvents.FocusListener; +import com.vaadin.event.FieldEvents.FocusNotifier; import com.vaadin.event.ShortcutAction; import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.event.ShortcutAction.ModifierKey; @@ -78,7 +84,8 @@ import com.vaadin.terminal.gwt.client.ui.VWindow; */ @SuppressWarnings("serial") @ClientWidget(VWindow.class) -public class Window extends Panel implements URIHandler, ParameterHandler { +public class Window extends Panel implements URIHandler, ParameterHandler, + FocusNotifier, BlurNotifier { /** * Application window only. A border style used for opening resources @@ -1084,6 +1091,12 @@ public class Window extends Panel implements URIHandler, ParameterHandler { fireResize(); } + if (variables.containsKey(FocusEvent.EVENT_ID)) { + fireEvent(new FocusEvent(this)); + } else if (variables.containsKey(BlurEvent.EVENT_ID)) { + fireEvent(new BlurEvent(this)); + } + } /** @@ -2126,4 +2139,46 @@ public class Window extends Panel implements URIHandler, ParameterHandler { window.close(); } } + + /** + * Note, that focus/blur listeners in Window class are only supported by sub + * windows. Also note that Window is not considered focused if its contained + * component currently has focus. + * + * @see com.vaadin.event.FieldEvents.FocusNotifier#addListener(com.vaadin.event.FieldEvents.FocusListener) + */ + public void addListener(FocusListener listener) { + addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, + FocusListener.focusMethod); + } + + public void removeListener(FocusListener listener) { + removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); + } + + /** + * Note, that focus/blur listeners in Window class are only supported by sub + * windows. Also note that Window is not considered focused if its contained + * component currently has focus. + * + * @see com.vaadin.event.FieldEvents.BlurNotifier#addListener(com.vaadin.event.FieldEvents.BlurListener) + */ + public void addListener(BlurListener listener) { + addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, + BlurListener.blurMethod); + } + + public void removeListener(BlurListener listener) { + removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); + } + + /** + * Works only for sub windows. + * + * TODO to be or not to be? If so, should be the same as bringToFront? Or to + * bringToFront() as a side effect? + */ + // public void focus() { + // + // } } -- 2.39.5