aboutsummaryrefslogtreecommitdiffstats
path: root/uitest/src/com/vaadin/tests/dd
diff options
context:
space:
mode:
Diffstat (limited to 'uitest/src/com/vaadin/tests/dd')
-rw-r--r--uitest/src/com/vaadin/tests/dd/AcceptAnythingWindow.java138
-rw-r--r--uitest/src/com/vaadin/tests/dd/AcceptFromComponent.java156
-rw-r--r--uitest/src/com/vaadin/tests/dd/ActiveDragSourceClassName.java121
-rw-r--r--uitest/src/com/vaadin/tests/dd/CustomDDImplementation.java85
-rw-r--r--uitest/src/com/vaadin/tests/dd/DDTest1.java270
-rw-r--r--uitest/src/com/vaadin/tests/dd/DDTest2.java322
-rw-r--r--uitest/src/com/vaadin/tests/dd/DDTest4.java163
-rw-r--r--uitest/src/com/vaadin/tests/dd/DDTest5.java179
-rw-r--r--uitest/src/com/vaadin/tests/dd/DDTest6.java566
-rw-r--r--uitest/src/com/vaadin/tests/dd/DDTest7.java191
-rw-r--r--uitest/src/com/vaadin/tests/dd/DDTest8.java180
-rw-r--r--uitest/src/com/vaadin/tests/dd/DragAndDropFiles.java132
-rw-r--r--uitest/src/com/vaadin/tests/dd/DragDropPane.java188
-rw-r--r--uitest/src/com/vaadin/tests/dd/HorizontalLayoutSortableWithWrappers.java111
-rw-r--r--uitest/src/com/vaadin/tests/dd/HorizontalSortableCssLayoutWithWrappers.java105
-rw-r--r--uitest/src/com/vaadin/tests/dd/MyDragSourceConnector.java41
-rw-r--r--uitest/src/com/vaadin/tests/dd/MyDropTargetConnector.java42
-rw-r--r--uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSource.html71
-rw-r--r--uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSource.java94
-rw-r--r--uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSourceInTabSheet.java79
-rw-r--r--uitest/src/com/vaadin/tests/dd/ScrolledDropTarget.html.disabled0
-rw-r--r--uitest/src/com/vaadin/tests/dd/ScrolledDropTarget.java70
-rw-r--r--uitest/src/com/vaadin/tests/dd/StartHtml5Drag.java66
-rw-r--r--uitest/src/com/vaadin/tests/dd/TreeDragStart.java330
-rw-r--r--uitest/src/com/vaadin/tests/dd/VMyDragSource.java89
-rw-r--r--uitest/src/com/vaadin/tests/dd/VMyDropTarget.java53
-rw-r--r--uitest/src/com/vaadin/tests/dd/html5drop.htm51
27 files changed, 3893 insertions, 0 deletions
diff --git a/uitest/src/com/vaadin/tests/dd/AcceptAnythingWindow.java b/uitest/src/com/vaadin/tests/dd/AcceptAnythingWindow.java
new file mode 100644
index 0000000000..5d57de388c
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/AcceptAnythingWindow.java
@@ -0,0 +1,138 @@
+package com.vaadin.tests.dd;
+
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.Transferable;
+import com.vaadin.event.TransferableImpl;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.ui.AbsoluteLayout;
+import com.vaadin.ui.AbsoluteLayout.ComponentPosition;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.DragAndDropWrapper.DragStartMode;
+import com.vaadin.ui.DragAndDropWrapper.WrapperTargetDetails;
+import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+
+public class AcceptAnythingWindow extends Window {
+
+ private AbsoluteLayout layout = new AbsoluteLayout();
+
+ public AcceptAnythingWindow() {
+ setCaption("Drop anything here");
+
+ final DragAndDropWrapper wrapper = new DragAndDropWrapper(layout);
+ wrapper.setDropHandler(new DropHandler() {
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ WrapperTargetDetails ed = (WrapperTargetDetails) event
+ .getTargetDetails();
+ Transferable transferable = event.getTransferable();
+ TransferableImpl ctr = (TransferableImpl) transferable;
+ Component component = ctr.getSourceComponent();
+ if (component == wrapper) {
+ // if the drag source was wrapper we are interested about
+ // the dragged component
+ WrapperTransferable tr = (WrapperTransferable) transferable;
+ component = tr.getDraggedComponent();
+ // html5 drag created by wrapper set component null
+ }
+
+ if (component != null) {
+
+ if (component.getParent() != layout) {
+ if (transferable instanceof DataBoundTransferable) {
+ // Item has been dragged, construct a Label from
+ // Item id
+ Label l = new Label();
+ l.setSizeUndefined();
+ l.setValue("ItemId : "
+ + ((DataBoundTransferable) transferable)
+ .getItemId());
+ layout.addComponent(l);
+ component = l;
+
+ } else {
+ // we have a component that is been dragged, add
+ // it to this
+ layout.addComponent(component);
+ }
+
+ Integer left = ed.getAbsoluteLeft();
+ Integer top = ed.getAbsoluteTop();
+
+ MouseEventDetails eventDetails = ed.getMouseEvent();
+
+ int clientX = eventDetails.getClientX();
+ int clientY = eventDetails.getClientY();
+
+ try {
+ layout.getPosition(component).setTopValue(
+ Float.valueOf(clientY - top));
+ layout.getPosition(component).setLeftValue(
+ Float.valueOf(clientX - left));
+ } catch (Exception e) {
+ // TODO: handle exception
+ }
+ } else {
+
+ WrapperTransferable tr = (WrapperTransferable) transferable;
+ // drag ended inside the this Pane
+
+ MouseEventDetails start = tr.getMouseDownEvent();
+ MouseEventDetails eventDetails = ed.getMouseEvent();
+
+ int deltaX = eventDetails.getClientX()
+ - start.getClientX();
+ int deltaY = eventDetails.getClientY()
+ - start.getClientY();
+
+ ComponentPosition p = layout.getPosition(component);
+ p.setTopValue(p.getTopValue() + deltaY);
+ p.setLeftValue(p.getLeftValue() + deltaX);
+
+ }
+
+ } else {
+ // drag coming outside of Vaadin
+ String object = (String) transferable.getData("Text");
+
+ String content = (String) transferable
+ .getData("fileContents");
+
+ Label l = new Label();
+ l.setCaption("Generated from HTML5 drag:");
+ if (object != null) {
+ l.setValue(object);
+ } else {
+ l.setValue("HTML5 dd");
+ }
+
+ l.setDescription(content);
+ l.setSizeUndefined();
+
+ layout.addComponent(l);
+
+ }
+ return;
+ }
+ });
+
+ wrapper.setDragStartMode(DragStartMode.COMPONENT);
+ wrapper.setSizeFull();
+ setContent(wrapper);
+
+ setWidth("250px");
+ setHeight("100px");
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/dd/AcceptFromComponent.java b/uitest/src/com/vaadin/tests/dd/AcceptFromComponent.java
new file mode 100644
index 0000000000..99dd069142
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/AcceptFromComponent.java
@@ -0,0 +1,156 @@
+package com.vaadin.tests.dd;
+
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.Transferable;
+import com.vaadin.event.TransferableImpl;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.ServerSideCriterion;
+import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.ui.AbsoluteLayout;
+import com.vaadin.ui.AbsoluteLayout.ComponentPosition;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.DragAndDropWrapper.WrapperTargetDetails;
+import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.Window;
+
+public class AcceptFromComponent extends Window {
+
+ private AbsoluteLayout layout;
+
+ public AcceptFromComponent(final Tree tree1) {
+ setCaption("Checks the source is tree1 on server");
+
+ layout = new AbsoluteLayout();
+ DragAndDropWrapper wrapper = new DragAndDropWrapper(layout);
+
+ setContent(wrapper);
+
+ wrapper.setSizeFull();
+ layout.setSizeFull();
+ setWidth("450px");
+ setHeight("150px");
+
+ final ServerSideCriterion serverSideCriterion = new ServerSideCriterion() {
+
+ @Override
+ public boolean accept(DragAndDropEvent dragEvent) {
+ Transferable transferable = dragEvent.getTransferable();
+ if (transferable instanceof TransferableImpl) {
+ TransferableImpl componentTransferrable = (TransferableImpl) transferable;
+ if (componentTransferrable.getSourceComponent() == tree1) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ wrapper.setDropHandler(new DropHandler() {
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return serverSideCriterion;
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+
+ WrapperTargetDetails ed = (WrapperTargetDetails) event
+ .getTargetDetails();
+ Transferable ctr = event.getTransferable();
+ if (ctr.getSourceComponent() != null) {
+ // use "component" (from DragDropPane) if available, else
+ // take
+ // the source component
+ Component component = (Component) ctr.getData("component");
+ if (component == null) {
+ component = ctr.getSourceComponent();
+ }
+
+ if (component.getParent() != layout) {
+ if (ctr instanceof DataBoundTransferable) {
+ // Item has been dragged, construct a Label from
+ // Item id
+ Label l = new Label();
+ l.setSizeUndefined();
+ l.setValue("ItemId : "
+ + ((DataBoundTransferable) ctr).getItemId());
+ layout.addComponent(l);
+ component = l;
+
+ } else {
+ // we have a component that is been dragged, add
+ // it
+ // to
+ // this
+ layout.addComponent(component);
+ }
+
+ Integer left = ed.getAbsoluteLeft();
+ Integer top = ed.getAbsoluteTop();
+
+ MouseEventDetails eventDetails = ed.getMouseEvent();
+
+ int clientX = eventDetails.getClientX();
+ int clientY = eventDetails.getClientY();
+
+ try {
+ layout.getPosition(component).setTopValue(
+ Float.valueOf(clientY - top));
+ layout.getPosition(component).setLeftValue(
+ Float.valueOf(clientX - left));
+ } catch (Exception e) {
+ // TODO: handle exception
+ }
+ } else {
+ // drag started and ended inside the this Pane
+
+ DragAndDropWrapper.WrapperTransferable tr = (WrapperTransferable) event
+ .getTransferable();
+
+ MouseEventDetails start = tr.getMouseDownEvent();
+
+ MouseEventDetails eventDetails = ed.getMouseEvent();
+
+ int deltaX = eventDetails.getClientX()
+ - start.getClientX();
+ int deltaY = eventDetails.getClientY()
+ - start.getClientY();
+
+ ComponentPosition p = layout.getPosition(component);
+ p.setTopValue(p.getTopValue() + deltaY);
+ p.setLeftValue(p.getLeftValue() + deltaX);
+
+ }
+
+ } else {
+ // drag coming outside of Vaadin
+ String object = (String) ctr.getData("text/plain");
+
+ String content = (String) ctr.getData("fileContents");
+
+ Label l = new Label();
+ l.setCaption("Generated from HTML5 drag:");
+ if (object != null) {
+ l.setValue(object);
+ } else {
+ l.setValue("HTML5 dd");
+ }
+
+ l.setDescription(content);
+ l.setSizeUndefined();
+
+ layout.addComponent(l);
+
+ }
+ return;
+ }
+ });
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/dd/ActiveDragSourceClassName.java b/uitest/src/com/vaadin/tests/dd/ActiveDragSourceClassName.java
new file mode 100644
index 0000000000..9ef1b4029b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/ActiveDragSourceClassName.java
@@ -0,0 +1,121 @@
+package com.vaadin.tests.dd;
+
+import java.util.Iterator;
+
+import com.vaadin.event.Transferable;
+import com.vaadin.event.TransferableImpl;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.DropTarget;
+import com.vaadin.event.dd.TargetDetails;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.util.TestUtils;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+
+public class ActiveDragSourceClassName extends TestBase {
+
+ private static final String GREENBOXES = ".greenblock {float:left; width:60px;height:60px;background: green !important; padding:0; margin:2px;-webkit-transition: width 0.3s ease-in-out;}";
+ private static final String HIDEDRAGSOURCE = ".v-active-drag-source { overflow:hidden; width:0px !important;}";
+
+ @Override
+ protected void setup() {
+ TestUtils.injectCSS(getMainWindow(), GREENBOXES + HIDEDRAGSOURCE);
+
+ VerticalLayout l = new VerticalLayout();
+ l.setWidth("400px");
+ l.setHeight("100px");
+ DragAndDropWrapper pane = new DragAndDropWrapper(cssLayout);
+ pane.setSizeFull();
+ l.addComponent(pane);
+
+ addComponent(l);
+
+ for (int i = 0; i < 4; i++) {
+ cssLayout.addComponent(new WrappedLabel("Block"));
+ }
+
+ }
+
+ static int count;
+
+ private CssLayout cssLayout = new CssLayout() {
+ };
+
+ class WrappedLabel extends DragAndDropWrapper {
+
+ private static final long serialVersionUID = 1L;
+
+ public WrappedLabel(String content) {
+ super(new Label(content + " c:" + ++count));
+ getCompositionRoot().setSizeUndefined();
+ setHeight("60px"); // FIXME custom component seems to be broken:
+ // can't set height with css only
+ setWidth("60px");
+ setDragStartMode(DragStartMode.WRAPPER);
+ addStyleName("greenblock");
+ }
+
+ @Override
+ public DropHandler getDropHandler() {
+ return dh;
+ }
+
+ }
+
+ private DropHandler dh = new DropHandler() {
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ @Override
+ public void drop(DragAndDropEvent dropEvent) {
+ Transferable transferable = dropEvent.getTransferable();
+ if (transferable instanceof TransferableImpl) {
+ TransferableImpl ct = (TransferableImpl) transferable;
+ Component sourceComponent = ct.getSourceComponent();
+ if (sourceComponent instanceof WrappedLabel) {
+ int index = 1;
+ Iterator<Component> componentIterator = cssLayout
+ .getComponentIterator();
+ Component next = componentIterator.next();
+ TargetDetails dropTargetData = dropEvent.getTargetDetails();
+ DropTarget target = dropTargetData.getTarget();
+ while (next != target) {
+ if (next != sourceComponent) {
+ index++;
+ }
+ next = componentIterator.next();
+ }
+ if (dropTargetData.getData("horizontalLocation").equals(
+ "LEFT")) {
+ index--;
+ if (index < 0) {
+ index = 0;
+ }
+ }
+
+ cssLayout.removeComponent(sourceComponent);
+ cssLayout.addComponent(sourceComponent, index);
+ }
+ }
+ }
+ };
+
+ @Override
+ protected String getDescription() {
+ return "It should be possible to style the source component during the drag.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 6813;
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/dd/CustomDDImplementation.java b/uitest/src/com/vaadin/tests/dd/CustomDDImplementation.java
new file mode 100644
index 0000000000..f6e196761e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/CustomDDImplementation.java
@@ -0,0 +1,85 @@
+package com.vaadin.tests.dd;
+
+import java.util.Map;
+
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.DropTarget;
+import com.vaadin.event.dd.TargetDetails;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Layout;
+
+/**
+ * Test/Example/Draft code how to build custom DD implementation using the thing
+ * framework provided by Vaadin.
+ *
+ */
+public class CustomDDImplementation extends CustomComponent {
+
+ public CustomDDImplementation() {
+ Layout l = new CssLayout();
+ l.addComponent(new MyDropTarget());
+ l.addComponent(new MyDragSource());
+ }
+
+ /**
+ * Server side component that accepts drags must implement HasDropHandler
+ * that have one method to get reference of DropHandler.
+ *
+ * DropHandler may be implemented directly or probably most commonly using a
+ * half baked implementation {@link AbstractDropHandler}.
+ *
+ * Check the @ClientWidget
+ *
+ */
+ class MyDropTarget extends AbstractComponent implements DropTarget {
+ @Override
+ public DropHandler getDropHandler() {
+ return new DropHandler() {
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ // Do something with data
+ return;
+ }
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ };
+ }
+
+ @Override
+ public TargetDetails translateDropTargetDetails(
+ Map<String, Object> clientVariables) {
+ // If component has some special drop details that it needs to
+ // translate for server side use, developer must return a
+ // DragDropDetails here. If details does not exist or raw client
+ // side data is ok, it is safe to return null here.
+ return null;
+ }
+
+ }
+
+ /**
+ * Server side implementation of source does not necessary need to contain
+ * anything.
+ *
+ * Check the @ClientWidget
+ *
+ * However component might have different modes to support starting drag
+ * operations that are controlled via server side api.
+ *
+ */
+ public class MyDragSource extends AbstractComponent implements Component {
+
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/DDTest1.java b/uitest/src/com/vaadin/tests/dd/DDTest1.java
new file mode 100644
index 0000000000..161a9b423e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/DDTest1.java
@@ -0,0 +1,270 @@
+package com.vaadin.tests.dd;
+
+import java.util.Collection;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.Transferable;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.ServerSideCriterion;
+import com.vaadin.server.ExternalResource;
+import com.vaadin.shared.ui.dd.VerticalDropLocation;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractSelect.AcceptItem;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.TableDragMode;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.Tree.TreeDragMode;
+import com.vaadin.ui.Tree.TreeTargetDetails;
+
+/**
+ * DD playground. Better quality example/prototype codes in {@link DDTest2}.
+ */
+public class DDTest1 extends TestBase {
+
+ @Override
+ protected void setup() {
+ GridLayout gl = new GridLayout(3, 2);
+ gl.setSizeFull();
+ gl.setSpacing(true);
+ Layout main = gl;
+
+ DragDropPane pane1 = new DragDropPane();
+ pane1.setSizeFull();
+ pane1.setCaption("Pane1");
+
+ Label label = new Label("Foo");
+ label.setSizeUndefined();
+
+ pane1.addComponent(label);
+
+ Link l = new Link("This is link", new ExternalResource(
+ "http://www.google.com/"));
+ pane1.addComponent(l, "top:100px; left: 20px;");
+
+ label = new Label("Bar");
+ label.setSizeUndefined();
+ pane1.addComponent(label);
+
+ DragDropPane pane2 = new DragDropPane();
+ pane2.setCaption("Pane2 (accept needs server side visit, check for \"Bar\")");
+ final AcceptCriterion crit = new ServerSideCriterion() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public boolean accept(DragAndDropEvent dragEvent) {
+ Transferable transferable = dragEvent.getTransferable();
+ // System.out.println("Simulating 500ms processing...");
+ // try {
+ // Thread.sleep(200);
+ // } catch (InterruptedException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
+ // System.out.println("Done get to work.");
+
+ Component component = (Component) transferable
+ .getData("component");
+ if (component == null) {
+ component = transferable.getSourceComponent();
+ }
+
+ if (component != null) {
+ if (component.toString() != null
+ && component.toString().contains("Bar")) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ pane2.setAcceptCriterion(crit);
+
+ pane2.setId("pane2");
+ pane2.setSizeFull();
+
+ DragDropPane pane3 = new DragDropPane();
+ pane3.setSizeFull();
+ pane3.setCaption("Pane3");
+
+ final Tree t = new Tree(
+ "Tree with sorting enabled. Also allows dragging elsewhere.");
+
+ final HierarchicalContainer idx = new HierarchicalContainer();
+ t.setContainerDataSource(idx);
+ t.setId("perseys");
+ t.addItem("Foo");
+ t.addItem("Bar");
+ t.addItem("Bar1");
+ t.addItem("Bar2");
+ t.addItem("Bar3");
+ t.addItem("Bar4");
+ t.addItem("Bar5");
+ t.addItem("Child");
+ t.setParent("Child", "Foo");
+ t.setSizeFull();
+ t.setDragMode(TreeDragMode.NODE);
+
+ /*
+ * Moves items in tree (and could work in Table too). Also supports
+ * "building" tree.
+ *
+ * TODO fix algorithm, broken in some cases.
+ */
+ DropHandler itemSorter = new DropHandler() {
+
+ @SuppressWarnings("unused")
+ private void populateSubTree(HierarchicalContainer idx,
+ HierarchicalContainer subtree, Object itemId) {
+ Collection<?> children = subtree.getChildren(itemId);
+ if (children != null) {
+
+ for (Object childId : children) {
+ Item addItem = idx.addItem(childId);
+ if (addItem != null) {
+ // did not exist, populate properties
+ Item item = subtree.getItem(itemId);
+ Collection<?> itemPropertyIds = item
+ .getItemPropertyIds();
+ for (Object propId : itemPropertyIds) {
+ addItem.getItemProperty(propId)
+ .setValue(
+ item.getItemProperty(propId)
+ .getValue());
+ }
+ }
+ idx.setParent(childId, itemId);
+ populateSubTree(idx, subtree, childId);
+ }
+ }
+
+ }
+
+ @SuppressWarnings("unused")
+ private HierarchicalContainer getSubTree(HierarchicalContainer idx,
+ Object itemId) {
+ HierarchicalContainer hierarchicalContainer = new HierarchicalContainer();
+ Collection<?> containerPropertyIds = idx
+ .getContainerPropertyIds();
+ for (Object object : containerPropertyIds) {
+ hierarchicalContainer.addContainerProperty(object,
+ idx.getType(object), null);
+ }
+ hierarchicalContainer.addItem(itemId);
+ copyChildren(idx, hierarchicalContainer, itemId);
+ return hierarchicalContainer;
+ }
+
+ private void copyChildren(HierarchicalContainer source,
+ HierarchicalContainer target, Object itemId) {
+ Collection<?> children = source.getChildren(itemId);
+ if (children != null) {
+ for (Object childId : children) {
+ Item item = source.getItem(childId);
+ Item addedItem = target.addItem(childId);
+ target.setParent(childId, itemId);
+ Collection<?> itemPropertyIds = item
+ .getItemPropertyIds();
+ for (Object propertyId : itemPropertyIds) {
+ addedItem.getItemProperty(propertyId)
+ .setValue(
+ item.getItemProperty(propertyId)
+ .getValue());
+ }
+ copyChildren(source, target, childId);
+ }
+ }
+
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ TreeTargetDetails details = (TreeTargetDetails) event
+ .getTargetDetails();
+ // TODO set properties, so same sorter could be used in Table
+ Transferable transferable = event.getTransferable();
+ if (transferable instanceof DataBoundTransferable) {
+ DataBoundTransferable transferrable2 = (DataBoundTransferable) transferable;
+
+ Object itemId = transferrable2.getItemId();
+
+ Object itemIdOver = details.getItemIdOver();
+
+ // TODO could use the "folder" node id to make the drop
+ // logic simpler
+ Object itemIdInto = details.getItemIdInto();
+ VerticalDropLocation dropLocation = details
+ .getDropLocation();
+
+ Object itemIdAfter = details.getItemIdAfter();
+
+ if (itemIdOver.equals(itemIdInto)) { // directly on a node
+ t.setParent(itemId, itemIdOver);
+ return;
+ }
+
+ idx.setParent(itemId, itemIdInto);
+
+ if (dropLocation == null) {
+ System.err.println("No detail of drop place available");
+ }
+ idx.moveAfterSibling(itemId, itemIdAfter);
+ }
+
+ return;
+ }
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ // TODO should actually check that source is same as target
+ return AcceptItem.ALL;
+ }
+
+ };
+
+ t.setDropHandler(itemSorter);
+
+ Table ta = new Table("Test table");
+ ta.setContainerDataSource(idx);
+ ta.addContainerProperty("Foos", String.class, "Foo");
+ ta.addContainerProperty("Bars", String.class, "Bar");
+ ta.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
+ ta.setSizeFull();
+ ta.setDragMode(TableDragMode.ROW);
+
+ main.addComponent(pane1);
+ main.addComponent(pane2);
+ main.addComponent(pane3);
+ main.addComponent(t);
+ main.addComponent(ta);
+ main.addComponent(new Link("Foo", new ExternalResource(
+ "http://www.itmill.com/")));
+
+ getLayout().setSizeFull();
+ addComponent(main);
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Random DD tests";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 119;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/DDTest2.java b/uitest/src/com/vaadin/tests/dd/DDTest2.java
new file mode 100644
index 0000000000..7757513fc1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/DDTest2.java
@@ -0,0 +1,322 @@
+package com.vaadin.tests.dd;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.Transferable;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.And;
+import com.vaadin.event.dd.acceptcriteria.Or;
+import com.vaadin.event.dd.acceptcriteria.SourceIs;
+import com.vaadin.server.Resource;
+import com.vaadin.server.ThemeResource;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.util.Person;
+import com.vaadin.tests.util.PersonContainer;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+import com.vaadin.ui.AbstractSelect.AcceptItem;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.TableTransferable;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.Tree.TargetItemAllowsChildren;
+import com.vaadin.ui.Tree.TreeDragMode;
+import com.vaadin.ui.Window;
+
+public class DDTest2 extends TestBase {
+
+ java.util.Random r = new java.util.Random(1);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ Tree tree1 = new Tree("Tree that accepts table rows to folders");
+ Table table = new Table("Drag rows to Tree on left or right");
+ Tree tree2 = new Tree("Accepts items, copies values");
+
+ private Tree tree3;
+
+ @Override
+ protected void setup() {
+ UI w = getLayout().getUI();
+ /* darn reindeer has no icons */
+
+ /* Make all trees (their nodes actually) draggable */
+ tree1.setDragMode(TreeDragMode.NODE);
+ tree2.setDragMode(TreeDragMode.NODE);
+
+ hl.addComponent(tree1);
+ hl.addComponent(table);
+ hl.addComponent(tree2);
+ hl.setWidth("100%");
+ hl.setSpacing(true);
+ hl.setExpandRatio(table, 1);
+ popuplateTrees();
+ table.setWidth("100%");
+ table.setPageLength(10);
+ populateTable();
+ addComponent(hl);
+
+ tree3 = new Tree(
+ "Tree with lazy loading criteria, of first server visit caches accept rules for all captions");
+ tree3.setDragMode(TreeDragMode.NODE);
+
+ tree3.addItem("Drag on me");
+ tree3.addItem("Or me");
+ /*
+ * An example of lazy initializing drop criterion with component
+ * specific api for easy rule writing.
+ *
+ * Example is pretty stupid (accepts drop on all nodes, but by
+ * explicitly defining them here), but demonstrates lazy initialization
+ * option if rules are heavy.
+ */
+ final AcceptCriterion crit = new Tree.TreeDropCriterion() {
+
+ @Override
+ protected Set<Object> getAllowedItemIds(DragAndDropEvent dragEvent,
+ Tree tree) {
+ return new HashSet<Object>(tree.getItemIds());
+ }
+ };
+
+ tree3.setDropHandler(new DropHandler() {
+ @Override
+ public void drop(DragAndDropEvent dropEvent) {
+ Transferable transferable = dropEvent.getTransferable();
+
+ String data = (String) transferable.getData("Text");
+ if (transferable instanceof TableTransferable) {
+ TableTransferable tr = (TableTransferable) transferable;
+ System.out.println("From table row" + tr.getPropertyId());
+ Object value = tr.getSourceContainer()
+ .getItem(tr.getItemId())
+ .getItemProperty(tr.getPropertyId()).getValue();
+ data = (null != value) ? value.toString() : null;
+ }
+ if (data == null) {
+ data = "-no Text data flavor-";
+ }
+ tree3.addItem(data);
+ AbstractSelect.AbstractSelectTargetDetails dropTargetData = (AbstractSelect.AbstractSelectTargetDetails) dropEvent
+ .getTargetDetails();
+ tree3.setParent(data, dropTargetData.getItemIdOver());
+
+ }
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return crit;
+ }
+ });
+
+ addComponent(tree3);
+
+ /*
+ * Make table rows draggable
+ */
+ table.setDragMode(Table.TableDragMode.ROW);
+
+ TargetItemAllowsChildren onNode = TargetItemAllowsChildren.get();
+ SourceIs fromTable = new SourceIs(table);
+
+ SourceIs fromTree = new SourceIs(tree1);
+ final Or fromTree1OrTable = new Or(fromTable, fromTree);
+ // Or could in the case be replaced with, keeping here as an example and
+ // test
+ @SuppressWarnings("unused")
+ SourceIs treeOrTable = new SourceIs(table, tree1);
+
+ final And and = new And(fromTree1OrTable, onNode);
+
+ DropHandler dropHandler = new DropHandler() {
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ /*
+ * We know transferrable is from table, so it is of type
+ * DataBoundTransferrable
+ */
+ DataBoundTransferable tr = (DataBoundTransferable) event
+ .getTransferable();
+ Object itemId = tr.getItemId();
+ Container sourceContainer = tr.getSourceContainer();
+ if (tr.getSourceComponent() != tree1) {
+ // if the source is from table (not from tree1 itself),
+ // transfer Name property and use it as an identifier in
+ // tree1
+ Object nameValue = sourceContainer.getItem(itemId)
+ .getItemProperty("Name").getValue();
+ String name = (null != nameValue) ? nameValue.toString()
+ : null;
+
+ tree1.addItem(name);
+ tree1.setChildrenAllowed(name, false);
+
+ /*
+ * Remove the item from table
+ */
+ sourceContainer.removeItem(itemId);
+
+ itemId = name;
+
+ }
+
+ /*
+ * As we also accept only drops on folders, we know dropDetails
+ * is from Tree and it contains itemIdOver.
+ */
+ AbstractSelectTargetDetails details = (AbstractSelectTargetDetails) event
+ .getTargetDetails();
+ Object idOver = details.getItemIdOver();
+ tree1.setParent(itemId, idOver);
+
+ }
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return and;
+ }
+ };
+ tree1.setDropHandler(dropHandler);
+
+ /*
+ * First step done. tree1 now accepts drags only from table and only
+ * over tree nodes aka "folders"
+ */
+
+ /*
+ * Now set the rightmost tree accept any item drag. On drop, copy from
+ * source. Also make drags from tree1 possible.
+ */
+
+ dropHandler = new DropHandler() {
+ @Override
+ public void drop(DragAndDropEvent event) {
+ AbstractSelectTargetDetails details = (AbstractSelectTargetDetails) event
+ .getTargetDetails();
+ Transferable transferable = event.getTransferable();
+
+ if (transferable instanceof DataBoundTransferable) {
+ DataBoundTransferable tr = (DataBoundTransferable) transferable;
+
+ Object itemId = tree2.addItem();
+ tree2.setParent(itemId, details.getItemIdOver());
+ if (tr.getSourceComponent() == tree1) {
+ // use item id from tree1 as caption
+ tree2.setItemCaption(itemId, (String) tr.getItemId());
+ // if comes from tree1, move subtree too
+ copySubTree(tr.getItemId(), itemId);
+ } else if (tr.getSourceComponent() == table) {
+ // comes from table, override caption with name
+ String name = (String) table.getItem(tr.getItemId())
+ .getItemProperty("Name").getValue();
+ tree2.setItemCaption(itemId, name);
+ } else if (tr.getSourceComponent() == tree2) {
+ tree2.setItemCaption(itemId,
+ tree2.getItemCaption(tr.getItemId()));
+ }
+ }
+ }
+
+ private void copySubTree(Object itemId, Object itemIdTo) {
+ Collection<?> children = tree1.getChildren(itemId);
+ if (children != null) {
+ for (Object childId : children) {
+ Object newItemId = tree2.addItem();
+ tree2.setItemCaption(newItemId, (String) childId);
+ tree2.setParent(newItemId, itemIdTo);
+ copySubTree(childId, newItemId);
+ }
+ }
+ }
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptItem.ALL;
+ }
+ };
+
+ tree2.setDropHandler(dropHandler);
+
+ /*
+ * Finally add two windows with DragDropPane. First accept anything,
+ * second has server side accept rule to allow only drops from Tree1.
+ * Check the code in implementing classes.
+ */
+ Window acceptAnyThing = new AcceptAnythingWindow();
+ Window acceptFromTree1viaServerCheck = new AcceptFromComponent(tree1);
+
+ w.addWindow(acceptAnyThing);
+ acceptAnyThing.setPositionY(450);
+ acceptAnyThing.setPositionX(150);
+ w.addWindow(acceptFromTree1viaServerCheck);
+ acceptFromTree1viaServerCheck.setPositionY(450);
+ acceptFromTree1viaServerCheck.setPositionX(450);
+
+ }
+
+ private void populateTable() {
+ table.addContainerProperty("Name", String.class, "");
+ table.addContainerProperty("Weight", Integer.class, 0);
+
+ PersonContainer testData = PersonContainer.createWithTestData();
+
+ for (int i = 0; i < 10; i++) {
+ Item addItem = table.addItem("Item" + i);
+ Person p = testData.getIdByIndex(i);
+ addItem.getItemProperty("Name").setValue(
+ p.getFirstName() + " " + p.getLastName());
+ addItem.getItemProperty("Weight").setValue(50 + r.nextInt(60));
+ }
+
+ }
+
+ private final static ThemeResource FOLDER = new ThemeResource(
+ "../runo/icons/16/folder.png");
+ private final static ThemeResource DOC = new ThemeResource(
+ "../runo/icons/16/document.png");
+
+ private void popuplateTrees() {
+ HierarchicalContainer hc = new HierarchicalContainer();
+ hc.addContainerProperty("icon", Resource.class, DOC);
+ Item addItem = hc.addItem("Fats");
+ addItem.getItemProperty("icon").setValue(FOLDER);
+ hc.addItem("Tarja");
+ hc.setParent("Tarja", "Fats");
+ hc.setChildrenAllowed("Tarja", false);
+ addItem = hc.addItem("Thins");
+ addItem.getItemProperty("icon").setValue(FOLDER);
+ addItem = hc.addItem("Anorectic");
+ addItem.getItemProperty("icon").setValue(FOLDER);
+ hc.setParent("Anorectic", "Thins");
+ addItem = hc.addItem("Normal weighted");
+ addItem.getItemProperty("icon").setValue(FOLDER);
+
+ tree1.setContainerDataSource(hc);
+ tree1.setItemIconPropertyId("icon");
+
+ tree2.setContainerDataSource(new HierarchicalContainer());
+
+ tree2.addItem("/");
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "dd";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 119;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/DDTest4.java b/uitest/src/com/vaadin/tests/dd/DDTest4.java
new file mode 100644
index 0000000000..044fe1f49a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/DDTest4.java
@@ -0,0 +1,163 @@
+package com.vaadin.tests.dd;
+
+import java.util.Collection;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.SourceIs;
+import com.vaadin.shared.ui.dd.VerticalDropLocation;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.util.Person;
+import com.vaadin.tests.util.PersonContainer;
+import com.vaadin.tests.util.TestUtils;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.Table;
+
+public class DDTest4 extends TestBase {
+
+ java.util.Random r = new java.util.Random(1);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ Table table = new Table("Drag and drop sortable table");
+
+ @Override
+ protected void setup() {
+ UI w = getLayout().getUI();
+
+ TestUtils
+ .injectCSS(
+ w,
+ ".v-table-row-drag-middle .v-table-cell-content {"
+ + " background-color: inherit ; border-bottom: 1px solid cyan;"
+ + "}"
+ + ".v-table-row-drag-middle .v-table-cell-wrapper {"
+ + " margin-bottom: -1px;" + "}" + ""
+
+ );
+
+ // hl.addComponent(tree1);
+ hl.addComponent(table);
+ // hl.addComponent(tree2);
+ hl.setWidth("100%");
+ hl.setSpacing(true);
+ hl.setExpandRatio(table, 1);
+ table.setWidth("100%");
+ table.setPageLength(10);
+ table.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
+ table.setSelectable(true);
+ table.setMultiSelect(true);
+ populateTable();
+ addComponent(hl);
+
+ /*
+ * Make table rows draggable
+ */
+ table.setDragMode(Table.TableDragMode.ROW);
+
+ table.setDropHandler(new DropHandler() {
+ // accept only drags from this table
+ AcceptCriterion crit = new SourceIs(table);
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return crit;
+ }
+
+ @Override
+ public void drop(DragAndDropEvent dropEvent) {
+ AbstractSelectTargetDetails dropTargetData = (AbstractSelectTargetDetails) dropEvent
+ .getTargetDetails();
+ DataBoundTransferable transferable = (DataBoundTransferable) dropEvent
+ .getTransferable();
+ Object itemIdOver = dropTargetData.getItemIdOver();
+ Object itemId = transferable.getItemId();
+ if (itemId == null || itemIdOver == null
+ || itemId.equals(itemIdOver)) {
+ return; // no move happened
+ }
+
+ // IndexedContainer goodies... (hint: don't use it in real apps)
+ IndexedContainer containerDataSource = (IndexedContainer) table
+ .getContainerDataSource();
+ int newIndex = containerDataSource.indexOfId(itemIdOver) - 1;
+ if (dropTargetData.getDropLocation() != VerticalDropLocation.TOP) {
+ newIndex++;
+ }
+ if (newIndex < 0) {
+ newIndex = 0;
+ }
+ Object idAfter = containerDataSource.getIdByIndex(newIndex);
+ Collection<?> selections = (Collection<?>) table.getValue();
+ if (selections != null && selections.contains(itemId)) {
+ // dragged a selected item, if multiple rows selected, drag
+ // them too (functionality similar to apple mail)
+ for (Object object : selections) {
+ moveAfter(containerDataSource, object, idAfter);
+ }
+
+ } else {
+ // move just the dragged row, not considering selection at
+ // all
+ moveAfter(containerDataSource, itemId, idAfter);
+ }
+
+ }
+
+ private void moveAfter(IndexedContainer containerDataSource,
+ Object itemId, Object idAfter) {
+ try {
+ IndexedContainer clone = null;
+ clone = (IndexedContainer) containerDataSource.clone();
+ containerDataSource.removeItem(itemId);
+ Item newItem = containerDataSource.addItemAfter(idAfter,
+ itemId);
+ Item item = clone.getItem(itemId);
+ for (Object propId : item.getItemPropertyIds()) {
+ newItem.getItemProperty(propId).setValue(
+ item.getItemProperty(propId).getValue());
+ }
+
+ // TODO Auto-generated method stub
+ } catch (CloneNotSupportedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+ });
+
+ }
+
+ private void populateTable() {
+ table.addContainerProperty("Name", String.class, "");
+ table.addContainerProperty("Weight", Integer.class, 0);
+
+ PersonContainer testData = PersonContainer.createWithTestData();
+
+ for (int i = 0; i < 10; i++) {
+ Item addItem = table.addItem("Item" + i);
+ Person p = testData.getIdByIndex(i);
+ addItem.getItemProperty("Name").setValue(
+ p.getFirstName() + " " + p.getLastName());
+ addItem.getItemProperty("Weight").setValue(50 + r.nextInt(60));
+ }
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "dd";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 119;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/DDTest5.java b/uitest/src/com/vaadin/tests/dd/DDTest5.java
new file mode 100644
index 0000000000..43342fdc35
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/DDTest5.java
@@ -0,0 +1,179 @@
+package com.vaadin.tests.dd;
+
+import java.util.Iterator;
+
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.DropTarget;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.DragAndDropWrapper.DragStartMode;
+import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.UI;
+
+public class DDTest5 extends TestBase {
+
+ java.util.Random r = new java.util.Random(1);
+
+ HorizontalLayout hl = new HorizontalLayout();
+
+ private DragAndDropWrapper dragAndDropWrapper2;
+
+ private DropHandler dh;
+
+ private static int count;
+
+ class WrappedLabel extends DragAndDropWrapper {
+
+ private static final long serialVersionUID = 1L;
+
+ public WrappedLabel(String content) {
+ super(new Label(content + " c:" + ++count));
+ setDragStartMode(DragStartMode.WRAPPER);
+ }
+
+ @Override
+ public DropHandler getDropHandler() {
+ return dh;
+ }
+
+ }
+
+ @Override
+ protected void setup() {
+ UI w = getLayout().getUI();
+
+ HorizontalSortableCssLayoutWithWrappers verticalSortableCssLayoutWithWrappers = new HorizontalSortableCssLayoutWithWrappers();
+ w.addWindow(verticalSortableCssLayoutWithWrappers);
+ verticalSortableCssLayoutWithWrappers.setPositionX(200);
+ verticalSortableCssLayoutWithWrappers.setPositionY(40); /*
+ * FIXME:
+ * subwindow
+ * horizontal
+ * position does
+ * not work if
+ * only x set
+ */
+
+ Label l;
+
+ l = new Label("Drag me");
+ DragAndDropWrapper dragAndDropWrapper = new DragAndDropWrapper(l);
+ dragAndDropWrapper.setDragStartMode(DragStartMode.COMPONENT);
+ dragAndDropWrapper.setWidth("100px");
+ dragAndDropWrapper.setHeight("100px");
+ getLayout().addComponent(dragAndDropWrapper);
+
+ l = new Label("Drag me too");
+ dragAndDropWrapper = new DragAndDropWrapper(l);
+ dragAndDropWrapper.setDragStartMode(DragStartMode.WRAPPER);
+ dragAndDropWrapper.setWidth("100px");
+ dragAndDropWrapper.setHeight("100px");
+ getLayout().addComponent(dragAndDropWrapper);
+
+ final CssLayout cssLayout = new CssLayout();
+ cssLayout.setHeight("300px");
+
+ dragAndDropWrapper2 = new DragAndDropWrapper(cssLayout);
+ dragAndDropWrapper2
+ .setCaption("Drop here or sort with dd (wrapper(csslayout(n*wrapper(label))))");
+
+ dh = new DropHandler() {
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ @Override
+ public void drop(DragAndDropEvent dropEvent) {
+
+ /*
+ * TODO wrap componentns in wrappers (so we can build reordering
+ * here)
+ */
+
+ if (dropEvent.getTransferable() instanceof WrapperTransferable) {
+ WrapperTransferable transferable = (WrapperTransferable) dropEvent
+ .getTransferable();
+ Component sourceComponent = transferable
+ .getSourceComponent();
+
+ Component draggedComponent = transferable
+ .getDraggedComponent();
+
+ DropTarget target = dropEvent.getTargetDetails()
+ .getTarget();
+
+ WrappedLabel wrappedLabel = new WrappedLabel(
+ draggedComponent.toString());
+ if (target instanceof WrappedLabel) {
+ int i = 1; // add next to reference by default
+ Iterator<Component> componentIterator = cssLayout
+ .getComponentIterator();
+ Component next = componentIterator.next();
+ while (next != target && componentIterator.hasNext()) {
+ if (next != sourceComponent) {
+ // don't count on index if component is being
+ // moved
+ i++;
+ }
+ next = componentIterator.next();
+ }
+
+ if (sourceComponent instanceof WrappedLabel) {
+ cssLayout.removeComponent(sourceComponent);
+ wrappedLabel = (WrappedLabel) sourceComponent;
+ }
+ if (dropEvent.getTargetDetails()
+ .getData("verticalLocation").equals("TOP")) {
+ // before reference if dropped on topmost part
+ i--;
+ if (i < 0) {
+ i = 0;
+ }
+ }
+ cssLayout.addComponent(wrappedLabel, i);
+
+ } else {
+ cssLayout.addComponent(wrappedLabel);
+ }
+
+ } else {
+ // no component, add label with "Text"
+
+ String data = (String) dropEvent.getTransferable().getData(
+ "text/plain");
+ if (data == null || "".equals(data)) {
+ data = "-- no Text --";
+ }
+ cssLayout.addComponent(new WrappedLabel(data));
+
+ }
+
+ }
+ };
+
+ dragAndDropWrapper2.setDropHandler(dh);
+
+ getLayout().addComponent(dragAndDropWrapper2);
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "dd: DragAndDropWrapper to build various use cases completely on server side";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 119;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/DDTest6.java b/uitest/src/com/vaadin/tests/dd/DDTest6.java
new file mode 100644
index 0000000000..a4c566d75a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/DDTest6.java
@@ -0,0 +1,566 @@
+package com.vaadin.tests.dd;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.util.BeanItemContainer;
+import com.vaadin.data.util.ContainerHierarchicalWrapper;
+import com.vaadin.event.Action;
+import com.vaadin.event.Action.Handler;
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.LayoutEvents.LayoutClickEvent;
+import com.vaadin.event.LayoutEvents.LayoutClickListener;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.Not;
+import com.vaadin.event.dd.acceptcriteria.SourceIsTarget;
+import com.vaadin.server.Resource;
+import com.vaadin.server.StreamResource;
+import com.vaadin.server.StreamVariable;
+import com.vaadin.server.ThemeResource;
+import com.vaadin.server.StreamResource.StreamSource;
+import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.util.TestUtils;
+import com.vaadin.ui.AbsoluteLayout;
+import com.vaadin.ui.AbsoluteLayout.ComponentPosition;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.HorizontalSplitPanel;
+import com.vaadin.ui.Html5File;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.Tree.TreeDragMode;
+import com.vaadin.ui.Tree.TreeTargetDetails;
+import com.vaadin.ui.Window;
+
+public class DDTest6 extends TestBase {
+
+ java.util.Random r = new java.util.Random(1);
+
+ File[] files = new File[] { new Folder("Docs"), new Folder("Music"),
+ new Folder("Images"), new File("document.doc"),
+ new File("song.mp3"), new File("photo.jpg") };
+
+ private static Tree tree1;
+
+ private HorizontalSplitPanel sp;
+
+ private BeanItemContainer<File> fs1;
+
+ private static DDTest6 instance;
+
+ @Override
+ protected void setup() {
+ instance = this; // Note, test only works with single app per server if
+ // get()
+ // not converted to thread local
+
+ sp = new HorizontalSplitPanel();
+ sp.setSplitPosition(20);
+ CssLayout l = new CssLayout();
+ sp.setFirstComponent(l);
+
+ tree1 = new Tree("Volume 1");
+ tree1.setImmediate(true);
+
+ fs1 = new BeanItemContainer<File>(File.class);
+ tree1.setContainerDataSource(fs1);
+ for (int i = 0; i < files.length; i++) {
+ fs1.addBean(files[i]);
+ if (files[i] instanceof Folder) {
+ tree1.setChildrenAllowed(files[i], true);
+ } else {
+ tree1.setChildrenAllowed(files[i], false);
+ }
+ if (i >= files.length / 2) {
+ tree1.setParent(files[i], files[i - files.length / 2]);
+ }
+ }
+ tree1.setItemCaptionPropertyId("name");
+ tree1.setItemIconPropertyId("icon");
+
+ tree1.setDragMode(TreeDragMode.NODE);
+
+ DropHandler dropHandler = new DropHandler() {
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ @Override
+ public void drop(DragAndDropEvent dropEvent) {
+ File file = null;
+ Folder folder = null;
+ TreeTargetDetails dropTargetData = (TreeTargetDetails) dropEvent
+ .getTargetDetails();
+ folder = (Folder) dropTargetData.getItemIdInto();
+ if (dropEvent.getTransferable() instanceof DataBoundTransferable) {
+ DataBoundTransferable transferable = (DataBoundTransferable) dropEvent
+ .getTransferable();
+ file = (File) transferable.getItemId();
+ } else if (dropEvent.getTransferable().getSourceComponent() instanceof FileIcon) {
+ FileIcon draggedIcon = (FileIcon) dropEvent
+ .getTransferable().getSourceComponent();
+ file = draggedIcon.file;
+
+ }
+ setParent(file, folder);
+ }
+ };
+
+ tree1.setDropHandler(dropHandler);
+
+ Handler actionHandler = new Handler() {
+
+ private Action[] actions = new Action[] { new Action("Remove") };
+
+ @Override
+ public void handleAction(Action action, Object sender, Object target) {
+ ContainerHierarchicalWrapper containerDataSource = (ContainerHierarchicalWrapper) tree1
+ .getContainerDataSource();
+ containerDataSource.removeItemRecursively(target);
+ }
+
+ @Override
+ public Action[] getActions(Object target, Object sender) {
+ return actions;
+ }
+ };
+ tree1.addActionHandler(actionHandler);
+
+ tree1.addListener(new Property.ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ Object value = event.getProperty().getValue();
+ if (value != null && !(value instanceof Folder)) {
+ value = tree1.getParent(value);
+ }
+ FolderView folderView = FolderView.get((Folder) value);
+ sp.setSecondComponent(folderView);
+ folderView.reload();
+ }
+ });
+
+ l.addComponent(tree1);
+
+ sp.setSecondComponent(FolderView.get(null));
+
+ getLayout().setSizeFull();
+ getLayout().addComponent(sp);
+ TestUtils
+ .injectCSS(
+ getLayout().getUI(),
+ ""
+ + ".v-tree .v-icon {height:16px;} "
+ + ".v-tree-node-caption-drag-top {/*border-top: none;*/} "
+ + ".v-tree-node-caption-drag-bottom {border-bottom: none ;} "
+ + ".v-tree-node-caption-drag-center {background-color: transparent;}"
+ + ".v-tree-node-caption-dragfolder { background-color: cyan;} ");
+
+ }
+
+ private final static ThemeResource FOLDER = new ThemeResource(
+ "../runo/icons/64/folder.png");
+ private final static ThemeResource DOC = new ThemeResource(
+ "../runo/icons/64/document.png");
+
+ public static class File {
+ private Resource icon = DOC;
+ private String name;
+ private ByteArrayOutputStream bas;
+ private String type;
+
+ public File(String fileName) {
+ name = fileName;
+ }
+
+ public File(String fileName, ByteArrayOutputStream bas) {
+ this(fileName);
+ this.bas = bas;
+ }
+
+ public void setIcon(Resource icon) {
+ this.icon = icon;
+ }
+
+ public Resource getIcon() {
+ return icon;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public Resource getResource() {
+ StreamSource streamSource = new StreamSource() {
+ @Override
+ public InputStream getStream() {
+ if (bas != null) {
+ byte[] byteArray = bas.toByteArray();
+ return new ByteArrayInputStream(byteArray);
+ }
+ return null;
+ }
+ };
+ return new StreamResource(streamSource, getName());
+ }
+ }
+
+ public static class Folder extends File {
+
+ public Folder(String fileName) {
+ super(fileName);
+ setIcon(FOLDER);
+ }
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "dd: tree and web desktop tests. FF36 supports draggin files from client side. (try dragging png image + double click) TODO more files, auto-opening folders";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 119;
+ }
+
+ private void openFile(File file) {
+ // ATM supports only images.
+ if (file.getType().equals("image/png")) {
+ Embedded embedded = new Embedded(file.getName(), file.getResource());
+ Window w = new Window(file.getName());
+ w.addComponent(embedded);
+ w.getContent().setSizeUndefined();
+ getMainWindow().addWindow(w);
+ } else if (file.getType().equals("text/csv")) {
+ showSpreadsheet(file);
+ }
+ }
+
+ private void showSpreadsheet(File file) {
+ // ApplicationResource resource = (ApplicationResource)
+ // file.getResource();
+ String string = new String(file.bas.toByteArray());
+ String[] rows = string.split("\n");
+ String[] cols = rows[0].split(",");
+ Table table = new Table();
+ for (String string2 : cols) {
+ // String col =
+ string2.replaceAll("\"", ""); // remove surrounding ""
+ table.addContainerProperty(string2, String.class, "");
+ }
+ for (int i = 1; i < rows.length; i++) {
+ String[] split = rows[i].split(",");
+ table.addItem(split, "" + i);
+ }
+ Window w = new Window(file.getName());
+ w.getContent().setSizeUndefined();
+ table.setEditable(true);
+ w.addComponent(table);
+ getMainWindow().addWindow(w);
+
+ }
+
+ static class FolderView extends DragAndDropWrapper implements DropHandler {
+
+ static final HashMap<Folder, FolderView> views = new HashMap<Folder, FolderView>();
+
+ public static FolderView get(Folder f) {
+
+ FolderView folder2 = views.get(f);
+ if (folder2 == null) {
+ folder2 = new FolderView(f);
+ views.put(f, folder2);
+ }
+ return folder2;
+ }
+
+ private Folder folder;
+ private AbsoluteLayout l;
+ private int x;
+ private int y;
+
+ private FolderView(Folder f) {
+ super(new AbsoluteLayout());
+ l = (AbsoluteLayout) getCompositionRoot();
+ setSizeFull();
+ l.setSizeFull();
+ folder = f;
+
+ setDropHandler(this);
+ }
+
+ @Override
+ public void attach() {
+ reload();
+ super.attach();
+ }
+
+ @SuppressWarnings("static-access")
+ void reload() {
+ Collection<?> children = folder == null ? DDTest6.get().tree1
+ .rootItemIds() : DDTest6.get().tree1.getChildren(folder);
+ if (children == null) {
+ l.removeAllComponents();
+ return;
+ } else {
+ // make modifiable
+ children = new HashSet<Object>(children);
+ }
+ Set<Component> removed = new HashSet<Component>();
+ for (Iterator<Component> componentIterator = l
+ .getComponentIterator(); componentIterator.hasNext();) {
+ FileIcon next = (FileIcon) componentIterator.next();
+ if (!children.contains(next.file)) {
+ removed.add(next);
+ } else {
+ children.remove(next.file);
+ }
+ }
+
+ for (Component component : removed) {
+ l.removeComponent(component);
+ }
+
+ for (Object object : children) {
+ FileIcon fileIcon = new FileIcon((File) object);
+ l.addComponent(fileIcon);
+ ComponentPosition position = l.getPosition(fileIcon);
+ position.setTop(Float.valueOf((y++ / 5) % 5 * 100),
+ UNITS_PIXELS);
+ position.setLeft(Float.valueOf(x++ % 5 * 100), UNITS_PIXELS);
+ }
+
+ }
+
+ @Override
+ @SuppressWarnings("static-access")
+ public void drop(DragAndDropEvent dropEvent) {
+
+ if (dropEvent.getTransferable().getSourceComponent() instanceof FileIcon) {
+ // update the position
+
+ DragAndDropWrapper.WrapperTransferable transferable = (WrapperTransferable) dropEvent
+ .getTransferable();
+ MouseEventDetails mouseDownEvent = transferable
+ .getMouseDownEvent();
+
+ WrapperTargetDetails dropTargetDetails = (WrapperTargetDetails) dropEvent
+ .getTargetDetails();
+
+ MouseEventDetails mouseEvent = dropTargetDetails
+ .getMouseEvent();
+
+ int deltaX = mouseEvent.getClientX()
+ - mouseDownEvent.getClientX();
+ int deltaY = mouseEvent.getClientY()
+ - mouseDownEvent.getClientY();
+
+ ComponentPosition position = l.getPosition(transferable
+ .getSourceComponent());
+ position.setTop(position.getTopValue() + deltaY, UNITS_PIXELS);
+ position.setLeft(position.getLeftValue() + deltaX, UNITS_PIXELS);
+
+ } else if (dropEvent.getTransferable().getSourceComponent() == tree1) {
+
+ // dragged something from tree to the folder shown
+
+ File draggedFile = (File) ((DataBoundTransferable) dropEvent
+ .getTransferable()).getItemId();
+ DDTest6.get().setParent(draggedFile, folder);
+ } else {
+ // expecting this to be an html5 drag
+ WrapperTransferable tr = (WrapperTransferable) dropEvent
+ .getTransferable();
+ Html5File[] files2 = tr.getFiles();
+ if (files2 != null) {
+ for (Html5File html5File : files2) {
+ String fileName = html5File.getFileName();
+ // int bytes = html5File.getFileSize();
+ final ByteArrayOutputStream bas = new ByteArrayOutputStream();
+
+ StreamVariable streamVariable = new StreamVariable() {
+
+ @Override
+ public OutputStream getOutputStream() {
+ return bas;
+ }
+
+ @Override
+ public boolean listenProgress() {
+ return false;
+ }
+
+ @Override
+ public void onProgress(StreamingProgressEvent event) {
+ }
+
+ @Override
+ public void streamingStarted(
+ StreamingStartEvent event) {
+ }
+
+ @Override
+ public void streamingFinished(
+ StreamingEndEvent event) {
+ }
+
+ @Override
+ public void streamingFailed(
+ StreamingErrorEvent event) {
+ }
+
+ @Override
+ public boolean isInterrupted() {
+ return false;
+ }
+ };
+
+ html5File.setStreamVariable(streamVariable);
+
+ File file = new File(fileName, bas);
+ file.setType(html5File.getType());
+ // FF don't know csv
+ if (fileName.endsWith(".csv")) {
+ file.setType("text/csv");
+ }
+ DDTest6.get().fs1.addBean(file);
+ DDTest6.get().tree1.setChildrenAllowed(file, false);
+ DDTest6.get().setParent(file, folder);
+ }
+
+ }
+
+ }
+ }
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ }
+
+ static class FileIcon extends DragAndDropWrapper {
+ private final File file;
+ private CssLayout l;
+
+ public FileIcon(final File file) {
+ super(new CssLayout());
+ l = (CssLayout) getCompositionRoot();
+ setWidth(null);
+ l.setWidth(null);
+ setDragStartMode(DragStartMode.WRAPPER); // drag all contained
+ // components, not just the
+ // one on it started
+ this.file = file;
+ Resource icon2 = file.getIcon();
+ String name = file.getName();
+ l.addComponent(new Embedded(null, icon2));
+ l.addComponent(new Label(name));
+
+ l.addListener(new LayoutClickListener() {
+ @Override
+ @SuppressWarnings("static-access")
+ public void layoutClick(LayoutClickEvent event) {
+ if (event.isDoubleClick()) {
+ if (file instanceof Folder) {
+ get().tree1.setValue(file);
+ } else {
+ String type = file.getType();
+ if (canDisplay(type)) {
+ DDTest6.get().openFile(file);
+ }
+ }
+ }
+
+ }
+
+ String[] knownTypes = new String[] { "image/png", "text/csv" };
+
+ private boolean canDisplay(String type) {
+ if (type != null) {
+ for (String t : knownTypes) {
+ if (t.equals(type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ });
+
+ if (file instanceof Folder) {
+
+ setDropHandler(new DropHandler() {
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return new Not(SourceIsTarget.get());
+ }
+
+ @Override
+ public void drop(DragAndDropEvent dropEvent) {
+ File f = null;
+
+ if (dropEvent.getTransferable().getSourceComponent() instanceof FileIcon) {
+ FileIcon new_name = (FileIcon) dropEvent
+ .getTransferable().getSourceComponent();
+ f = new_name.file;
+ } else if (dropEvent.getTransferable()
+ .getSourceComponent() == tree1) {
+ f = (File) ((DataBoundTransferable) dropEvent
+ .getTransferable()).getItemId();
+ }
+
+ if (f != null) {
+ get().setParent(f, (Folder) FileIcon.this.file);
+ }
+
+ }
+ });
+
+ }
+ }
+ }
+
+ static DDTest6 get() {
+ return instance;
+ }
+
+ public void setParent(File file, Folder newParent) {
+ tree1.setParent(file, newParent);
+ if (sp.getSecondComponent() instanceof FolderView) {
+ FolderView view = (FolderView) sp.getSecondComponent();
+ view.reload();
+ }
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/dd/DDTest7.java b/uitest/src/com/vaadin/tests/dd/DDTest7.java
new file mode 100644
index 0000000000..1abf9e379c
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/DDTest7.java
@@ -0,0 +1,191 @@
+package com.vaadin.tests.dd;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.util.Person;
+import com.vaadin.tests.util.PersonContainer;
+import com.vaadin.tests.util.TestUtils;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.Table;
+
+public class DDTest7 extends TestBase {
+
+ java.util.Random r = new java.util.Random(1);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ Table table = new Table(
+ "Drag and drop sortable table with lazy loading rule. Dragged row can only be accepted after hevier row (weigh column). If starting from topmost row in viewport, heviests will end up on top.");
+
+ @Override
+ protected void setup() {
+ UI w = getLayout().getUI();
+
+ TestUtils
+ .injectCSS(
+ w,
+ ".v-table-row-drag-middle .v-table-cell-content {"
+ + " background-color: inherit ; border-bottom: 1px solid cyan;"
+ + "}"
+ + ".v-table-row-drag-middle .v-table-cell-wrapper {"
+ + " margin-bottom: -1px;"
+ + "}"
+ + ""
+ // always show the drop hint below
+ + ".v-table-row-drag-top .v-table-cell-content {"
+ + "border-top: 0; margin-top:0;border-bottom:1px solid cyan;"
+ + " margin-bottom: -1px;" + "}" + ""
+
+ );
+
+ // hl.addComponent(tree1);
+ hl.addComponent(table);
+ // hl.addComponent(tree2);
+ hl.setWidth("100%");
+ hl.setSpacing(true);
+ hl.setExpandRatio(table, 1);
+ table.setWidth("100%");
+ table.setPageLength(10);
+ table.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
+ table.setSelectable(true);
+ table.setMultiSelect(true);
+ populateTable();
+ addComponent(hl);
+
+ /*
+ * Make table rows draggable
+ */
+ table.setDragMode(Table.TableDragMode.ROW);
+
+ table.setDropHandler(new DropHandler() {
+ // accept only drags from this table
+ AcceptCriterion crit = new Table.TableDropCriterion() {
+ @Override
+ protected Set<Object> getAllowedItemIds(
+ DragAndDropEvent dragEvent, Table table,
+ Collection<Object> visibleItemIds) {
+
+ Object draggedItemId = ((Table.TableTransferable) dragEvent
+ .getTransferable()).getItemId();
+ Integer weightOfDraggedRow = (Integer) table
+ .getItem(draggedItemId).getItemProperty("Weight")
+ .getValue();
+
+ HashSet<Object> accepted = new HashSet<Object>();
+ for (Object itemId : visibleItemIds) {
+ Item item = table.getItem(itemId);
+ Integer w = (Integer) item.getItemProperty("Weight")
+ .getValue();
+ if (weightOfDraggedRow < w) {
+ accepted.add(itemId);
+ }
+
+ }
+ return accepted;
+ }
+ };
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return crit;
+ }
+
+ @Override
+ public void drop(DragAndDropEvent dropEvent) {
+ AbstractSelectTargetDetails dropTargetData = (AbstractSelectTargetDetails) dropEvent
+ .getTargetDetails();
+ DataBoundTransferable transferable = (DataBoundTransferable) dropEvent
+ .getTransferable();
+ Object itemIdOver = dropTargetData.getItemIdOver();
+ Object itemId = transferable.getItemId();
+ if (itemId == null || itemIdOver == null
+ || itemId.equals(itemIdOver)) {
+ return; // no move happened
+ }
+
+ // IndexedContainer goodies... (hint: don't use it in real apps)
+ IndexedContainer containerDataSource = (IndexedContainer) table
+ .getContainerDataSource();
+ int newIndex = containerDataSource.indexOfId(itemIdOver) - 1;
+ // always add after
+ newIndex++;
+ if (newIndex < 0) {
+ newIndex = 0;
+ }
+ Object idAfter = containerDataSource.getIdByIndex(newIndex);
+ Collection<?> selections = (Collection<?>) table.getValue();
+ if (selections != null && selections.contains(itemId)) {
+ // dragged a selected item, if multiple rows selected, drag
+ // them too (functionality similar to apple mail)
+ for (Object object : selections) {
+ moveAfter(containerDataSource, object, idAfter);
+ }
+
+ } else {
+ // move just the dragged row, not considering selection at
+ // all
+ moveAfter(containerDataSource, itemId, idAfter);
+ }
+
+ }
+
+ private void moveAfter(IndexedContainer containerDataSource,
+ Object itemId, Object idAfter) {
+ try {
+ IndexedContainer clone = null;
+ clone = (IndexedContainer) containerDataSource.clone();
+ containerDataSource.removeItem(itemId);
+ Item newItem = containerDataSource.addItemAfter(idAfter,
+ itemId);
+ Item item = clone.getItem(itemId);
+ for (Object propId : item.getItemPropertyIds()) {
+ newItem.getItemProperty(propId).setValue(
+ item.getItemProperty(propId).getValue());
+ }
+
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+
+ }
+ });
+
+ }
+
+ private void populateTable() {
+ table.addContainerProperty("Name", String.class, "");
+ table.addContainerProperty("Weight", Integer.class, 0);
+
+ PersonContainer testData = PersonContainer.createWithTestData();
+
+ for (int i = 0; i < 40; i++) {
+ Item addItem = table.addItem("Item" + i);
+ Person p = testData.getIdByIndex(i);
+ addItem.getItemProperty("Name").setValue(
+ p.getFirstName() + " " + p.getLastName());
+ addItem.getItemProperty("Weight").setValue(50 + r.nextInt(60));
+ }
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "dd";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 119;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/DDTest8.java b/uitest/src/com/vaadin/tests/dd/DDTest8.java
new file mode 100644
index 0000000000..ee7d8d9dc5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/DDTest8.java
@@ -0,0 +1,180 @@
+package com.vaadin.tests.dd;
+
+import java.util.Collection;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.Transferable;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.Or;
+import com.vaadin.shared.ui.dd.VerticalDropLocation;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.Tree.TreeDragMode;
+import com.vaadin.ui.Tree.TreeTargetDetails;
+
+/**
+ * DD playground. Better quality example/prototype codes in {@link DDTest2}.
+ */
+public class DDTest8 extends TestBase {
+
+ @Override
+ protected void setup() {
+ final Tree t = new Tree(
+ "Tree with criteria from AbstractSelect (OverItem, ContainsItem). Foo can be dragged anywhere, anything can be dropped on Foo or Bar. Bar5 subtree is also valid drop target.");
+
+ final HierarchicalContainer idx = new HierarchicalContainer();
+ t.setContainerDataSource(idx);
+ t.addItem("Foo");
+ t.addItem("Bar");
+ t.addItem("Bar1");
+ t.addItem("Bar2");
+ t.addItem("Bar3");
+ t.addItem("Bar4");
+ t.addItem("Bar5");
+ t.addItem("Child");
+ t.setParent("Child", "Foo");
+ t.setSizeFull();
+ t.setDragMode(TreeDragMode.NODE);
+
+ /*
+ * Moves items in tree (and could work in Table too). Also supports
+ * "building" tree.
+ *
+ * TODO fix algorithm, broken in some cases.
+ */
+ DropHandler itemSorter = new DropHandler() {
+
+ @SuppressWarnings("unused")
+ private void populateSubTree(HierarchicalContainer idx,
+ HierarchicalContainer subtree, Object itemId) {
+ Collection<?> children = subtree.getChildren(itemId);
+ if (children != null) {
+
+ for (Object childId : children) {
+ Item addItem = idx.addItem(childId);
+ if (addItem != null) {
+ // did not exist, populate properties
+ Item item = subtree.getItem(itemId);
+ Collection<?> itemPropertyIds = item
+ .getItemPropertyIds();
+ for (Object propId : itemPropertyIds) {
+ addItem.getItemProperty(propId)
+ .setValue(
+ item.getItemProperty(propId)
+ .getValue());
+ }
+ }
+ idx.setParent(childId, itemId);
+ populateSubTree(idx, subtree, childId);
+ }
+ }
+
+ }
+
+ @SuppressWarnings("unused")
+ private HierarchicalContainer getSubTree(HierarchicalContainer idx,
+ Object itemId) {
+ HierarchicalContainer hierarchicalContainer = new HierarchicalContainer();
+ Collection<?> containerPropertyIds = idx
+ .getContainerPropertyIds();
+ for (Object object : containerPropertyIds) {
+ hierarchicalContainer.addContainerProperty(object,
+ idx.getType(object), null);
+ }
+ hierarchicalContainer.addItem(itemId);
+ copyChildren(idx, hierarchicalContainer, itemId);
+ return hierarchicalContainer;
+ }
+
+ private void copyChildren(HierarchicalContainer source,
+ HierarchicalContainer target, Object itemId) {
+ Collection<?> children = source.getChildren(itemId);
+ if (children != null) {
+ for (Object childId : children) {
+ Item item = source.getItem(childId);
+ Item addedItem = target.addItem(childId);
+ target.setParent(childId, itemId);
+ Collection<?> itemPropertyIds = item
+ .getItemPropertyIds();
+ for (Object propertyId : itemPropertyIds) {
+ addedItem.getItemProperty(propertyId)
+ .setValue(
+ item.getItemProperty(propertyId)
+ .getValue());
+ }
+ copyChildren(source, target, childId);
+ }
+ }
+
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ TreeTargetDetails details = (TreeTargetDetails) event
+ .getTargetDetails();
+ // TODO set properties, so same sorter could be used in Table
+ Transferable transferable = event.getTransferable();
+ if (transferable instanceof DataBoundTransferable) {
+ DataBoundTransferable transferrable2 = (DataBoundTransferable) transferable;
+
+ Object itemId = transferrable2.getItemId();
+
+ Object itemIdOver = details.getItemIdOver();
+
+ // TODO could use the "folder" node id to make the drop
+ // logic simpler
+ Object itemIdInto = details.getItemIdInto();
+ VerticalDropLocation dropLocation = details
+ .getDropLocation();
+
+ Object itemIdAfter = details.getItemIdAfter();
+
+ if (itemIdOver.equals(itemIdInto)) { // directly on a node
+ t.setParent(itemId, itemIdOver);
+ return;
+ }
+
+ idx.setParent(itemId, itemIdInto);
+
+ if (dropLocation == null) {
+ System.err.println("No detail of drop place available");
+ }
+ idx.moveAfterSibling(itemId, itemIdAfter);
+ }
+
+ return;
+ }
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return new Or(new AbstractSelect.TargetItemIs(t, "Foo", "Bar"),
+ new AbstractSelect.AcceptItem(t, "Foo"),
+ t.new TargetInSubtree("Bar5") //
+ );
+ }
+
+ };
+
+ t.setDropHandler(itemSorter);
+
+ getLayout().setSizeFull();
+ addComponent(t);
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Random DD tests";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 119;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/DragAndDropFiles.java b/uitest/src/com/vaadin/tests/dd/DragAndDropFiles.java
new file mode 100644
index 0000000000..4ecabee617
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/DragAndDropFiles.java
@@ -0,0 +1,132 @@
+package com.vaadin.tests.dd;
+
+import java.io.OutputStream;
+
+import org.apache.commons.io.output.NullOutputStream;
+
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.server.StreamVariable;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable;
+import com.vaadin.ui.Html5File;
+import com.vaadin.ui.Label;
+
+public class DragAndDropFiles extends TestBase {
+
+ @Override
+ protected void setup() {
+ CssLayout cssLayout = new CssLayout() {
+ @Override
+ protected String getCss(Component c) {
+ return "display: block; padding:20px; border: 2px dotted black; background: #aaa;";
+ }
+ };
+ Component l = new Label("Drag file on me");
+ l.setSizeUndefined();
+ cssLayout.addComponent(l);
+ DragAndDropWrapper dragAndDropWrapper = new DragAndDropWrapper(
+ cssLayout);
+ dragAndDropWrapper.setSizeUndefined();
+ dragAndDropWrapper.setDropHandler(new DropHandler() {
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ WrapperTransferable transferable = (WrapperTransferable) event
+ .getTransferable();
+ Html5File[] files = transferable.getFiles();
+ if (files != null) {
+
+ for (int i = 0; i < files.length; i++) {
+ Html5File file = files[i];
+ // Max 1 MB files are uploaded
+ if (file.getFileSize() > 1024 * 1024) {
+ getMainWindow()
+ .showNotification(
+ "File "
+ + file.getFileName()
+ + " was too large, not transferred to the server side.");
+ continue;
+ }
+
+ StreamVariable streamVariable = new StreamVariable() {
+
+ @Override
+ public OutputStream getOutputStream() {
+ return new NullOutputStream();
+ }
+
+ @Override
+ public boolean listenProgress() {
+ return true;
+ }
+
+ @Override
+ public void onProgress(StreamingProgressEvent event) {
+ System.err.println("Progress"
+ + event.getBytesReceived());
+ }
+
+ @Override
+ public void streamingStarted(
+ StreamingStartEvent event) {
+ getMainWindow().showNotification(
+ "Started uploading "
+ + event.getFileName());
+ }
+
+ @Override
+ public void streamingFinished(
+ StreamingEndEvent event) {
+ getMainWindow().showNotification(
+ "Finished uploading "
+ + event.getFileName());
+ }
+
+ @Override
+ public void streamingFailed(
+ StreamingErrorEvent event) {
+ getMainWindow().showNotification(
+ "Failed uploading "
+ + event.getFileName());
+ }
+
+ @Override
+ public boolean isInterrupted() {
+ return false;
+ }
+ };
+ file.setStreamVariable(streamVariable);
+ }
+ }
+
+ }
+ });
+
+ addComponent(dragAndDropWrapper);
+ }
+
+ /*
+ * TODO implement 'handbrake' for testing, progresss listener, interrupting.
+ */
+ @Override
+ protected String getDescription() {
+ return "Should work. Over 1 MB files will not be posted. TODO implement 'handbrake' for testing, progresss listener, interrupting.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return null;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/DragDropPane.java b/uitest/src/com/vaadin/tests/dd/DragDropPane.java
new file mode 100644
index 0000000000..970e1b0141
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/DragDropPane.java
@@ -0,0 +1,188 @@
+package com.vaadin.tests.dd;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.Transferable;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.server.StreamVariable;
+import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.ui.AbsoluteLayout;
+import com.vaadin.ui.AbsoluteLayout.ComponentPosition;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.Html5File;
+import com.vaadin.ui.Label;
+
+/**
+ * replacement for a proto class to keep tests working
+ */
+public class DragDropPane extends DragAndDropWrapper implements DropHandler {
+
+ private AbsoluteLayout root;
+ private AcceptCriterion crit;
+
+ public DragDropPane() {
+ super(new AbsoluteLayout());
+ root = (AbsoluteLayout) getCompositionRoot();
+ setDropHandler(this);
+ setDragStartMode(DragStartMode.COMPONENT);
+ }
+
+ @Override
+ public void addComponent(Component c) {
+ root.addComponent(c);
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public void addComponent(Component l, String string) {
+ root.addComponent(l, string);
+ }
+
+ public void setAcceptCriterion(AcceptCriterion crit) {
+ this.crit = crit;
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+
+ WrapperTargetDetails ed = (WrapperTargetDetails) event
+ .getTargetDetails();
+ Transferable ctr = event.getTransferable();
+ // use "component" (from DragDropPane) if available, else take
+ // the source component
+ Component component = null;
+ if (ctr instanceof WrapperTransferable) {
+ component = ((WrapperTransferable) ctr).getDraggedComponent();
+ } else if (ctr instanceof DataBoundTransferable) {
+ // Item has been dragged, construct a Label from
+ // Item id
+ Label l = new Label();
+ l.setSizeUndefined();
+ l.setValue("ItemId : " + ((DataBoundTransferable) ctr).getItemId());
+ component = l;
+ }
+
+ if (component != null) {
+
+ if (component.getParent() != root) {
+
+ root.addComponent(component);
+
+ Integer left = ed.getAbsoluteLeft();
+ Integer top = ed.getAbsoluteTop();
+
+ MouseEventDetails eventDetails = ed.getMouseEvent();
+
+ int clientX = eventDetails.getClientX();
+ int clientY = eventDetails.getClientY();
+
+ try {
+ root.getPosition(component).setTopValue(
+ Float.valueOf(clientY - top));
+ root.getPosition(component).setLeftValue(
+ Float.valueOf(clientX - left));
+ } catch (Exception e) {
+ }
+ } else {
+ // drag started and ended inside the this Pane
+
+ MouseEventDetails start = ((WrapperTransferable) event
+ .getTransferable()).getMouseDownEvent();
+ MouseEventDetails eventDetails = ed.getMouseEvent();
+
+ int deltaX = eventDetails.getClientX() - start.getClientX();
+ int deltaY = eventDetails.getClientY() - start.getClientY();
+
+ ComponentPosition p = root.getPosition(component);
+ p.setTopValue(p.getTopValue() + deltaY);
+ p.setLeftValue(p.getLeftValue() + deltaX);
+
+ }
+ }
+
+ else {
+ // drag coming outside of Vaadin
+
+ WrapperTransferable wtr = (WrapperTransferable) ctr;
+
+ String object = wtr.getText();
+ // String html = wtr.getHtml();
+ // String url = (String) ctr.getData("Url");
+
+ final Label l = new Label();
+ l.setCaption("Generated from HTML5 drag:");
+ if (object != null) {
+ if (object.length() > 80) {
+ object = object.substring(0, 79);
+ }
+ l.setValue(object);
+ } else {
+ l.setValue("HTML5 dd");
+ }
+
+ Html5File[] files = wtr.getFiles();
+ if (files != null) {
+ for (Html5File html5File : files) {
+ l.setCaption(html5File.getFileName());
+ html5File.setStreamVariable(new StreamVariable() {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+
+ @Override
+ public OutputStream getOutputStream() {
+ return byteArrayOutputStream;
+ }
+
+ @Override
+ public boolean listenProgress() {
+ return false;
+ }
+
+ @Override
+ public void onProgress(StreamingProgressEvent event) {
+ }
+
+ @Override
+ public void streamingStarted(StreamingStartEvent event) {
+ }
+
+ @Override
+ public void streamingFinished(StreamingEndEvent event) {
+ l.setValue((new String(byteArrayOutputStream
+ .toByteArray()).substring(0, 80) + "..."));
+ }
+
+ @Override
+ public void streamingFailed(StreamingErrorEvent event) {
+ }
+
+ @Override
+ public boolean isInterrupted() {
+ return false;
+ }
+ });
+ }
+ }
+
+ l.setSizeUndefined();
+
+ root.addComponent(l);
+
+ }
+ return;
+ }
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return crit != null ? crit : AcceptAll.get();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/HorizontalLayoutSortableWithWrappers.java b/uitest/src/com/vaadin/tests/dd/HorizontalLayoutSortableWithWrappers.java
new file mode 100644
index 0000000000..fe33bce76b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/HorizontalLayoutSortableWithWrappers.java
@@ -0,0 +1,111 @@
+package com.vaadin.tests.dd;
+
+import java.util.Iterator;
+
+import com.vaadin.event.Transferable;
+import com.vaadin.event.TransferableImpl;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.DropTarget;
+import com.vaadin.event.dd.TargetDetails;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.And;
+import com.vaadin.event.dd.acceptcriteria.Not;
+import com.vaadin.event.dd.acceptcriteria.SourceIsTarget;
+import com.vaadin.event.dd.acceptcriteria.TargetDetailIs;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+
+/**
+ * Same as with css layout but tests size change propagation on emphasis +
+ * rules.
+ *
+ *
+ */
+public class HorizontalLayoutSortableWithWrappers extends Window {
+
+ static int count;
+
+ private HorizontalLayout layout = new HorizontalLayout();
+
+ class WrappedLabel extends DragAndDropWrapper {
+
+ private static final long serialVersionUID = 1L;
+
+ public WrappedLabel(String content) {
+ super(new Label(content + " c:" + ++count));
+ getCompositionRoot().setWidth("60px");
+ getCompositionRoot().setHeight("60px");
+ setSizeUndefined();
+ setDragStartMode(DragStartMode.WRAPPER);
+ }
+
+ @Override
+ public DropHandler getDropHandler() {
+ return dh;
+ }
+
+ }
+
+ private DropHandler dh = new DropHandler() {
+ AcceptCriterion crit = new And(new TargetDetailIs("horizontalLocation",
+ "LEFT"), new Not(SourceIsTarget.get()));
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return crit;
+ }
+
+ @Override
+ public void drop(DragAndDropEvent dropEvent) {
+ Transferable transferable = dropEvent.getTransferable();
+ if (transferable instanceof TransferableImpl) {
+ TransferableImpl ct = (TransferableImpl) transferable;
+ Component sourceComponent = ct.getSourceComponent();
+ if (sourceComponent instanceof WrappedLabel) {
+ int index = 1;
+ Iterator<Component> componentIterator = layout
+ .getComponentIterator();
+ Component next = componentIterator.next();
+ TargetDetails dropTargetData = dropEvent.getTargetDetails();
+ DropTarget target = dropTargetData.getTarget();
+ while (next != target) {
+ if (next != sourceComponent) {
+ index++;
+ }
+ next = componentIterator.next();
+ }
+ if (dropTargetData.getData("horizontalLocation").equals(
+ "LEFT")) {
+ index--;
+ if (index < 0) {
+ index = 0;
+ }
+ }
+
+ layout.removeComponent(sourceComponent);
+ layout.addComponent(sourceComponent, index);
+ }
+ }
+ // TODO Auto-generated method stub
+
+ }
+ };
+
+ public HorizontalLayoutSortableWithWrappers() {
+ setCaption("Horizontally sortable layout via (ddwrappers): Try sorting blocks by dragging them");
+ DragAndDropWrapper pane = new DragAndDropWrapper(layout);
+ setContent(pane);
+ pane.setSizeFull();
+ setWidth("400px");
+ setHeight("100px");
+
+ for (int i = 0; i < 4; i++) {
+ layout.addComponent(new WrappedLabel("Block"));
+ }
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/dd/HorizontalSortableCssLayoutWithWrappers.java b/uitest/src/com/vaadin/tests/dd/HorizontalSortableCssLayoutWithWrappers.java
new file mode 100644
index 0000000000..4e9e89add5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/HorizontalSortableCssLayoutWithWrappers.java
@@ -0,0 +1,105 @@
+package com.vaadin.tests.dd;
+
+import java.util.Iterator;
+
+import com.vaadin.event.Transferable;
+import com.vaadin.event.TransferableImpl;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.DropTarget;
+import com.vaadin.event.dd.TargetDetails;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+
+public class HorizontalSortableCssLayoutWithWrappers extends Window {
+
+ static int count;
+
+ private CssLayout cssLayout = new CssLayout() {
+ @Override
+ protected String getCss(Component c) {
+ return "float:left; width:60px;height:60px;background: yellow;padding:2px;";
+ };
+ };
+
+ class WrappedLabel extends DragAndDropWrapper {
+
+ private static final long serialVersionUID = 1L;
+
+ public WrappedLabel(String content) {
+ super(new Label(content + " c:" + ++count));
+ setSizeUndefined(); // via css
+ setHeight("60px"); // FIXME custom component seems to be broken:
+ // can't set height with css only
+ setDragStartMode(DragStartMode.WRAPPER);
+ }
+
+ @Override
+ public DropHandler getDropHandler() {
+ return dh;
+ }
+
+ }
+
+ private DropHandler dh = new DropHandler() {
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ @Override
+ public void drop(DragAndDropEvent dropEvent) {
+ Transferable transferable = dropEvent.getTransferable();
+ if (transferable instanceof TransferableImpl) {
+ TransferableImpl ct = (TransferableImpl) transferable;
+ Component sourceComponent = ct.getSourceComponent();
+ if (sourceComponent instanceof WrappedLabel) {
+ int index = 1;
+ Iterator<Component> componentIterator = cssLayout
+ .getComponentIterator();
+ Component next = componentIterator.next();
+ TargetDetails dropTargetData = dropEvent.getTargetDetails();
+ DropTarget target = dropTargetData.getTarget();
+ while (next != target) {
+ if (next != sourceComponent) {
+ index++;
+ }
+ next = componentIterator.next();
+ }
+ if (dropTargetData.getData("horizontalLocation").equals(
+ "LEFT")) {
+ index--;
+ if (index < 0) {
+ index = 0;
+ }
+ }
+
+ cssLayout.removeComponent(sourceComponent);
+ cssLayout.addComponent(sourceComponent, index);
+ }
+ }
+ // TODO Auto-generated method stub
+
+ }
+ };
+
+ public HorizontalSortableCssLayoutWithWrappers() {
+ setCaption("Horizontally sortable csslayout via (ddwrappers):Try sorting blocks by draggin them");
+ DragAndDropWrapper pane = new DragAndDropWrapper(cssLayout);
+ setContent(pane);
+ pane.setSizeFull();
+ setWidth("400px");
+ setHeight("100px");
+
+ for (int i = 0; i < 4; i++) {
+ cssLayout.addComponent(new WrappedLabel("Block"));
+ }
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/dd/MyDragSourceConnector.java b/uitest/src/com/vaadin/tests/dd/MyDragSourceConnector.java
new file mode 100644
index 0000000000..e787a182e4
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/MyDragSourceConnector.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * 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 com.vaadin.tests.dd;
+
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.Paintable;
+import com.vaadin.client.UIDL;
+import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.tests.dd.CustomDDImplementation.MyDragSource;
+
+@Connect(MyDragSource.class)
+public class MyDragSourceConnector extends AbstractComponentConnector implements
+ Paintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (!isRealUpdate(uidl)) {
+ return;
+ }
+ }
+
+ @Override
+ public VMyDragSource getWidget() {
+ return (VMyDragSource) super.getWidget();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/MyDropTargetConnector.java b/uitest/src/com/vaadin/tests/dd/MyDropTargetConnector.java
new file mode 100644
index 0000000000..f0f2b5dfd6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/MyDropTargetConnector.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * 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 com.vaadin.tests.dd;
+
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.Paintable;
+import com.vaadin.client.UIDL;
+import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.tests.dd.CustomDDImplementation.MyDropTarget;
+
+@Connect(MyDropTarget.class)
+public class MyDropTargetConnector extends AbstractComponentConnector implements
+ Paintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (!isRealUpdate(uidl)) {
+ return;
+ }
+ getWidget().client = client;
+ }
+
+ @Override
+ public VMyDropTarget getWidget() {
+ return (VMyDropTarget) super.getWidget();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSource.html b/uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSource.html
new file mode 100644
index 0000000000..03a4830584
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSource.html
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.dd.NotPaintedAcceptSource?restartApplication</td>
+ <td></td>
+</tr>
+<!--Drag value 0 to target-->
+<tr>
+ <td>drag</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>50,9</td>
+</tr>
+<tr>
+ <td>drop</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>124,20</td>
+</tr>
+<!--Assert drag was successful-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
+ <td>Source 1 value 0</td>
+</tr>
+<!--Swap source and verify it was properly painted-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/VVerticalLayout[0]/VHorizontalLayout[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>Source 2</td>
+</tr>
+<!--Drag value 0 from source 2 and verify-->
+<tr>
+ <td>drag</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>19,8</td>
+</tr>
+<tr>
+ <td>drop</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>139,18</td>
+</tr>
+<tr>
+ <td>contextmenu</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[0]</td>
+ <td>Source 2 value 0</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSource.java b/uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSource.java
new file mode 100644
index 0000000000..020a6b56c5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSource.java
@@ -0,0 +1,94 @@
+package com.vaadin.tests.dd;
+
+import com.vaadin.data.Item;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.SourceIs;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.TableDragMode;
+import com.vaadin.ui.Table.TableTransferable;
+
+public class NotPaintedAcceptSource extends TestBase {
+
+ @Override
+ protected void setup() {
+ final Table source1 = createTable("Source 1");
+ final Table source2 = createTable("Source 2");
+ final Table target = createTable("Target");
+
+ source1.setDragMode(TableDragMode.ROW);
+ source2.setDragMode(TableDragMode.ROW);
+
+ target.setDropHandler(new DropHandler() {
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return new SourceIs(source1, source2);
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ TableTransferable transferable = (TableTransferable) event
+ .getTransferable();
+ Item item = transferable.getSourceComponent().getItem(
+ transferable.getItemId());
+ Object value = item.getItemProperty("value").getValue();
+ AbstractSelectTargetDetails targetDetails = (AbstractSelectTargetDetails) event
+ .getTargetDetails();
+ Object targetItemId = targetDetails.getItemIdOver();
+ Object addItemAfter = target.addItemAfter(targetItemId);
+ target.getItem(addItemAfter).getItemProperty("value")
+ .setValue(value);
+ transferable.getSourceComponent().removeItem(
+ transferable.getItemId());
+ }
+ });
+
+ final HorizontalLayout horizontalLayout = new HorizontalLayout();
+ horizontalLayout.setSpacing(true);
+ horizontalLayout.addComponent(source1);
+ horizontalLayout.addComponent(target);
+
+ addComponent(horizontalLayout);
+
+ addComponent(new Button("Swap sources", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ if (source1.getParent() != null) {
+ horizontalLayout.replaceComponent(source1, source2);
+ } else {
+ horizontalLayout.replaceComponent(source2, source1);
+ }
+ target.markAsDirty();
+ }
+ }));
+
+ }
+
+ private Table createTable(String caption) {
+ Table table = new Table(caption);
+ table.addContainerProperty("value", String.class, "");
+ for (int i = 0; i < 10; i++) {
+ table.addItem(new Object[] { caption + " value " + i },
+ Integer.valueOf(i));
+ }
+ table.setWidth("300px");
+ return table;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Including a component in an accept criterion when the actual component is not included in a layout and thus not painted should still allow painting the component properly when it is added to a layout.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(8730);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSourceInTabSheet.java b/uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSourceInTabSheet.java
new file mode 100644
index 0000000000..e19bbaf2c5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/NotPaintedAcceptSourceInTabSheet.java
@@ -0,0 +1,79 @@
+package com.vaadin.tests.dd;
+
+import com.vaadin.data.Item;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.SourceIs;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.TableDragMode;
+import com.vaadin.ui.Table.TableTransferable;
+
+public class NotPaintedAcceptSourceInTabSheet extends TestBase {
+
+ @Override
+ protected void setup() {
+ final Table source1 = createTable("Source 1");
+ final Table source2 = createTable("Source 2");
+ final Table target = createTable("Target");
+
+ source1.setDragMode(TableDragMode.ROW);
+ source2.setDragMode(TableDragMode.ROW);
+
+ target.setDropHandler(new DropHandler() {
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return new SourceIs(source1, source2);
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ TableTransferable transferable = (TableTransferable) event
+ .getTransferable();
+ Item item = transferable.getSourceComponent().getItem(
+ transferable.getItemId());
+ Object value = item.getItemProperty("value").getValue();
+ AbstractSelectTargetDetails targetDetails = (AbstractSelectTargetDetails) event
+ .getTargetDetails();
+ Object targetItemId = targetDetails.getItemIdOver();
+ Object addItemAfter = target.addItemAfter(targetItemId);
+ target.getItem(addItemAfter).getItemProperty("value")
+ .setValue(value);
+ transferable.getSourceComponent().removeItem(
+ transferable.getItemId());
+ }
+ });
+
+ TabSheet tabSheet = new TabSheet();
+ tabSheet.addComponent(source1);
+ tabSheet.addComponent(source2);
+
+ addComponent(tabSheet);
+ addComponent(target);
+ }
+
+ private Table createTable(String caption) {
+ Table table = new Table(caption);
+ table.addContainerProperty("value", String.class, "");
+ for (int i = 0; i < 10; i++) {
+ table.addItem(new Object[] { caption + " value " + i },
+ Integer.valueOf(i));
+ }
+ table.setWidth("300px");
+ return table;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Including a component in an accept criterion when the actual component is in a TabSheet and has not yet been painted should still allow painting the component properly when the tab is opened.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(8730);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/ScrolledDropTarget.html.disabled b/uitest/src/com/vaadin/tests/dd/ScrolledDropTarget.html.disabled
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/ScrolledDropTarget.html.disabled
diff --git a/uitest/src/com/vaadin/tests/dd/ScrolledDropTarget.java b/uitest/src/com/vaadin/tests/dd/ScrolledDropTarget.java
new file mode 100644
index 0000000000..951b9a4a57
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/ScrolledDropTarget.java
@@ -0,0 +1,70 @@
+package com.vaadin.tests.dd;
+
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.shared.ui.dd.VerticalDropLocation;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.util.Log;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+import com.vaadin.ui.AbstractSelect.VerticalLocationIs;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.TableDragMode;
+
+public class ScrolledDropTarget extends TestBase {
+ private final Log log = new Log(5);
+
+ @Override
+ protected void setup() {
+
+ Table table = new Table();
+ table.addContainerProperty("A", String.class, "");
+ for (int i = 0; i < 100; i++) {
+ table.addItem(new Object[] { Integer.toString(i) },
+ Integer.valueOf(i));
+ }
+
+ table.setDragMode(TableDragMode.ROW);
+ table.setDropHandler(new DropHandler() {
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return VerticalLocationIs.MIDDLE;
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ AbstractSelectTargetDetails targetDetails = (AbstractSelectTargetDetails) event
+ .getTargetDetails();
+ VerticalDropLocation dropLocation = targetDetails
+ .getDropLocation();
+ log.log("Drop at " + dropLocation + " relative to "
+ + targetDetails.getItemIdOver());
+ }
+ });
+
+ addComponent(table);
+ addComponent(new Button("Scroll body", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ getMainWindow().executeJavaScript(
+ "document.body.style.overflow = 'auto';"
+ + "document.body.style.height = '200%';"
+ + "window.scrollTo(0,18)");
+ }
+ }));
+ addComponent(log);
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Vertical location for drags should work even when the browser window is scrolled";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(6021);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/StartHtml5Drag.java b/uitest/src/com/vaadin/tests/dd/StartHtml5Drag.java
new file mode 100644
index 0000000000..609b2fe4fc
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/StartHtml5Drag.java
@@ -0,0 +1,66 @@
+package com.vaadin.tests.dd;
+
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.server.ClassResource;
+import com.vaadin.server.Sizeable;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.DragAndDropWrapper.DragStartMode;
+import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.Label;
+
+public class StartHtml5Drag extends TestBase {
+
+ @Override
+ protected void setup() {
+ DragAndDropWrapper dragStart = new DragAndDropWrapper(new Label(
+ "Drag me"));
+ dragStart.setDragStartMode(DragStartMode.HTML5);
+ dragStart.setHTML5DataFlavor("Text", "HTML5!");
+ addComponent(dragStart);
+
+ DragAndDropWrapper dropTarget = new DragAndDropWrapper(new Label(
+ "over here"));
+ dropTarget.setDropHandler(new DropHandler() {
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ getWindows()
+ .iterator()
+ .next()
+ .showNotification(
+ ((WrapperTransferable) event.getTransferable())
+ .getText());
+ }
+ });
+ addComponent(dropTarget);
+
+ Embedded iframe = new Embedded("", new ClassResource("html5drop.htm"));
+ iframe.setType(Embedded.TYPE_BROWSER);
+ iframe.setWidth(400, Sizeable.UNITS_PIXELS);
+ iframe.setHeight(400, Sizeable.UNITS_PIXELS);
+ addComponent(iframe);
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Should work. Try to e.g. drag the 'Hello Vaadin user' "
+ + "label to native text editor application. In text "
+ + "editor app 'HTML5!' text should appear.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 7833;
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/dd/TreeDragStart.java b/uitest/src/com/vaadin/tests/dd/TreeDragStart.java
new file mode 100644
index 0000000000..27ac8b6586
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/TreeDragStart.java
@@ -0,0 +1,330 @@
+package com.vaadin.tests.dd;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.data.util.BeanItemContainer;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.Not;
+import com.vaadin.event.dd.acceptcriteria.Or;
+import com.vaadin.shared.ui.dd.VerticalDropLocation;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+import com.vaadin.ui.AbstractSelect.VerticalLocationIs;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.TableDragMode;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.Tree.TreeDragMode;
+import com.vaadin.ui.Tree.TreeTargetDetails;
+
+public class TreeDragStart extends TestBase {
+
+ @Override
+ protected void setup() {
+ final Tree tree = new Tree("Inventory");
+
+ CheckBox checkBox = new CheckBox("Enabled");
+ checkBox.setImmediate(true);
+ checkBox.setValue(true);
+ checkBox.addListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ tree.setEnabled(!tree.isEnabled());
+ }
+ });
+ addComponent(checkBox);
+ checkBox = new CheckBox("Drag start");
+ checkBox.setImmediate(true);
+ checkBox.setValue(true);
+ checkBox.addListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ if ((Boolean) ((CheckBox) event.getProperty()).getValue()) {
+ tree.setDragMode(TreeDragMode.NODE);
+ } else {
+ tree.setDragMode(TreeDragMode.NONE);
+ }
+ }
+ });
+ addComponent(checkBox);
+
+ tree.setContainerDataSource(createTreeContent());
+ tree.setItemCaptionMode(Tree.ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID);
+ for (Object item : tree.getItemIds().toArray()) {
+ tree.setItemCaption(item, (String) ((BeanItem<?>) item)
+ .getItemProperty("name").getValue());
+ }
+ getLayout().addComponent(tree);
+
+ // Expand all items
+ for (Iterator<?> it = tree.rootItemIds().iterator(); it.hasNext();) {
+ tree.expandItemsRecursively(it.next());
+ }
+
+ // Set the tree in drag source mode
+ tree.setDragMode(TreeDragMode.NODE);
+
+ // Allow the tree to receive drag drops and handle them
+ tree.setDropHandler(new DropHandler() {
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ // Accept drops in the middle of container items
+ // and below and above all items.
+ return new Or(Tree.TargetItemAllowsChildren.get(), new Not(
+ VerticalLocationIs.MIDDLE));
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ // Wrapper for the object that is dragged
+ DataBoundTransferable t = (DataBoundTransferable) event
+ .getTransferable();
+
+ TreeTargetDetails target = (TreeTargetDetails) event
+ .getTargetDetails();
+
+ // Get ids of the dragged item and the target item
+ Object sourceItemId = t.getData("itemId");
+ Object targetItemId = target.getItemIdOver();
+
+ // On which side of the target the item was dropped
+ VerticalDropLocation location = target.getDropLocation();
+
+ HierarchicalContainer container = (HierarchicalContainer) tree
+ .getContainerDataSource();
+
+ BeanItem<?> beanItem = null;
+ if (sourceItemId instanceof BeanItem<?>) {
+ beanItem = (BeanItem<?>) sourceItemId;
+ } else if (sourceItemId instanceof InventoryObject) {
+ beanItem = new BeanItem<InventoryObject>(
+ (InventoryObject) sourceItemId);
+ }
+
+ // Remove the item from the source container and
+ // add it to the tree's container
+ Container sourceContainer = t.getSourceContainer();
+ sourceContainer.removeItem(sourceItemId);
+ tree.addItem(beanItem);
+ InventoryObject bean = (InventoryObject) beanItem.getBean();
+ tree.setChildrenAllowed(beanItem, bean.isContainer());
+
+ // Drop right on an item -> make it a child
+ if (location == VerticalDropLocation.MIDDLE) {
+ tree.setParent(beanItem, targetItemId);
+ } else if (location == VerticalDropLocation.TOP) {
+ Object parentId = container.getParent(targetItemId);
+ tree.setParent(beanItem, parentId);
+ container.moveAfterSibling(beanItem, targetItemId);
+ container.moveAfterSibling(targetItemId, beanItem);
+ }
+
+ // Drop below another item -> make it next
+ else if (location == VerticalDropLocation.BOTTOM) {
+ Object parentId = container.getParent(targetItemId);
+ tree.setParent(beanItem, parentId);
+ container.moveAfterSibling(beanItem, targetItemId);
+ }
+
+ tree.setItemCaption(beanItem, bean.getName());
+ }
+ });
+
+ // Have a table that allows dragging from
+ final Table table = new Table("Inventory List");
+ table.setDragMode(TableDragMode.ROW);
+
+ // Initialize the table container
+ ArrayList<InventoryObject> collection = new ArrayList<InventoryObject>();
+ collection.add(new InventoryObject("Dummy Item", 0.0, false));
+ final BeanItemContainer<InventoryObject> tableContainer = new BeanItemContainer<InventoryObject>(
+ collection);
+ table.setContainerDataSource(tableContainer);
+ table.setVisibleColumns(new String[] { "name", "weight" });
+ table.removeAllItems();
+
+ // Allow the table to receive drops and handle them
+ table.setDropHandler(new DropHandler() {
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return new Not(VerticalLocationIs.MIDDLE);
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ // Wrapper for the object that is dragged
+ DataBoundTransferable t = (DataBoundTransferable) event
+ .getTransferable();
+
+ // Make sure the drag source is the same tree
+ if (t.getSourceComponent() != tree
+ && t.getSourceComponent() != table) {
+ return;
+ }
+
+ AbstractSelectTargetDetails target = (AbstractSelectTargetDetails) event
+ .getTargetDetails();
+
+ // Get ids of the dragged item and the target item
+ Object sourceItemId = t.getData("itemId");
+ Object targetItemId = target.getItemIdOver();
+
+ // Do not allow drop on the item itself
+ if (sourceItemId.equals(targetItemId)) {
+ return;
+ }
+
+ InventoryObject bean = null;
+ if (sourceItemId instanceof BeanItem<?>) {
+ bean = (InventoryObject) ((BeanItem<?>) sourceItemId)
+ .getBean();
+ } else if (sourceItemId instanceof InventoryObject) {
+ bean = (InventoryObject) sourceItemId;
+ }
+
+ // Remove the item from the source container
+ t.getSourceContainer().removeItem(sourceItemId);
+
+ // On which side of the target the item was dropped
+ VerticalDropLocation location = target.getDropLocation();
+
+ // The table was empty or otherwise not on an item
+ if (targetItemId == null) {
+ tableContainer.addItem(bean); // Add to the end
+ } else if (location == VerticalDropLocation.TOP) {
+ tableContainer.addItemAt(
+ tableContainer.indexOfId(targetItemId), bean);
+ } else if (location == VerticalDropLocation.BOTTOM) {
+ tableContainer.addItemAfter(targetItemId, bean);
+ }
+ }
+ });
+ getLayout().addComponent(table);
+ }
+
+ public class InventoryObject implements Serializable {
+ private static final long serialVersionUID = -8943498783302996516L;
+
+ String name;
+ double weight;
+ boolean container;
+
+ public InventoryObject(String name, double weight, boolean container) {
+ this.name = name;
+ this.weight = weight;
+ this.container = container;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public double getWeight() {
+ return weight;
+ }
+
+ public void setWeight(double weight) {
+ this.weight = weight;
+ }
+
+ public boolean isContainer() {
+ return container;
+ }
+
+ public void setContainer(boolean container) {
+ this.container = container;
+ }
+ }
+
+ HashMap<String, InventoryObject> inventoryStore = new HashMap<String, InventoryObject>();
+
+ public HierarchicalContainer createTreeContent() {
+ final Object[] inventory = new Object[] {
+ new InventoryObject("root", 0.0, true),
+ new InventoryObject("+5 Quarterstaff (blessed)", 3.5, false),
+ new InventoryObject("+3 Elven Dagger (blessed)", 0.2, false),
+ new InventoryObject("+5 Helmet (greased)", 1.5, false),
+ new Object[] {
+ new InventoryObject("Sack", 0.2, true),
+ new InventoryObject("Pick-Axe", 2.5, false),
+ new InventoryObject("Lock Pick", 0.1, false),
+ new InventoryObject("Tinning Kit", 0.5, false),
+ new InventoryObject("Potion of Healing (blessed)", 0.7,
+ false), },
+ new Object[] {
+ new InventoryObject("Bag of Holding", 0.1, true),
+ new InventoryObject("Magic Marker", 0.05, false),
+ new InventoryObject("Can of Grease (blessed)", 0.5,
+ false), },
+ new Object[] {
+ new InventoryObject("Chest", 10.0, true),
+ new InventoryObject("Scroll of Identify", 0.1, false),
+ new InventoryObject("Scroll of Genocide", 0.1, false),
+ new InventoryObject("Towel", 0.3, false),
+ new Object[] {
+ new InventoryObject("Large Box", 8.0, true),
+ new InventoryObject("Figurine of Vaadin", 0.4,
+ false),
+ new InventoryObject("Expensive Camera", 1.5,
+ false), },
+ new InventoryObject("Tin Opener", 0.02, false), }, };
+
+ HierarchicalContainer container = new HierarchicalContainer();
+
+ new Object() {
+ public void put(Object[] data, Object parent,
+ HierarchicalContainer container) {
+ for (int i = 1; i < data.length; i++) {
+ BeanItem<InventoryObject> item;
+ if (data[i].getClass() == InventoryObject.class) {
+ InventoryObject object = (InventoryObject) data[i];
+ item = new BeanItem<InventoryObject>(object);
+ container.addItem(item);
+ container.setParent(item, parent);
+ container.setChildrenAllowed(item, false);
+ } else {// It's an Object[]
+ Object[] sub = (Object[]) data[i];
+ InventoryObject object = (InventoryObject) sub[0];
+ item = new BeanItem<InventoryObject>(object);
+ container.addItem(item);
+ container.setParent(item, parent);
+
+ // Add children recursively
+ put(sub, item, container);
+ }
+
+ inventoryStore
+ .put(item.getBean().getName(), item.getBean());
+ }
+ }
+ }.put(inventory, null, container);
+
+ return container;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Should work";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 6320;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/VMyDragSource.java b/uitest/src/com/vaadin/tests/dd/VMyDragSource.java
new file mode 100644
index 0000000000..8cca6d6459
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/VMyDragSource.java
@@ -0,0 +1,89 @@
+package com.vaadin.tests.dd;
+
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
+import com.google.gwt.event.dom.client.MouseMoveEvent;
+import com.google.gwt.event.dom.client.MouseMoveHandler;
+import com.google.gwt.event.dom.client.MouseOutEvent;
+import com.google.gwt.event.dom.client.MouseOutHandler;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ui.dd.VDragAndDropManager;
+import com.vaadin.client.ui.dd.VTransferable;
+
+/**
+ * Example code to implement Component that has something to drag.
+ */
+public class VMyDragSource extends Composite implements MouseDownHandler,
+ MouseMoveHandler, MouseOutHandler {
+
+ private boolean mouseDown;
+ private MouseDownEvent mDownEvent;
+
+ @SuppressWarnings("unused")
+ public VMyDragSource() {
+ FlowPanel fp = new FlowPanel();
+ initWidget(fp);
+
+ HTML html = new HTML("DragThis");
+
+ fp.add(html);
+
+ html.addMouseDownHandler(this);
+ html.addMouseMoveHandler(this);
+ html.addMouseOutHandler(this);
+
+ }
+
+ /*
+ * Below a sophisticated drag start implementation. Drag event is started if
+ * mouse is moved 5 pixels with left mouse key down.
+ */
+
+ @Override
+ public void onMouseDown(MouseDownEvent event) {
+ if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) {
+ mouseDown = true;
+ mDownEvent = event;
+ }
+ }
+
+ @Override
+ public void onMouseMove(MouseMoveEvent event) {
+ if (mouseDown) {
+ int deltaX = Math.abs(mDownEvent.getClientX() - event.getClientX());
+ int deltaY = Math.abs(mDownEvent.getClientY() - event.getClientY());
+ if (deltaX > 5 || deltaY > 5) {
+ // Start the drag and drop operation
+
+ // create Transferable, that contains the payload
+ VTransferable transferable = new VTransferable();
+ transferable.setData("Text", "myPayload");
+
+ // Tell DragAndDropManager to start a drag and drop operation.
+ // Also let it handle all events (last parameter true). Could
+ // also do all event handling here too.
+ VDragAndDropManager.get().startDrag(transferable,
+ mDownEvent.getNativeEvent(), true);
+
+ mouseDown = false;
+ mDownEvent = null;
+ }
+ }
+
+ }
+
+ @Override
+ public void onMouseOut(MouseOutEvent event) {
+ mouseDown = false;
+ mDownEvent = null;
+ }
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/VMyDropTarget.java b/uitest/src/com/vaadin/tests/dd/VMyDropTarget.java
new file mode 100644
index 0000000000..58bd326524
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/VMyDropTarget.java
@@ -0,0 +1,53 @@
+package com.vaadin.tests.dd;
+
+import com.google.gwt.user.client.ui.Composite;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ui.dd.VDragEvent;
+import com.vaadin.client.ui.dd.VDropHandler;
+import com.vaadin.client.ui.dd.VHasDropHandler;
+
+public class VMyDropTarget extends Composite implements VHasDropHandler,
+ VDropHandler {
+
+ ApplicationConnection client;
+
+ @Override
+ public void dragEnter(VDragEvent drag) {
+ }
+
+ @Override
+ public void dragLeave(VDragEvent drag) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void dragOver(VDragEvent currentDrag) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public boolean drop(VDragEvent drag) {
+ // TODO Auto-generated method stub
+ // return true to tell DDManager do server visit
+ return false;
+ }
+
+ @Override
+ public VDropHandler getDropHandler() {
+ // Drophandler implemented by widget itself
+ return this;
+ }
+
+ @Override
+ public ComponentConnector getConnector() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ApplicationConnection getApplicationConnection() {
+ return client;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/dd/html5drop.htm b/uitest/src/com/vaadin/tests/dd/html5drop.htm
new file mode 100644
index 0000000000..ed05fcedea
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/dd/html5drop.htm
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>Insert title here</title>
+<script type="text/javascript">
+ if (window.addEventListener) {
+ window.addEventListener('load', init, false); //W3C
+ } else {
+ window.attachEvent('onload', init); //IE
+ }
+
+ function init(event) {
+ var el = document.getElementById("drop");
+ if (el.addEventListener) {
+ el.addEventListener("dragover", dragover, false);
+ el.addEventListener("dragenter", dragenter, false);
+ el.addEventListener("drop", drop, false);
+ } else if (el.attachEvent) {
+ el.attachEvent('ondragover', dragover);
+ el.attachEvent('ondragenter', dragenter);
+ el.attachEvent('ondrop', drop);
+ }
+ }
+
+ function dragover(event) {
+ event.dataTransfer.dropEffect = 'copy';
+ return cancel(event);
+ }
+
+ function drop(event) {
+ document.getElementById("drop").innerHTML = event.dataTransfer.getData('Text');
+ return cancel(event);
+ }
+
+ function dragenter(event) {
+ return cancel(event);
+ }
+
+ function cancel(event) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ }
+ return false;
+ }
+</script>
+</head>
+<body>
+ <div id="drop">or over here</div>
+</body>
+</html> \ No newline at end of file