]> source.dussan.org Git - vaadin-framework.git/commitdiff
merged changes from 6.3 + some container related changes
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Fri, 5 Mar 2010 13:43:43 +0000 (13:43 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Fri, 5 Mar 2010 13:43:43 +0000 (13:43 +0000)
svn changeset:11664/svn branch:6.3_dd

15 files changed:
1  2 
WebContent/VAADIN/themes/base/styles.css
WebContent/VAADIN/themes/base/table/table.css
WebContent/VAADIN/themes/reindeer/styles.css
WebContent/VAADIN/themes/runo/styles.css
src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
src/com/vaadin/data/util/HierarchicalContainer.java
src/com/vaadin/data/util/IndexedContainer.java
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java
src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
src/com/vaadin/ui/Table.java
src/com/vaadin/ui/Tree.java
tests/src/com/vaadin/tests/dd/DDTest1.java

index 60fb294fa09dcffcc6c76b3bd85ecfb54c21746c,bb582c26050e83e3b5d83a39de0b86f897a6e00f..ae67ae2a7a0980c209f5cd77245502f09669523e
@@@ -1,5 -1,5 +1,5 @@@
- .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 {
index c2df4128e4c9324123b6a5b27d31edb9d0934c5d,051d79f37861931140fe98a5e31bd7f8819b8fdd..60451c64c720beecd3fa7915fcfb2d2b05d37fe5
@@@ -1,5 -1,5 +1,5 @@@
- .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 {
index cf6236a8869a57932242f599ba51d40af863d4e1,822f5702ae317d4029ee891d9832fdc6d6388e2b..493a7ea8eb884aecc07ca6e1e38e9a486c76a1a2
@@@ -1,5 -1,5 +1,5 @@@
- .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 {
index 2b5519e6514e583f7351fcba088cde314b498f83,a264eafc71672e31364a5e0f447d9a0496c97dbe..a404d83eb1ae48d00cc0cf60f7ee4c280440191a
@@@ -191,11 -208,15 +208,17 @@@ public class HierarchicalContainer exte
              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);
+                     }
+                 }
+             }
+         }
+     }
++
  }
index d6d6d9e77c4e2ec5c05ec42beeab3e1b3c98d726,5131923eacd47e4d72ea8005034d5769cc40f980..3bac19cd7aec52e9dddc2b5b2198600272508ab0
@@@ -953,7 -965,7 +968,7 @@@ public class IndexedContainer implement
       * @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(
index 59c5d252fe652be3269de25dd637fcb01726b08b,04a73939a731d7f109f49291d5da86dc3bd0815b..53f0033bcdc3cea5efa29a2184b34e05b9930808
@@@ -72,7 -68,7 +75,7 @@@ import com.vaadin.terminal.gwt.client.u
   * 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();
+     }
++    
  }
index 67b806f0f0e5e2119132604d2ec8bfe13aba33a1,66b3eb30cafbccc59a2674458c600c58f10e9d4e..481e42c0e9e4c8239cc331a672615b4ef5d8a741
@@@ -941,13 -938,8 +940,12 @@@ public abstract class AbstractCommunica
              // add any pending locale definitions requested by the client
              printLocaleDeclarations(outWriter);
  
 +            if (dragAndDropService != null) {
 +                dragAndDropService.printJSONResponse(outWriter);
 +            }
 +
              outWriter.print("}]");
          }
-         outWriter.flush();
          outWriter.close();
  
      }
Simple merge
index 665e98cfeed3d1430b341582dfd88c7fc3afba34,7b1dad391122cbc1e3a9d20106340e19cb255575..d28d02216c2cfb31db131d6a876f1c992b9b406e
@@@ -41,10 -32,7 +41,11 @@@ import com.vaadin.terminal.PaintTarget
  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));
 +        }
 +
 +    }
 +
  }
index e51f9fa1bc39718aed931029dbeccca47ddea5d6,0000000000000000000000000000000000000000..55ef48e5e647ba6ee4b6b4e8ae6c3c019e53661e
mode 100644,000000..100644
--- /dev/null
@@@ -1,284 -1,0 +1,282 @@@
-                         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;
 +    }
 +
 +}