fi.jasoft.dragdroplayouts.client.ui.VDragDropUtil.java Source code

Java tutorial

Introduction

Here is the source code for fi.jasoft.dragdroplayouts.client.ui.VDragDropUtil.java

Source

/*
 * 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 com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.Container;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VCaption;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.ui.VScrollTable;
import com.vaadin.terminal.gwt.client.ui.VTwinColSelect;
import com.vaadin.terminal.gwt.client.ui.dd.HorizontalDropLocation;
import com.vaadin.terminal.gwt.client.ui.dd.VTransferable;
import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;

import fi.jasoft.dragdroplayouts.client.ui.interfaces.VHasDragMode;

public final class VDragDropUtil {

    private VDragDropUtil() {
        // Prevent instantiation
    }

    /**
     * Get the vertical drop location in a ordered layout
     * 
     * @param element
     *            The target element or cell
     * @param clientY
     *            The client y-coordinate
     * @param topBottomRatio
     *            The ratio how the cell has been divided
     * @return The drop location
     */
    public static VerticalDropLocation getVerticalDropLocation(Element element, int clientY,
            double topBottomRatio) {
        int offsetHeight = element.getOffsetHeight();
        return getVerticalDropLocation(element, offsetHeight, clientY, topBottomRatio);
    }

    /**
     * Get the vertical drop location in a ordered layout
     * 
     * @param element
     *            The target element or cell
     * @param offsetHeight
     *            The height of the cell
     * @param clientY
     *            The width of the cell
     * @param topBottomRatio
     *            The ratio of the cell
     * @return The location of the drop
     */
    public static VerticalDropLocation getVerticalDropLocation(Element element, int offsetHeight, int clientY,
            double topBottomRatio) {

        int absoluteTop = element.getAbsoluteTop();
        int fromTop = clientY - absoluteTop;

        float percentageFromTop = (fromTop / (float) offsetHeight);
        if (percentageFromTop < topBottomRatio) {
            return VerticalDropLocation.TOP;
        } else if (percentageFromTop > 1 - topBottomRatio) {
            return VerticalDropLocation.BOTTOM;
        } else {
            return VerticalDropLocation.MIDDLE;
        }
    }

    /**
     * Get the horizontal drop location in an ordered layout
     * 
     * @param element
     *            The target element or cell
     * @param clientX
     *            The x-coordinate of the drop
     * @param leftRightRatio
     *            The ratio of how the cell has been divided
     * @return the drop location relative to the cell
     */
    public static HorizontalDropLocation getHorizontalDropLocation(Element element, int clientX,
            double leftRightRatio) {

        int absoluteLeft = element.getAbsoluteLeft();
        int offsetWidth = element.getOffsetWidth();
        int fromTop = clientX - absoluteLeft;

        float percentageFromTop = (fromTop / (float) offsetWidth);
        if (percentageFromTop < leftRightRatio) {
            return HorizontalDropLocation.LEFT;
        } else if (percentageFromTop > 1 - leftRightRatio) {
            return HorizontalDropLocation.RIGHT;
        } else {
            return HorizontalDropLocation.CENTER;
        }
    }

    /**
     * Creates a transferable for the tabsheet
     * 
     * @param tabsheet
     *            The tabsheet the event occurred
     * @param tab
     *            The tab on which the event occurred
     * @param event
     *            The event
     * @param root
     *            The root widget
     * @return
     */
    private static VTransferable createTabsheetTransferableFromMouseDown(VDDTabSheet tabsheet, Widget tab,
            NativeEvent event) {

        // Create transferable
        VTransferable transferable = new VTransferable();
        transferable.setDragSource(tabsheet);
        if (tabsheet != tab) {
            transferable.setData(Constants.TRANSFERABLE_DETAIL_COMPONENT, tab);
            transferable.setData(Constants.TRANSFERABLE_DETAIL_INDEX, tabsheet.getTabPosition(tab));
            transferable.setData("tabSheetAbsoluteTop", tabsheet.getAbsoluteTop());
            transferable.setData("tabSheetAbsoluteLeft", tabsheet.getAbsoluteLeft());
        }
        transferable.setData(Constants.TRANSFERABLE_DETAIL_MOUSEDOWN, new MouseEventDetails(event).serialize());

        return transferable;
    }

    /**
     * Creates a transferable for the Accordion
     * 
     * @param accordion
     *            The Accordion where the event occurred
     * @param tab
     *            The tab on which the event occurred
     * @param event
     *            The event
     * @param root
     *            The root widget
     * @return
     */
    private static VTransferable createAccordionTransferableFromMouseDown(VDDAccordion accordion,
            VCaption tabCaption, NativeEvent event) {

        // Create transferable
        VTransferable transferable = new VTransferable();
        transferable.setDragSource(accordion);
        transferable.setData(Constants.TRANSFERABLE_DETAIL_CAPTION, tabCaption);
        transferable.setData(Constants.TRANSFERABLE_DETAIL_COMPONENT, tabCaption.getParent());
        transferable.setData(Constants.TRANSFERABLE_DETAIL_INDEX, accordion.getWidgetIndex(tabCaption.getParent()));
        transferable.setData(Constants.TRANSFERABLE_DETAIL_MOUSEDOWN, new MouseEventDetails(event).serialize());

        return transferable;
    }

    /**
     * Creates a transferable from a mouse down event. Returns null if creation
     * was not successful.
     * 
     * @param event
     *            The mouse down event
     * @param root
     *            The root layout from where the component is dragged
     * @return A transferable or NULL if something failed
     */
    public static VTransferable createLayoutTransferableFromMouseDown(NativeEvent event, Widget root) {

        Widget w = Util.findWidget((Element) event.getEventTarget().cast(), null);

        // NPE check
        if (w == null) {
            VConsole.error("Could not find widget");
            return null;
        }

        // Special treatment for Tabsheet
        if (root instanceof VDDTabSheet) {
            if (w instanceof VCaption || w == root) {
                // We are dragging a tabsheet tab, handle it
                return createTabsheetTransferableFromMouseDown((VDDTabSheet) root, w, event);
            } else {
                return null;
            }
        }

        // Special treatment for Accordion
        if (root instanceof VDDAccordion) {
            if (w instanceof VCaption || w == root) {
                // We are dragging a Accordion tab, handle it
                return createAccordionTransferableFromMouseDown((VDDAccordion) root, (VCaption) w, event);
            } else {
                // Do not allow dragging content, only the "tab"
                return null;
            }
        }

        // Ensure we have the right widget
        w = getTransferableWidget(w);

        // Find the containing layout of the component
        Container layout = Util.getLayout(w);

        // Iterate until parent either is the root or a layout with drag and
        // drop enabled
        while (layout != root && layout != null) {
            if (layout instanceof VHasDragMode && ((VHasDragMode) layout).getDragMode() != LayoutDragMode.NONE) {
                // Found parent layout with support for drag and drop
                break;
            }
            w = (Widget) layout;
            layout = Util.getLayout(w);
        }

        // Consistency check
        if (w == null || root == w || layout == null) {
            VConsole.error("Consistency check failed");
            return null;
        }

        // Ensure layout allows dragging
        if (!isDraggingEnabled(layout)) {
            return null;
        }

        return createTransferable(layout, w, event);
    }

    private static VTransferable createTransferable(Container layout, Widget widget, NativeEvent event) {
        VTransferable transferable = new VTransferable();
        transferable.setDragSource(layout);
        transferable.setData(Constants.TRANSFERABLE_DETAIL_COMPONENT, widget);
        transferable.setData(Constants.TRANSFERABLE_DETAIL_MOUSEDOWN, new MouseEventDetails(event).serialize());
        return transferable;
    }

    private static Widget getTransferableWidget(Widget w) {
        // Ensure w is Paintable
        while (!(w instanceof Paintable) && w.getParent() != null) {
            w = w.getParent();
        }

        // Are we grabbing the caption of a component
        boolean isCaption = w instanceof VCaption;

        if (isCaption) {
            // Dragging caption means dragging component the caption belongs to
            Widget owner = (Widget) ((VCaption) w).getOwner();
            if (owner != null) {
                w = owner;
            }
        } else if (w instanceof VScrollTable.VScrollTableBody.VScrollTableRow) {
            // Table rows are paintable but we do not want to drag them so
            // search for next paintable which should be the table itself
            w = w.getParent();
            while (!(w instanceof Paintable)) {
                w = w.getParent();
            }
        } else if (w.getParent().getParent().getParent() instanceof VTwinColSelect) {
            // TwinColSelect has paintable buttons..
            w = w.getParent().getParent().getParent();
        }

        return w;
    }

    /**
     * Is dragging enabled for a component container
     * 
     * @param layout
     *            The component container to check
     * @return
     */
    private static boolean isDraggingEnabled(Container layout) {
        if (layout instanceof VHasDragMode) {
            LayoutDragMode dm = ((VHasDragMode) layout).getDragMode();
            return dm != LayoutDragMode.NONE;
        }
        return false;
    }

    /**
     * Removes the Drag and drop fake paintable from an UIDL
     * 
     * @param uidl
     *            The uidl which contains a dragdrop paintable (-ac)
     * @return UIDL stripped of the paintable
     */
    public static native UIDL removeDragDropCriteraFromUIDL(UIDL uidl)
    /*-{
    var obj = new Array();
    for(key in uidl){
        if(uidl[key][0] != "-ac"){
           obj[key] = uidl[key];
        }
    }
    return obj;
    }-*/;

    /**
     * Measures the left margin of an element
     * 
     * @param element
     *            The element to measure
     * @return Left margin in pixels
     */
    public static int measureMarginLeft(Element element) {
        return element.getAbsoluteLeft() - element.getParentElement().getAbsoluteLeft();
    }

    /**
     * Measures the top margin of an element
     * 
     * @param element
     *            The element to measure
     * @return Top margin in pixels
     */
    public static int measureMarginTop(Element element) {
        return element.getAbsoluteTop() - element.getParentElement().getAbsoluteTop();
    }
}