/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.server.headlessclient.dnd; import org.apache.wicket.Component; import org.apache.wicket.Component.IVisitor; import org.apache.wicket.MarkupContainer; import org.apache.wicket.Page; import org.apache.wicket.Request; import org.apache.wicket.Session; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.behavior.IIgnoreDisabledComponentBehavior; import org.apache.wicket.markup.html.IHeaderResponse; import com.servoy.j2db.dnd.DRAGNDROP; import com.servoy.j2db.server.headlessclient.WebClientSession; import com.servoy.j2db.server.headlessclient.dataui.AbstractServoyDefaultAjaxBehavior; import com.servoy.j2db.server.headlessclient.dataui.WebEventExecutor; import com.servoy.j2db.server.headlessclient.yui.YUILoader; import com.servoy.j2db.ui.IComponent; import com.servoy.j2db.util.Utils; /** * Class used to add drag and drop support for web components * * @author gboros */ public abstract class DraggableBehavior extends AbstractServoyDefaultAjaxBehavior implements IIgnoreDisabledComponentBehavior { private static final long serialVersionUID = 1L; /** * Drag start action name. */ public static final String ACTION_DRAG_START = "aStart"; /** * Drag end action name. */ public static final String ACTION_DRAG_END = "aEnd"; /** * Drop hover action name. */ public static final String ACTION_DROP_HOVER = "aHover"; /** * Drop action name. */ public static final String ACTION_DROP = "aDrop"; /** * Action parameter name. */ public static final String PARAM_ACTION = "a"; /** * Draggable element id parameter name. */ public static final String PARAM_DRAGGABLE_ID = "draggableID"; /** * Target element id parameter name. */ public static final String PARAM_TARGET_ID = "targetID"; /** * Mouse x coordinate parameter name. */ public static final String PARAM_X = "xc"; /** * Mouse y coordinate parameter name. */ public static final String PARAM_Y = "yc"; /** * Modifiers parameter name. */ public static final String PARAM_MODIFIERS = "m"; private boolean bUseProxy; private boolean bResizeProxyFrame; private boolean bXConstraint; private boolean bYConstraint; private boolean isRenderOnHead = true; protected static boolean dropResult; /** * Sets whatever the behavior javascript code will be rendered * in the response head, or on the body * * @param isRenderOnHead true to render the behavior javascript in the response head */ public void setRenderOnHead(boolean isRenderOnHead) { this.isRenderOnHead = isRenderOnHead; } /** * Sets whatever a floating element (proxy) is showing for the dragging element. * * @param bUseProxy whatever to show floating element for the drag */ public void setUseProxy(boolean bUseProxy) { this.bUseProxy = bUseProxy; } /** * Returns whatever a floating element (proxy) is showing for the dragging element. * * @return whatever floating element is showing for the drag */ public boolean isUseProxy() { return this.bUseProxy; } /** * Sets whatever the proxy frame is resized to the dragged element size. * * @param bResizeProxyFrame whatever the proxy frame is resized to the dragged element size */ public void setResizeProxyFrame(boolean bResizeProxyFrame) { this.bResizeProxyFrame = bResizeProxyFrame; } /** * Returns whatever the proxy frame is resized to the dragged element size. * * @return whatever the proxy frame is resized to the dragged element size */ public boolean isResizeProxyFrame() { return this.bResizeProxyFrame; } /** * Sets whatever dragging is only possible vertically. * * @param bXConstraint whatever dragging is only possible vertically */ public void setXConstraint(boolean bXConstraint) { this.bXConstraint = bXConstraint; } /** * Returns whatever dragging is only possible vertically. * * @return whatever dragging is only possible vertically. */ public boolean isXConstraint() { return this.bXConstraint; } /** * Sets whatever dragging is only possible horizontally. * * @param bYConstraint whatever dragging is only possible horizontally */ public void setYConstraint(boolean bYConstraint) { this.bYConstraint = bYConstraint; } /** * Returns whatever dragging is only possible horizontally. * * @return whatever dragging is only possible horizontally. */ public boolean isYConstraint() { return this.bYConstraint; } /** * Sets the dragging data. * * @param dragData the data * @param mimeType the data mime type */ public void setDragData(Object dragData, String mimeType) { ((WebClientSession)Session.get()).getDNDSessionInfo().setData(dragData, mimeType); } /** * Gets the drag data. * * @return the drag data */ public Object getDragData() { return ((WebClientSession)Session.get()).getDNDSessionInfo().getData(); } /** * Gets the drag data mime type. * * @return the drag data mime type */ public String getDragDataMimeType() { return ((WebClientSession)Session.get()).getDNDSessionInfo().getMimeType(); } /** * Sets the current drag operation, a DRAGNDROP constant or a combination of that * * @param currentDragOperation */ public void setCurrentDragOperation(int currentDragOperation) { ((WebClientSession)Session.get()).getDNDSessionInfo().setCurrentOperation(currentDragOperation); } /** * Returns the current drag operation, a DRAGNDROP constant or a combination of that * @return the current drag operation */ public int getCurrentDragOperation() { return ((WebClientSession)Session.get()).getDNDSessionInfo().getCurrentOperation(); } /** * Sets the drag component. * * @param component that is dragged */ public void setDragComponent(IComponent component) { ((WebClientSession)Session.get()).getDNDSessionInfo().setComponent(component); } /** * Returns the drag component. * * @return the drag component */ public IComponent getDragComponent() { return ((WebClientSession)Session.get()).getDNDSessionInfo().getComponent(); } /** * Sets the drop result. * * @param dropResult whatever it was a successful drop */ public void setDropResult(boolean dropResult) { ((WebClientSession)Session.get()).getDNDSessionInfo().setDropResult(dropResult); } /** * Returns the drop result. * * @return whatever it was a successful drop */ public boolean getDropResult() { return ((WebClientSession)Session.get()).getDNDSessionInfo().getDropResult(); } /** * Get the child component with the specified id. * * @param childId id of child component * * @return the child component or null if not found */ public IComponent getBindedComponentChild(final String childId) { IComponent bindedComponentChild = null; Component bindedComponent = getComponent(); if (bindedComponent instanceof MarkupContainer) { bindedComponentChild = (IComponent)((MarkupContainer)bindedComponent).visitChildren(IComponent.class, new IVisitor<Component>() { public Object component(Component component) { if (component.getMarkupId().equals(childId)) { return component; } return IVisitor.CONTINUE_TRAVERSAL; } }); } return bindedComponentChild; } @Override protected void onComponentRendered() { super.onComponentRendered(); if (!isRenderOnHead) WebEventExecutor.generateDragAttach(getComponent(), null); } @Override protected void respond(AjaxRequestTarget ajaxRequestTarget) { Page componentPage = getComponent().getPage(); Request componentRequest = getComponent().getRequest(); String action = componentRequest.getParameter(PARAM_ACTION); String id = componentRequest.getParameter(PARAM_DRAGGABLE_ID); int modifiers = WebEventExecutor.convertModifiers(Integer.parseInt(componentRequest.getParameter(PARAM_MODIFIERS))); if (ACTION_DRAG_START.equals(action)) { boolean dragStartReturn = onDragStart(id, Utils.getAsInteger(componentRequest.getParameter(PARAM_X)), Utils.getAsInteger(componentRequest.getParameter(PARAM_Y)), modifiers, ajaxRequestTarget); if (!dragStartReturn) ajaxRequestTarget.appendJavascript("YAHOO.util.DragDropMgr.stopDrag(Servoy.DD.mouseDownEvent, false);"); } else if (ACTION_DRAG_END.equals(action)) { onDragEnd(id, Utils.getAsInteger(componentRequest.getParameter(PARAM_X)), Utils.getAsInteger(componentRequest.getParameter(PARAM_Y)), modifiers, ajaxRequestTarget); } else if (ACTION_DROP_HOVER.equals(action)) { onDropHover(id, componentRequest.getParameter(PARAM_TARGET_ID), modifiers, ajaxRequestTarget); } else if (ACTION_DROP.equals(action)) { onDrop(id, componentRequest.getParameter(PARAM_TARGET_ID), Utils.getAsInteger(componentRequest.getParameter(PARAM_X)), Utils.getAsInteger(componentRequest.getParameter(PARAM_Y)), modifiers, ajaxRequestTarget); } WebEventExecutor.generateResponse(ajaxRequestTarget, componentPage); } /** * @see org.apache.wicket.ajax.AbstractDefaultAjaxBehavior#renderHead(org.apache.wicket.markup.html.IHeaderResponse) */ @Override public void renderHead(IHeaderResponse response) { super.renderHead(response); YUILoader.renderDragNDrop(response); if (isRenderOnHead) WebEventExecutor.generateDragAttach(getComponent(), response); } /** * Called when a drag is started. * * @param id drag component id * @param x mouse x coordinate * @param y mouse y coordinate * @param m modifiers * @param ajaxRequestTarget * @return whatever the drag can start */ protected abstract boolean onDragStart(String id, int x, int y, int m, AjaxRequestTarget ajaxRequestTarget); /** * Called when a drag ends. * * @param id target component id * @param x mouse x coordinate * @param y mouse y coordinate * @param m modifiers * @param ajaxRequestTarget */ protected void onDragEnd(String id, int x, int y, int m, AjaxRequestTarget ajaxRequestTarget) { setDragData(null, null); setCurrentDragOperation(DRAGNDROP.NONE); } /** * Called on drop hover. * * @param id drag component id * @param targeid target component id * @param m modifiers * @param ajaxRequestTarget */ protected abstract void onDropHover(String id, String targeid, int m, AjaxRequestTarget ajaxRequestTarget); /** * Called on drop. * @param id drag component id * @param targetid target component id * @param x mouse x coordinate * @param y mouse y coordinate * @param m modifiers * @param ajaxRequestTarget */ protected abstract void onDrop(String id, String targetid, int x, int y, int m, AjaxRequestTarget ajaxRequestTarget); }