summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorHenrik Paul <henrik@vaadin.com>2014-06-30 18:18:32 +0300
committerLeif Åstrand <leif@vaadin.com>2014-07-04 13:45:32 +0000
commit6653224d8defe79ecb8749eab96adccd626c76bf (patch)
treeacc3311fad73dcdc2f602e366ad007f2e8962cd6 /client
parente845b4128a0ddf5b488f5c5cf5e0ea33c5b393dc (diff)
downloadvaadin-framework-6653224d8defe79ecb8749eab96adccd626c76bf.tar.gz
vaadin-framework-6653224d8defe79ecb8749eab96adccd626c76bf.zip
Adds the ability to swap between the three client side selection models (#13334)
So, this means when the selection model is modified on the server side, the client side changes accordingly. Change-Id: I3c7e3802cecdf9dfd64f5296c48fca5dfc58787d
Diffstat (limited to 'client')
-rw-r--r--client/src/com/vaadin/client/ui/grid/Grid.java6
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridConnector.java157
-rw-r--r--client/src/com/vaadin/client/ui/grid/selection/AbstractRowHandleSelectionModel.java65
-rw-r--r--client/src/com/vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java12
-rw-r--r--client/src/com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java10
-rw-r--r--client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java5
-rw-r--r--client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java22
-rw-r--r--client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java22
8 files changed, 240 insertions, 59 deletions
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java
index da5adfc34a..4bd07f1909 100644
--- a/client/src/com/vaadin/client/ui/grid/Grid.java
+++ b/client/src/com/vaadin/client/ui/grid/Grid.java
@@ -1077,10 +1077,10 @@ public class Grid<T> extends Composite implements
// Default action on SelectionChangeEvents. Refresh the body so changed
// become visible.
- addSelectionChangeHandler(new SelectionChangeHandler() {
+ addSelectionChangeHandler(new SelectionChangeHandler<T>() {
@Override
- public void onSelectionChange(SelectionChangeEvent<?> event) {
+ public void onSelectionChange(SelectionChangeEvent<T> event) {
refreshBody();
}
});
@@ -2370,7 +2370,7 @@ public class Grid<T> extends Composite implements
@Override
public HandlerRegistration addSelectionChangeHandler(
- final SelectionChangeHandler handler) {
+ final SelectionChangeHandler<T> handler) {
return addHandler(handler, SelectionChangeEvent.getType());
}
diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java
index ee1cc0ee75..daf938a784 100644
--- a/client/src/com/vaadin/client/ui/grid/GridConnector.java
+++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java
@@ -32,12 +32,16 @@ import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONValue;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.communication.StateChangeEvent;
+import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector;
+import com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel;
import com.vaadin.client.ui.grid.selection.SelectionChangeEvent;
import com.vaadin.client.ui.grid.selection.SelectionChangeHandler;
import com.vaadin.client.ui.grid.selection.SelectionModelMulti;
+import com.vaadin.client.ui.grid.selection.SelectionModelNone;
+import com.vaadin.client.ui.grid.selection.SelectionModelSingle;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.ColumnGroupRowState;
import com.vaadin.shared.ui.grid.ColumnGroupState;
@@ -62,39 +66,78 @@ import com.vaadin.shared.ui.grid.ScrollDestination;
@Connect(com.vaadin.ui.components.grid.Grid.class)
public class GridConnector extends AbstractComponentConnector {
- /**
- * Hacked SelectionModelMulti to make selection communication work for now.
+ /*
+ * TODO: henrik paul (4.7.2014)
+ *
+ * This class should optimally not be needed. We should be able to use the
+ * keys in the state as the primary source of selection, and "simply" diff
+ * things once the state changes (we can't rebuild the selection pins from
+ * scratch, since we might lose some data that's currently out of view).
+ *
+ * I was unable to remove this class with little effort, so it may remain as
+ * a todo for now.
*/
- private class RowKeyBasedMultiSelection extends
- SelectionModelMulti<JSONObject> {
+ private class RowKeyHelper {
+ private LinkedHashSet<String> selectedKeys = new LinkedHashSet<String>();
+
+ public LinkedHashSet<String> getSelectedKeys() {
+ return selectedKeys;
+ }
+
+ public void add(Collection<JSONObject> rows) {
+ for (JSONObject row : rows) {
+ add(row);
+ }
+ }
- private final LinkedHashSet<String> selectedKeys = new LinkedHashSet<String>();
+ private void add(JSONObject row) {
+ selectedKeys.add((String) dataSource.getRowKey(row));
+ }
- public List<String> getSelectedKeys() {
- List<String> keys = new ArrayList<String>();
- keys.addAll(selectedKeys);
- return keys;
+ public void remove(Collection<JSONObject> rows) {
+ for (JSONObject row : rows) {
+ remove(row);
+ }
+ }
+
+ private void remove(JSONObject row) {
+ selectedKeys.remove(dataSource.getRowKey(row));
}
public void updateFromState() {
boolean changed = false;
- Set<String> stateKeys = new LinkedHashSet<String>();
- stateKeys.addAll(getState().selectedKeys);
+
+ List<String> stateKeys = getState().selectedKeys;
+
+ // find new selections
for (String key : stateKeys) {
if (!selectedKeys.contains(key)) {
changed = true;
selectByHandle(dataSource.getHandleByKey(key));
}
}
+
+ // find new deselections
for (String key : selectedKeys) {
changed = true;
if (!stateKeys.contains(key)) {
deselectByHandle(dataSource.getHandleByKey(key));
}
}
- selectedKeys.clear();
- selectedKeys.addAll(stateKeys);
+ /*
+ * A defensive copy in case the collection in the state is mutated
+ * instead of re-assigned.
+ */
+ selectedKeys = new LinkedHashSet<String>(stateKeys);
+
+ /*
+ * We need to fire this event so that Grid is able to re-render the
+ * selection changes (if applicable).
+ *
+ * add/remove methods will be called from the
+ * internalSelectionChangeHandler, so they shouldn't be called here.
+ */
if (changed) {
// At least for now there's no way to send the selected and/or
// deselected row data. Some data is only stored as keys
@@ -103,22 +146,6 @@ public class GridConnector extends AbstractComponentConnector {
(List<JSONObject>) null, null));
}
}
-
- @Override
- public boolean select(Collection<JSONObject> rows) {
- for (JSONObject row : rows) {
- selectedKeys.add((String) dataSource.getRowKey(row));
- }
- return super.select(rows);
- }
-
- @Override
- public boolean deselect(Collection<JSONObject> rows) {
- for (JSONObject row : rows) {
- selectedKeys.remove(dataSource.getRowKey(row));
- }
- return super.deselect(rows);
- }
}
/**
@@ -176,9 +203,24 @@ public class GridConnector extends AbstractComponentConnector {
* Maps a generated column id to a grid column instance
*/
private Map<String, CustomGridColumn> columnIdToColumn = new HashMap<String, CustomGridColumn>();
- private final RowKeyBasedMultiSelection selectionModel = new RowKeyBasedMultiSelection();
+ private AbstractRowHandleSelectionModel<JSONObject> selectionModel = new SelectionModelMulti<JSONObject>();
private RpcDataSource dataSource;
+ private final RowKeyHelper rowKeyHelper = new RowKeyHelper();
+
+ private SelectionChangeHandler<JSONObject> internalSelectionChangeHandler = new SelectionChangeHandler<JSONObject>() {
+ @Override
+ public void onSelectionChange(SelectionChangeEvent<JSONObject> event) {
+ rowKeyHelper.remove(event.getRemoved());
+ rowKeyHelper.add(event.getAdded());
+
+ // TODO change this to diff based. (henrik paul 24.6.2014)
+ List<String> selectedKeys = new ArrayList<String>(
+ rowKeyHelper.getSelectedKeys());
+ getRpcProxy(GridServerRpc.class).selectionChange(selectedKeys);
+ }
+ };
+
@Override
@SuppressWarnings("unchecked")
public Grid<JSONObject> getWidget() {
@@ -213,14 +255,7 @@ public class GridConnector extends AbstractComponentConnector {
getWidget().setSelectionModel(selectionModel);
- getWidget().addSelectionChangeHandler(new SelectionChangeHandler() {
- @Override
- public void onSelectionChange(SelectionChangeEvent<?> event) {
- // TODO change this to diff based. (henrik paul 24.6.2014)
- getRpcProxy(GridServerRpc.class).selectionChange(
- selectionModel.getSelectedKeys());
- }
- });
+ getWidget().addSelectionChangeHandler(internalSelectionChangeHandler);
}
@@ -285,7 +320,7 @@ public class GridConnector extends AbstractComponentConnector {
}
if (stateChangeEvent.hasPropertyChanged("selectedKeys")) {
- selectionModel.updateFromState();
+ rowKeyHelper.updateFromState();
}
}
@@ -452,13 +487,53 @@ public class GridConnector extends AbstractComponentConnector {
private void onSelectionModeChange() {
SharedSelectionMode mode = getState().selectionMode;
if (mode == null) {
- getLogger().warning("ignored mode change");
+ getLogger().fine("ignored mode change");
return;
}
- getLogger().warning(mode.toString());
+
+ AbstractRowHandleSelectionModel<JSONObject> model = createSelectionModel(mode);
+ if (!model.getClass().equals(selectionModel.getClass())) {
+ selectionModel = model;
+ getWidget().setSelectionModel(model);
+ }
}
private Logger getLogger() {
return Logger.getLogger(getClass().getName());
}
+
+ @SuppressWarnings("static-method")
+ private AbstractRowHandleSelectionModel<JSONObject> createSelectionModel(
+ SharedSelectionMode mode) {
+ switch (mode) {
+ case SINGLE:
+ return new SelectionModelSingle<JSONObject>();
+ case MULTI:
+ return new SelectionModelMulti<JSONObject>();
+ case NONE:
+ return new SelectionModelNone<JSONObject>();
+ default:
+ throw new IllegalStateException("unexpected mode value: " + mode);
+ }
+ }
+
+ /**
+ * A workaround method for accessing the protected method
+ * {@code AbstractRowHandleSelectionModel.selectByHandle}
+ */
+ private native void selectByHandle(RowHandle<JSONObject> handle)
+ /*-{
+ var model = this.@com.vaadin.client.ui.grid.GridConnector::selectionModel;
+ model.@com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel::selectByHandle(*)(handle);
+ }-*/;
+
+ /**
+ * A workaround method for accessing the protected method
+ * {@code AbstractRowHandleSelectionModel.deselectByHandle}
+ */
+ private native void deselectByHandle(RowHandle<JSONObject> handle)
+ /*-{
+ var model = this.@com.vaadin.client.ui.grid.GridConnector::selectionModel;
+ model.@com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel::deselectByHandle(*)(handle);
+ }-*/;
}
diff --git a/client/src/com/vaadin/client/ui/grid/selection/AbstractRowHandleSelectionModel.java b/client/src/com/vaadin/client/ui/grid/selection/AbstractRowHandleSelectionModel.java
new file mode 100644
index 0000000000..f55229d86c
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/grid/selection/AbstractRowHandleSelectionModel.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2014 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.ui.grid.selection;
+
+import com.vaadin.client.data.DataSource.RowHandle;
+
+/**
+ * An abstract class that adds a consistent API for common methods that's needed
+ * by Vaadin's server-based selection models to work.
+ * <p>
+ * <em>Note:</em> This should be an interface instead of an abstract class, if
+ * only we could define protected methods in an interface.
+ *
+ * @author Vaadin Ltd
+ * @param <T>
+ * The grid's row type
+ */
+public abstract class AbstractRowHandleSelectionModel<T> implements
+ SelectionModel<T> {
+ /**
+ * Select a row, based on its
+ * {@link com.vaadin.client.data.DataSource.RowHandle RowHandle}.
+ * <p>
+ * <em>Note:</em> this method may not fire selection change events.
+ *
+ * @param handle
+ * the handle to select by
+ * @return <code>true</code> iff the selection state was changed by this
+ * call
+ * @throws UnsupportedOperationException
+ * if the selection model does not support either handles or
+ * selection
+ */
+ protected abstract boolean selectByHandle(RowHandle<T> handle);
+
+ /**
+ * Deselect a row, based on its
+ * {@link com.vaadin.client.data.DataSource.RowHandle RowHandle}.
+ * <p>
+ * <em>Note:</em> this method may not fire selection change events.
+ *
+ * @param handle
+ * the handle to deselect by
+ * @return <code>true</code> iff the selection state was changed by this
+ * call
+ * @throws UnsupportedOperationException
+ * if the selection model does not support either handles or
+ * deselection
+ */
+ protected abstract boolean deselectByHandle(RowHandle<T> handle)
+ throws UnsupportedOperationException;
+}
diff --git a/client/src/com/vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java b/client/src/com/vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java
index 78b6f098d9..c531265590 100644
--- a/client/src/com/vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java
+++ b/client/src/com/vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java
@@ -16,11 +16,10 @@
package com.vaadin.client.ui.grid.selection;
import com.google.gwt.event.shared.HandlerRegistration;
-import com.vaadin.client.ui.grid.Grid.SelectionMode;
/**
* Marker interface for widgets that fires selection change events.
- *
+ *
* @author Vaadin Ltd
* @since 7.4
*/
@@ -29,15 +28,16 @@ public interface HasSelectionChangeHandlers<T> {
/**
* Register a selection change handler.
* <p>
- * This handler is called whenever a {@link SelectionMode} detects a change
- * in selection state.
- *
+ * This handler is called whenever a
+ * {@link com.vaadin.ui.components.grid.selection.SelectionModel
+ * SelectionModel} detects a change in selection state.
+ *
* @param handler
* a {@link SelectionChangeHandler}
* @return a handler registration object, which can be used to remove the
* handler.
*/
public HandlerRegistration addSelectionChangeHandler(
- SelectionChangeHandler handler);
+ SelectionChangeHandler<T> handler);
}
diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java
index e5d15386c0..aa61bdecdf 100644
--- a/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java
+++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java
@@ -19,19 +19,21 @@ import com.google.gwt.event.shared.EventHandler;
/**
* Handler for {@link SelectionChangeEvent}s.
- *
+ *
* @since 7.4
* @author Vaadin Ltd
+ * @param <T>
+ * The row data type
*/
-public interface SelectionChangeHandler extends EventHandler {
+public interface SelectionChangeHandler<T> extends EventHandler {
/**
* Called when a selection model's selection state is changed.
- *
+ *
* @param event
* a selection change event, containing info about rows that have
* been added to or removed from the selection.
*/
- public void onSelectionChange(SelectionChangeEvent<?> event);
+ public void onSelectionChange(SelectionChangeEvent<T> event);
}
diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java
index de62dc9cbc..6ebd7f4044 100644
--- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java
+++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java
@@ -30,7 +30,8 @@ import com.vaadin.client.ui.grid.Renderer;
* @author Vaadin Ltd
* @since 7.4
*/
-public class SelectionModelMulti<T> implements SelectionModel.Multi<T> {
+public class SelectionModelMulti<T> extends AbstractRowHandleSelectionModel<T>
+ implements SelectionModel.Multi<T> {
private final Set<RowHandle<T>> selectedRows;
private Renderer<Boolean> renderer;
@@ -147,6 +148,7 @@ public class SelectionModelMulti<T> implements SelectionModel.Multi<T> {
return selectedRows.contains(handle);
}
+ @Override
protected boolean selectByHandle(RowHandle<T> handle) {
if (selectedRows.add(handle)) {
handle.pin();
@@ -155,6 +157,7 @@ public class SelectionModelMulti<T> implements SelectionModel.Multi<T> {
return false;
}
+ @Override
protected boolean deselectByHandle(RowHandle<T> handle) {
if (selectedRows.remove(handle)) {
handle.unpin();
diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java
index 93dfb49df2..59bf248032 100644
--- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java
+++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java
@@ -18,6 +18,7 @@ package com.vaadin.client.ui.grid.selection;
import java.util.Collection;
import java.util.Collections;
+import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.ui.grid.Grid;
import com.vaadin.client.ui.grid.Renderer;
@@ -27,7 +28,8 @@ import com.vaadin.client.ui.grid.Renderer;
* @author Vaadin Ltd
* @since 7.4
*/
-public class SelectionModelNone<T> implements SelectionModel.None<T> {
+public class SelectionModelNone<T> extends AbstractRowHandleSelectionModel<T>
+ implements SelectionModel.None<T> {
@Override
public boolean isSelected(T row) {
@@ -41,12 +43,12 @@ public class SelectionModelNone<T> implements SelectionModel.None<T> {
@Override
public void setGrid(Grid<T> grid) {
-
+ // noop
}
@Override
public void reset() {
-
+ // noop
}
@Override
@@ -54,4 +56,18 @@ public class SelectionModelNone<T> implements SelectionModel.None<T> {
return Collections.emptySet();
}
+ @Override
+ protected boolean selectByHandle(RowHandle<T> handle)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("This selection model "
+ + "does not support selection");
+ }
+
+ @Override
+ protected boolean deselectByHandle(RowHandle<T> handle)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("This selection model "
+ + "does not support deselection");
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java
index 775e1878c5..4ef792f1c7 100644
--- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java
+++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java
@@ -28,7 +28,8 @@ import com.vaadin.client.ui.grid.Renderer;
* @author Vaadin Ltd
* @since 7.4
*/
-public class SelectionModelSingle<T> implements SelectionModel.Single<T> {
+public class SelectionModelSingle<T> extends AbstractRowHandleSelectionModel<T>
+ implements SelectionModel.Single<T> {
private Grid<T> grid;
private RowHandle<T> selectedRow;
@@ -123,4 +124,23 @@ public class SelectionModelSingle<T> implements SelectionModel.Single<T> {
return Collections.emptySet();
}
+ @Override
+ protected boolean selectByHandle(RowHandle<T> handle) {
+ if (!handle.equals(selectedRow)) {
+ selectedRow = handle;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected boolean deselectByHandle(RowHandle<T> handle) {
+ if (handle.equals(selectedRow)) {
+ selectedRow = null;
+ return true;
+ } else {
+ return false;
+ }
+ }
}