Java tutorial
/* * Copyright 2011 John Ahlroos * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package fi.jasoft.dragdroplayouts.client.ui; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.dom.client.TouchStartEvent; import com.google.gwt.event.dom.client.TouchStartHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.ui.VButton; import com.vaadin.terminal.gwt.client.ui.VCssLayout; import com.vaadin.terminal.gwt.client.ui.VSlider; import com.vaadin.terminal.gwt.client.ui.VTextField; import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager; import com.vaadin.terminal.gwt.client.ui.dd.VDragEvent; import com.vaadin.terminal.gwt.client.ui.dd.VTransferable; /** * Mouse handler for starting component drag operations * * @author John Ahlroos */ public class VLayoutDragDropMouseHandler implements MouseDownHandler, TouchStartHandler { public static final String ACTIVE_DRAG_SOURCE_STYLENAME = "v-dd-active-drag-source"; private LayoutDragMode dragMode = LayoutDragMode.NONE; private final Widget root; private Widget currentDraggedWidget; private HandlerRegistration mouseUpHandlerReg; private final List<HandlerRegistration> handlers = new LinkedList<HandlerRegistration>(); private final List<DragStartListener> dragStartListeners = new ArrayList<VLayoutDragDropMouseHandler.DragStartListener>(); /** * A listener to listen for drag start events */ public interface DragStartListener { /** * Called when a drag is about to begin * * @param widget * The widget which is about to be dragged * @param mode * The draggin mode * @return Should the dragging be commenced. */ boolean dragStart(Widget widget, LayoutDragMode mode); } /** * Constructor * * @param root * The root element * @param dragMode * The drag mode of the layout */ public VLayoutDragDropMouseHandler(Widget root, LayoutDragMode dragMode) { this.dragMode = dragMode; this.root = root; } /** * Is the mouse down event a valid mouse drag event, i.e. left mouse button * is pressed without any modifier keys * * @param event * The mouse event * @return Is the mouse event a valid drag event */ private boolean isMouseDragEvent(NativeEvent event) { boolean hasModifierKey = event.getAltKey() || event.getCtrlKey() || event.getMetaKey() || event.getShiftKey(); return !(hasModifierKey || event.getButton() > NativeEvent.BUTTON_LEFT); } /* * (non-Javadoc) * * @see * com.google.gwt.event.dom.client.TouchStartHandler#onTouchStart(com.google * .gwt.event.dom.client.TouchStartEvent) */ public void onTouchStart(TouchStartEvent event) { initiateDrag(event.getNativeEvent()); } /* * (non-Javadoc) * * @see * com.google.gwt.event.dom.client.MouseDownHandler#onMouseDown(com.google * .gwt.event.dom.client.MouseDownEvent) */ public void onMouseDown(MouseDownEvent event) { initiateDrag(event.getNativeEvent()); event.preventDefault(); event.stopPropagation(); } /** * Called when the dragging a component should be initiated by both a mouse * down event as well as a touch start event * * @param event */ protected void initiateDrag(NativeEvent event) { // Check that dragging is enabled if (dragMode == LayoutDragMode.NONE) { return; } // Dragging can only be done with left mouse button and no modifier keys if (!isMouseDragEvent(event) && !Util.isTouchEvent(event)) { return; } // Create the transfarable VTransferable transferable = VDragDropUtil.createLayoutTransferableFromMouseDown(event, root); // Are we trying to drag the root layout if (transferable == null) { VConsole.error("Creating transferable on mouse down returned null"); return; } // Resolve the component final Widget w; if (root instanceof VDDAccordion && transferable.getData(Constants.TRANSFERABLE_DETAIL_CAPTION) != null) { w = (Widget) transferable.getData(Constants.TRANSFERABLE_DETAIL_CAPTION); } else if (transferable.getData(Constants.TRANSFERABLE_DETAIL_COMPONENT) != null) { w = (Widget) transferable.getData(Constants.TRANSFERABLE_DETAIL_COMPONENT); } else { // Failsafe if no widget was found w = root; VConsole.log("Could not resolve component, using root as component"); } // Announce drag start to listeners for (DragStartListener dl : dragStartListeners) { if (!dl.dragStart(w, dragMode)) { VDragAndDropManager.get().interruptDrag(); return; } } /* * A hack to remove slider popup when dragging. This is done by first * focusing the slider and then unfocusing so we get a blur event which * will remove the popup. */ if (w instanceof VSlider) { VSlider slider = (VSlider) w; slider.setFocus(true); slider.setFocus(false); } currentDraggedWidget = w; // Announce to handler that we are starting a drag operation VDragEvent currentDragEvent = VDragAndDropManager.get().startDrag(transferable, event, true); if (w instanceof VButton && BrowserInfo.get().isIE()) { /* * Due to Buttons crazy implementation we need to simulate a mouse * move to get the drag going in IE without first focusing the * button. Crazy shit. */ VButton button = (VButton) w; NativeEvent evt = Document.get().createMouseMoveEvent(1, event.getScreenX(), event.getScreenY(), Util.getTouchOrMouseClientX(event), Util.getTouchOrMouseClientY(event), false, false, false, false, 0); button.getElement().dispatchEvent(evt); } // Create the drag image if (root instanceof VCssLayout) { /* * CSS Layout does not have an enclosing div so we just use the * component dov */ currentDragEvent.createDragImage((Element) w.getElement().cast(), true); } else { /* * Other layouts uses a enclosing div so we use it. */ currentDragEvent.createDragImage((Element) w.getElement().getParentNode().cast(), true); } if (BrowserInfo.get().isIE7() && w instanceof VTextField) { currentDragEvent.createDragImage(w.getElement(), true); // Capture something so focus is not applied to elements Event.setCapture(RootPanel.getBodyElement()); } Element clone = currentDragEvent.getDragImage(); Style cloneStyle = clone.getStyle(); if (BrowserInfo.get().isIE()) { // Fix IE not aligning the drag image correctly when dragging // layouts cloneStyle.setPosition(Position.ABSOLUTE); } currentDraggedWidget.addStyleName(ACTIVE_DRAG_SOURCE_STYLENAME); // Listen to mouse up for cleanup mouseUpHandlerReg = Event.addNativePreviewHandler(new Event.NativePreviewHandler() { public void onPreviewNativeEvent(NativePreviewEvent event) { if (event.getTypeInt() == Event.ONMOUSEUP || event.getTypeInt() == Event.ONTOUCHEND || event.getTypeInt() == Event.ONTOUCHCANCEL) { if (mouseUpHandlerReg != null) { mouseUpHandlerReg.removeHandler(); if (currentDraggedWidget != null) { currentDraggedWidget.removeStyleName(ACTIVE_DRAG_SOURCE_STYLENAME); currentDraggedWidget = null; } } // Ensure capturing is turned off at mouse up Event.releaseCapture(RootPanel.getBodyElement()); } } }); } /** * Set the current drag mode * * @param dragMode * The drag mode to use */ public void updateDragMode(LayoutDragMode dragMode) { this.dragMode = dragMode; } /** * Add a drag start listener to monitor drag starts * * @param listener */ public void addDragStartListener(DragStartListener listener) { dragStartListeners.add(listener); } /** * Remove a drag start listener * * @param listener */ public void removeDragStartListener(DragStartListener listener) { dragStartListeners.remove(listener); } /** * Start listening to events */ public void attach() { if (handlers.isEmpty()) { handlers.add(root.addDomHandler(this, MouseDownEvent.getType())); handlers.add(root.addDomHandler(this, TouchStartEvent.getType())); } } /** * Attach to another widget than root * * @param widget * The widget to attach to */ public void attachTo(Widget widget) { if (handlers.isEmpty()) { handlers.add(widget.addDomHandler(this, MouseDownEvent.getType())); handlers.add(widget.addDomHandler(this, TouchStartEvent.getType())); } } /** * Stop listening to events */ public void detach() { for (HandlerRegistration reg : handlers) { reg.removeHandler(); } handlers.clear(); } }