From: Matti Tahvonen Date: Fri, 5 Mar 2010 13:43:43 +0000 (+0000) Subject: merged changes from 6.3 + some container related changes X-Git-Tag: 6.7.0.beta1~1988^2 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=7cefe21c703e6e7822ba7456d45fa49a14dd067d;p=vaadin-framework.git merged changes from 6.3 + some container related changes svn changeset:11664/svn branch:6.3_dd --- 7cefe21c703e6e7822ba7456d45fa49a14dd067d diff --cc WebContent/VAADIN/themes/base/styles.css index 60fb294fa0,bb582c2605..ae67ae2a7a --- a/WebContent/VAADIN/themes/base/styles.css +++ b/WebContent/VAADIN/themes/base/styles.css @@@ -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 { diff --cc WebContent/VAADIN/themes/reindeer/styles.css index c2df4128e4,051d79f378..60451c64c7 --- a/WebContent/VAADIN/themes/reindeer/styles.css +++ b/WebContent/VAADIN/themes/reindeer/styles.css @@@ -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 { diff --cc WebContent/VAADIN/themes/runo/styles.css index cf6236a886,822f5702ae..493a7ea8eb --- a/WebContent/VAADIN/themes/runo/styles.css +++ b/WebContent/VAADIN/themes/runo/styles.css @@@ -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 { diff --cc src/com/vaadin/data/util/HierarchicalContainer.java index 2b5519e651,a264eafc71..a404d83eb1 --- a/src/com/vaadin/data/util/HierarchicalContainer.java +++ b/src/com/vaadin/data/util/HierarchicalContainer.java @@@ -191,11 -208,15 +208,17 @@@ public class HierarchicalContainer exte return true; } - // Making root + // Making root? if (newParentId == null) { + // The itemId should become a root so we need to - // - Remove it from the old parent's children list (also filtered list) ++ // - 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) - ++ // - 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 l = children.get(itemId); if (l != null) { l.remove(itemId); if (l.isEmpty()) { @@@ -209,9 -245,16 +247,19 @@@ // Updates parent parent.remove(itemId); ++ fireContentsChange(-1); ++ return true; } + // 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 - ++ // - 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)) { @@@ -247,11 -303,20 +308,61 @@@ children.remove(oldParentId); } } + if (filteredChildren != null) { + LinkedList 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 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) * @@@ -309,20 -398,41 +444,44 @@@ 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 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 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 c = children.get(parentItemId); if (c != null) { c.remove(itemId); + + // Found in the children list so might also be in the + // filteredChildren list + if (filteredChildren != null) { - LinkedList f = filteredChildren.get(parentItemId); ++ LinkedList f = filteredChildren ++ .get(parentItemId); + if (f != null) { + f.remove(parentItemId); + } + } } } parent.remove(itemId); @@@ -332,6 -442,6 +491,35 @@@ 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 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) * @@@ -347,4 -457,39 +535,40 @@@ } } + /* + * 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(); + filteredChildren = new HashMap>(); + + // 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 filtered = new LinkedList(); + filteredChildren.put(parent, filtered); + for (Object child : children.get(parent)) { + if (passesFilters(child)) { + filtered.add(child); + } + } + } + } + + } ++ } diff --cc src/com/vaadin/data/util/IndexedContainer.java index d6d6d9e77c,5131923eac..3bac19cd7a --- a/src/com/vaadin/data/util/IndexedContainer.java +++ b/src/com/vaadin/data/util/IndexedContainer.java @@@ -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( diff --cc src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java index 59c5d252fe,04a73939a7..53f0033bcd --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java @@@ -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 { ++ VHasDropHandler, ValueChangeHandler { public static final String CLASSNAME = "v-table"; public static final String ITEM_CLICK_EVENT_ID = "itemClick"; @@@ -3111,157 -3070,8 +3116,161 @@@ } } + 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 arg0) { + client.getContextMenu().hide(); + } - ++ } diff --cc src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 67b806f0f0,66b3eb30ca..481e42c0e9 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@@ -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(); } diff --cc src/com/vaadin/ui/Tree.java index 665e98cfee,7b1dad3911..d28d02216c --- a/src/com/vaadin/ui/Tree.java +++ b/src/com/vaadin/ui/Tree.java @@@ -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 @@@ -58,25 -46,8 +59,8 @@@ @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 */ /** @@@ -1109,291 -1068,4 +1102,291 @@@ return super.removeItem(itemId); } + 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 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()}. + *

+ * In other words this method returns the identifier of the "folder" + * into the drag operation is targeted. + *

+ * If the method returns null, the current target is on a root node or + * on other undefined area over the tree component. + *

+ * 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.TOP) { ++ && getDropLocation() == VerticalDropLocation.MIDDLE) { + return itemIdOver; + } + return getParent(itemIdOver); + } + + } + + /** + * TODO Javadoc! + * + * @since 6.3 + */ + public TreeDropTargetDetails translateDropTargetDetails( + Map 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 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 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. + *

+ * See client side counterpart + */ + @ClientCriterion(VLazyInitItemIdentifiers.class) + public static abstract class TreeDropCriterion extends ServerSideCriterion { + + private Tree tree; + + private Set 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 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)); + } + + } + } diff --cc tests/src/com/vaadin/tests/dd/DDTest1.java index e51f9fa1bc,0000000000..55ef48e5e6 mode 100644,000000..100644 --- a/tests/src/com/vaadin/tests/dd/DDTest1.java +++ b/tests/src/com/vaadin/tests/dd/DDTest1.java @@@ -1,284 -1,0 +1,282 @@@ +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 - 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"); ++ 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); + - 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); ++ 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; + } + +}