From: Matti Tahvonen Date: Tue, 2 Feb 2010 12:12:45 +0000 (+0000) Subject: Helpers, IE fixes, possibility to align proxy image below cursor X-Git-Tag: 6.7.0.beta1~1988^2~35 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f9c180ebdd2e4d83c89ab8413f133fe56eafed9a;p=vaadin-framework.git Helpers, IE fixes, possibility to align proxy image below cursor svn changeset:11103/svn branch:6.3_dd --- diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java index b0f48d74c6..9c6d998adc 100644 --- a/src/com/vaadin/terminal/gwt/client/Util.java +++ b/src/com/vaadin/terminal/gwt/client/Util.java @@ -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 latelyChangedWidgets = new HashSet(); diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDragDropPane.java b/src/com/vaadin/terminal/gwt/client/ui/VDragDropPane.java index 50e1c1554d..5d3f4ae40a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VDragDropPane.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VDragDropPane.java @@ -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; diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java index bef74ff274..88e8da5147 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java @@ -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; diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTree.java b/src/com/vaadin/terminal/gwt/client/ui/VTree.java index f31e652ffc..745ec31878 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTree.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTree.java @@ -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(); diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java index f01c936168..41f058a994 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java @@ -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); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragEvent.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragEvent.java index ee31f77b94..0dfb204d23 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragEvent.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragEvent.java @@ -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 dropDetails = new HashMap(); + 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); + } + + } + }