package com.vaadin.v7.tests.components.tree; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; import com.vaadin.shared.ui.MultiSelectMode; import com.vaadin.tests.components.select.AbstractSelectTestCase; import com.vaadin.v7.data.Container; import com.vaadin.v7.data.Container.Hierarchical; import com.vaadin.v7.data.util.HierarchicalContainer; import com.vaadin.v7.ui.Tree; import com.vaadin.v7.ui.Tree.CollapseEvent; import com.vaadin.v7.ui.Tree.CollapseListener; import com.vaadin.v7.ui.Tree.ExpandEvent; import com.vaadin.v7.ui.Tree.ExpandListener; import com.vaadin.v7.ui.Tree.ItemStyleGenerator; public class Trees extends AbstractSelectTestCase<Tree> implements ExpandListener, CollapseListener { private int rootItemIds = 3; private ItemStyleGenerator rootGreenSecondLevelRed = new com.vaadin.v7.ui.Tree.ItemStyleGenerator() { @Override public String getStyle(Tree source, Object itemId) { Hierarchical c = (Container.Hierarchical) getComponent() .getContainerDataSource(); if (c.isRoot(itemId)) { return "green"; } Object parent = c.getParent(itemId); if (!c.isRoot(parent)) { return "red"; } return null; } @Override public String toString() { return "Root green, second level red"; } }; private ItemStyleGenerator evenItemsBold = new com.vaadin.v7.ui.Tree.ItemStyleGenerator() { @Override public String getStyle(Tree source, Object itemId) { Hierarchical c = (Container.Hierarchical) getComponent() .getContainerDataSource(); int idx = 0; for (Iterator<?> i = c.getItemIds().iterator(); i.hasNext();) { Object id = i.next(); if (id == itemId) { if (idx % 2 == 1) { return "bold"; } else { return null; } } idx++; } return null; } @Override public String toString() { return "Even items bold"; } }; private Command<Tree, ContextMenu> contextMenuCommand = new Command<Tree, ContextMenu>() { @Override public void execute(Tree c, final ContextMenu value, Object data) { c.removeAllActionHandlers(); if (value != null) { c.addActionHandler(new Handler() { @Override public void handleAction(Action action, Object sender, Object target) { log("Action " + action.getCaption() + " performed on " + target); } @Override public Action[] getActions(Object target, Object sender) { return value.getActions(target, sender); } }); } } }; @Override protected Class<Tree> getTestClass() { return Tree.class; } @Override protected void createActions() { super.createActions(); // Causes container changes so doing this first.. createRootItemSelectAction(CATEGORY_DATA_SOURCE); createExpandCollapseActions(CATEGORY_FEATURES); createSelectionModeSelect(CATEGORY_SELECTION); createChildrenAllowedAction(CATEGORY_DATA_SOURCE); createListeners(CATEGORY_LISTENERS); createItemStyleGenerator(CATEGORY_FEATURES); createContextMenuAction(CATEGORY_FEATURES); // TODO: DropHandler // TODO: DragMode // TODO: ActionHandler } private void createContextMenuAction(String category) { LinkedHashMap<String, ContextMenu> options = new LinkedHashMap<>(); options.put("None", null); options.put("Item without icon", new ContextMenu("No icon", null)); ContextMenu cm = new ContextMenu(); cm.addItem("Caption only", null); cm.addItem("Has icon", ICON_16_USER_PNG_UNCACHEABLE); options.put("With and without icon", cm); options.put("Only one large icon", new ContextMenu("Icon", ICON_64_EMAIL_REPLY_PNG_UNCACHEABLE)); createSelectAction("Context menu", category, options, "None", contextMenuCommand, true); } private void createItemStyleGenerator(String category) { LinkedHashMap<String, com.vaadin.v7.ui.Tree.ItemStyleGenerator> options = new LinkedHashMap<>(); options.put("-", null); options.put(rootGreenSecondLevelRed.toString(), rootGreenSecondLevelRed); options.put(evenItemsBold.toString(), evenItemsBold); createSelectAction("Item Style generator", category, options, "-", itemStyleGeneratorCommand); } private void createListeners(String category) { createBooleanAction("Expand listener", category, false, expandListenerCommand); createBooleanAction("Collapse listener", category, false, collapseListenerCommand); createBooleanAction("Item click listener", category, false, itemClickListenerCommand); } private enum SelectMode { NONE, SINGLE, MULTI_SIMPLE, MULTI; } protected void createSelectionModeSelect(String category) { LinkedHashMap<String, SelectMode> options = new LinkedHashMap<>(); options.put("None", SelectMode.NONE); options.put("Single", SelectMode.SINGLE); options.put("Multi - simple", SelectMode.MULTI_SIMPLE); options.put("Multi - ctrl/shift", SelectMode.MULTI); createSelectAction("Selection Mode", category, options, "Multi - ctrl/shift", new Command<Tree, SelectMode>() { @Override public void execute(Tree t, SelectMode value, Object data) { switch (value) { case NONE: t.setSelectable(false); break; case SINGLE: t.setMultiSelect(false); t.setSelectable(true); break; case MULTI_SIMPLE: t.setSelectable(true); t.setMultiSelect(true); t.setMultiselectMode(MultiSelectMode.SIMPLE); break; case MULTI: t.setSelectable(true); t.setMultiSelect(true); t.setMultiselectMode(MultiSelectMode.DEFAULT); break; } } }); } @Override protected Container createContainer(int properties, int items) { return createHierarchicalContainer(properties, items, rootItemIds); } private Container.Hierarchical createHierarchicalContainer(int properties, int items, int roots) { Container.Hierarchical c = new HierarchicalContainer(); populateContainer(c, properties, items); if (items <= roots) { return c; } // "roots" roots, each with // "firstLevel" children, two with no children (one with childAllowed, // one without) // ("firstLevel"-2)*"secondLevel" children ("secondLevel"/2 with // childAllowed, "secondLevel"/2 without) // N*M+N*(M-2)*C = items // items=N(M+MC-2C) // Using secondLevel=firstLevel/2 => // items = roots*(firstLevel+firstLevel*firstLevel/2-2*firstLevel/2) // =roots*(firstLevel+firstLevel^2/2-firstLevel) // = roots*firstLevel^2/2 // => firstLevel = sqrt(items/roots*2) int firstLevel = (int) Math.ceil(Math.sqrt(items / roots * 2.0)); int secondLevel = firstLevel / 2; while (roots * (1 + 2 + (firstLevel - 2) * secondLevel) < items) { // Increase something so we get enough items secondLevel++; } List<Object> itemIds = new ArrayList<>(c.getItemIds()); int nextItemId = roots; for (int rootIndex = 0; rootIndex < roots; rootIndex++) { // roots use items 0..roots-1 Object rootItemId = itemIds.get(rootIndex); // force roots to be roots even though they automatically should be c.setParent(rootItemId, null); for (int firstLevelIndex = 0; firstLevelIndex < firstLevel; firstLevelIndex++) { if (nextItemId >= items) { break; } Object firstLevelItemId = itemIds.get(nextItemId++); c.setParent(firstLevelItemId, rootItemId); if (firstLevelIndex < 2) { continue; } // firstLevelChildren 2.. have child nodes for (int secondLevelIndex = 0; secondLevelIndex < secondLevel; secondLevelIndex++) { if (nextItemId >= items) { break; } Object secondLevelItemId = itemIds.get(nextItemId++); c.setParent(secondLevelItemId, firstLevelItemId); } } } return c; } private void createRootItemSelectAction(String category) { LinkedHashMap<String, Integer> options = new LinkedHashMap<>(); for (int i = 1; i <= 10; i++) { options.put(String.valueOf(i), i); } options.put("20", 20); options.put("50", 50); options.put("100", 100); createSelectAction("Number of root items", category, options, "3", rootItemIdsCommand); } private void createExpandCollapseActions(String category) { LinkedHashMap<String, Object> options = new LinkedHashMap<>(); for (Object id : getComponent().getItemIds()) { options.put(id.toString(), id); } createMultiClickAction("Expand", category, options, expandItemCommand, null); createMultiClickAction("Expand recursively", category, options, expandItemRecursivelyCommand, null); createMultiClickAction("Collapse", category, options, collapseItemCommand, null); } private void createChildrenAllowedAction(String category) { LinkedHashMap<String, Object> options = new LinkedHashMap<>(); for (Object id : getComponent().getItemIds()) { options.put(id.toString(), id); } createMultiToggleAction("Children allowed", category, options, setChildrenAllowedCommand, true); } /* * COMMANDS */ private Command<Tree, Integer> rootItemIdsCommand = new Command<Tree, Integer>() { @Override public void execute(Tree c, Integer value, Object data) { rootItemIds = value; updateContainer(); } }; private Command<Tree, Object> expandItemCommand = new Command<Tree, Object>() { @Override public void execute(Tree c, Object itemId, Object data) { c.expandItem(itemId); } }; private Command<Tree, Object> expandItemRecursivelyCommand = new Command<Tree, Object>() { @Override public void execute(Tree c, Object itemId, Object data) { c.expandItemsRecursively(itemId); } }; private Command<Tree, Object> collapseItemCommand = new Command<Tree, Object>() { @Override public void execute(Tree c, Object itemId, Object data) { c.collapseItem(itemId); } }; private Command<Tree, Boolean> setChildrenAllowedCommand = new Command<Tree, Boolean>() { @Override public void execute(Tree c, Boolean areChildrenAllowed, Object itemId) { c.setChildrenAllowed(itemId, areChildrenAllowed); } }; private Command<Tree, Boolean> expandListenerCommand = new Command<Tree, Boolean>() { @Override public void execute(Tree c, Boolean value, Object data) { if (value) { c.addListener((ExpandListener) Trees.this); } else { c.removeListener((ExpandListener) Trees.this); } } }; private Command<Tree, Boolean> collapseListenerCommand = new Command<Tree, Boolean>() { @Override public void execute(Tree c, Boolean value, Object data) { if (value) { c.addListener((CollapseListener) Trees.this); } else { c.removeListener((CollapseListener) Trees.this); } } }; private Command<Tree, com.vaadin.v7.ui.Tree.ItemStyleGenerator> itemStyleGeneratorCommand = new Command<Tree, com.vaadin.v7.ui.Tree.ItemStyleGenerator>() { @Override public void execute(Tree c, com.vaadin.v7.ui.Tree.ItemStyleGenerator value, Object data) { c.setItemStyleGenerator(value); } }; @Override public void nodeCollapse(CollapseEvent event) { log(event.getClass().getSimpleName() + ": " + event.getItemId()); } @Override public void nodeExpand(ExpandEvent event) { log(event.getClass().getSimpleName() + ": " + event.getItemId()); } }