From 423628adf0080175c851b35fddd6fc0e803857c6 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 28 May 2014 11:11:35 +0300 Subject: [PATCH] Add SubPartAware interface to Grid client side (#13334) Change-Id: I067f2a248a84076531b0b0b18b4e39c493db457f --- .../com/vaadin/client/ui/grid/Escalator.java | 40 +++++++- .../src/com/vaadin/client/ui/grid/Grid.java | 98 ++++++++++++++++++- .../vaadin/client/ui/grid/RowContainer.java | 22 +++++ 3 files changed, 157 insertions(+), 3 deletions(-) diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index cc3ee55182..53c70bbb70 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -1090,6 +1090,11 @@ public class Escalator extends Widget { root = rowContainerElement; } + @Override + public Element getElement() { + return root; + } + /** * Gets the tag name of an element to represent a cell in a row. *

@@ -1375,6 +1380,11 @@ public class Escalator extends Widget { return cellElem; } + @Override + public Element getRowElement(int index) { + return getTrByVisualIndex(index); + } + /** * Gets the child element that is visually at a certain index * @@ -1384,7 +1394,7 @@ public class Escalator extends Widget { * @throws IndexOutOfBoundsException * if {@code index} is not valid within {@link #root} */ - abstract protected Element getTrByVisualIndex(int index) + protected abstract Element getTrByVisualIndex(int index) throws IndexOutOfBoundsException; protected void paintRemoveColumns(final int offset, @@ -3041,6 +3051,22 @@ public class Escalator extends Widget { } } + @Override + public Element getRowElement(int index) { + if (index < 0 || index >= getRowCount()) { + throw new IndexOutOfBoundsException("No such logical index: " + + index); + } + int visualIndex = index + - getLogicalRowIndex(visualRowOrder.getFirst()); + if (visualIndex >= 0 && visualIndex < visualRowOrder.size()) { + return super.getRowElement(visualIndex); + } else { + throw new IllegalStateException("Row with logical index " + + index + " is currently not available in the DOM"); + } + } + private void setBodyScrollPosition(final double scrollLeft, final double scrollTop) { tBodyScrollLeft = scrollLeft; @@ -4215,7 +4241,6 @@ public class Escalator extends Widget { .getLast()) + 1; int visibleRowCount = visibleRangeEnd - visibleRangeStart; - fireEvent(new RowVisibilityChangeEvent(visibleRangeStart, visibleRowCount)); } else { @@ -4223,6 +4248,17 @@ public class Escalator extends Widget { } } + /** + * Gets the range of currently visible rows + * + * @return range of visible rows + */ + public Range getVisibleRowRange() { + return Range.between( + body.getLogicalRowIndex(body.visualRowOrder.getFirst()), + body.getLogicalRowIndex(body.visualRowOrder.getLast()) + 1); + } + /** * Accesses the package private method Widget#setParent() * diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 25186ae80a..c5eb76c6ad 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -16,11 +16,13 @@ package com.vaadin.client.ui.grid; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.logging.Level; import java.util.logging.Logger; import com.google.gwt.core.shared.GWT; @@ -28,15 +30,18 @@ import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.EventTarget; import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HasVisibility; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; +import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.TextRenderer; import com.vaadin.shared.ui.grid.GridConstants; import com.vaadin.shared.ui.grid.HeightMode; +import com.vaadin.shared.ui.grid.Range; import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.shared.util.SharedUtil; @@ -72,7 +77,7 @@ import com.vaadin.shared.util.SharedUtil; * @since 7.4 * @author Vaadin Ltd */ -public class Grid extends Composite { +public class Grid extends Composite implements SubPartAware { /** * Escalator used internally by grid to render the rows @@ -1485,4 +1490,95 @@ public class Grid extends Composite { } } } + + @Override + public com.google.gwt.user.client.Element getSubPartElement(String subPart) { + // Parse SubPart string to type and indices + String[] splitArgs = subPart.split("\\["); + + String type = splitArgs[0]; + int[] indices = new int[splitArgs.length - 1]; + for (int i = 0; i < indices.length; ++i) { + String tmp = splitArgs[i + 1]; + indices[i] = Integer.parseInt(tmp.substring(0, tmp.length() - 1)); + } + + // Get correct RowContainer for type from Escalator + RowContainer container = null; + if (type.equalsIgnoreCase("header")) { + container = escalator.getHeader(); + } else if (type.equalsIgnoreCase("cell")) { + // If wanted row is not visible, we need to scroll there. + Range visibleRowRange = escalator.getVisibleRowRange(); + if (!visibleRowRange.contains(indices[0])) { + try { + scrollToRow(indices[0]); + } catch (IllegalArgumentException e) { + getLogger().log(Level.SEVERE, e.getMessage()); + } + // Scrolling causes a lazy loading event. No element can + // currently be retrieved. + return null; + } + container = escalator.getBody(); + } else if (type.equalsIgnoreCase("footer")) { + container = escalator.getFooter(); + } + + if (null != container) { + if (indices.length == 0) { + // No indexing. Just return the wanted container element + return DOM.asOld(container.getElement()); + } else { + try { + return DOM.asOld(getSubPart(container, indices)); + } catch (Exception e) { + getLogger().log(Level.SEVERE, e.getMessage()); + } + } + } + return null; + } + + private Element getSubPart(RowContainer container, int[] indices) { + // Scroll wanted column to view if able + if (indices.length > 1 + && escalator.getColumnConfiguration().getFrozenColumnCount() <= indices[1]) { + escalator.scrollToColumn(indices[1], ScrollDestination.ANY, 0); + } + + Element targetElement = container.getRowElement(indices[0]); + for (int i = 1; i < indices.length && targetElement != null; ++i) { + targetElement = (Element) targetElement.getChild(indices[i]); + } + return targetElement; + } + + @Override + public String getSubPartName(com.google.gwt.user.client.Element subElement) { + // Containers and matching SubPart types + List containers = Arrays.asList(escalator.getHeader(), + escalator.getBody(), escalator.getFooter()); + List containerType = Arrays.asList("header", "cell", "footer"); + + for (int i = 0; i < containers.size(); ++i) { + RowContainer container = containers.get(i); + boolean containerRow = (subElement.getTagName().equalsIgnoreCase( + "tr") && subElement.getParentElement() == container + .getElement()); + if (containerRow) { + // Wanted SubPart is row that is a child of containers root + // To get indices, we use a cell that is a child of this row + subElement = DOM.asOld(subElement.getFirstChildElement()); + } + + Cell cell = container.getCell(subElement); + if (cell != null) { + // Skip the column index if subElement was a child of root + return containerType.get(i) + "[" + cell.getRow() + + (containerRow ? "]" : "][" + cell.getColumn() + "]"); + } + } + return null; + } } diff --git a/client/src/com/vaadin/client/ui/grid/RowContainer.java b/client/src/com/vaadin/client/ui/grid/RowContainer.java index 9cf5d02742..b0b580d665 100644 --- a/client/src/com/vaadin/client/ui/grid/RowContainer.java +++ b/client/src/com/vaadin/client/ui/grid/RowContainer.java @@ -169,4 +169,26 @@ public interface RowContainer { */ public Cell getCell(Element element); + /** + * Gets the row element with given logical index. For lazy loaded containers + * such as Escalators BodyRowContainer visibility should be checked before + * calling this function. See {@link Escalator#getVisibleRowRange()}. + * + * @param index + * the logical index of the element to retrieve + * @return the element at position {@code index} + * @throws IndexOutOfBoundsException + * if {@code index} is not valid within container + * @throws IllegalStateException + * if {@code index} is currently not available in the DOM + */ + public Element getRowElement(int index) throws IndexOutOfBoundsException, + IllegalStateException; + + /** + * Returns the root element of RowContainer + * + * @return RowContainer root element + */ + public Element getElement(); } -- 2.39.5