]> source.dussan.org Git - vaadin-framework.git/commitdiff
#5039: introduced focus/blur events for (sub)window, client side support and some...
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Fri, 17 Dec 2010 09:11:43 +0000 (09:11 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Fri, 17 Dec 2010 09:11:43 +0000 (09:11 +0000)
svn changeset:16556/svn branch:6.5

src/com/vaadin/terminal/gwt/client/ui/VWindow.java
src/com/vaadin/ui/Window.java

index 9691acc31c9f9d98a44d78a181206d452281536f..18c41d2e4a51b67a3a6dd633ed75a9dfbecadb33 100644 (file)
@@ -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 )
+    }
+
 }
index 37f5f8390e70e58077af813cdc3863cc5738df20..57dd4fd82b2193866a587f513d97d34457b9c843 100644 (file)
@@ -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 {
 
     /**
      * <b>Application window only</b>. 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() {
+    //
+    // }
 }