summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <teemusa@vaadin.com>2016-08-24 14:05:02 +0300
committerVaadin Code Review <review@vaadin.com>2016-08-29 08:56:56 +0000
commitb4861eda6bbda053277e3fb6858b8a94e8c3243b (patch)
tree5b120ff177526702a4586eeb4afdd46aef341ea1 /client
parent010954022ddf6d0bcac3df9a098ce67603d3322b (diff)
downloadvaadin-framework-b4861eda6bbda053277e3fb6858b8a94e8c3243b.tar.gz
vaadin-framework-b4861eda6bbda053277e3fb6858b8a94e8c3243b.zip
Implement DetailsGenerators for Grid
Change-Id: I09057b990f10bde6cf72a16677e58cb2bc9a7029
Diffstat (limited to 'client')
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/DetailsManagerConnector.java216
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java40
2 files changed, 255 insertions, 1 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/DetailsManagerConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/DetailsManagerConnector.java
new file mode 100644
index 0000000000..28b42f2721
--- /dev/null
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/DetailsManagerConnector.java
@@ -0,0 +1,216 @@
+/*
+ * 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.grid;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ConnectorMap;
+import com.vaadin.client.LayoutManager;
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.data.DataChangeHandler;
+import com.vaadin.client.extensions.AbstractExtensionConnector;
+import com.vaadin.client.widget.grid.HeightAwareDetailsGenerator;
+import com.vaadin.client.widgets.Grid;
+import com.vaadin.shared.Registration;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.grid.GridState;
+import com.vaadin.ui.Grid.DetailsManager;
+
+import elemental.json.JsonObject;
+
+/**
+ * Connector class for {@link DetailsManager} of the Grid component.
+ *
+ * @author Vaadin Ltd
+ * @since
+ */
+@Connect(DetailsManager.class)
+public class DetailsManagerConnector extends AbstractExtensionConnector {
+
+ /* Map for tracking which details are open on which row */
+ private Map<Integer, String> indexToDetailConnectorId = new HashMap<>();
+ /* Boolean flag to avoid multiple refreshes */
+ private boolean refreshing;
+ /* Registration for data change handler. */
+ private Registration dataChangeRegistration;
+
+ /**
+ * DataChangeHandler for updating the visibility of detail widgets.
+ */
+ private final class DetailsChangeHandler implements DataChangeHandler {
+ @Override
+ public void resetDataAndSize(int estimatedNewDataSize) {
+ // Full clean up
+ indexToDetailConnectorId.clear();
+ }
+
+ @Override
+ public void dataUpdated(int firstRowIndex, int numberOfRows) {
+ for (int i = 0; i < numberOfRows; ++i) {
+ int index = firstRowIndex + i;
+ detachIfNeeded(index, getDetailsComponentConnectorId(index));
+ }
+ // Deferred opening of new ones.
+ refreshDetails();
+ }
+
+ /* The remaining methods will do a full refresh for now */
+
+ @Override
+ public void dataRemoved(int firstRowIndex, int numberOfRows) {
+ refreshDetails();
+ }
+
+ @Override
+ public void dataAvailable(int firstRowIndex, int numberOfRows) {
+ refreshDetails();
+ }
+
+ @Override
+ public void dataAdded(int firstRowIndex, int numberOfRows) {
+ refreshDetails();
+ }
+ }
+
+ /**
+ * Height aware details generator for client-side Grid.
+ */
+ private class CustomDetailsGenerator
+ implements HeightAwareDetailsGenerator {
+
+ @Override
+ public Widget getDetails(int rowIndex) {
+ String id = getDetailsComponentConnectorId(rowIndex);
+ if (id == null) {
+ return null;
+ }
+
+ return getConnector(id).getWidget();
+ }
+
+ @Override
+ public double getDetailsHeight(int rowIndex) {
+ // Case of null is handled in the getDetails method and this method
+ // will not called if it returns null.
+ String id = getDetailsComponentConnectorId(rowIndex);
+ ComponentConnector componentConnector = getConnector(id);
+
+ getLayoutManager().setNeedsMeasureRecursively(componentConnector);
+ getLayoutManager().layoutNow();
+
+ return getLayoutManager().getOuterHeightDouble(
+ componentConnector.getWidget().getElement());
+ }
+
+ private ComponentConnector getConnector(String id) {
+ return (ComponentConnector) ConnectorMap.get(getConnection())
+ .getConnector(id);
+ }
+ }
+
+ @Override
+ protected void extend(ServerConnector target) {
+ getWidget().setDetailsGenerator(new CustomDetailsGenerator());
+ dataChangeRegistration = getWidget().getDataSource()
+ .addDataChangeHandler(new DetailsChangeHandler());
+ }
+
+ private void detachIfNeeded(int rowIndex, String id) {
+ if (indexToDetailConnectorId.containsKey(rowIndex)) {
+ if (indexToDetailConnectorId.get(rowIndex).equals(id)) {
+ return;
+ }
+
+ // New Details component, hide old one
+ getWidget().setDetailsVisible(rowIndex, false);
+ indexToDetailConnectorId.remove(rowIndex);
+ }
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+
+ dataChangeRegistration.remove();
+ dataChangeRegistration = null;
+
+ indexToDetailConnectorId.clear();
+ }
+
+ @Override
+ public GridConnector getParent() {
+ return (GridConnector) super.getParent();
+ }
+
+ private Grid<JsonObject> getWidget() {
+ return getParent().getWidget();
+ }
+
+ /**
+ * Returns the connector id for a details component.
+ *
+ * @param rowIndex
+ * the row index of details component
+ * @return connector id; {@code null} if row or id is not found
+ */
+ private String getDetailsComponentConnectorId(int rowIndex) {
+ JsonObject row = getParent().getWidget().getDataSource()
+ .getRow(rowIndex);
+
+ if (row == null || !row.hasKey(GridState.JSONKEY_DETAILS_VISIBLE)
+ || row.getString(GridState.JSONKEY_DETAILS_VISIBLE).isEmpty()) {
+ return null;
+ }
+
+ return row.getString(GridState.JSONKEY_DETAILS_VISIBLE);
+ }
+
+ private LayoutManager getLayoutManager() {
+ return LayoutManager.get(getConnection());
+ }
+
+ /**
+ * Schedules a deferred opening for new details components.
+ */
+ private void refreshDetails() {
+ if (refreshing) {
+ return;
+ }
+
+ refreshing = true;
+ Scheduler.get().scheduleFinally(this::refreshDetailsVisibility);
+ }
+
+ private void refreshDetailsVisibility() {
+ for (int i = 0; i < getWidget().getDataSource().size(); ++i) {
+ String id = getDetailsComponentConnectorId(i);
+
+ detachIfNeeded(i, id);
+
+ if (id == null) {
+ continue;
+ }
+
+ indexToDetailConnectorId.put(i, id);
+ getWidget().setDetailsVisible(i, true);
+ }
+ refreshing = false;
+ }
+}
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
index 6c809f731c..3f22f419e7 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
@@ -16,11 +16,17 @@
package com.vaadin.client.connectors.grid;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ConnectorHierarchyChangeEvent;
+import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler;
import com.vaadin.client.DeferredWorker;
+import com.vaadin.client.HasComponentsConnector;
import com.vaadin.client.connectors.AbstractListingConnector;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.ui.SimpleManagedLayout;
@@ -43,9 +49,12 @@ import elemental.json.JsonObject;
*/
@Connect(com.vaadin.ui.Grid.class)
public class GridConnector extends AbstractListingConnector
- implements SimpleManagedLayout, DeferredWorker {
+ implements HasComponentsConnector, SimpleManagedLayout, DeferredWorker {
+
/* Map to keep track of all added columns */
private Map<Column<?, JsonObject>, String> columnToIdMap = new HashMap<>();
+ /* Child component list for HasComponentsConnector */
+ private List<ComponentConnector> childComponents;
@Override
public Grid<JsonObject> getWidget() {
@@ -133,4 +142,33 @@ public class GridConnector extends AbstractListingConnector
sortDirections.toArray(new SortDirection[0]),
event.isUserOriginated());
}
+
+ /* HasComponentsConnector */
+
+ @Override
+ public void updateCaption(ComponentConnector connector) {
+ // Details components don't support captions.
+ }
+
+ @Override
+ public List<ComponentConnector> getChildComponents() {
+ if (childComponents == null) {
+ return Collections.emptyList();
+ }
+
+ return childComponents;
+ }
+
+ @Override
+ public void setChildComponents(List<ComponentConnector> children) {
+ this.childComponents = children;
+
+ }
+
+ @Override
+ public HandlerRegistration addConnectorHierarchyChangeHandler(
+ ConnectorHierarchyChangeHandler handler) {
+ return ensureHandlerManager()
+ .addHandler(ConnectorHierarchyChangeEvent.TYPE, handler);
+ }
}