From dc14ea4ca1cec8a4fc1ac23c07151e11cd2ac72b Mon Sep 17 00:00:00 2001 From: Jonatan Kronqvist Date: Mon, 9 Sep 2013 15:52:23 +0300 Subject: [PATCH] Implemented SubPartAware in VScrollTable #12514 This allows for "//VScrollTable#row[n]/col[m]" -style locator strings. Change-Id: I65bea31ab0eaa59fcd5a566ea3d1a43465ef298f --- .../VaadinFinderLocatorStrategy.java | 55 +++++++-- .../com/vaadin/client/ui/VScrollTable.java | 108 +++++++++++++++++- 2 files changed, 151 insertions(+), 12 deletions(-) diff --git a/client/src/com/vaadin/client/componentlocator/VaadinFinderLocatorStrategy.java b/client/src/com/vaadin/client/componentlocator/VaadinFinderLocatorStrategy.java index f597003b60..3516aa3e93 100644 --- a/client/src/com/vaadin/client/componentlocator/VaadinFinderLocatorStrategy.java +++ b/client/src/com/vaadin/client/componentlocator/VaadinFinderLocatorStrategy.java @@ -28,6 +28,7 @@ import com.vaadin.client.metadata.NoDataException; import com.vaadin.client.metadata.Property; import com.vaadin.client.ui.AbstractConnector; import com.vaadin.client.ui.AbstractHasComponentsConnector; +import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.VNotification; import com.vaadin.shared.AbstractComponentState; @@ -50,6 +51,7 @@ import com.vaadin.shared.AbstractComponentState; */ public class VaadinFinderLocatorStrategy implements LocatorStrategy { + private static final String SUBPART_SEPARATOR = "#"; private ComponentLocator componentLocator; public VaadinFinderLocatorStrategy(ComponentLocator componentLocator) { @@ -76,8 +78,8 @@ public class VaadinFinderLocatorStrategy implements LocatorStrategy { if (path.startsWith("//VNotification")) { return findNotificationByPath(path); } - return findElementByPath(path, componentLocator.getClient() - .getUIConnector()); + return getElementByPathStartingAtConnector(path, componentLocator + .getClient().getUIConnector()); } /** @@ -110,23 +112,54 @@ public class VaadinFinderLocatorStrategy implements LocatorStrategy { */ @Override public Element getElementByPathStartingAt(String path, Element root) { - return findElementByPath(path, + return getElementByPathStartingAtConnector(path, Util.findPaintable(componentLocator.getClient(), root)); } /** - * Recursively finds an element identified by the provided path by - * traversing the connector hierarchy starting from the {@code parent} - * connector. + * Finds an element by the specified path, starting traversal of the + * connector hierarchy from the specified root. + * + * @param path + * the locator path + * @param root + * the root connector + * @return the element identified by path or null if not found. + */ + private Element getElementByPathStartingAtConnector(String path, + ComponentConnector root) { + String[] pathComponents = path.split(SUBPART_SEPARATOR); + ComponentConnector connector = findConnectorByPath(pathComponents[0], + root); + if (connector != null) { + if (pathComponents.length > 1) { + // We have subparts + if (connector.getWidget() instanceof SubPartAware) { + return ((SubPartAware) connector.getWidget()) + .getSubPartElement(pathComponents[1]); + } else { + return null; + } + } + return connector.getWidget().getElement(); + } + return null; + } + + /** + * Recursively finds a connector for the element identified by the provided + * path by traversing the connector hierarchy starting from the + * {@code parent} connector. * * @param path * The path identifying an element. * @param parent * The connector to start traversing from. - * @return The element identified by {@code path} or null if it no such - * element could be found. + * @return The connector identified by {@code path} or null if it no such + * connector could be found. */ - private Element findElementByPath(String path, ComponentConnector parent) { + private ComponentConnector findConnectorByPath(String path, + ComponentConnector parent) { boolean findRecursively = path.startsWith("//"); // Strip away the one or two slashes from the beginning of the path path = path.substring(findRecursively ? 2 : 1); @@ -138,9 +171,9 @@ public class VaadinFinderLocatorStrategy implements LocatorStrategy { extractPredicateString(fragments[0])); if (connector != null) { if (fragments.length > 1) { - return findElementByPath(fragments[1], connector); + return findConnectorByPath(fragments[1], connector); } else { - return connector.getWidget().getElement(); + return connector; } } return null; diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 3733ee204a..fe2e99a28f 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -61,6 +61,8 @@ import com.google.gwt.event.dom.client.ScrollHandler; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.regexp.shared.MatchResult; +import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; @@ -123,7 +125,7 @@ import com.vaadin.shared.ui.table.TableConstants; */ public class VScrollTable extends FlowPanel implements HasWidgets, ScrollHandler, VHasDropHandler, FocusHandler, BlurHandler, Focusable, - ActionOwner { + ActionOwner, SubPartAware { public static final String STYLENAME = "v-table"; @@ -5031,6 +5033,20 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } + public int indexOf(Widget row) { + int relIx = -1; + for (int ix = 0; ix < renderedRows.size(); ix++) { + if (renderedRows.get(ix) == row) { + relIx = ix; + break; + } + } + if (relIx >= 0) { + return this.firstRendered + relIx; + } + return -1; + } + public class VScrollTableRow extends Panel implements ActionOwner { private static final int TOUCHSCROLL_TIMEOUT = 100; @@ -7728,4 +7744,94 @@ public class VScrollTable extends FlowPanel implements HasWidgets, return this; } + private static final String SUBPART_HEADER = "header"; + private static final String SUBPART_FOOTER = "footer"; + private static final String SUBPART_ROW = "row"; + private static final String SUBPART_COL = "col"; + /** Matches header[ix] - used for extracting the index of the targeted header cell */ + private static final RegExp SUBPART_HEADER_REGEXP = RegExp + .compile(SUBPART_HEADER + "\\[(\\d+)\\]"); + /** Matches footer[ix] - used for extracting the index of the targeted footer cell */ + private static final RegExp SUBPART_FOOTER_REGEXP = RegExp + .compile(SUBPART_FOOTER + "\\[(\\d+)\\]"); + /** Matches row[ix] - used for extracting the index of the targeted row */ + private static final RegExp SUBPART_ROW_REGEXP = RegExp.compile(SUBPART_ROW + + "\\[(\\d+)]"); + /** Matches col[ix] - used for extracting the index of the targeted column */ + private static final RegExp SUBPART_ROW_COL_REGEXP = RegExp + .compile(SUBPART_ROW + "\\[(\\d+)\\]/" + SUBPART_COL + "\\[(\\d+)\\]"); + + @Override + public Element getSubPartElement(String subPart) { + if (SUBPART_ROW_COL_REGEXP.test(subPart)) { + MatchResult result = SUBPART_ROW_COL_REGEXP.exec(subPart); + int rowIx = Integer.valueOf(result.getGroup(1)); + int colIx = Integer.valueOf(result.getGroup(2)); + VScrollTableRow row = scrollBody.getRowByRowIndex(rowIx); + if (row != null) { + Element rowElement = row.getElement(); + if (colIx < rowElement.getChildCount()) { + return rowElement.getChild(colIx).getFirstChild().cast(); + } + } + + } else if (SUBPART_ROW_REGEXP.test(subPart)) { + MatchResult result = SUBPART_ROW_REGEXP.exec(subPart); + int rowIx = Integer.valueOf(result.getGroup(1)); + VScrollTableRow row = scrollBody.getRowByRowIndex(rowIx); + if (row != null) { + return row.getElement(); + } + + } else if (SUBPART_HEADER_REGEXP.test(subPart)) { + MatchResult result = SUBPART_HEADER_REGEXP.exec(subPart); + int headerIx = Integer.valueOf(result.getGroup(1)); + HeaderCell headerCell = tHead.getHeaderCell(headerIx); + if (headerCell != null) { + return headerCell.getElement(); + } + + } else if (SUBPART_FOOTER_REGEXP.test(subPart)) { + MatchResult result = SUBPART_FOOTER_REGEXP.exec(subPart); + int footerIx = Integer.valueOf(result.getGroup(1)); + FooterCell footerCell = tFoot.getFooterCell(footerIx); + if (footerCell != null) { + return footerCell.getElement(); + } + } + // Nothing found. + return null; + } + + @Override + public String getSubPartName(Element subElement) { + Widget widget = Util.findWidget(subElement, null); + if (widget instanceof HeaderCell) { + return SUBPART_HEADER + "[" + tHead.visibleCells.indexOf(widget) + + "]"; + } else if (widget instanceof FooterCell) { + return SUBPART_FOOTER + "[" + tFoot.visibleCells.indexOf(widget) + + "]"; + } else if (widget instanceof VScrollTableRow) { + // a cell in a row + VScrollTableRow row = (VScrollTableRow) widget; + int rowIx = scrollBody.indexOf(row); + if (rowIx >= 0) { + int colIx = -1; + for (int ix = 0; ix < row.getElement().getChildCount(); ix++) { + if (row.getElement().getChild(ix).isOrHasChild(subElement)) { + colIx = ix; + break; + } + } + if (colIx >= 0) { + return SUBPART_ROW + "[" + rowIx + "]/" + SUBPART_COL + "[" + + colIx + "]"; + } + return SUBPART_ROW + "[" + rowIx + "]"; + } + } + // Nothing found. + return null; + } } -- 2.39.5