From 97a1087ebd22fd2c68535d2613e567fe80bfda60 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Wed, 20 Apr 2011 13:49:32 +0000 Subject: [PATCH] merged fix for #6320 svn changeset:18415/svn branch:6.6 --- src/com/vaadin/ui/Tree.java | 3 +- .../com/vaadin/tests/dd/TreeDragStart.java | 324 ++++++++++++++++++ 2 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 tests/src/com/vaadin/tests/dd/TreeDragStart.java diff --git a/src/com/vaadin/ui/Tree.java b/src/com/vaadin/ui/Tree.java index 79ce7cf47f..523f3fe739 100644 --- a/src/com/vaadin/ui/Tree.java +++ b/src/com/vaadin/ui/Tree.java @@ -107,7 +107,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, */ public enum TreeDragMode { /** - * When drag mode is NONE, draggin from Tree is not supported. Browsers + * When drag mode is NONE, dragging from Tree is not supported. Browsers * may still support selecting text/icons from Tree which can initiate * HTML 5 style drag and drop operation. */ @@ -1293,6 +1293,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, */ public void setDragMode(TreeDragMode dragMode) { this.dragMode = dragMode; + requestRepaint(); } /** diff --git a/tests/src/com/vaadin/tests/dd/TreeDragStart.java b/tests/src/com/vaadin/tests/dd/TreeDragStart.java new file mode 100644 index 0000000000..4a719bfa7f --- /dev/null +++ b/tests/src/com/vaadin/tests/dd/TreeDragStart.java @@ -0,0 +1,324 @@ +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.terminal.gwt.client.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() { + 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() { + public void valueChange(ValueChangeEvent event) { + if (((CheckBox) event.getProperty()).booleanValue()) { + 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() { + 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)); + } + + 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) 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 collection = new ArrayList(); + collection.add(new InventoryObject("Dummy Item", 0.0, false)); + final BeanItemContainer tableContainer = new BeanItemContainer( + 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() { + public AcceptCriterion getAcceptCriterion() { + return new Not(VerticalLocationIs.MIDDLE); + } + + 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 inventoryStore = new HashMap(); + + 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 item; + if (data[i].getClass() == InventoryObject.class) { + InventoryObject object = (InventoryObject) data[i]; + item = new BeanItem(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(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; + } + +} -- 2.39.5