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>();
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;
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())
}
}, MouseDownEvent.getType());
- hookHtml5Events(getElement());
+ if (!BrowserInfo.get().isIE()) {
+ // TODO make this IE compatible
+ hookHtml5Events(getElement());
+ }
getStyleElement().getStyle().setBackgroundColor("yellow");
}
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;
if (dragmode != 0) {
mDown = true;
event.preventDefault();
+ event.stopPropagation();
}
break;
case Event.ONMOUSEOUT:
// 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;
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;
}
- private void updateTreeRelatedTransferData(VDragEvent drag) {
+ private void updateTreeRelatedDragData(VDragEvent drag) {
+
+ currentMouseOverKey = findCurrentMouseOverKey(drag.getElementOver());
+
drag.getEventDetails().put("itemIdOver", currentMouseOverKey);
if (currentMouseOverKey != null) {
}
}
+ 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);
}
"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
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);
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;
mouseDownEvent = null;
}
if (type == Event.ONMOUSEOVER) {
+ ApplicationConnection.getConsole().log(
+ "Treenode mouse over");
mouseDownEvent = null;
currentMouseOverKey = key;
event.stopPropagation();
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;
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;
/**
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(
}
}
+
}
public enum DragEventType {
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);
}
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,
*/
public class VDragEvent {
+ private static final int DEFAULT_OFFSET = 10;
+
private static int eventId = 0;
private VTransferable transferable;
private HashMap<String, Object> dropDetails = new HashMap<String, Object>();
+ private Element elementOver;
+
VDragEvent(VTransferable t, NativeEvent startEvent) {
transferable = t;
this.startEvent = startEvent;
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".
*
* @param node
*/
public void setDragImage(Element node) {
- VDragAndDropManager.get().setDragElement(node);
+ setDragImage(node, DEFAULT_OFFSET, DEFAULT_OFFSET);
}
/**
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);
+ }
+
+ }
+
}