- .v-theme-version:after {content:"6_3_0_dev-20100304";}
- .v-theme-version-6_3_0_dev-20100304 {display: none;}
-.v-theme-version:after {content:"9_9_9_INTERNAL-DEBUG-BUILD";}
-.v-theme-version-9_9_9_INTERNAL-DEBUG-BUILD {display: none;}
++.v-theme-version:after {content:"6_3_0_dev-20100305";}
++.v-theme-version-6_3_0_dev-20100305 {display: none;}
/* Automatically compiled css file from subdirectories. */
.v-absolutelayout-wrapper {
- .v-theme-version:after {content:"6_3_0_dev-20100304";}
- .v-theme-version-6_3_0_dev-20100304 {display: none;}
-.v-theme-version:after {content:"9_9_9_INTERNAL-DEBUG-BUILD";}
-.v-theme-version-9_9_9_INTERNAL-DEBUG-BUILD {display: none;}
++.v-theme-version:after {content:"6_3_0_dev-20100305";}
++.v-theme-version-6_3_0_dev-20100305 {display: none;}
/* Automatically compiled css file from subdirectories. */
.v-absolutelayout-wrapper {
- .v-theme-version:after {content:"6_3_0_dev-20100304";}
- .v-theme-version-6_3_0_dev-20100304 {display: none;}
-.v-theme-version:after {content:"9_9_9_INTERNAL-DEBUG-BUILD";}
-.v-theme-version-9_9_9_INTERNAL-DEBUG-BUILD {display: none;}
++.v-theme-version:after {content:"6_3_0_dev-20100305";}
++.v-theme-version-6_3_0_dev-20100305 {display: none;}
/* Automatically compiled css file from subdirectories. */
.v-absolutelayout-wrapper {
return true;
}
- // Making root
+ // Making root?
if (newParentId == null) {
- // - Remove it from the old parent's children list (also filtered list)
+ // The itemId should become a root so we need to
- // - Remove it from the item -> parent list (parent is null for roots)
-
++ // - Remove it from the old parent's children list (also filtered
++ // list)
+ // - Add it as a root
++ // - Remove it from the item -> parent list (parent is null for
++ // roots)
+
// Removes from old parents children list
- final LinkedList l = children.get(itemId);
+ final LinkedList<Object> l = children.get(itemId);
if (l != null) {
l.remove(itemId);
if (l.isEmpty()) {
// Updates parent
parent.remove(itemId);
++ fireContentsChange(-1);
++
return true;
}
- // - Remove the item from the old parent's children list if it was not a root
-
+ // We get here when the item should not become a root and we need to
+ // - Verify the new parent exists and can have children
+ // - Check that the new parent is not a child of the selected itemId
+ // - Updated the item -> parent mapping to point to the new parent
+ // - Remove the item from the roots list if it was a root
++ // - Remove the item from the old parent's children list if it was not a
++ // root
++
// Checks that the new parent exists in container and can have
// children
if (!containsId(newParentId) || noChildrenAllowed.contains(newParentId)) {
children.remove(oldParentId);
}
}
+ if (filteredChildren != null) {
+ LinkedList<Object> f = filteredChildren.get(oldParentId);
+ if (f != null) {
+ f.remove(itemId);
+ if (f.isEmpty()) {
+ filteredChildren.remove(oldParentId);
+ }
+ }
+ }
}
++ fireContentsChange(-1);
++
return true;
}
++ /**
++ * TODO javadoc
++ *
++ * @param itemId
++ * @param siblingId
++ */
++ public void moveAfterSibling(Object itemId, Object siblingId) {
++ Object parent2 = getParent(itemId);
++ LinkedList<Object> childrenList;
++ if (parent2 == null) {
++ childrenList = roots;
++ } else {
++ childrenList = children.get(parent2);
++ }
++ if (siblingId == null) {
++ childrenList.remove(itemId);
++ childrenList.addFirst(itemId);
++
++ } else {
++ int oldIndex = childrenList.indexOf(itemId);
++ int indexOfSibling = childrenList.indexOf(siblingId);
++ if (indexOfSibling != -1 && oldIndex != -1) {
++ int newIndex;
++ if (oldIndex > indexOfSibling) {
++ newIndex = indexOfSibling + 1;
++ } else {
++ newIndex = indexOfSibling;
++ }
++ childrenList.remove(oldIndex);
++ childrenList.add(newIndex, itemId);
++ } else {
++ throw new IllegalArgumentException(
++ "Given identifiers no not have the same parent.");
++ }
++ }
++ fireContentsChange(-1);
++
++ }
++
/*
* (non-Javadoc)
*
final boolean success = super.removeItem(itemId);
if (success) {
- if (isRoot(itemId)) {
- roots.remove(itemId);
-
+ // Remove from roots if this was a root
+ if (roots.remove(itemId)) {
+
+ // If filtering is enabled we might need to remove it from the
+ // filtered list also
+ if (filteredRoots != null) {
+ filteredRoots.remove(itemId);
+ }
}
- LinkedList<Object> remove = children.remove(itemId);
- if (remove != null) {
- for (Object object : remove) {
- removeItem(object);
+
- // Clear the children list. Old children will now be unattached
- // FIXME Should these be made into roots?
- if (children.remove(itemId) != null) {
++ // Clear the children list. Old children will now become root nodes
++ LinkedList<Object> childNodeIds = children.remove(itemId);
++ if (childNodeIds != null) {
+ if (filteredChildren != null) {
+ filteredChildren.remove(itemId);
+ }
++ for (Object childId : childNodeIds) {
++ setParent(childId, null);
+ }
}
- final Object p = parent.get(itemId);
- if (p != null) {
- final LinkedList c = children.get(p);
+
+ // Parent of the item that we are removing will contain the item id
+ // in its children list
+ final Object parentItemId = parent.get(itemId);
+ if (parentItemId != null) {
+ final LinkedList<Object> c = children.get(parentItemId);
if (c != null) {
c.remove(itemId);
- LinkedList<Object> f = filteredChildren.get(parentItemId);
+
+ // Found in the children list so might also be in the
+ // filteredChildren list
+ if (filteredChildren != null) {
++ LinkedList<Object> f = filteredChildren
++ .get(parentItemId);
+ if (f != null) {
+ f.remove(parentItemId);
+ }
+ }
}
}
parent.remove(itemId);
return success;
}
++ /**
++ * Removes the Item identified by ItemId from the Container and all its
++ * children.
++ *
++ * @see #removeItem(Object)
++ * @param itemId
++ * the identifier of the Item to remove
++ * @return true if the operation succeeded
++ */
++ public boolean removeItemRecursively(Object itemId) {
++ boolean success = true;
++ Collection<Object> children2 = getChildren(itemId);
++ if (children2 != null) {
++ Object[] array = children2.toArray();
++ for (int i = 0; i < array.length; i++) {
++ boolean removeItemRecursively = removeItemRecursively(array[i]);
++ if (!removeItemRecursively) {
++ success = false;
++ }
++ }
++ }
++ boolean removeItem = removeItem(itemId);
++ if (!removeItem) {
++ success = false;
++ }
++ return success;
++
++ }
++
/*
* (non-Javadoc)
*
}
}
+ /*
+ * Overridden to provide filtering for root & children items.
+ *
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.IndexedContainer#updateContainerFiltering()
+ */
+ @Override
+ protected void updateContainerFiltering() {
+ super.updateContainerFiltering();
+
+ filteredRoots = new LinkedList<Object>();
+ filteredChildren = new HashMap<Object, LinkedList<Object>>();
+
+ // Filter root item ids
+ for (Object rootId : roots) {
+ if (passesFilters(rootId)) {
+ filteredRoots.add(rootId);
+ }
+ }
+
+ // Filter children
+ for (Object parent : children.keySet()) {
+ if (passesFilters(parent)) {
+ LinkedList<Object> filtered = new LinkedList<Object>();
+ filteredChildren.put(parent, filtered);
+ for (Object child : children.get(parent)) {
+ if (passesFilters(child)) {
+ filtered.add(child);
+ }
+ }
+ }
+ }
+
+ }
++
}
* @param addedItemIndex
* index of new item if change event was an item addition
*/
-- private void fireContentsChange(int addedItemIndex) {
++ protected void fireContentsChange(int addedItemIndex) {
if (itemSetChangeListeners != null) {
final Object[] l = itemSetChangeListeners.toArray();
final Container.ItemSetChangeEvent event = new IndexedContainer.ItemSetChangeEvent(
* TODO implement unregistering for child components in Cells
*/
public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
- VHasDropHandler {
- ValueChangeHandler<String> {
++ VHasDropHandler, ValueChangeHandler<String> {
public static final String CLASSNAME = "v-table";
public static final String ITEM_CLICK_EVENT_ID = "itemClick";
}
}
-
+ public VScrollTableDropHandler getDropHandler() {
+ return dropHandler;
+ }
+
+ private static class TableDDDetails {
+ int overkey = -1;
+ VerticalDropLocation dropLocation;
+ String colkey;
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof TableDDDetails) {
+ TableDDDetails other = (TableDDDetails) obj;
+ return dropLocation == other.dropLocation
+ && overkey == other.overkey
+ && ((colkey != null && colkey.equals(other.colkey)) || (colkey == null && other.colkey == null));
+ }
+ return false;
+ }
+
+ // @Override
+ // public int hashCode() {
+ // return overkey;
+ // }
+ }
+
+ public class VScrollTableDropHandler extends VAbstractDropHandler {
+
+ private static final String ROWSTYLEBASE = "v-table-row-drag-";
+ private TableDDDetails dropDetails;
+ private TableDDDetails lastEmphasized;
+
+ @Override
+ public void dragEnter(VDragEvent drag) {
+ updateDropDetails(drag);
+ super.dragEnter(drag);
+ }
+
+ private void updateDropDetails(VDragEvent drag) {
+ dropDetails = new TableDDDetails();
+ Element elementOver = drag.getElementOver();
+
+ VScrollTableRow row = Util.findWidget(elementOver,
+ VScrollTableRow.class);
+ if (row != null) {
+ dropDetails.overkey = row.rowKey;
+ Element tr = row.getElement();
+ Element element = elementOver;
+ while (element != null && element.getParentElement() != tr) {
+ element = (Element) element.getParentElement();
+ }
+ int childIndex = DOM.getChildIndex(tr, element);
+ dropDetails.colkey = tHead.getHeaderCell(childIndex)
+ .getColKey();
+ dropDetails.dropLocation = VerticalDropLocation.get(row
+ .getElement(), drag.getCurrentGwtEvent().getClientY(),
+ 0.2);
+ }
+
+ drag.getDropDetails().put("itemIdOver", dropDetails.overkey + "");
+ drag.getDropDetails().put(
+ "detail",
+ dropDetails.dropLocation != null ? dropDetails.dropLocation
+ .toString() : null);
+
+ }
+
+ @Override
+ public void dragOver(VDragEvent drag) {
+ TableDDDetails oldDetails = dropDetails;
+ updateDropDetails(drag);
+ if (!oldDetails.equals(dropDetails)) {
+ deEmphasis();
+ VAcceptCallback cb = new VAcceptCallback() {
+ public void accepted(VDragEvent event) {
+ dragAccepted(event);
+ }
+ };
+ validate(cb, drag);
+ }
+ }
+
+ @Override
+ public void dragLeave(VDragEvent drag) {
+ deEmphasis();
+ super.dragLeave(drag);
+ }
+
+ @Override
+ public boolean drop(VDragEvent drag) {
+ deEmphasis();
+ return super.drop(drag);
+ }
+
+ private void deEmphasis() {
+ if (lastEmphasized == null) {
+ return;
+ }
+ for (Widget w : scrollBody.renderedRows) {
+ VScrollTableRow row = (VScrollTableRow) w;
+ if (lastEmphasized != null
+ && row.rowKey == lastEmphasized.overkey) {
+ if (row != null) {
+ String stylename = ROWSTYLEBASE
+ + lastEmphasized.dropLocation.toString()
+ .toLowerCase();
+ VScrollTableRow.setStyleName(row.getElement(),
+ stylename, false);
+ }
+ lastEmphasized = null;
+ return;
+ }
+ }
+ }
+
+ /**
+ * TODO needs different drop modes ?? (on cells, on rows), now only
+ * supports rows
+ */
+ private void emphasis(TableDDDetails details) {
+ deEmphasis();
+ // iterate old and new emphasized row
+ for (Widget w : scrollBody.renderedRows) {
+ VScrollTableRow row = (VScrollTableRow) w;
+ if (details != null && details.overkey == row.rowKey) {
+ if (row != null) {
+ String stylename = ROWSTYLEBASE
+ + details.dropLocation.toString().toLowerCase();
+ VScrollTableRow.setStyleName(row.getElement(),
+ stylename, true);
+ }
+ lastEmphasized = details;
+ return;
+ }
+ }
+ }
+
+ @Override
+ protected void dragAccepted(VDragEvent drag) {
+ emphasis(dropDetails);
+ }
+
+ @Override
+ public Paintable getPaintable() {
+ return VScrollTable.this;
+ }
+
+ public ApplicationConnection getApplicationConnection() {
+ return client;
+ }
+
+ }
+
+ public void onValueChange(ValueChangeEvent<String> arg0) {
+ client.getContextMenu().hide();
+ }
++
}
// add any pending locale definitions requested by the client
printLocaleDeclarations(outWriter);
+ if (dragAndDropService != null) {
+ dragAndDropService.printJSONResponse(outWriter);
+ }
+
outWriter.print("}]");
}
- outWriter.flush();
outWriter.close();
}
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.VTree;
+import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers;
+import com.vaadin.terminal.gwt.client.ui.dd.VOverTreeNode;
+import com.vaadin.terminal.gwt.client.ui.dd.VTargetNodeIsChildOf;
+import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
+ import com.vaadin.tools.ReflectTools;
/**
* Tree component. A Tree can be used to select an item (or multiple items) from
@SuppressWarnings("serial")
@ClientWidget(VTree.class)
public class Tree extends AbstractSelect implements Container.Hierarchical,
- Action.Container, ItemClickSource {
+ Action.Container, ItemClickSource, DragSource, DropTarget {
- private static final Method EXPAND_METHOD;
-
- private static final Method COLLAPSE_METHOD;
-
- static {
- try {
- EXPAND_METHOD = ExpandListener.class.getDeclaredMethod(
- "nodeExpand", new Class[] { ExpandEvent.class });
- COLLAPSE_METHOD = CollapseListener.class.getDeclaredMethod(
- "nodeCollapse", new Class[] { CollapseEvent.class });
- } catch (final java.lang.NoSuchMethodException e) {
- // This should never happen
- throw new java.lang.RuntimeException(
- "Internal error finding methods in Tree");
- }
- }
-
/* Private members */
/**
return super.removeItem(itemId);
}
- && getDropLocation() != VerticalDropLocation.TOP) {
+ public DropHandler getDropHandler() {
+ return dropHandler;
+ }
+
+ public void setDropHandler(DropHandler dropHandler) {
+ this.dropHandler = dropHandler;
+ }
+
+ /**
+ * TODO Javadoc!
+ *
+ * @since 6.3
+ */
+ public class TreeDropTargetDetails extends AbstractSelectDropTargetDetails {
+
+ TreeDropTargetDetails(Map<String, Object> rawVariables) {
+ super(rawVariables);
+ }
+
+ @Override
+ public Tree getTarget() {
+ return (Tree) super.getTarget();
+ }
+
+ /**
+ * If the event is on a node that can not have children (see
+ * {@link Tree#areChildrenAllowed(Object)}), this method returns the
+ * parent item id of the target item (see {@link #getItemIdOver()} ).
+ * The identifier of the parent node is also returned if the cursor is
+ * on the top part of node. Else this method returns the same as
+ * {@link #getItemIdOver()}.
+ * <p>
+ * In other words this method returns the identifier of the "folder"
+ * into the drag operation is targeted.
+ * <p>
+ * If the method returns null, the current target is on a root node or
+ * on other undefined area over the tree component.
+ * <p>
+ * The default Tree implementation marks the targetted tree node with
+ * CSS classnames v-tree-node-dragfolder and
+ * v-tree-node-caption-dragfolder (for the caption element).
+ */
+ public Object getItemIdInto() {
+
+ Object itemIdOver = getItemIdOver();
+ if (areChildrenAllowed(itemIdOver)
++ && getDropLocation() == VerticalDropLocation.MIDDLE) {
+ return itemIdOver;
+ }
+ return getParent(itemIdOver);
+ }
+
+ }
+
+ /**
+ * TODO Javadoc!
+ *
+ * @since 6.3
+ */
+ public TreeDropTargetDetails translateDropTargetDetails(
+ Map<String, Object> clientVariables) {
+ return new TreeDropTargetDetails(clientVariables);
+ }
+
+ /**
+ * API for {@link TreeDropCriterion}
+ *
+ * @param itemId
+ * @return
+ */
+ private String key(Object itemId) {
+ return itemIdMapper.key(itemId);
+ }
+
+ public void setDragMode(TreeDragMode dragMode) {
+ this.dragMode = dragMode;
+ }
+
+ public TreeDragMode getDragMode() {
+ return dragMode;
+ }
+
+ /**
+ * TODO Javadoc!
+ *
+ * @since 6.3
+ */
+ public class TreeTransferable extends DataBoundTransferable {
+
+ public TreeTransferable(Component sourceComponent,
+ Map<String, Object> rawVariables) {
+ super(sourceComponent, rawVariables);
+ }
+
+ @Override
+ public Object getItemId() {
+ return getData("itemId");
+ }
+
+ @Override
+ public Object getPropertyId() {
+ return getItemCaptionPropertyId();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.event.dd.DragSource#getTransferable(java.util.Map)
+ */
+ public Transferable getTransferable(Map<String, Object> payload) {
+ TreeTransferable transferable = new TreeTransferable(this, payload);
+ // updating drag source variables
+ Object object = payload.get("itemId");
+ if (object != null) {
+ transferable.setData("itemId", itemIdMapper.get((String) object));
+ }
+
+ return transferable;
+ }
+
+ /**
+ * An example of lazy initializing criterion. Initially pretty much no data
+ * is sent to client, on first accepts set (per drag request) the client
+ * side data structure is initialized and no subsequent requests requests
+ * are needed during that drag and drop operation.
+ * <p>
+ * See client side counterpart
+ */
+ @ClientCriterion(VLazyInitItemIdentifiers.class)
+ public static abstract class TreeDropCriterion extends ServerSideCriterion {
+
+ private Tree tree;
+
+ private Set<Object> allowedItemIds;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.event.dd.acceptCriteria.ServerSideCriterion#getIdentifier
+ * ()
+ */
+ @Override
+ protected String getIdentifier() {
+ return TreeDropCriterion.class.getCanonicalName();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.event.dd.acceptCriteria.AcceptCriterion#accepts(com.vaadin
+ * .event.dd.DragAndDropEvent)
+ */
+ public boolean accepts(DragAndDropEvent dragEvent) {
+ AbstractSelectDropTargetDetails dropTargetData = (AbstractSelectDropTargetDetails) dragEvent
+ .getDropTargetDetails();
+ tree = (Tree) dragEvent.getDropTargetDetails().getTarget();
+ allowedItemIds = getAllowedItemIds(dragEvent, tree);
+
+ return allowedItemIds.contains(dropTargetData.getItemIdOver());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.event.dd.acceptCriteria.AcceptCriterion#paintResponse(
+ * com.vaadin.terminal.PaintTarget)
+ */
+ @Override
+ public void paintResponse(PaintTarget target) throws PaintException {
+ /*
+ * send allowed nodes to client so subsequent requests can be
+ * avoided
+ */
+ Object[] array = allowedItemIds.toArray();
+ for (int i = 0; i < array.length; i++) {
+ String key = tree.key(array[i]);
+ array[i] = key;
+ }
+ target.addAttribute("allowedIds", array);
+ }
+
+ protected abstract Set<Object> getAllowedItemIds(
+ DragAndDropEvent dragEvent, Tree tree);
+
+ }
+
+ /**
+ * Accepts transferable only on tree Node (middle of the node + can has
+ * child)
+ *
+ * TODO replace by composition of itemIdIs + drop property
+ *
+ * @since 6.3
+ */
+ @ClientCriterion(VOverTreeNode.class)
+ public static class OverFolderNode extends ClientSideCriterion {
+
+ private static final long serialVersionUID = 1L;
+
+ public boolean accepts(DragAndDropEvent dragEvent) {
+ try {
+ // must be over tree node and in the middle of it (not top or
+ // bottom
+ // part)
+ TreeDropTargetDetails eventDetails = (TreeDropTargetDetails) dragEvent
+ .getDropTargetDetails();
+
+ Object itemIdOver = eventDetails.getItemIdOver();
+ if (!eventDetails.getTarget().areChildrenAllowed(itemIdOver)) {
+ return false;
+ }
+ // return true if directly over
+ return eventDetails.getDropLocation() == VerticalDropLocation.MIDDLE;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Checks to parent (or parent hierarchy) for the item identifier given in
+ * constructor. If the parent is found, content is accepted.
+ */
+ @ClientCriterion(VTargetNodeIsChildOf.class)
+ public class TargetNodeIsChildOf extends ClientSideCriterion {
+
+ private Object parentItemId;
+ private int depthToCheck = 1;
+
+ /**
+ *
+ * @param parentItemId
+ */
+ public TargetNodeIsChildOf(Object parentItemId) {
+ this.parentItemId = parentItemId;
+ }
+
+ /**
+ *
+ * @param parentItemId
+ * @param depthToCheck
+ * the depth that tree is traversed upwards to seek for the
+ * parent, -1 means that the whole structure should be
+ * checked
+ */
+ public TargetNodeIsChildOf(Object parentItemId, int depthToCheck) {
+ this.parentItemId = parentItemId;
+ this.depthToCheck = depthToCheck;
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ public boolean accepts(DragAndDropEvent dragEvent) {
+ try {
+ TreeDropTargetDetails eventDetails = (TreeDropTargetDetails) dragEvent
+ .getDropTargetDetails();
+
+ if (eventDetails.getItemIdOver() != null) {
+ Object itemIdOver = eventDetails.getItemIdOver();
+ Object parent2 = getParent(itemIdOver);
+ int i = 0;
+ while (parent2 != null && i < depthToCheck) {
+ if (parent2.equals(parentItemId)) {
+ return true;
+ }
+ i++;
+ }
+ }
+ return false;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ super.paintContent(target);
+ target.addAttribute("depth", depthToCheck);
+ target.addAttribute("key", key(parentItemId));
+ }
+
+ }
+
}
--- /dev/null
- itemIdOver = idx.prevItemId(itemIdOver);
- }
-
- if (itemId.equals(itemIdOver)) {
- // the location is same
- return;
- }
-
- HierarchicalContainer subtree = getSubTree(idx, itemId);
- boolean removed = idx.removeItem(itemId);
-
- if (removed) {
-
- if (dropLocation == null) {
- System.err
- .println("No detail of drop place available");
+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.IsDataBound;
+import com.vaadin.event.dd.acceptCriteria.ServerSideCriterion;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.DragDropPane;
+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.Tree;
+import com.vaadin.ui.Table.DragModes;
+import com.vaadin.ui.Tree.TreeDragMode;
+import com.vaadin.ui.Tree.TreeDropTargetDetails;
+
+/**
+ * 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\")");
+ DropHandler dropHandler = new DragDropPane.ImportPrettyMuchAnything() {
+ private final AcceptCriterion crit = new ServerSideCriterion() {
+ public boolean accepts(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;
+ }
+ };
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return crit;
+ }
+
+ };
+ pane2.setDropHandler(dropHandler);
+ pane2.setDebugId("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.setDebugId("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() {
+
+ 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);
+ }
+ }
+
+ }
+
+ 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);
+ }
+ }
+
+ }
+
+ public void drop(DragAndDropEvent event) {
+ TreeDropTargetDetails details = (TreeDropTargetDetails) event
+ .getDropTargetDetails();
+ // 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 = itemIdOver;
+ if (dropLocation == VerticalDropLocation.MIDDLE) {
+ t.setParent(itemId, itemIdOver);
+ return;
+ } else if (VerticalDropLocation.TOP == dropLocation) {
+ // if on top of the caption area, add before
- Item addItemAfter = idx
- .addItemAfter(itemIdOver, itemId);
- populateSubTree(idx, subtree, itemId);
- // ensure the same parent as with related item
- Object parent = idx.getParent(itemIdOver);
- idx.setParent(itemId, parent);
++ Collection children;
++ if (itemIdInto != null) {
++ // seek the previous from child list
++ children = idx.getChildren(itemIdInto);
++ } else {
++ children = idx.rootItemIds();
+ }
++ Object ref = null;
++ for (Object object : children) {
++ if (object.equals(itemIdOver)) {
++ itemIdAfter = ref;
++ break;
++ }
++ ref = object;
++ }
++ }
++ idx.setParent(itemId, itemIdInto);
+
++ if (dropLocation == null) {
++ System.err.println("No detail of drop place available");
+ }
++ idx.moveAfterSibling(itemId, itemIdAfter);
+ }
+
+ return;
+ }
+
+ public AcceptCriterion getAcceptCriterion() {
+ // TODO should actually check that source is same as target
+ return IsDataBound.get();
+ }
+
+ };
+
+ 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(DragModes.ROWS);
+
+ 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;
+ }
+
+}