aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/terminal/gwt/client/ui/dd/VDragEvent.java
blob: 306659a5719f61e5e83bbc4597dd62475e1e896c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
@ITMillApache2LicenseForJavaFiles@
 */
package com.vaadin.terminal.gwt.client.ui.dd;

import java.util.HashMap;
import java.util.Map;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.TableElement;
import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.user.client.Element;
import com.vaadin.terminal.gwt.client.BrowserInfo;

/**
 * DragEvent used by Vaadin client side engine. Supports components, items,
 * properties and custom payload (HTML5 style).
 * 
 * 
 */
public class VDragEvent {

    private static final int DEFAULT_OFFSET = 10;

    private static int eventId = 0;

    private VTransferable transferable;

    private NativeEvent currentGwtEvent;

    private NativeEvent startEvent;

    private int id;

    private HashMap<String, Object> dropDetails = new HashMap<String, Object>();

    private Element elementOver;

    VDragEvent(VTransferable t, NativeEvent startEvent) {
        transferable = t;
        this.startEvent = startEvent;
        id = eventId++;
    }

    public VTransferable getTransferable() {
        return transferable;
    }

    /**
     * Returns the the latest {@link NativeEvent} that relates to this drag and
     * drop operation. For example on {@link VDropHandler#dragEnter(VDragEvent)}
     * this is commonly a {@link MouseOverEvent}.
     * 
     * @return
     */
    public NativeEvent getCurrentGwtEvent() {
        return currentGwtEvent;
    }

    public void setCurrentGwtEvent(NativeEvent event) {
        currentGwtEvent = event;
    }

    int getEventId() {
        return id;
    }

    /**
     * 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 also 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 drag image used for current drag and drop operation. Drag image
     * is displayed next to mouse cursor during drag and drop.
     * <p>
     * The element to be used as drag image will automatically get CSS style
     * name "v-drag-element".
     * 
     * TODO decide if this method should be here or in {@link VTransferable} (in
     * HTML5 it is in DataTransfer) or {@link VDragAndDropManager}
     * 
     * TODO should be possible to override behavior. Like to proxy the element
     * to HTML5 DataTransfer
     * 
     * @param node
     */
    public void setDragImage(Element node) {
        setDragImage(node, DEFAULT_OFFSET, DEFAULT_OFFSET);
    }

    /**
     * TODO consider using similar smaller (than map) api as in Transferable
     * 
     * TODO clean up when drop handler changes
     * 
     * @return
     */
    public Map<String, Object> getDropDetails() {
        return dropDetails;
    }

    /**
     * Sets the drag image used for current drag and drop operation. Drag image
     * is displayed next to mouse cursor during drag and drop.
     * <p>
     * The element to be used as drag image will automatically get CSS style
     * name "v-drag-element".
     * 
     * @param element
     *            the dom element to be positioned next to mouse cursor
     * @param offsetX
     *            the horizontal offset of drag image from mouse cursor
     * @param offsetY
     *            the vertical offset of drag image from mouse cursor
     */
    public void setDragImage(Element element, int offsetX, int offsetY) {
        element.getStyle().setMarginLeft(offsetX, Unit.PX);
        element.getStyle().setMarginTop(offsetY, Unit.PX);
        VDragAndDropManager.get().setDragElement(element);
    }

    /**
     * @return the current Element used as a drag image (aka drag proxy) or null
     *         if drag image is not currently set for this drag operation.
     */
    public Element getDragImage() {
        return (Element) VDragAndDropManager.get().getDragElement();
    }

    /**
     * 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);
        if (BrowserInfo.get().isIE()) {
            if (cloneNode.getTagName().toLowerCase().equals("tr")) {
                TableElement table = Document.get().createTableElement();
                TableSectionElement tbody = Document.get().createTBodyElement();
                table.appendChild(tbody);
                tbody.appendChild(cloneNode);
                cloneNode = table.cast();
            }
        }
        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);
        }

    }

}