/*
* 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.Iterator;
import java.util.Set;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
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.ui.VAbsoluteLayout;
import com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler;
import com.vaadin.terminal.gwt.client.ui.dd.VDragEvent;
import com.vaadin.terminal.gwt.client.ui.dd.VDropHandler;
import com.vaadin.terminal.gwt.client.ui.dd.VHasDropHandler;
import fi.jasoft.dragdroplayouts.client.ui.VLayoutDragDropMouseHandler.DragStartListener;
import fi.jasoft.dragdroplayouts.client.ui.interfaces.VHasDragMode;
import fi.jasoft.dragdroplayouts.client.ui.util.IframeCoverUtility;
public class VDDAbsoluteLayout extends VAbsoluteLayout implements VHasDragMode,
VHasDropHandler, DragStartListener {
public static final String CLASSNAME = "v-ddabsolutelayout";
private VAbstractDropHandler dropHandler;
private LayoutDragMode dragMode = LayoutDragMode.NONE;
private final VLayoutDragDropMouseHandler ddHandler = new VLayoutDragDropMouseHandler(
this, dragMode);
protected boolean iframeCoversEnabled = false;
private final VDragFilter dragFilter = new VDragFilter();
private final IframeCoverUtility iframeCoverUtility = new IframeCoverUtility();
public VDDAbsoluteLayout() {
super();
ddHandler.addDragStartListener(this);
}
@Override
protected void onUnload() {
super.onUnload();
ddHandler.detach();
iframeCoverUtility.setIframeCoversEnabled(false, getElement());
}
@Override
public boolean requestLayout(Set<Paintable> children) {
iframeCoverUtility.setIframeCoversEnabled(iframeCoversEnabled,
getElement());
return super.requestLayout(children);
}
@Override
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
// Drag mode
handleDragModeUpdate(uidl);
// Drop handlers
UIDL c = null;
for (final Iterator<Object> it = uidl.getChildIterator(); it.hasNext();) {
c = (UIDL) it.next();
if (c.getTag().equals("-ac")) {
updateDropHandler(c);
break;
}
}
UIDL modifiedUIDL = VDragDropUtil.removeDragDropCriteraFromUIDL(uidl);
super.updateFromUIDL(modifiedUIDL, client);
/*
* Always check for iframe covers so new added/removed components get
* covered
*/
iframeCoverUtility.setIframeCoversEnabled(iframeCoversEnabled,
getElement());
// Drag filters
dragFilter.update(modifiedUIDL, client);
}
private void handleDragModeUpdate(UIDL uidl) {
if (uidl.hasAttribute(VHasDragMode.DRAGMODE_ATTRIBUTE)) {
LayoutDragMode[] modes = LayoutDragMode.values();
dragMode = modes[uidl
.getIntAttribute(VHasDragMode.DRAGMODE_ATTRIBUTE)];
ddHandler.updateDragMode(dragMode);
if (dragMode != LayoutDragMode.NONE) {
// Cover iframes if necessery
iframeCoversEnabled = uidl
.getBooleanAttribute(IframeCoverUtility.SHIM_ATTRIBUTE);
// Listen to mouse down events
ddHandler.attach();
} else if (dragMode == LayoutDragMode.NONE) {
// Remove iframe covers
iframeCoversEnabled = false;
// Remove mouse down handler
ddHandler.detach();
}
}
}
/**
* Updates the drag details while a component is dragged
*
* @param drag
* The drag event to update the details from
*/
protected void updateDragDetails(VDragEvent drag) {
// Get absolute coordinates
int absoluteLeft = getAbsoluteLeft();
int absoluteTop = getAbsoluteTop();
drag.getDropDetails().put(Constants.DROP_DETAIL_ABSOLUTE_LEFT,
absoluteLeft);
drag.getDropDetails().put(Constants.DROP_DETAIL_ABSOLUTE_TOP,
absoluteTop);
// Get relative coordinates
String offsetLeftStr = drag.getDragImage().getStyle().getMarginLeft();
int offsetLeft = Integer.parseInt(offsetLeftStr.substring(0,
offsetLeftStr.length() - 2));
int relativeLeft = Util.getTouchOrMouseClientX(drag
.getCurrentGwtEvent()) - canvas.getAbsoluteLeft() + offsetLeft;
String offsetTopStr = drag.getDragImage().getStyle().getMarginTop();
int offsetTop = Integer.parseInt(offsetTopStr.substring(0,
offsetTopStr.length() - 2));
int relativeTop = Util
.getTouchOrMouseClientY(drag.getCurrentGwtEvent())
- canvas.getAbsoluteTop() + offsetTop;
drag.getDropDetails().put(Constants.DROP_DETAIL_RELATIVE_LEFT,
relativeLeft);
drag.getDropDetails().put(Constants.DROP_DETAIL_RELATIVE_TOP,
relativeTop);
// Get component size
Widget w = (Widget) drag.getTransferable().getData(
Constants.TRANSFERABLE_DETAIL_COMPONENT);
if (w != null) {
drag.getDropDetails().put(Constants.DROP_DETAIL_COMPONENT_WIDTH,
w.getOffsetWidth());
drag.getDropDetails().put(Constants.DROP_DETAIL_COMPONENT_HEIGHT,
w.getOffsetHeight());
} else {
drag.getDropDetails()
.put(Constants.DROP_DETAIL_COMPONENT_WIDTH, -1);
drag.getDropDetails().put(Constants.DROP_DETAIL_COMPONENT_HEIGHT,
-1);
}
// Add mouse event details
MouseEventDetails details = new MouseEventDetails(
drag.getCurrentGwtEvent(), getElement());
drag.getDropDetails().put(Constants.DROP_DETAIL_MOUSE_EVENT,
details.serialize());
}
/**
* A hook for extended components to post process the the drop before it is
* sent to the server. Useful if you don't want to override the whole drop
* handler.
*/
protected boolean postDropHook(VDragEvent drag) {
// Extended classes can add content here...
return true;
}
/**
* A hook for extended components to post process the the enter event.
* Useful if you don't want to override the whole drophandler.
*/
protected void postEnterHook(VDragEvent drag) {
// Extended classes can add content here...
}
/**
* A hook for extended components to post process the the leave event.
* Useful if you don't want to override the whole drophandler.
*/
protected void postLeaveHook(VDragEvent drag) {
// Extended classes can add content here...
}
/**
* A hook for extended components to post process the the over event. Useful
* if you don't want to override the whole drophandler.
*/
protected void postOverHook(VDragEvent drag) {
// Extended classes can add content here...
}
/**
* Can be used to listen to drag start events, must return true for the drag
* to commence. Return false to interrupt the drag:
*/
public boolean dragStart(Widget widget, LayoutDragMode mode) {
return dragMode != LayoutDragMode.NONE
&& dragFilter.isDraggable(widget);
}
/**
* Updates the drop handler. Creates a drop handler if it does not exist.
*
* @param childUidl
* The child UIDL containing the rules
*/
protected void updateDropHandler(UIDL childUidl) {
if (dropHandler == null) {
dropHandler = new VAbstractDropHandler() {
/*
* (non-Javadoc)
*
* @see com.vaadin.terminal.gwt.client.ui.dd.VDropHandler#
* getApplicationConnection()
*/
public ApplicationConnection getApplicationConnection() {
return client;
}
/*
* (non-Javadoc)
*
* @see
* com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
* #getPaintable()
*/
@Override
public Paintable getPaintable() {
return VDDAbsoluteLayout.this;
}
/*
* (non-Javadoc)
*
* @see
* com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
* #dragAccepted
* (com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
*/
@Override
protected void dragAccepted(VDragEvent drag) {
}
/*
* (non-Javadoc)
*
* @see
* com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
* #drop(com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
*/
@Override
public boolean drop(VDragEvent drag) {
if (super.drop(drag)) {
updateDragDetails(drag);
return postDropHook(drag);
}
return false;
};
/*
* (non-Javadoc)
*
* @see
* com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
* #dragEnter(com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
*/
@Override
public void dragEnter(VDragEvent drag) {
super.dragEnter(drag);
Object w = drag.getTransferable().getData(
Constants.TRANSFERABLE_DETAIL_COMPONENT);
if (w instanceof Container) {
drag.getDragImage().addClassName(
CLASSNAME + "-drag-shadow");
}
postEnterHook(drag);
};
/*
* (non-Javadoc)
*
* @see
* com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
* #dragLeave(com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
*/
@Override
public void dragLeave(VDragEvent drag) {
super.dragLeave(drag);
Object w = drag.getTransferable().getData(
Constants.TRANSFERABLE_DETAIL_COMPONENT);
if (w instanceof Container) {
drag.getDragImage().removeClassName(
CLASSNAME + "-drag-shadow");
}
postLeaveHook(drag);
};
/*
* (non-Javadoc)
*
* @see
* com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler
* #dragOver(com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
*/
@Override
public void dragOver(VDragEvent drag) {
drag.getDragImage().getStyle().setProperty("display", "");
// Update drop details with the location so we can
// validate it
updateDragDetails(drag);
postOverHook(drag);
};
};
}
dropHandler.updateAcceptRules(childUidl);
}
/**
* Returns the drag mode
*
* @return
*/
public LayoutDragMode getDragMode() {
return dragMode;
}
/**
* Returns the drop handler which handles the drop events
*/
public VDropHandler getDropHandler() {
return dropHandler;
}
}