aboutsummaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <teemusa@vaadin.com>2015-07-06 10:01:17 +0300
committerTeemu Suo-Anttila <teemusa@vaadin.com>2015-09-01 11:58:57 +0000
commit53a4b2c77a6af86c157884c62e6193911242a7f9 (patch)
tree033b8b64744abb3a8b63df52a748261b656247cd /server/src
parent9899aa2009d32e375ccd21e2edf50cb6d2d557bb (diff)
downloadvaadin-framework-53a4b2c77a6af86c157884c62e6193911242a7f9.tar.gz
vaadin-framework-53a4b2c77a6af86c157884c62e6193911242a7f9.zip
Refactor Grid SelectionModels as extensions (#18624)
This patch removes all selection related variables and API from several core parts of Grid. Change-Id: Idb7aa48fda69ded1ef58a69c1f7dbc78b7f52a54
Diffstat (limited to 'server/src')
-rw-r--r--server/src/com/vaadin/data/RpcDataProviderExtension.java25
-rw-r--r--server/src/com/vaadin/ui/Grid.java317
2 files changed, 171 insertions, 171 deletions
diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java
index f5d712f6b2..c8f3604fd9 100644
--- a/server/src/com/vaadin/data/RpcDataProviderExtension.java
+++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java
@@ -744,15 +744,11 @@ public class RpcDataProviderExtension extends AbstractExtension {
// Send current rows again if needed.
if (refreshCache) {
- for (Object itemId : activeItemHandler.getActiveItemIds()) {
- internalUpdateRowData(itemId);
- }
+ updatedItemIds.addAll(activeItemHandler.getActiveItemIds());
}
}
- for (Object itemId : updatedItemIds) {
- internalUpdateRowData(itemId);
- }
+ internalUpdateRows(updatedItemIds);
// Clear all changes.
rowChanges.clear();
@@ -913,11 +909,20 @@ public class RpcDataProviderExtension extends AbstractExtension {
updatedItemIds.add(itemId);
}
- private void internalUpdateRowData(Object itemId) {
- if (activeItemHandler.getActiveItemIds().contains(itemId)) {
- JsonObject row = getRowData(getGrid().getColumns(), itemId);
- rpc.updateRowData(row);
+ private void internalUpdateRows(Set<Object> itemIds) {
+ if (itemIds.isEmpty()) {
+ return;
+ }
+
+ JsonArray rowData = Json.createArray();
+ int i = 0;
+ for (Object itemId : itemIds) {
+ if (activeItemHandler.getActiveItemIds().contains(itemId)) {
+ JsonObject row = getRowData(getGrid().getColumns(), itemId);
+ rowData.set(i++, row);
+ }
}
+ rpc.updateRowData(rowData);
}
/**
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index d9c011677b..f58280c6fe 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -82,6 +82,7 @@ import com.vaadin.server.AbstractClientConnector;
import com.vaadin.server.AbstractExtension;
import com.vaadin.server.EncodeResult;
import com.vaadin.server.ErrorMessage;
+import com.vaadin.server.Extension;
import com.vaadin.server.JsonCodec;
import com.vaadin.server.KeyMapper;
import com.vaadin.server.VaadinSession;
@@ -94,13 +95,16 @@ import com.vaadin.shared.ui.grid.GridColumnState;
import com.vaadin.shared.ui.grid.GridConstants;
import com.vaadin.shared.ui.grid.GridServerRpc;
import com.vaadin.shared.ui.grid.GridState;
-import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode;
import com.vaadin.shared.ui.grid.GridStaticCellType;
import com.vaadin.shared.ui.grid.GridStaticSectionState;
import com.vaadin.shared.ui.grid.GridStaticSectionState.CellState;
import com.vaadin.shared.ui.grid.GridStaticSectionState.RowState;
import com.vaadin.shared.ui.grid.HeightMode;
import com.vaadin.shared.ui.grid.ScrollDestination;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelServerRpc;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelState;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelServerRpc;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelState;
import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
@@ -111,7 +115,6 @@ import com.vaadin.ui.renderers.TextRenderer;
import com.vaadin.util.ReflectTools;
import elemental.json.Json;
-import elemental.json.JsonArray;
import elemental.json.JsonObject;
import elemental.json.JsonValue;
@@ -710,8 +713,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
/**
* The server-side interface that controls Grid's selection state.
+ * SelectionModel should extend {@link AbstractGridExtension}.
*/
- public interface SelectionModel extends Serializable {
+ public interface SelectionModel extends Serializable, Extension {
/**
* Checks whether an item is selected or not.
*
@@ -730,6 +734,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
/**
* Injects the current {@link Grid} instance into the SelectionModel.
+ * This method should usually call the extend method of
+ * {@link AbstractExtension}.
* <p>
* <em>Note:</em> This method should not be called manually.
*
@@ -971,10 +977,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
* A base class for SelectionModels that contains some of the logic that is
* reusable.
*/
- public static abstract class AbstractSelectionModel implements
- SelectionModel {
+ public static abstract class AbstractSelectionModel extends
+ AbstractGridExtension implements SelectionModel, DataGenerator {
protected final LinkedHashSet<Object> selection = new LinkedHashSet<Object>();
- protected Grid grid = null;
@Override
public boolean isSelected(final Object itemId) {
@@ -988,7 +993,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
@Override
public void setGrid(final Grid grid) {
- this.grid = grid;
+ if (grid != null) {
+ extend(grid);
+ }
}
/**
@@ -1002,7 +1009,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
*/
protected void checkItemIdExists(Object itemId)
throws IllegalArgumentException {
- if (!grid.getContainerDataSource().containsId(itemId)) {
+ if (!getParentGrid().getContainerDataSource().containsId(itemId)) {
throw new IllegalArgumentException("Given item id (" + itemId
+ ") does not exist in the container");
}
@@ -1044,7 +1051,19 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
protected void fireSelectionEvent(
final Collection<Object> oldSelection,
final Collection<Object> newSelection) {
- grid.fireSelectionEvent(oldSelection, newSelection);
+ getParentGrid().fireSelectionEvent(oldSelection, newSelection);
+ }
+
+ @Override
+ public void generateData(Object itemId, Item item, JsonObject rowData) {
+ if (isSelected(itemId)) {
+ rowData.put(GridState.JSONKEY_SELECTED, true);
+ }
+ }
+
+ @Override
+ protected Object getItemId(String rowKey) {
+ return rowKey != null ? super.getItemId(rowKey) : null;
}
}
@@ -1053,8 +1072,25 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
*/
public static class SingleSelectionModel extends AbstractSelectionModel
implements SelectionModel.Single {
+
+ @Override
+ protected void extend(AbstractClientConnector target) {
+ super.extend(target);
+ registerRpc(new SingleSelectionModelServerRpc() {
+
+ @Override
+ public void select(String rowKey) {
+ SingleSelectionModel.this.select(getItemId(rowKey), false);
+ }
+ });
+ }
+
@Override
public boolean select(final Object itemId) {
+ return select(itemId, true);
+ }
+
+ protected boolean select(final Object itemId, boolean refresh) {
if (itemId == null) {
return deselect(getSelectedRow());
}
@@ -1066,7 +1102,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
if (modified) {
final Collection<Object> deselected;
if (selectedRow != null) {
- deselectInternal(selectedRow, false);
+ deselectInternal(selectedRow, false, true);
deselected = Collections.singleton(selectedRow);
} else {
deselected = Collections.emptySet();
@@ -1075,19 +1111,28 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
fireSelectionEvent(deselected, selection);
}
+ if (refresh) {
+ refreshRow(itemId);
+ }
+
return modified;
}
private boolean deselect(final Object itemId) {
- return deselectInternal(itemId, true);
+ return deselectInternal(itemId, true, true);
}
private boolean deselectInternal(final Object itemId,
- boolean fireEventIfNeeded) {
+ boolean fireEventIfNeeded, boolean refresh) {
final boolean modified = selection.remove(itemId);
- if (fireEventIfNeeded && modified) {
- fireSelectionEvent(Collections.singleton(itemId),
- Collections.emptySet());
+ if (modified) {
+ if (refresh) {
+ refreshRow(itemId);
+ }
+ if (fireEventIfNeeded) {
+ fireSelectionEvent(Collections.singleton(itemId),
+ Collections.emptySet());
+ }
}
return modified;
}
@@ -1113,23 +1158,25 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
@Override
public void setDeselectAllowed(boolean deselectAllowed) {
- grid.getState().singleSelectDeselectAllowed = deselectAllowed;
+ getState().deselectAllowed = deselectAllowed;
}
@Override
public boolean isDeselectAllowed() {
- return grid.getState(false).singleSelectDeselectAllowed;
+ return getState().deselectAllowed;
+ }
+
+ @Override
+ protected SingleSelectionModelState getState() {
+ return (SingleSelectionModelState) super.getState();
}
}
/**
* A default implementation for a {@link SelectionModel.None}
*/
- public static class NoSelectionModel implements SelectionModel.None {
- @Override
- public void setGrid(final Grid grid) {
- // NOOP, not needed for anything
- }
+ public static class NoSelectionModel extends AbstractSelectionModel
+ implements SelectionModel.None {
@Override
public boolean isSelected(final Object itemId) {
@@ -1167,7 +1214,40 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
private int selectionLimit = DEFAULT_MAX_SELECTIONS;
- private boolean allSelected;
+ @Override
+ protected void extend(AbstractClientConnector target) {
+ super.extend(target);
+ registerRpc(new MultiSelectionModelServerRpc() {
+
+ @Override
+ public void select(List<String> rowKeys) {
+ List<Object> items = new ArrayList<Object>();
+ for (String rowKey : rowKeys) {
+ items.add(getItemId(rowKey));
+ }
+ MultiSelectionModel.this.select(items, false);
+ }
+
+ @Override
+ public void deselect(List<String> rowKeys) {
+ List<Object> items = new ArrayList<Object>();
+ for (String rowKey : rowKeys) {
+ items.add(getItemId(rowKey));
+ }
+ MultiSelectionModel.this.deselect(items, false);
+ }
+
+ @Override
+ public void selectAll() {
+ MultiSelectionModel.this.selectAll(false);
+ }
+
+ @Override
+ public void deselectAll() {
+ MultiSelectionModel.this.deselectAll(false);
+ }
+ });
+ }
@Override
public boolean select(final Object... itemIds)
@@ -1190,6 +1270,10 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
@Override
public boolean select(final Collection<?> itemIds)
throws IllegalArgumentException {
+ return select(itemIds, true);
+ }
+
+ protected boolean select(final Collection<?> itemIds, boolean refresh) {
if (itemIds == null) {
throw new IllegalArgumentException("itemIds may not be null");
}
@@ -1217,6 +1301,12 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
updateAllSelectedState();
+ if (refresh) {
+ for (Object itemId : itemIds) {
+ refreshRow(itemId);
+ }
+ }
+
return selectionWillChange;
}
@@ -1270,6 +1360,10 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
@Override
public boolean deselect(final Collection<?> itemIds)
throws IllegalArgumentException {
+ return deselect(itemIds, true);
+ }
+
+ protected boolean deselect(final Collection<?> itemIds, boolean refresh) {
if (itemIds == null) {
throw new IllegalArgumentException("itemIds may not be null");
}
@@ -1285,15 +1379,25 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
updateAllSelectedState();
+ if (refresh) {
+ for (Object itemId : itemIds) {
+ refreshRow(itemId);
+ }
+ }
+
return hasCommonElements;
}
@Override
public boolean selectAll() {
+ return selectAll(true);
+ }
+
+ protected boolean selectAll(boolean refresh) {
// select will fire the event
- final Indexed container = grid.getContainerDataSource();
+ final Indexed container = getParentGrid().getContainerDataSource();
if (container != null) {
- return select(container.getItemIds());
+ return select(container.getItemIds(), refresh);
} else if (selection.isEmpty()) {
return false;
} else {
@@ -1302,14 +1406,18 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
* but I guess the only theoretically correct course of
* action...
*/
- return deselectAll();
+ return deselectAll(false);
}
}
@Override
public boolean deselectAll() {
+ return deselectAll(true);
+ }
+
+ protected boolean deselectAll(boolean refresh) {
// deselect will fire the event
- return deselect(getSelectedRows());
+ return deselect(getSelectedRows(), refresh);
}
/**
@@ -1382,11 +1490,15 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
}
private void updateAllSelectedState() {
- if (allSelected != selection.size() >= selectionLimit) {
- allSelected = selection.size() >= selectionLimit;
- grid.getRpcProxy(GridClientRpc.class).setSelectAll(allSelected);
+ if (getState().allSelected != selection.size() >= selectionLimit) {
+ getState().allSelected = selection.size() >= selectionLimit;
}
}
+
+ @Override
+ protected MultiSelectionModelState getState() {
+ return (MultiSelectionModelState) super.getState();
+ }
}
/**
@@ -1571,7 +1683,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
* Grid rows. If a description is generated for a row, it is used for all
* the cells in the row for which a {@link CellDescriptionGenerator cell
* description} is not generated.
- *
+ *
* @see Grid#setRowDescriptionGenerator(CellDescriptionGenerator)
*
* @since 7.6
@@ -3783,6 +3895,17 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
+ " instead");
}
}
+
+ /**
+ * Resends the row data for given item id to the client.
+ *
+ * @since
+ * @param itemId
+ * row to refresh
+ */
+ protected void refreshRow(Object itemId) {
+ getParentGrid().datasourceExtension.updateRowData(itemId);
+ }
}
/**
@@ -3982,117 +4105,10 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
*/
private void initGrid() {
setSelectionMode(getDefaultSelectionMode());
- addSelectionListener(new SelectionListener() {
- @Override
- public void select(SelectionEvent event) {
- if (applyingSelectionFromClient) {
- /*
- * Avoid sending changes back to the client if they
- * originated from the client. Instead, the RPC handler is
- * responsible for keeping track of the resulting selection
- * state and notifying the client if it doens't match the
- * expectation.
- */
- return;
- }
-
- /*
- * The rows are pinned here to ensure that the client gets the
- * correct key from server when the selected row is first
- * loaded.
- *
- * Once the client has gotten info that it is supposed to select
- * a row, it will pin the data from the client side as well and
- * it will be unpinned once it gets deselected. Nothing on the
- * server side should ever unpin anything from KeyMapper.
- * Pinning is mostly a client feature and is only used when
- * selecting something from the server side.
- */
- for (Object addedItemId : event.getAdded()) {
- if (!getKeyMapper().isPinned(addedItemId)) {
- getKeyMapper().pin(addedItemId);
- }
- }
-
- getState().selectedKeys = getKeyMapper().getKeys(
- getSelectedRows());
- }
- });
registerRpc(new GridServerRpc() {
@Override
- public void select(List<String> selection) {
- Collection<Object> receivedSelection = getKeyMapper()
- .getItemIds(selection);
-
- applyingSelectionFromClient = true;
- try {
- SelectionModel selectionModel = getSelectionModel();
- if (selectionModel instanceof SelectionModel.Single
- && selection.size() <= 1) {
- Object select = null;
- if (selection.size() == 1) {
- select = getKeyMapper().getItemId(selection.get(0));
- }
- ((SelectionModel.Single) selectionModel).select(select);
- } else if (selectionModel instanceof SelectionModel.Multi) {
- ((SelectionModel.Multi) selectionModel)
- .setSelected(receivedSelection);
- } else {
- throw new IllegalStateException("SelectionModel "
- + selectionModel.getClass().getSimpleName()
- + " does not support selecting the given "
- + selection.size() + " items.");
- }
- } finally {
- applyingSelectionFromClient = false;
- }
-
- Collection<Object> actualSelection = getSelectedRows();
-
- // Make sure all selected rows are pinned
- for (Object itemId : actualSelection) {
- if (!getKeyMapper().isPinned(itemId)) {
- getKeyMapper().pin(itemId);
- }
- }
-
- // Don't mark as dirty since this might be the expected state
- getState(false).selectedKeys = getKeyMapper().getKeys(
- actualSelection);
-
- JsonObject diffState = getUI().getConnectorTracker()
- .getDiffState(Grid.this);
-
- final String diffstateKey = "selectedKeys";
-
- assert diffState.hasKey(diffstateKey) : "Field name has changed";
-
- if (receivedSelection.equals(actualSelection)) {
- /*
- * We ended up with the same selection state that the client
- * sent us. There's nothing to send back to the client, just
- * update the diffstate so subsequent changes will be
- * detected.
- */
- JsonArray diffSelected = Json.createArray();
- for (String rowKey : getState(false).selectedKeys) {
- diffSelected.set(diffSelected.length(), rowKey);
- }
- diffState.put(diffstateKey, diffSelected);
- } else {
- /*
- * Actual selection is not what the client expects. Make
- * sure the client gets a state change event by clearing the
- * diffstate and marking as dirty
- */
- diffState.remove(diffstateKey);
- markAsDirty();
- }
- }
-
- @Override
public void sort(String[] columnIds, SortDirection[] directions,
boolean userOriginated) {
assert columnIds.length == directions.length;
@@ -4121,13 +4137,6 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
}
@Override
- public void selectAll() {
- assert getSelectionModel() instanceof SelectionModel.Multi : "Not a multi selection model!";
-
- ((SelectionModel.Multi) getSelectionModel()).selectAll();
- }
-
- @Override
public void itemClick(String rowKey, String columnId,
MouseEventDetails details) {
Object itemId = getKeyMapper().getItemId(rowKey);
@@ -5019,25 +5028,11 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
if (this.selectionModel != selectionModel) {
// this.selectionModel is null on init
if (this.selectionModel != null) {
- this.selectionModel.reset();
- this.selectionModel.setGrid(null);
+ this.selectionModel.remove();
}
this.selectionModel = selectionModel;
- this.selectionModel.setGrid(this);
- this.selectionModel.reset();
-
- if (selectionModel.getClass().equals(SingleSelectionModel.class)) {
- getState().selectionMode = SharedSelectionMode.SINGLE;
- } else if (selectionModel.getClass().equals(
- MultiSelectionModel.class)) {
- getState().selectionMode = SharedSelectionMode.MULTI;
- } else if (selectionModel.getClass().equals(NoSelectionModel.class)) {
- getState().selectionMode = SharedSelectionMode.NONE;
- } else {
- throw new UnsupportedOperationException("Grid currently "
- + "supports only its own bundled selection models");
- }
+ selectionModel.setGrid(this);
}
}