]> source.dussan.org Git - vaadin-framework.git/commitdiff
- Added Ctrl+Shift multiple selection to Tree
authorJohn Alhroos <john.ahlroos@itmill.com>
Thu, 6 May 2010 13:32:45 +0000 (13:32 +0000)
committerJohn Alhroos <john.ahlroos@itmill.com>
Thu, 6 May 2010 13:32:45 +0000 (13:32 +0000)
- Moved MultiSelectMode enum to AbstractSelect
- Added test application for Tree ctrl+Shift selection
- Added keyboard navigation sample to the Sampler feature set

svn changeset:13070/svn branch:6.4

src/com/vaadin/terminal/gwt/client/ui/VTree.java
src/com/vaadin/ui/AbstractSelect.java
src/com/vaadin/ui/Table.java
src/com/vaadin/ui/Tree.java
tests/src/com/vaadin/tests/components/tree/CtrlShiftMultiselect.java [new file with mode: 0644]
tests/src/com/vaadin/tests/server/component/table/TestMultipleSelection.java

index 42421b80de497d572c54ca92636bd429cd9ad445..f4d968df5d27623c8139230a5bf3d083ac7ba638 100644 (file)
@@ -4,9 +4,12 @@
 
 package com.vaadin.terminal.gwt.client.ui;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Set;
 
 import com.google.gwt.dom.client.NativeEvent;
@@ -43,12 +46,17 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
 
     public static final String ITEM_CLICK_EVENT_ID = "itemClick";
 
+    public static final int MULTISELECT_MODE_DEFAULT = 0;
+    public static final int MULTISELECT_MODE_SIMPLE = 1;
+
     private Set<String> selectedIds = new HashSet<String>();
     private ApplicationConnection client;
     private String paintableId;
     private boolean selectable;
     private boolean isMultiselect;
     private String currentMouseOverKey;
+    private TreeNode lastSelection;
+    private int multiSelectMode = MULTISELECT_MODE_DEFAULT;
 
     private final HashMap<String, TreeNode> keyToNode = new HashMap<String, TreeNode>();
 
@@ -152,6 +160,10 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
         selectable = !"none".equals(selectMode);
         isMultiselect = "multi".equals(selectMode);
 
+        if (isMultiselect) {
+            multiSelectMode = uidl.getIntAttribute("multiselectmode");
+        }
+
         selectedIds = uidl.getStringArrayVariableAsSet("selected");
 
         rendering = false;
@@ -314,6 +326,10 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
             treeNode.setSelected(false);
         }
 
+        sendSelectionToServer();
+    }
+
+    private void sendSelectionToServer() {
         client.updateVariable(paintableId, "selected", selectedIds
                 .toArray(new String[selectedIds.size()]), immediate);
     }
@@ -430,6 +446,47 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
             }
         }
 
+        /**
+         * Handles mouse selection
+         * 
+         * @param ctrl
+         *            Was the ctrl-key pressed
+         * @param shift
+         *            Was the shift-key pressed
+         * @return Returns true if event was handled, else false
+         */
+        private boolean handleClickSelection(boolean ctrl, boolean shift) {
+
+            if (multiSelectMode == MULTISELECT_MODE_SIMPLE || !isMultiselect) {
+                toggleSelection();
+                lastSelection = this;
+            } else if (multiSelectMode == MULTISELECT_MODE_DEFAULT) {
+                // Handle ctrl+click
+                if (isMultiselect && ctrl && !shift) {
+                    toggleSelection();
+                    lastSelection = this;
+
+                    // Handle shift+click
+                } else if (isMultiselect && !ctrl && shift) {
+                    deselectAll();
+                    selectNodeRange(lastSelection.key, key);
+                    sendSelectionToServer();
+
+                    // Handle ctrl+shift click
+                } else if (isMultiselect && ctrl && shift) {
+                    selectNodeRange(lastSelection.key, key);
+
+                    // Handle click
+                } else {
+                    deselectAll();
+                    toggleSelection();
+                    lastSelection = this;
+                }
+            }
+
+            return true;
+        }
+
         @Override
         public void onBrowserEvent(Event event) {
             super.onBrowserEvent(event);
@@ -453,13 +510,20 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
                     toggleState();
                 } else if (!readonly && inCaption) {
                     // caption click = selection change && possible click event
-                    toggleSelection();
+                    if (handleClickSelection(event.getCtrlKey()
+                            || event.getMetaKey(), event.getShiftKey())) {
+                        event.preventDefault();
+                    }
                 }
                 DOM.eventCancelBubble(event, true);
             } else if (type == Event.ONCONTEXTMENU) {
                 showContextMenu(event);
             }
 
+            if (type == Event.ONMOUSEDOWN) {
+                event.preventDefault();
+            }
+
             if (dragMode != 0 || dropHandler != null) {
                 if (type == Event.ONMOUSEDOWN) {
                     if (nodeCaptionDiv.isOrHasChild(event.getTarget())) {
@@ -674,6 +738,24 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
             return childrenLoaded;
         }
 
+        /**
+         * Returns the children of the node
+         * 
+         * @return A set of tree nodes
+         */
+        public List<TreeNode> getChildren() {
+            List<TreeNode> nodes = new LinkedList<TreeNode>();
+
+            if (!isLeaf() && isChildrenLoaded()) {
+                Iterator<Widget> iter = childNodeContainer.iterator();
+                while (iter.hasNext()) {
+                    TreeNode node = (TreeNode) iter.next();
+                    nodes.add(node);
+                }
+            }
+            return nodes;
+        }
+
         public Action[] getActions() {
             if (actionKeys == null) {
                 return new Action[] {};
@@ -713,6 +795,30 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
             return VTree.this.isSelected(this);
         }
 
+        /**
+         * Travels up the hierarchy looking for this node
+         * 
+         * @param child
+         *            The child which grandparent this is or is not
+         * @return True if this is a grandparent of the child node
+         */
+        public boolean isGrandParentOf(TreeNode child) {
+            TreeNode currentNode = child;
+            boolean isGrandParent = false;
+            while (currentNode != null) {
+                currentNode = currentNode.getParentNode();
+                if (currentNode == this) {
+                    isGrandParent = true;
+                    break;
+                }
+            }
+            return isGrandParent;
+        }
+
+        public boolean isSibling(TreeNode node) {
+            return node.getParentNode() == getParentNode();
+        }
+
         public void showContextMenu(Event event) {
             if (!readonly && !disabled) {
                 if (actionKeys != null) {
@@ -753,6 +859,11 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
             super.onDetach();
             client.getContextMenu().ensureHidden(this);
         }
+
+        @Override
+        public String toString() {
+            return nodeCaptionSpan.getInnerText();
+        }
     }
 
     public VDropHandler getDropHandler() {
@@ -762,4 +873,345 @@ public class VTree extends FlowPanel implements Paintable, VHasDropHandler {
     public TreeNode getNodeByKey(String key) {
         return keyToNode.get(key);
     }
+
+    /**
+     * Deselects all items in the tree
+     */
+    public void deselectAll() {
+        for (String key : selectedIds) {
+            TreeNode node = keyToNode.get(key);
+            if (node != null) {
+                node.setSelected(false);
+            }
+        }
+        selectedIds.clear();
+    }
+
+    /**
+     * Selects a range of nodes
+     * 
+     * @param startNodeKey
+     *            The start node key
+     * @param endNodeKey
+     *            The end node key
+     */
+    private void selectNodeRange(String startNodeKey, String endNodeKey){
+        
+        TreeNode startNode = keyToNode.get(startNodeKey);
+        TreeNode endNode = keyToNode.get(endNodeKey);
+
+        // The nodes have the same parent
+        if(startNode.getParent() == endNode.getParent()){
+            doSiblingSelection(startNode, endNode);
+
+            // The start node is a grandparent of the end node
+        } else if (startNode.isGrandParentOf(endNode)) {
+            doRelationSelection(startNode, endNode);
+
+            // The end node is a grandparent of the start node
+        } else if (endNode.isGrandParentOf(startNode)) {
+            doRelationSelection(endNode, startNode);
+
+        } else {
+            doNoRelationSelection(startNode, endNode);
+        }
+    }
+
+    /**
+     * Selects all the open children to a node
+     * 
+     * @param node
+     *            The parent node
+     */
+    private void selectAllChildren(TreeNode node, boolean includeRootNode) {
+        if (includeRootNode) {
+            node.setSelected(true);
+            selectedIds.add(node.key);
+        }
+
+        for (TreeNode child : node.getChildren()) {
+            if (!child.isLeaf() && child.getState()) {
+                selectAllChildren(child, true);
+            } else {
+                child.setSelected(true);
+                selectedIds.add(child.key);
+            }
+        }
+    }
+
+    /**
+     * Selects all children until a stop child is reached
+     * 
+     * @param root
+     *            The root not to start from
+     * @param stopNode
+     *            The node to finish with
+     * @param includeRootNode
+     *            Should the root node be selected
+     * @param includeStopNode
+     *            Should the stop node be selected
+     * 
+     * @return Returns false if the stop child was found, else true if all
+     *         children was selected
+     */
+    private boolean selectAllChildrenUntil(TreeNode root, TreeNode stopNode,
+            boolean includeRootNode, boolean includeStopNode) {
+        if (includeRootNode) {
+            root.setSelected(true);
+            selectedIds.add(root.key);
+        }
+        if (root.getState() && root != stopNode) {
+            for (TreeNode child : root.getChildren()) {
+                if (!child.isLeaf() && child.getState() && child != stopNode) {
+                    if (!selectAllChildrenUntil(child, stopNode, true,
+                            includeStopNode)) {
+                        return false;
+                    }
+                } else if (child == stopNode) {
+                    if (includeStopNode) {
+                        child.setSelected(true);
+                        selectedIds.add(child.key);
+                    }
+                    return false;
+                } else if (child.isLeaf()) {
+                    child.setSelected(true);
+                    selectedIds.add(child.key);
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Select a range between two nodes which have no relation to each other
+     * 
+     * @param startNode
+     *            The start node to start the selection from
+     * @param endNode
+     *            The end node to end the selection to
+     */
+    private void doNoRelationSelection(TreeNode startNode, TreeNode endNode) {
+
+        TreeNode commonParent = getCommonGrandParent(startNode, endNode);
+        TreeNode startBranch = null, endBranch = null;
+        
+        // Find the children of the common parent
+        List<TreeNode> children;
+        if(commonParent != null){
+            children = commonParent.getChildren(); 
+        }else{
+            children = new LinkedList<TreeNode>();
+            for (Widget w : getChildren()) {
+                children.add((TreeNode) w);
+            }
+        }
+            
+        // Find the start and end branches
+        for (TreeNode node : children) {
+            if (nodeIsInBranch(startNode, node)) {
+                startBranch = node;
+            }
+            if (nodeIsInBranch(endNode, node)) {
+                endBranch = node;
+            }
+        }
+
+        // Swap nodes if necessary
+        if (children.indexOf(startBranch) > children.indexOf(endBranch)) {
+            TreeNode temp = startBranch;
+            startBranch = endBranch;
+            endBranch = temp;
+
+            temp = startNode;
+            startNode = endNode;
+            endNode = temp;
+        }
+
+        // Select all children under the start node
+        selectAllChildren(startNode, true);
+        TreeNode startParent = startNode.getParentNode();
+        TreeNode currentNode = startNode;
+        while (startParent != null && startParent != commonParent) {
+            List<TreeNode> startChildren = startParent.getChildren();
+            for (int i = startChildren.indexOf(currentNode) + 1; i < startChildren
+                    .size(); i++) {
+                selectAllChildren(startChildren.get(i), true);
+            }
+
+            currentNode = startParent;
+            startParent = startParent.getParentNode();
+        }
+
+        // Select nodes until the end node is reached
+        for (int i = children.indexOf(startBranch) + 1; i <= children
+                .indexOf(endBranch); i++) {
+            selectAllChildrenUntil(children.get(i), endNode, true, true);
+        }
+
+        // Ensure end node was selected
+        endNode.setSelected(true);
+        selectedIds.add(endNode.key);
+    }
+
+    /**
+     * Examines the children of the branch node and returns true if a node is in
+     * that branch
+     * 
+     * @param node
+     *            The node to search for
+     * @param branch
+     *            The branch to search in
+     * @return True if found, false if not found
+     */
+    private boolean nodeIsInBranch(TreeNode node, TreeNode branch) {
+        if (node == branch) {
+            return true;
+        }
+        for (TreeNode child : branch.getChildren()) {
+            if (child == node) {
+                return true;
+            }
+            if (!child.isLeaf() && child.getState()) {
+                if (nodeIsInBranch(node, child)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Selects a range of items which are in direct relation with each other.<br/>
+     * NOTE: The start node <b>MUST</b> be before the end node!
+     * 
+     * @param startNode
+     * 
+     * @param endNode
+     */
+    private void doRelationSelection(TreeNode startNode, TreeNode endNode) {
+        TreeNode currentNode = endNode;
+        while (currentNode != startNode) {
+            currentNode.setSelected(true);
+            selectedIds.add(currentNode.key);
+
+            // Traverse children above the selection
+            List<TreeNode> subChildren = currentNode.getParentNode()
+                    .getChildren();
+            if (subChildren.size() > 1) {
+                selectNodeRange(subChildren.iterator().next().key,
+                        currentNode.key);
+            } else if (subChildren.size() == 1) {
+                TreeNode n = subChildren.get(0);
+                n.setSelected(true);
+                selectedIds.add(n.key);
+            }
+
+            currentNode = currentNode.getParentNode();
+        }
+        startNode.setSelected(true);
+        selectedIds.add(startNode.key);
+    }
+
+    /**
+     * Selects a range of items which have the same parent.
+     * 
+     * @param startNode
+     *            The start node
+     * @param endNode
+     *            The end node
+     */
+    private void doSiblingSelection(TreeNode startNode, TreeNode endNode) {
+        TreeNode parent = startNode.getParentNode();
+
+        List<TreeNode> children = new LinkedList<TreeNode>();
+        if (parent == null) {
+            // Topmost parent
+            for (Widget w : getChildren()) {
+                TreeNode node = (TreeNode) w;
+                children.add(node);
+            }
+        } else {
+            children = parent.getChildren();
+        }
+
+        // Swap start and end point if needed
+        if (children.indexOf(startNode) > children.indexOf(endNode)) {
+            TreeNode temp = startNode;
+            startNode = endNode;
+            endNode = temp;
+        }
+
+        Iterator<TreeNode> childIter = children.iterator();
+        boolean startFound = false;
+        while (childIter.hasNext()) {
+            TreeNode node = childIter.next();
+            if (node == startNode) {
+                startFound = true;
+            }
+
+            if (startFound && node != endNode && node.getState()) {
+                selectAllChildren(node, true);
+            } else if (startFound && node != endNode) {
+                node.setSelected(true);
+                selectedIds.add(node.key);
+            }
+
+            if (node == endNode) {
+                node.setSelected(true);
+                selectedIds.add(node.key);
+                break;
+            }
+        }
+    }
+
+    /**
+     * Returns the first common parent of two nodes
+     * 
+     * @param node1
+     *            The first node
+     * @param node2
+     *            The second node
+     * @return The common parent or null
+     */
+    public TreeNode getCommonGrandParent(TreeNode node1, TreeNode node2) {
+        // If either one does not have a grand parent then return null
+        if (node1.getParentNode() == null || node2.getParentNode() == null) {
+            return null;
+        }
+
+        // If the nodes are parents of each other then return null
+        if (node1.isGrandParentOf(node2) || node2.isGrandParentOf(node1)) {
+            return null;
+        }
+
+        // Get parents of node1
+        List<TreeNode> parents1 = new ArrayList<TreeNode>();
+        TreeNode parent1 = node1.getParentNode();
+        while (parent1 != null) {
+            parents1.add(parent1);
+            parent1 = parent1.getParentNode();
+        }
+
+        // Get parents of node2
+        List<TreeNode> parents2 = new ArrayList<TreeNode>();
+        TreeNode parent2 = node2.getParentNode();
+        while (parent2 != null) {
+            parents2.add(parent2);
+            parent2 = parent2.getParentNode();
+        }
+
+        // Search the parents for the first common parent
+        for (int i = 0; i < parents1.size(); i++) {
+            parent1 = parents1.get(i);
+            for (int j = 0; j < parents2.size(); j++) {
+                parent2 = parents2.get(j);
+                if (parent1 == parent2) {
+                    return parent1;
+                }
+            }
+        }
+
+        return null;
+    }
 }
index 9667de32d6426fc55f1aa8cd7ac8c1a7c1c3a863..a8451e7ef6b228275858205bd53ec02728391308 100644 (file)
@@ -126,6 +126,21 @@ public abstract class AbstractSelect extends AbstractField implements
 
     }
 
+    /**
+     * Multi select modes that controls how multi select behaves.
+     */
+    public enum MultiSelectMode {
+        /**
+         * The default behavior of the multi select mode
+         */
+        DEFAULT,
+
+        /**
+         * The previous more simple behavior of the multselect
+         */
+        SIMPLE
+    }
+
     /**
      * Is the select in multiselect mode?
      */
index 9322447bf960c10525d30f5a681bc43bf2299942..4fde62d4bdaff4698de49be44b46dcae26aa1dcb 100644 (file)
@@ -94,22 +94,6 @@ public class Table extends AbstractSelect implements Action.Container,
         MULTIROW
     }
 
-    /**
-     * Multi select modes that controls how multi select behaves.
-     */
-    public enum MultiSelectMode {
-        /**
-         * Simple left clicks only selects one item, CTRL+left click selects
-         * multiple items and SHIFT-left click selects a range of items.
-         */
-        DEFAULT,
-        /**
-         * Uses the old method of selection. CTRL- and SHIFT-clicks are disabled and
-         * clicking on the items selects/deselects them.
-         */
-        SIMPLE
-    }
-
     private static final int CELL_KEY = 0;
 
     private static final int CELL_HEADER = 1;
index 2b38d5a6eb001f8a71a339e3f2afe3474aabb17a..11b049d80382f2d9b176de78397ee0a2893d1e37 100644 (file)
@@ -119,7 +119,9 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
     }
 
     private TreeDragMode dragMode = TreeDragMode.NONE;
-
+    
+    private MultiSelectMode multiSelectMode = MultiSelectMode.DEFAULT;
+    
     /* Tree constructors */
 
     /**
@@ -338,6 +340,29 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
             requestRepaint();
         }
     }
+    
+    /**
+     * Sets the behavior of the multiselect mode
+     * 
+     * @param mode
+     *            The mode to set
+     */
+    public void setMultiselectMode(MultiSelectMode mode) {
+        if (multiSelectMode != mode && mode != null) {
+            multiSelectMode = mode;
+            requestRepaint();
+        }
+    }
+
+    /**
+     * Returns the mode the multiselect is in. The mode controls how
+     * multiselection can be done.
+     * 
+     * @return The mode
+     */
+    public MultiSelectMode getMultiselectMode() {
+        return multiSelectMode;
+    }
 
     /* Component API */
 
@@ -396,6 +421,15 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
             }
         }
 
+        // AbstractSelect cannot handle multiselection so we handle
+        // it ourself
+        if (variables.containsKey("selected") && isMultiSelect()
+                && multiSelectMode == MultiSelectMode.DEFAULT) {
+            handleSelectedItems(variables);
+            variables = new HashMap<String, Object>(variables);
+            variables.remove("selected");
+        }
+
         // Selections are handled by the select component
         super.changeVariables(source, variables);
 
@@ -418,6 +452,37 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
         }
     }
 
+    /**
+     * Handles the selection
+     * 
+     * @param variables
+     *            The variables sent to the server from the client
+     */
+    private void handleSelectedItems(Map<String, Object> variables) {
+        final String[] ka = (String[]) variables.get("selected");
+
+        // Converts the key-array to id-set
+        final LinkedList s = new LinkedList();
+        for (int i = 0; i < ka.length; i++) {
+            final Object id = itemIdMapper.get(ka[i]);
+            if (!isNullSelectionAllowed()
+                    && (id == null || id == getNullSelectionItemId())) {
+                // skip empty selection if nullselection is not allowed
+                requestRepaint();
+            } else if (id != null && containsId(id)) {
+                s.add(id);
+            }
+        }
+
+        if (!isNullSelectionAllowed() && s.size() < 1) {
+            // empty selection not allowed, keep old value
+            requestRepaint();
+            return;
+        }
+
+        setValue(s, true);
+    }
+
     /**
      * Paints any needed component-specific things to the given UIDL stream.
      * 
@@ -442,6 +507,10 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
             if (isSelectable()) {
                 target.addAttribute("selectmode", (isMultiSelect() ? "multi"
                         : "single"));
+                if (isMultiSelect()) {
+                    target.addAttribute("multiselectmode", multiSelectMode
+                            .ordinal());
+                }
             } else {
                 target.addAttribute("selectmode", "none");
             }
diff --git a/tests/src/com/vaadin/tests/components/tree/CtrlShiftMultiselect.java b/tests/src/com/vaadin/tests/components/tree/CtrlShiftMultiselect.java
new file mode 100644 (file)
index 0000000..1a329b1
--- /dev/null
@@ -0,0 +1,117 @@
+package com.vaadin.tests.components.tree;
+
+import java.util.Set;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Tree;
+
+public class CtrlShiftMultiselect extends TestBase {
+
+    private final Tree tree = new Tree();
+    private final Label valueLbl = new Label("No selection");
+
+    @Override
+    protected void setup() {
+
+        getLayout().setSpacing(true);
+
+        tree.setContainerDataSource(createContainer());
+        tree.setItemCaptionPropertyId("name");
+        tree.setWidth("300px");
+        tree.setImmediate(true);
+        tree.setSelectable(true);
+        tree.setMultiSelect(true);
+        tree.expandItemsRecursively("Item 1");
+        tree.expandItemsRecursively("Item 4");
+
+        tree.addListener(new Property.ValueChangeListener() {
+            public void valueChange(ValueChangeEvent event) {
+                if (tree.getValue() instanceof Set) {
+                    Set<Object> itemIds = (Set<Object>) tree.getValue();
+                    if (itemIds.size() == 0) {
+                        valueLbl.setValue("No selection");
+                    } else {
+                        valueLbl.setValue(itemIds);
+                    }
+                } else {
+                    valueLbl.setValue(tree.getValue());
+                }
+            }
+        });
+
+        addComponent(tree);
+
+        valueLbl.setWidth("300px");
+        valueLbl.setHeight("600px");
+        addComponent(valueLbl);
+
+    }
+
+    @Override
+    protected String getDescription() {
+        return "Add ctlr+shift multi selection in Tree";
+    }
+
+    @Override
+    protected Integer getTicketNumber() {
+        return 4259;
+    }
+
+    private HierarchicalContainer createContainer() {
+        HierarchicalContainer cont = new HierarchicalContainer();
+        cont.addContainerProperty("name", String.class, "");
+        
+        for (int i = 0; i < 20; i++) {
+            Item item = cont.addItem("Item " + i);
+            item.getItemProperty("name").setValue("Item " + i);
+            cont.setChildrenAllowed("Item " + i, false);
+
+            if (i == 1 || i == 4) {
+                cont.setChildrenAllowed("Item " + i, true);
+            }
+
+            // Add three items to item 1
+            if (i > 1 && i < 4) {
+                cont.setParent("Item " + i, "Item 1");
+            }
+
+            // Add 5 items to item 4
+            if (i > 4 && i < 10) {
+                cont.setChildrenAllowed("Item " + i, true);
+
+                if (i == 7) {
+                    item = cont.addItem("Item 71");
+                    item.getItemProperty("name").setValue("Item 71");
+                    cont.setParent("Item 71", "Item " + i);
+                    cont.setChildrenAllowed("Item 71", false);
+
+                    item = cont.addItem("Item 72");
+                    item.getItemProperty("name").setValue("Item 72");
+                    cont.setParent("Item 72", "Item " + i);
+                    cont.setChildrenAllowed("Item 72", true);
+
+                    item = cont.addItem("Item 73");
+                    item.getItemProperty("name").setValue("Item 73");
+                    cont.setParent("Item 73", "Item 72");
+                    cont.setChildrenAllowed("Item 73", true);
+
+                    item = cont.addItem("Item 74");
+                    item.getItemProperty("name").setValue("Item 74");
+                    cont.setParent("Item 74", "Item " + i);
+                    cont.setChildrenAllowed("Item 74", true);
+                }
+
+                cont.setParent("Item " + i, "Item " + (i - 1));
+
+            }
+        }
+
+        return cont;
+    }
+
+}
index 42d60bdfef2d06f9946a2596786c92efb8057947..c87ebe9a916e431afdb90f4adb6c8ad6a06db541 100644 (file)
@@ -8,7 +8,7 @@ import junit.framework.TestCase;
 import com.vaadin.data.Container;
 import com.vaadin.data.util.IndexedContainer;
 import com.vaadin.ui.Table;
-import com.vaadin.ui.Table.MultiSelectMode;
+import com.vaadin.ui.AbstractSelect.MultiSelectMode;
 
 public class TestMultipleSelection extends TestCase {