aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>2017-05-23 12:54:26 +0300
committerAleksi Hietanen <aleksi@vaadin.com>2017-05-23 12:54:26 +0300
commit6b6dc9306a749e24f498507d0eddce10b5c6cbf5 (patch)
treea4be32a24c55a67d7c6c6682f15397273807ca7a
parente746334d6444bb16c099f31480919b9020a69bc7 (diff)
downloadvaadin-framework-6b6dc9306a749e24f498507d0eddce10b5c6cbf5.tar.gz
vaadin-framework-6b6dc9306a749e24f498507d0eddce10b5c6cbf5.zip
Add MultiSelection support for Tree Component (#9354)
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java14
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/tree/TreeMultiSelectionModelConnector.java71
-rw-r--r--server/src/main/java/com/vaadin/ui/Tree.java58
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/tree/TreeMultiSelectionModelState.java27
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/tree/TreeBasicFeatures.java8
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/tree/TreeBasicFeaturesTest.java39
6 files changed, 214 insertions, 3 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java
index 83008b5a88..92b858cb97 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java
@@ -125,12 +125,24 @@ public class MultiSelectionModelConnector
@Override
protected void initSelectionModel() {
- getGrid().setSelectionModel(new MultiSelectionModel());
+ getGrid().setSelectionModel(createSelectionModel());
// capture current rows so that can show selection update immediately
dataAvailable = getGrid().addDataAvailableHandler(
event -> availableRows = event.getAvailableRows());
}
+ /**
+ * Creates an instance of MultiSelectionModel. Method provided overriding
+ * features of the selection model without copying all logic.
+ *
+ * @since 8.1
+ *
+ * @return selection model instance, not {@code null}
+ */
+ protected MultiSelectionModel createSelectionModel() {
+ return new MultiSelectionModel();
+ }
+
@Override
public void onUnregister() {
super.onUnregister();
diff --git a/client/src/main/java/com/vaadin/client/connectors/tree/TreeMultiSelectionModelConnector.java b/client/src/main/java/com/vaadin/client/connectors/tree/TreeMultiSelectionModelConnector.java
new file mode 100644
index 0000000000..bcb3a66faa
--- /dev/null
+++ b/client/src/main/java/com/vaadin/client/connectors/tree/TreeMultiSelectionModelConnector.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.connectors.tree;
+
+import com.vaadin.client.connectors.grid.MultiSelectionModelConnector;
+import com.vaadin.client.renderers.Renderer;
+import com.vaadin.client.widget.grid.selection.ClickSelectHandler;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.tree.TreeMultiSelectionModelState;
+import com.vaadin.ui.Tree.TreeMultiSelectionModel;
+
+import elemental.json.JsonObject;
+
+/**
+ * Connector for the server side multiselection model of the tree component.
+ * <p>
+ * Implementation detail: The selection is updated immediately on client side,
+ * without waiting for the server response.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ */
+@Connect(TreeMultiSelectionModel.class)
+public class TreeMultiSelectionModelConnector
+ extends MultiSelectionModelConnector {
+
+ private ClickSelectHandler<JsonObject> clickSelectHandler;
+
+ @Override
+ protected MultiSelectionModel createSelectionModel() {
+ return new MultiSelectionModel() {
+ @Override
+ public Renderer<Boolean> getRenderer() {
+ // Prevent selection column.
+ return null;
+ }
+ };
+ }
+
+ @Override
+ public TreeMultiSelectionModelState getState() {
+ return (TreeMultiSelectionModelState) super.getState();
+ }
+
+ @Override
+ protected void initSelectionModel() {
+ super.initSelectionModel();
+ clickSelectHandler = new ClickSelectHandler<>(getParent().getWidget());
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+ if (clickSelectHandler != null) {
+ clickSelectHandler.removeHandler();
+ }
+ }
+}
diff --git a/server/src/main/java/com/vaadin/ui/Tree.java b/server/src/main/java/com/vaadin/ui/Tree.java
index c89d0796bc..998c61cf18 100644
--- a/server/src/main/java/com/vaadin/ui/Tree.java
+++ b/server/src/main/java/com/vaadin/ui/Tree.java
@@ -43,8 +43,10 @@ import com.vaadin.server.Resource;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ContentMode;
import com.vaadin.shared.ui.grid.HeightMode;
+import com.vaadin.shared.ui.tree.TreeMultiSelectionModelState;
import com.vaadin.shared.ui.tree.TreeRendererState;
import com.vaadin.ui.Grid.SelectionMode;
+import com.vaadin.ui.components.grid.MultiSelectionModelImpl;
import com.vaadin.ui.renderers.AbstractRenderer;
import com.vaadin.util.ReflectTools;
@@ -190,6 +192,29 @@ public class Tree<T> extends Composite
}
}
+ /**
+ * Custom MultiSelectionModel for Tree. TreeMultiSelectionModel does not
+ * show selection column.
+ *
+ * @param <T>
+ * the tree item type
+ *
+ * @since 8.1
+ */
+ public final static class TreeMultiSelectionModel<T>
+ extends MultiSelectionModelImpl<T> {
+
+ @Override
+ protected TreeMultiSelectionModelState getState() {
+ return (TreeMultiSelectionModelState) super.getState();
+ }
+
+ @Override
+ protected TreeMultiSelectionModelState getState(boolean markAsDirty) {
+ return (TreeMultiSelectionModelState) super.getState(markAsDirty);
+ }
+ }
+
private TreeGrid<T> treeGrid = new TreeGrid<>();
private ItemCaptionGenerator<T> captionGenerator = String::valueOf;
private IconGenerator<T> iconProvider = t -> null;
@@ -551,7 +576,7 @@ public class Tree<T> extends Composite
/**
* Gets the item collapse allowed provider.
- *
+ *
* @return the item collapse allowed provider
*/
public ItemCollapseAllowedProvider<T> getItemCollapseAllowedProvider() {
@@ -560,7 +585,7 @@ public class Tree<T> extends Composite
/**
* Gets the style generator.
- *
+ *
* @see StyleGenerator
*
* @return the item style generator
@@ -582,6 +607,35 @@ public class Tree<T> extends Composite
}
/**
+ * Sets the tree's selection mode.
+ * <p>
+ * The built-in selection modes are:
+ * <ul>
+ * <li>{@link SelectionMode#SINGLE} <b>the default model</b></li>
+ * <li>{@link SelectionMode#MULTI}</li>
+ * <li>{@link SelectionMode#NONE} preventing selection</li>
+ * </ul>
+ *
+ * @param selectionMode
+ * the selection mode to switch to, not {@code null}
+ * @return the used selection model
+ *
+ * @see SelectionMode
+ */
+ public SelectionModel<T> setSelectionMode(SelectionMode selectionMode) {
+ Objects.requireNonNull(selectionMode,
+ "Can not set selection mode to null");
+ switch (selectionMode) {
+ case MULTI:
+ TreeMultiSelectionModel<T> model = new TreeMultiSelectionModel<>();
+ treeGrid.setSelectionModel(model);
+ return model;
+ default:
+ return treeGrid.setSelectionMode(selectionMode);
+ }
+ }
+
+ /**
* @deprecated This component's height is always set to be undefined.
* Calling this method will have no effect.
*/
diff --git a/shared/src/main/java/com/vaadin/shared/ui/tree/TreeMultiSelectionModelState.java b/shared/src/main/java/com/vaadin/shared/ui/tree/TreeMultiSelectionModelState.java
new file mode 100644
index 0000000000..dca676b5b2
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/tree/TreeMultiSelectionModelState.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.tree;
+
+import com.vaadin.shared.ui.grid.MultiSelectionModelState;
+
+/**
+ * State for TreeMultiSelectionModel.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ */
+public class TreeMultiSelectionModelState extends MultiSelectionModelState {
+}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/tree/TreeBasicFeatures.java b/uitest/src/main/java/com/vaadin/tests/components/tree/TreeBasicFeatures.java
index a579c98a12..9f69f3d760 100644
--- a/uitest/src/main/java/com/vaadin/tests/components/tree/TreeBasicFeatures.java
+++ b/uitest/src/main/java/com/vaadin/tests/components/tree/TreeBasicFeatures.java
@@ -21,6 +21,7 @@ import com.vaadin.ui.MenuBar.Command;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Tree;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Grid.SelectionMode;
@Theme("tests-valo-disabled-animations")
@Widgetset("com.vaadin.DefaultWidgetSet")
@@ -68,6 +69,7 @@ public class TreeBasicFeatures extends AbstractTestUIWithLog {
MenuItem componentMenu = menu.addItem("Component", null);
createIconMenu(componentMenu.addItem("Icons", null));
createCaptionMenu(componentMenu.addItem("Captions", null));
+ createSelectionModeMenu(componentMenu.addItem("Selection Mode", null));
componentMenu.addItem("Item Click Listener", new Command() {
private Registration registration;
@@ -108,6 +110,12 @@ public class TreeBasicFeatures extends AbstractTestUIWithLog {
return menu;
}
+ private void createSelectionModeMenu(MenuItem modeMenu) {
+ for (SelectionMode mode : SelectionMode.values()) {
+ modeMenu.addItem(mode.name(), item -> tree.setSelectionMode(mode));
+ }
+ }
+
private void createCaptionMenu(MenuItem captionMenu) {
captionMenu.addItem("String.valueOf",
menu -> tree.setItemCaptionGenerator(String::valueOf));
diff --git a/uitest/src/test/java/com/vaadin/tests/components/tree/TreeBasicFeaturesTest.java b/uitest/src/test/java/com/vaadin/tests/components/tree/TreeBasicFeaturesTest.java
index 8d95bf5ef6..bde38a963a 100644
--- a/uitest/src/test/java/com/vaadin/tests/components/tree/TreeBasicFeaturesTest.java
+++ b/uitest/src/test/java/com/vaadin/tests/components/tree/TreeBasicFeaturesTest.java
@@ -7,6 +7,8 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.interactions.Actions;
import com.vaadin.testbench.TestBenchElement;
import com.vaadin.testbench.elements.TreeElement;
@@ -164,4 +166,41 @@ public class TreeBasicFeaturesTest extends MultiBrowserTest {
Assert.assertEquals("Tree should prevent collapsing all nodes.",
"2 | 0", tree.getItem(2).getText());
}
+
+ @Test
+ public void tree_multiselect() {
+ selectMenuPath("Component", "Selection Mode", "MULTI");
+ TreeElement tree = $(TreeElement.class).first();
+ tree.getItem(0).click();
+ TreeGridElement wrap = tree.wrap(TreeGridElement.class);
+ Assert.assertFalse(
+ "Tree MultiSelection shouldn't have selection column",
+ wrap.getCell(0, 0).isElementPresent(By.tagName("input")));
+ Assert.assertTrue("First row was not selected",
+ wrap.getRow(0).isSelected());
+ new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN, Keys.SPACE)
+ .perform();
+ Assert.assertTrue("First row was deselected",
+ wrap.getRow(0).isSelected());
+ Assert.assertTrue("Second row was not selected",
+ wrap.getRow(1).isSelected());
+ }
+
+ @Test
+ public void tree_multiselect_click() {
+ selectMenuPath("Component", "Selection Mode", "MULTI");
+ TreeElement tree = $(TreeElement.class).first();
+ TreeGridElement wrap = tree.wrap(TreeGridElement.class);
+ tree.getItem(0).click();
+ Assert.assertTrue("First row was not selected",
+ wrap.getRow(0).isSelected());
+ tree.getItem(1).click();
+ Assert.assertTrue("First row was deselected",
+ wrap.getRow(0).isSelected());
+ Assert.assertTrue("Second row was not selected",
+ wrap.getRow(1).isSelected());
+ tree.getItem(0).click();
+ Assert.assertFalse("First row was not deselected",
+ wrap.getRow(0).isSelected());
+ }
}