View Javadoc
1   /**********************************************
2    * Copyright (C) 2011 Lukas laag
3    * This file is part of lib-gwt-file.
4    * 
5    * lib-gwt-file is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU Lesser General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * lib-gwt-file is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU Lesser General Public License for more details.
14   * 
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with lib-gwt-file.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  package org.vectomatic.dnd;
19  
20  import com.google.gwt.dom.client.Element;
21  import com.google.gwt.dom.client.NativeEvent;
22  import com.google.gwt.dom.client.Node;
23  import com.google.gwt.event.dom.client.DomEvent;
24  import com.google.gwt.event.dom.client.DragEnterEvent;
25  import com.google.gwt.event.dom.client.DragEnterHandler;
26  import com.google.gwt.event.dom.client.DragLeaveEvent;
27  import com.google.gwt.event.dom.client.DragLeaveHandler;
28  import com.google.gwt.event.dom.client.DragOverEvent;
29  import com.google.gwt.event.dom.client.DragOverHandler;
30  import com.google.gwt.event.dom.client.DropEvent;
31  import com.google.gwt.event.dom.client.DropHandler;
32  import com.google.gwt.event.dom.client.HasDragEnterHandlers;
33  import com.google.gwt.event.dom.client.HasDragLeaveHandlers;
34  import com.google.gwt.event.dom.client.HasDragOverHandlers;
35  import com.google.gwt.event.dom.client.HasDropHandlers;
36  import com.google.gwt.event.shared.EventBus;
37  import com.google.gwt.event.shared.GwtEvent;
38  import com.google.gwt.event.shared.HandlerRegistration;
39  import com.google.gwt.event.shared.SimpleEventBus;
40  import com.google.gwt.user.client.ui.SimplePanel;
41  
42  /**
43   * A widget which accepts file drag and drop.
44   * <i>Note: users must add a handler for ALL four main
45   * events (dragenter, dragleave, dragover and drop) to prevent
46   * the default browser behavior from applying, otherwise dropping
47   * will result in the browser opening a new page with the dropped
48   * resource.</i>
49   * @author laaglu
50   */
51  public class DropPanel extends SimplePanel implements HasDropHandlers, HasDragEnterHandlers, HasDragLeaveHandlers, HasDragOverHandlers {
52  	/**
53  	 * The event bus shared by all drop panels
54  	 */
55  	static protected EventBus eventBus;
56  
57  	/**
58  	 * Returns the event bus shared by all drop panels
59  	 * @return the event bus shared by all drop panels
60  	 */
61  	public static EventBus getEventBus() {
62  		if (eventBus == null) {
63  			eventBus = new SimpleEventBus();
64  		}
65  		return eventBus;
66  	}
67  	
68  	/**
69  	 * Sets the event bus shared by all drop panels
70  	 * @param eventBus the event bus shared by all drop panels
71  	 */
72  	public static void setEventBus(EventBus eventBus) {
73  		DropPanel.eventBus = eventBus;
74  	}
75  	
76  	/**
77  	 * Constructor. The size of the widget should be set using CSS.
78  	 */
79  	public DropPanel() {
80  		super();
81  		setup(getElement());
82  	}
83  	
84  	private final native void setup(Element elem) /*-{
85  	    var x = this;
86  		var handler = function(evt) {
87  	        x.@org.vectomatic.dnd.DropPanel::dispatch(Lcom/google/gwt/dom/client/NativeEvent;)(evt);
88  		};
89  		elem.addEventListener("dragenter", handler, false);
90  		elem.addEventListener("dragleave", handler, false);
91  		elem.addEventListener("dragover", handler, false);
92  		elem.addEventListener("drop", handler, false);
93  	}-*/;
94  	
95  	public void fireEvent(GwtEvent<?> event) {
96  		revive(event);
97  		getEventBus().fireEventFromSource(event, this);
98  	}
99  	/**
100 	 * Revive the event. GWT does it by taking advantage of the
101 	 * fact that HandlerManager has package access to GwtEvent.
102 	 * Here we use a JSNI call to bypass scope restrictions
103 	 */
104 	private static final native void revive(GwtEvent<?> event) /*-{
105 	  event.@com.google.gwt.event.shared.GwtEvent::revive()();
106 	}-*/;
107 	
108 	/**
109 	 * Dispatches the specified event to this node
110 	 * event handlers
111 	 * @param event The event to dispatch
112 	 */
113 	public void dispatch(NativeEvent event) {
114 		// dragenter and dragleave deserve special treatment
115 		// to solve issues described in:
116 		// http://www.quirksmode.org/js/events_mouse.html
117 		if ("dragenter".equals(event.getType())
118 		 || "dragleave".equals(event.getType())) {
119 			if (isChildOf((Node)event.getCurrentEventTarget().cast(), (Node)event.getRelatedEventTarget().cast())) {
120 				return;
121 			}
122 		}
123 		// This call wraps the native event into a DomEvent
124 		// and invokes fireEvent
125 	    DomEvent.fireNativeEvent(event, this, (Element)event.getCurrentEventTarget().cast());
126 	}
127 	
128 	/**
129 	 * Tests if a node is part of a DOM subtree.  
130 	 * @param root
131 	 * The subtree root
132 	 * @param node
133 	 * The node to be tested
134 	 * @return
135 	 * True if the node is part of the subtree, false otherwise
136 	 */
137 	protected native boolean isChildOf(Node root, Node node) /*-{
138 		while (node != null && node != root && node.nodeName != 'BODY') {
139 			node= node.parentNode
140 		}
141 		if (node === root) {
142 			return true;
143 		}
144 		return false;
145 	}-*/;
146 
147 	
148 	@Override
149 	public HandlerRegistration addDropHandler(DropHandler handler) {
150 		return getEventBus().addHandlerToSource(DropEvent.getType(), this, handler);
151 	}
152 
153 	@Override
154 	public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) {
155 		return getEventBus().addHandlerToSource(DragLeaveEvent.getType(), this, handler);
156 	}
157 
158 	@Override
159 	public HandlerRegistration addDragEnterHandler(DragEnterHandler handler) {
160 		return getEventBus().addHandlerToSource(DragEnterEvent.getType(), this, handler);
161 	}
162 
163 	@Override
164 	public HandlerRegistration addDragOverHandler(DragOverHandler handler) {
165 		return getEventBus().addHandlerToSource(DragOverEvent.getType(), this, handler);
166 	}
167 
168 }