]> source.dussan.org Git - vaadin-framework.git/commitdiff
Helpers, IE fixes, possibility to align proxy image below cursor
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Tue, 2 Feb 2010 12:12:45 +0000 (12:12 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Tue, 2 Feb 2010 12:12:45 +0000 (12:12 +0000)
svn changeset:11103/svn branch:6.3_dd

src/com/vaadin/terminal/gwt/client/Util.java
src/com/vaadin/terminal/gwt/client/ui/VDragDropPane.java
src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
src/com/vaadin/terminal/gwt/client/ui/VTree.java
src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java
src/com/vaadin/terminal/gwt/client/ui/dd/VDragEvent.java

index b0f48d74c669578001ce1082791d101a75c413e8..9c6d998adcc87e141ccf1d25bcdad687ffab9e08 100644 (file)
@@ -37,6 +37,25 @@ public class Util {
             debugger;
     }-*/;
 
+    /**
+     * 
+     * Returns the topmost element of from given coordinates.
+     * 
+     * TODO fix crossplat issues clientX vs pageX. See quircksmode
+     * 
+     * @param x
+     * @param y
+     * @return the element at given coordinates
+     */
+    public static native Element getElementFromPoint(int clientX, int clientY)
+    /*-{
+        var el = $wnd.document.elementFromPoint(clientX, clientY);
+        if(el.nodeType == 3) {
+            el = el.parentNode;
+        }
+        return el;
+    }-*/;
+
     private static final int LAZY_SIZE_CHANGE_TIMEOUT = 400;
     private static Set<Paintable> latelyChangedWidgets = new HashSet<Paintable>();
 
index 50e1c1554d464fc230be1a077889ca5c2fa4455a..5d3f4ae40ab4ffb1cc391f020aee24dd4a2d8068 100644 (file)
@@ -11,6 +11,7 @@ import com.google.gwt.user.client.DeferredCommand;
 import com.google.gwt.user.client.Element;
 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.MouseEventDetails;
 import com.vaadin.terminal.gwt.client.Paintable;
@@ -44,11 +45,7 @@ public class VDragDropPane extends VAbsoluteLayout implements Container,
                 transferable.setComponent(paintable);
                 VDragEvent drag = VDragAndDropManager.get().startDrag(
                         transferable, event.getNativeEvent(), true);
-                Element cloneNode = (Element) ((Widget) paintable).getElement()
-                        .cloneNode(true);
-                cloneNode.getStyle().setBackgroundColor("#999");
-                cloneNode.getStyle().setOpacity(0.4);
-                drag.setDragImage(cloneNode);
+                drag.createDragImage(((Widget) paintable).getElement(), true);
                 drag.getEventDetails().put(
                         "mouseDown",
                         new MouseEventDetails(event.getNativeEvent())
@@ -57,7 +54,10 @@ public class VDragDropPane extends VAbsoluteLayout implements Container,
             }
         }, MouseDownEvent.getType());
 
-        hookHtml5Events(getElement());
+        if (!BrowserInfo.get().isIE()) {
+            // TODO make this IE compatible
+            hookHtml5Events(getElement());
+        }
         getStyleElement().getStyle().setBackgroundColor("yellow");
 
     }
@@ -184,6 +184,12 @@ public class VDragDropPane extends VAbsoluteLayout implements Container,
         if (dropHandler == null) {
             dropHandler = new VAbstractDropHandler() {
 
+                @Override
+                public void dragEnter(VDragEvent drag) {
+                    ApplicationConnection.getConsole().log("DDPane DragEnter");
+                    super.dragEnter(drag);
+                }
+
                 @Override
                 public Paintable getPaintable() {
                     return VDragDropPane.this;
index bef74ff274f0b645266f70b9d185b0c6bb44c98a..88e8da5147369dbc54786b2c69973a1bb8819cdb 100644 (file)
@@ -2492,6 +2492,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler {
                             if (dragmode != 0) {
                                 mDown = true;
                                 event.preventDefault();
+                                event.stopPropagation();
                             }
                             break;
                         case Event.ONMOUSEOUT:
@@ -2506,11 +2507,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler {
                                 // TODO propertyId
                                 VDragEvent ev = VDragAndDropManager.get()
                                         .startDrag(transferable, event, true);
-                                Element cloneNode = (Element) getElement()
-                                        .cloneNode(true);
-                                cloneNode.getStyle().setOpacity(0.4);
-                                ev.setDragImage(cloneNode);
+                                ev.createDragImage(getElement(), true);
+
                                 mDown = false;
+                                // prevent text selection
+                                event.preventDefault();
+                                event.stopPropagation();
                             }
                         default:
                             break;
index f31e652ffc971bbfabd45f2f06a978137d9b0736..745ec31878ea3ef1d4b296e463c42407a142f02c 100644 (file)
@@ -11,11 +11,10 @@ import java.util.Set;
 
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.dom.client.Style;
-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.EventListener;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.SimplePanel;
@@ -161,7 +160,10 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
 
     }
 
-    private void updateTreeRelatedTransferData(VDragEvent drag) {
+    private void updateTreeRelatedDragData(VDragEvent drag) {
+
+        currentMouseOverKey = findCurrentMouseOverKey(drag.getElementOver());
+
         drag.getEventDetails().put("itemIdOver", currentMouseOverKey);
 
         if (currentMouseOverKey != null) {
@@ -177,13 +179,36 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
         }
     }
 
+    private String findCurrentMouseOverKey(Element elementOver) {
+        TreeNode treeNode = null;
+        Element curEl = elementOver;
+        while (curEl != null) {
+            try {
+                EventListener eventListener = Event.getEventListener(curEl);
+                if (eventListener != null) {
+                    // found a widget
+                    if (eventListener instanceof TreeNode) {
+                        treeNode = (TreeNode) eventListener;
+                    }
+                    break;
+                } else {
+                    curEl = (Element) curEl.getParentElement();
+                }
+            } catch (Exception e) {
+                ApplicationConnection.getConsole().log(e.getMessage());
+                e.printStackTrace();
+            }
+        }
+        return treeNode == null ? null : treeNode.key;
+    }
+
     private void updateDropHandler(UIDL childUidl) {
         if (dropHandler == null) {
             dropHandler = new VAbstractDropHandler() {
 
                 @Override
                 public void dragEnter(VDragEvent drag) {
-                    updateTreeRelatedTransferData(drag);
+                    updateTreeRelatedDragData(drag);
                     super.dragEnter(drag);
                 }
 
@@ -197,59 +222,47 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
                             "itemIdOver");
                     final String oldDetail = (String) currentDrag
                             .getEventDetails().get("detail");
-                    /*
-                     * Using deferred command, so event bubbles to TreeNode
-                     * event listener. Currently here via preview
-                     */
-                    DeferredCommand.addCommand(new Command() {
-                        public void execute() {
-                            final String detail = getDropDetail(currentDrag
-                                    .getCurrentGwtEvent());
-                            boolean nodeHasChanged = (currentMouseOverKey != null && currentMouseOverKey != oldIdOver)
-                                    || (oldIdOver != null);
-                            boolean detailHasChanded = !detail
-                                    .equals(oldDetail);
-
-                            if (nodeHasChanged || detailHasChanded) {
-                                ApplicationConnection.getConsole().log(
-                                        "Change in Transferable "
-                                                + currentMouseOverKey + " "
-                                                + detail);
-
-                                updateTreeRelatedTransferData(currentDrag);
-                                VAcceptCallback accpectedCb = new VAcceptCallback() {
-                                    public void handleResponse(
-                                            ValueMap responseData) {
-                                        if (responseData == null // via client
-                                                // side
-                                                // validation
-                                                || responseData
-                                                        .containsKey("accepted")) {
-                                            keyToNode.get(currentMouseOverKey)
-                                                    .emphasis(detail);
-                                        }
-                                    }
-                                };
-                                if (validateOnServer()) {
-                                    VDragAndDropManager.get().visitServer(
-                                            DragEventType.OVER, accpectedCb);
-
-                                } else {
-                                    if (validates(currentDrag)) {
-                                        accpectedCb.handleResponse(null);
-                                    } else {
-                                        keyToNode.get(currentMouseOverKey)
-                                                .emphasis(null);
-                                    }
-                                    if (oldIdOver != null
-                                            && oldIdOver != currentMouseOverKey) {
-                                        keyToNode.get(oldIdOver).emphasis(null);
-                                    }
+
+                    updateTreeRelatedDragData(currentDrag);
+                    final String detail = getDropDetail(currentDrag
+                            .getCurrentGwtEvent());
+                    boolean nodeHasChanged = (currentMouseOverKey != null && currentMouseOverKey != oldIdOver)
+                            || (oldIdOver != null);
+                    boolean detailHasChanded = !detail.equals(oldDetail);
+
+                    if (nodeHasChanged || detailHasChanded) {
+                        ApplicationConnection.getConsole().log(
+                                "Change in Transferable " + currentMouseOverKey
+                                        + " " + detail);
+                        VAcceptCallback accpectedCb = new VAcceptCallback() {
+                            public void handleResponse(ValueMap responseData) {
+                                if (responseData == null // via client
+                                        // side
+                                        // validation
+                                        || responseData.containsKey("accepted")) {
+                                    keyToNode.get(currentMouseOverKey)
+                                            .emphasis(detail);
                                 }
                             }
-
+                        };
+                        if (validateOnServer()) {
+                            VDragAndDropManager.get().visitServer(
+                                    DragEventType.OVER, accpectedCb);
+
+                        } else {
+                            if (validates(currentDrag)) {
+                                accpectedCb.handleResponse(null);
+                            } else {
+                                keyToNode.get(currentMouseOverKey).emphasis(
+                                        null);
+                            }
+                            if (oldIdOver != null
+                                    && oldIdOver != currentMouseOverKey) {
+                                keyToNode.get(oldIdOver).emphasis(null);
+                            }
                         }
-                    });
+                    }
+
                 }
 
                 @Override
@@ -385,9 +398,9 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
         public void emphasis(String string) {
             // ApplicationConnection.getConsole().log("OUTLINE" + string);
             Style style = nodeCaptionDiv.getStyle();
-            String top = "Top".equals(string) ? "2px solid green" : null;
-            String bottom = "Bottom".equals(string) ? "2px solid green" : null;
-            String bg = "Center".equals(string) ? "green" : null;
+            String top = "Top".equals(string) ? "2px solid green" : "";
+            String bottom = "Bottom".equals(string) ? "2px solid green" : "";
+            String bg = "Center".equals(string) ? "green" : "";
 
             style.setProperty("borderTop", top);
             style.setProperty("borderBottom", bottom);
@@ -439,12 +452,10 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
                         VTransferable t = new VTransferable();
                         t.setComponent(VTree.this);
                         t.setItemId(key);
-                        VDragEvent drag = VDragAndDropManager.get().startDrag(t,
-                                mouseDownEvent, true);
-                        Element node = (Element) nodeCaptionDiv.cloneNode(true);
-                        node.getStyle().setOpacity(0.4);
-                        node.getStyle().setBackgroundColor("#999");
-                        drag.setDragImage(node);
+                        VDragEvent drag = VDragAndDropManager.get().startDrag(
+                                t, mouseDownEvent, true);
+
+                        drag.createDragImage(nodeCaptionDiv, true);
                         event.stopPropagation();
 
                         mouseDownEvent = null;
@@ -453,6 +464,8 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
                     mouseDownEvent = null;
                 }
                 if (type == Event.ONMOUSEOVER) {
+                    ApplicationConnection.getConsole().log(
+                            "Treenode mouse over");
                     mouseDownEvent = null;
                     currentMouseOverKey = key;
                     event.stopPropagation();
index f01c936168ba0da7880e86e18043b7a690867d9e..41f058a99494682b3bb2afd5bfc31c6e9e8a148b 100644 (file)
@@ -3,6 +3,7 @@ package com.vaadin.terminal.gwt.client.ui.dd;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Display;
 import com.google.gwt.dom.client.Style.Position;
 import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.event.shared.HandlerRegistration;
@@ -16,6 +17,7 @@ import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
 import com.vaadin.terminal.gwt.client.MouseEventDetails;
 import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.Util;
 import com.vaadin.terminal.gwt.client.ValueMap;
 
 /**
@@ -32,22 +34,90 @@ public class VDragAndDropManager {
 
     private final class DefaultDragAndDropEventHandler implements
             NativePreviewHandler {
+
         public void onPreviewNativeEvent(NativePreviewEvent event) {
-            updateCurrentEvent(event.getNativeEvent());
+            NativeEvent nativeEvent = event.getNativeEvent();
+            updateCurrentEvent(nativeEvent);
             updateDragImagePosition();
 
-            NativeEvent nativeEvent = event.getNativeEvent();
+            int typeInt = event.getTypeInt();
             Element targetElement = (Element) nativeEvent.getEventTarget()
                     .cast();
-            if (dragElement != null && targetElement.isOrHasChild(dragElement)) {
-                ApplicationConnection.getConsole().log(
-                        "Event on dragImage, ignored");
-                event.cancel();
-                nativeEvent.stopPropagation();
-                return;
+            if (dragElement != null && dragElement.isOrHasChild(targetElement)) {
+
+                // to detect the "real" target, hide dragelement temporary and
+                // use elementFromPoint
+                String display = dragElement.getStyle().getDisplay();
+                dragElement.getStyle().setDisplay(Display.NONE);
+                try {
+                    int x = nativeEvent.getClientX();
+                    int y = nativeEvent.getClientY();
+                    // Util.browserDebugger();
+                    targetElement = Util.getElementFromPoint(x, y);
+                    if (targetElement == null) {
+                        ApplicationConnection.getConsole().log(
+                                "Event on dragImage, ignored");
+                        event.cancel();
+                        nativeEvent.stopPropagation();
+                        return;
+
+                    } else {
+                        ApplicationConnection.getConsole().log(
+                                "Event on dragImage, target changed");
+                        // special handling for events over dragImage
+                        // pretty much all events are mousemove althout below
+                        // kind of happens mouseover
+                        switch (typeInt) {
+                        case Event.ONMOUSEOVER:
+                        case Event.ONMOUSEOUT:
+                            ApplicationConnection
+                                    .getConsole()
+                                    .log(
+                                            "IGNORING proxy image event, fired because of hack or not significant");
+                            // TODO consider if mouseover should actually do
+                            // same as mouse move.
+                            return;
+                        case Event.ONMOUSEMOVE:
+                            VDropHandler findDragTarget = findDragTarget(targetElement);
+                            if (findDragTarget != currentDropHandler) {
+                                // dragleave on old
+                                if (currentDropHandler != null) {
+                                    currentDropHandler.dragLeave(currentDrag);
+                                    acceptCallback = null;
+                                }
+                                // dragenter on new
+                                currentDropHandler = findDragTarget;
+                                if (currentDropHandler != null) {
+                                    currentDrag
+                                            .setElementOver((com.google.gwt.user.client.Element) targetElement);
+                                    currentDropHandler.dragEnter(currentDrag);
+                                }
+                            } else if (findDragTarget != null) {
+                                currentDrag
+                                        .setElementOver((com.google.gwt.user.client.Element) targetElement);
+                                currentDropHandler.dragOver(currentDrag);
+                            }
+                            nativeEvent.preventDefault(); // prevent text
+                                                          // selection on IE
+                            return;
+                        default:
+                            // just update element over and let the actual
+                            // handling code do the thing
+                            currentDrag
+                                    .setElementOver((com.google.gwt.user.client.Element) targetElement);
+                            break;
+                        }
+
+                    }
+                } catch (Exception e) {
+                    ApplicationConnection.getConsole().log(
+                            "FIXME : ERROR in elementFromPoint hack.");
+                    e.printStackTrace();
+                } finally {
+                    dragElement.getStyle().setProperty("display", display);
+                }
             }
 
-            int typeInt = event.getTypeInt();
             switch (typeInt) {
             case Event.ONMOUSEOVER:
                 ApplicationConnection.getConsole().log(
@@ -99,6 +169,7 @@ public class VDragAndDropManager {
             }
 
         }
+
     }
 
     public enum DragEventType {
@@ -258,8 +329,8 @@ public class VDragAndDropManager {
     private void updateDragImagePosition() {
         if (currentDrag.currentGwtEvent != null && dragElement != null) {
             Style style = dragElement.getStyle();
-            int clientY = currentDrag.currentGwtEvent.getClientY() + 6;
-            int clientX = currentDrag.currentGwtEvent.getClientX() + 6;
+            int clientY = currentDrag.currentGwtEvent.getClientY();
+            int clientX = currentDrag.currentGwtEvent.getClientX();
             style.setTop(clientY, Unit.PX);
             style.setLeft(clientX, Unit.PX);
         }
index ee31f77b940c7fd58f1c3b918719d307f3b08d1a..0dfb204d236cb3f75292f54c23e7f922f700e1e0 100644 (file)
@@ -5,7 +5,9 @@ import java.util.HashMap;
 import java.util.Map;
 
 import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.user.client.Element;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
 
 /**
  * DragEvent used by Vaadin client side engine. Supports components, items,
@@ -15,6 +17,8 @@ import com.google.gwt.user.client.Element;
  */
 public class VDragEvent {
 
+    private static final int DEFAULT_OFFSET = 10;
+
     private static int eventId = 0;
 
     private VTransferable transferable;
@@ -29,6 +33,8 @@ public class VDragEvent {
 
     private HashMap<String, Object> dropDetails = new HashMap<String, Object>();
 
+    private Element elementOver;
+
     VDragEvent(VTransferable t, NativeEvent startEvent) {
         transferable = t;
         this.startEvent = startEvent;
@@ -52,6 +58,32 @@ public class VDragEvent {
         return new Date().getTime() - start.getTime();
     }
 
+    /**
+     * Detecting the element on which the the event is happening may be
+     * problematic during drag and drop operation. This is especially the case
+     * if a drag image (often called drag proxy) is kept under the mouse cursor
+     * (see {@link #createDragImage(Element, boolean)}. Drag and drop event
+     * handlers (like the one provided by {@link VDragAndDropManager} ) should
+     * set elmentOver field to reflect the the actual element on which the
+     * pointer currently is (drag image excluded). {@link VDropHandler}s can
+     * then more easily react properly on drag events by reading the element via
+     * this method.
+     * 
+     * @return the element in {@link VDropHandler} on which mouse cursor is on
+     */
+    public Element getElementOver() {
+        if (elementOver != null) {
+            return elementOver;
+        } else if (currentGwtEvent != null) {
+            return currentGwtEvent.getEventTarget().cast();
+        }
+        return null;
+    }
+
+    public void setElementOver(Element targetElement) {
+        elementOver = targetElement;
+    }
+
     /**
      * Sets the element that will be used as "drag icon".
      * 
@@ -64,7 +96,7 @@ public class VDragEvent {
      * @param node
      */
     public void setDragImage(Element node) {
-        VDragAndDropManager.get().setDragElement(node);
+        setDragImage(node, DEFAULT_OFFSET, DEFAULT_OFFSET);
     }
 
     /**
@@ -78,4 +110,39 @@ public class VDragEvent {
         return dropDetails;
     }
 
+    public void setDragImage(Element cloneNode, int offsetX, int offsetY) {
+        cloneNode.getStyle().setMarginLeft(offsetX, Unit.PX);
+        cloneNode.getStyle().setMarginTop(offsetY, Unit.PX);
+        VDragAndDropManager.get().setDragElement(cloneNode);
+
+    }
+
+    /**
+     * Automatically tries to create a proxy image from given element.
+     * 
+     * @param element
+     * @param alignImageToEvent
+     *            if true, proxy image is aligned to start event, else next to
+     *            mouse cursor
+     */
+    public void createDragImage(Element element, boolean alignImageToEvent) {
+        Element cloneNode = (Element) element.cloneNode(true);
+        cloneNode.getStyle().setOpacity(0.4);
+        if (BrowserInfo.get().isIE()) {
+            cloneNode.getStyle().setProperty("filter", "alpha(opacity=70)");
+        }
+        if (alignImageToEvent) {
+            int absoluteTop = element.getAbsoluteTop();
+            int absoluteLeft = element.getAbsoluteLeft();
+            int clientX = startEvent.getClientX();
+            int clientY = startEvent.getClientY();
+            int offsetX = absoluteLeft - clientX;
+            int offsetY = absoluteTop - clientY;
+            setDragImage(cloneNode, offsetX, offsetY);
+        } else {
+            setDragImage(cloneNode);
+        }
+
+    }
+
 }