diff options
Diffstat (limited to 'client')
6 files changed, 228 insertions, 84 deletions
diff --git a/client/src/com/vaadin/client/ui/AbstractConnector.java b/client/src/com/vaadin/client/ui/AbstractConnector.java index 898b8cc483..32f5370dc3 100644 --- a/client/src/com/vaadin/client/ui/AbstractConnector.java +++ b/client/src/com/vaadin/client/ui/AbstractConnector.java @@ -18,9 +18,7 @@ package com.vaadin.client.ui; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import com.google.gwt.core.client.JsArrayString; @@ -417,10 +415,6 @@ public abstract class AbstractConnector implements ServerConnector, * {@link com.vaadin.terminal.AbstractClientConnector#setResource(String, com.vaadin.terminal.Resource)} * with the same key. <code>null</code> is returned if no corresponding * resource is found. - * <p> - * To get an event when a resource changes, you can use - * {@link #addStateChangeHandler(String, StateChangeHandler)} with - * <code>resources.[key]</code> as the property name. * * @param key * a string identifying the resource. diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 8553398718..75d67b82d6 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -500,7 +500,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, /** * Read from the "recalcWidths" -attribute. When it is true, the table will * recalculate the widths for columns - desirable in some cases. For #1983, - * marked experimental. + * marked experimental. See also variable <code>refreshContentWidths</code> + * in method {@link TableHead#updateCellsFromUIDL(UIDL)}. * <p> * For internal use only. May be removed or replaced in the future. */ @@ -539,6 +540,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public int serverCacheFirst = -1; public int serverCacheLast = -1; + /** + * In several cases TreeTable depends on the scrollBody.lastRendered being + * 'out of sync' while the update is being done. In those cases the sanity + * check must be performed afterwards. + */ + public boolean postponeSanityCheckForLastRendered; + /** For internal use only. May be removed or replaced in the future. */ public boolean sizeNeedsInit = true; @@ -563,6 +571,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, /** For internal use only. May be removed or replaced in the future. */ public ContextMenuDetails contextMenu = null; + private boolean hadScrollBars = false; + public VScrollTable() { setMultiSelectMode(MULTISELECT_MODE_DEFAULT); @@ -1375,9 +1385,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (uidl == null || reqRows < 1) { // container is empty, remove possibly existing rows if (firstRow <= 0) { - while (scrollBody.getLastRendered() > scrollBody.firstRendered) { + postponeSanityCheckForLastRendered = true; + while (scrollBody.getLastRendered() > scrollBody + .getFirstRendered()) { scrollBody.unlinkRow(false); } + postponeSanityCheckForLastRendered = false; scrollBody.unlinkRow(false); } return; @@ -1408,6 +1421,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * cache_rate); int lastRowToKeep = (int) (firstRowInViewPort + pageLength + pageLength * cache_rate); + // sanity checks: + if (firstRowToKeep < 0) { + firstRowToKeep = 0; + } + if (lastRowToKeep > totalRows) { + lastRowToKeep = totalRows - 1; + } debug("Client side calculated cache rows to keep: " + firstRowToKeep + "-" + lastRowToKeep); @@ -1999,15 +2019,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (totalRows - 1 > scrollBody.getLastRendered()) { // fetch cache rows int firstInNewSet = scrollBody.getLastRendered() + 1; - rowRequestHandler.setReqFirstRow(firstInNewSet); int lastInNewSet = (int) (firstRowInViewPort + pageLength + cache_rate * pageLength); if (lastInNewSet > totalRows - 1) { lastInNewSet = totalRows - 1; } - rowRequestHandler.setReqRows(lastInNewSet - firstInNewSet - + 1); - rowRequestHandler.deferRowFetch(1); + rowRequestHandler.triggerRowFetch(firstInNewSet, + lastInNewSet - firstInNewSet + 1, 1); } } } @@ -2023,6 +2041,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); } }); + + hadScrollBars = willHaveScrollbarz; } /** @@ -2093,6 +2113,18 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private int reqRows = 0; private boolean isRunning = false; + public void triggerRowFetch(int first, int rows) { + setReqFirstRow(first); + setReqRows(rows); + deferRowFetch(); + } + + public void triggerRowFetch(int first, int rows, int delay) { + setReqFirstRow(first); + setReqRows(rows); + deferRowFetch(delay); + } + public void deferRowFetch() { deferRowFetch(250); } @@ -2119,17 +2151,28 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } + public int getReqFirstRow() { + return reqFirstRow; + } + public void setReqFirstRow(int reqFirstRow) { if (reqFirstRow < 0) { - reqFirstRow = 0; + this.reqFirstRow = 0; } else if (reqFirstRow >= totalRows) { - reqFirstRow = totalRows - 1; + this.reqFirstRow = totalRows - 1; + } else { + this.reqFirstRow = reqFirstRow; } - this.reqFirstRow = reqFirstRow; } public void setReqRows(int reqRows) { - this.reqRows = reqRows; + if (reqRows < 0) { + this.reqRows = 0; + } else if (reqFirstRow + reqRows > totalRows) { + this.reqRows = totalRows - reqFirstRow; + } else { + this.reqRows = reqRows; + } } @Override @@ -2140,7 +2183,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, schedule(250); } else { - int firstToBeRendered = scrollBody.firstRendered; + int firstRendered = scrollBody.getFirstRendered(); + int lastRendered = scrollBody.getLastRendered(); + if (lastRendered > totalRows) { + lastRendered = totalRows - 1; + } + boolean rendered = firstRendered >= 0 && lastRendered >= 0; + + int firstToBeRendered = firstRendered; + if (reqFirstRow < firstToBeRendered) { firstToBeRendered = reqFirstRow; } else if (firstRowInViewPort - (int) (cache_rate * pageLength) > firstToBeRendered) { @@ -2149,12 +2200,24 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (firstToBeRendered < 0) { firstToBeRendered = 0; } + } else if (rendered && firstRendered + 1 < reqFirstRow + && lastRendered + 1 < reqFirstRow) { + // requested rows must fall within the requested rendering + // area + firstToBeRendered = reqFirstRow; + } + if (firstToBeRendered + reqRows < firstRendered) { + // must increase the required row count accordingly, + // otherwise may leave a gap and the rows beyond will get + // removed + setReqRows(firstRendered - firstToBeRendered); } - int lastToBeRendered = scrollBody.lastRendered; + int lastToBeRendered = lastRendered; + int lastReqRow = reqFirstRow + reqRows - 1; - if (reqFirstRow + reqRows - 1 > lastToBeRendered) { - lastToBeRendered = reqFirstRow + reqRows - 1; + if (lastReqRow > lastToBeRendered) { + lastToBeRendered = lastReqRow; } else if (firstRowInViewPort + pageLength + pageLength * cache_rate < lastToBeRendered) { lastToBeRendered = (firstRowInViewPort + pageLength + (int) (pageLength * cache_rate)); @@ -2163,14 +2226,36 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } // due Safari 3.1 bug (see #2607), verify reqrows, original // problem unknown, but this should catch the issue - if (reqFirstRow + reqRows - 1 > lastToBeRendered) { - reqRows = lastToBeRendered - reqFirstRow; + if (lastReqRow > lastToBeRendered) { + setReqRows(lastToBeRendered - reqFirstRow); } + } else if (rendered && lastRendered - 1 > lastReqRow + && firstRendered - 1 > lastReqRow) { + // requested rows must fall within the requested rendering + // area + lastToBeRendered = lastReqRow; + } + + if (lastToBeRendered > totalRows) { + lastToBeRendered = totalRows - 1; + } + if (reqFirstRow < firstToBeRendered + || (reqFirstRow > firstToBeRendered && (reqFirstRow < firstRendered || reqFirstRow > lastRendered + 1))) { + setReqFirstRow(firstToBeRendered); + } + if (lastRendered < lastToBeRendered + && lastRendered + reqRows < lastToBeRendered) { + // must increase the required row count accordingly, + // otherwise may leave a gap and the rows after will get + // removed + setReqRows(lastToBeRendered - lastRendered); + } else if (lastToBeRendered >= firstRendered + && reqFirstRow + reqRows < firstRendered) { + setReqRows(lastToBeRendered - lastRendered); } client.updateVariable(paintableId, "firstToBeRendered", firstToBeRendered, false); - client.updateVariable(paintableId, "lastToBeRendered", lastToBeRendered, false); // remember which firstvisible we requested, in case the server @@ -2191,10 +2276,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } - public int getReqFirstRow() { - return reqFirstRow; - } - /** * Sends request to refresh content at this position. */ @@ -2908,7 +2989,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public void updateCellsFromUIDL(UIDL uidl) { Iterator<?> it = uidl.getChildIterator(); HashSet<String> updated = new HashSet<String>(); - boolean refreshContentWidths = false; + boolean refreshContentWidths = initializedAndAttached + && hadScrollBars != willHaveScrollbars(); while (it.hasNext()) { final UIDL col = (UIDL) it.next(); final String cid = col.getStringAttribute("cid"); @@ -3991,6 +4073,24 @@ public class VScrollTable extends FlowPanel implements HasWidgets, setElement(container); } + public void setLastRendered(int lastRendered) { + if (totalRows >= 0 && lastRendered > totalRows) { + VConsole.log("setLastRendered: " + this.lastRendered + " -> " + + lastRendered); + this.lastRendered = totalRows - 1; + } else { + this.lastRendered = lastRendered; + } + } + + public int getLastRendered() { + return lastRendered; + } + + public int getFirstRendered() { + return firstRendered; + } + public VScrollTableRow getRowByRowIndex(int indexInTable) { int internalIndex = indexInTable - firstRendered; if (internalIndex >= 0 && internalIndex < renderedRows.size()) { @@ -4045,7 +4145,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public void renderInitialRows(UIDL rowData, int firstIndex, int rows) { firstRendered = firstIndex; - lastRendered = firstIndex + rows - 1; + setLastRendered(firstIndex + rows - 1); final Iterator<?> it = rowData.getChildIterator(); aligns = tHead.getColumnAlignments(); while (it.hasNext()) { @@ -4065,7 +4165,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, while (it.hasNext()) { final VScrollTableRow row = prepareRow((UIDL) it.next()); addRow(row); - lastRendered++; + setLastRendered(lastRendered + 1); } fixSpacers(); } else if (firstIndex + rows == firstRendered) { @@ -4081,19 +4181,27 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } else { // completely new set of rows + + // there can't be sanity checks for last rendered within this + // while loop regardless of what has been set previously, so + // change it temporarily to true and then return the original + // value + boolean temp = postponeSanityCheckForLastRendered; + postponeSanityCheckForLastRendered = true; while (lastRendered + 1 > firstRendered) { unlinkRow(false); } - final VScrollTableRow row = prepareRow((UIDL) it.next()); + postponeSanityCheckForLastRendered = temp; + VScrollTableRow row = prepareRow((UIDL) it.next()); firstRendered = firstIndex; - lastRendered = firstIndex - 1; + setLastRendered(firstIndex - 1); addRow(row); - lastRendered++; + setLastRendered(lastRendered + 1); setContainerHeight(); fixSpacers(); while (it.hasNext()) { addRow(prepareRow((UIDL) it.next())); - lastRendered++; + setLastRendered(lastRendered + 1); } fixSpacers(); } @@ -4129,14 +4237,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * not waste time rendering a set of rows that will never be * visible... */ - rowRequestHandler.setReqFirstRow(reactFirstRow); - rowRequestHandler.setReqRows(reactLastRow - reactFirstRow + 1); - rowRequestHandler.deferRowFetch(1); + rowRequestHandler.triggerRowFetch(reactFirstRow, reactLastRow + - reactFirstRow + 1, 1); } else if (lastRendered < reactLastRow) { // get some cache rows below visible area - rowRequestHandler.setReqFirstRow(lastRendered + 1); - rowRequestHandler.setReqRows(reactLastRow - lastRendered); - rowRequestHandler.deferRowFetch(1); + rowRequestHandler.triggerRowFetch(lastRendered + 1, + reactLastRow - lastRendered, 1); } else if (firstRendered > reactFirstRow) { /* * Branch for fetching cache above visible area. @@ -4146,9 +4252,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * some rare situations the table may make two cache visits to * server. */ - rowRequestHandler.setReqFirstRow(reactFirstRow); - rowRequestHandler.setReqRows(firstRendered - reactFirstRow); - rowRequestHandler.deferRowFetch(1); + rowRequestHandler.triggerRowFetch(reactFirstRow, firstRendered + - reactFirstRow, 1); } } @@ -4172,7 +4277,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets, final VScrollTableRow row = prepareRow((UIDL) it.next()); addRow(row); insertedRows.add(row); - lastRendered++; + if (postponeSanityCheckForLastRendered) { + lastRendered++; + } else { + setLastRendered(lastRendered + 1); + } } fixSpacers(); } else if (firstIndex + rows == firstRendered) { @@ -4194,7 +4303,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets, VScrollTableRow row = prepareRow((UIDL) it.next()); insertRowAt(row, ix); insertedRows.add(row); - lastRendered++; + if (postponeSanityCheckForLastRendered) { + lastRendered++; + } else { + setLastRendered(lastRendered + 1); + } ix++; } fixSpacers(); @@ -4307,7 +4420,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets, firstRendered++; } else { actualIx = renderedRows.size() - 1; - lastRendered--; + if (postponeSanityCheckForLastRendered) { + --lastRendered; + } else { + setLastRendered(lastRendered - 1); + } } if (actualIx >= 0) { unlinkRowAtActualIndex(actualIx); @@ -4323,6 +4440,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } if (firstRendered > firstIndex && firstRendered < firstIndex + count) { + count = count - (firstRendered - firstIndex); firstIndex = firstRendered; } int lastIndex = firstIndex + count - 1; @@ -4331,7 +4449,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } for (int ix = lastIndex; ix >= firstIndex; ix--) { unlinkRowAtActualIndex(actualIndex(ix)); - lastRendered--; + if (postponeSanityCheckForLastRendered) { + // partialUpdate handles sanity check later + lastRendered--; + } else { + setLastRendered(lastRendered - 1); + } } fixSpacers(); } @@ -4352,7 +4475,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } for (int ix = renderedRows.size() - 1; ix >= index; ix--) { unlinkRowAtActualIndex(actualIndex(ix)); - lastRendered--; + setLastRendered(lastRendered - 1); } fixSpacers(); } @@ -4538,14 +4661,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } - public int getLastRendered() { - return lastRendered; - } - - public int getFirstRendered() { - return firstRendered; - } - public void moveCol(int oldIndex, int newIndex) { // loop all rows and move given index to its new place @@ -5911,8 +6026,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, client.updateVariable(paintableId, "pagelength", pageLength, false); if (!rendering) { - int currentlyVisible = scrollBody.lastRendered - - scrollBody.firstRendered; + int currentlyVisible = scrollBody.getLastRendered() + - scrollBody.getFirstRendered(); if (currentlyVisible < pageLength && currentlyVisible < totalRows) { // shake scrollpanel to fill empty space @@ -6397,10 +6512,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } if (postLimit > lastRendered) { // need some rows to the end of the rendered area - rowRequestHandler.setReqFirstRow(lastRendered + 1); - rowRequestHandler.setReqRows((int) ((firstRowInViewPort - + pageLength + pageLength * cache_rate) - lastRendered)); - rowRequestHandler.deferRowFetch(); + int reqRows = (int) ((firstRowInViewPort + pageLength + pageLength + * cache_rate) - lastRendered); + rowRequestHandler.triggerRowFetch(lastRendered + 1, reqRows); } } diff --git a/client/src/com/vaadin/client/ui/button/ButtonConnector.java b/client/src/com/vaadin/client/ui/button/ButtonConnector.java index 0439cd4fdc..9733d206c7 100644 --- a/client/src/com/vaadin/client/ui/button/ButtonConnector.java +++ b/client/src/com/vaadin/client/ui/button/ButtonConnector.java @@ -77,7 +77,7 @@ public class ButtonConnector extends AbstractComponentConnector implements } }); - addStateChangeHandler("resources.icon", new StateChangeHandler() { + addStateChangeHandler("resources", new StateChangeHandler() { @Override public void onStateChanged(StateChangeEvent stateChangeEvent) { if (getIcon() != null) { diff --git a/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java b/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java index 4c46846d14..2ce45623d0 100644 --- a/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java +++ b/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java @@ -410,41 +410,73 @@ public class LayoutDependencyTree { public void setNeedsMeasure(ComponentConnector connector, boolean needsMeasure) { - setNeedsMeasure(connector.getConnectorId(), needsMeasure); + setNeedsHorizontalMeasure(connector, needsMeasure); + setNeedsVerticalMeasure(connector, needsMeasure); } public void setNeedsMeasure(String connectorId, boolean needsMeasure) { - setNeedsHorizontalMeasure(connectorId, needsMeasure); - setNeedsVerticalMeasure(connectorId, needsMeasure); + ComponentConnector connector = (ComponentConnector) ConnectorMap.get( + connection).getConnector(connectorId); + if (connector == null) { + return; + } + + setNeedsMeasure(connector, needsMeasure); } public void setNeedsHorizontalMeasure(ComponentConnector connector, boolean needsMeasure) { - setNeedsHorizontalMeasure(connector.getConnectorId(), needsMeasure); + LayoutDependency dependency = getDependency(connector, HORIZONTAL); + dependency.setNeedsMeasure(needsMeasure); } public void setNeedsHorizontalMeasure(String connectorId, boolean needsMeasure) { - LayoutDependency dependency = getDependency(connectorId, HORIZONTAL); - dependency.setNeedsMeasure(needsMeasure); + // Ensure connector exists + ComponentConnector connector = (ComponentConnector) ConnectorMap.get( + connection).getConnector(connectorId); + if (connector == null) { + return; + } + + setNeedsHorizontalMeasure(connector, needsMeasure); } public void setNeedsVerticalMeasure(ComponentConnector connector, boolean needsMeasure) { - setNeedsVerticalMeasure(connector.getConnectorId(), needsMeasure); + LayoutDependency dependency = getDependency(connector, VERTICAL); + dependency.setNeedsMeasure(needsMeasure); } public void setNeedsVerticalMeasure(String connectorId, boolean needsMeasure) { - LayoutDependency dependency = getDependency(connectorId, VERTICAL); - dependency.setNeedsMeasure(needsMeasure); + // Ensure connector exists + ComponentConnector connector = (ComponentConnector) ConnectorMap.get( + connection).getConnector(connectorId); + if (connector == null) { + return; + } + + setNeedsVerticalMeasure(connector, needsMeasure); + } + + private LayoutDependency getDependency(ComponentConnector connector, + int direction) { + return getDependency(connector.getConnectorId(), connector, direction); } private LayoutDependency getDependency(String connectorId, int direction) { + return getDependency(connectorId, null, direction); + } + + private LayoutDependency getDependency(String connectorId, + ComponentConnector connector, int direction) { FastStringMap<LayoutDependency> dependencies = dependenciesInDirection[direction]; LayoutDependency dependency = dependencies.get(connectorId); if (dependency == null) { - ComponentConnector connector = (ComponentConnector) ConnectorMap - .get(connection).getConnector(connectorId); + if (connector == null) { + connector = (ComponentConnector) ConnectorMap.get(connection) + .getConnector(connectorId); + } dependency = new LayoutDependency(connector, direction); dependencies.put(connectorId, dependency); } diff --git a/client/src/com/vaadin/client/ui/link/LinkConnector.java b/client/src/com/vaadin/client/ui/link/LinkConnector.java index 59d24ce986..807a9bcc64 100644 --- a/client/src/com/vaadin/client/ui/link/LinkConnector.java +++ b/client/src/com/vaadin/client/ui/link/LinkConnector.java @@ -38,16 +38,13 @@ public class LinkConnector extends AbstractComponentConnector implements @Override protected void init() { super.init(); - addStateChangeHandler("resources." + LinkConstants.HREF_RESOURCE, - new StateChangeHandler() { - @Override - public void onStateChanged(StateChangeEvent stateChangeEvent) { - getWidget().src = getResourceUrl(LinkConstants.HREF_RESOURCE); - getWidget().anchor - .setAttribute("href", getWidget().src); - - } - }); + addStateChangeHandler("resources", new StateChangeHandler() { + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + getWidget().src = getResourceUrl(LinkConstants.HREF_RESOURCE); + getWidget().anchor.setAttribute("href", getWidget().src); + } + }); } @Override diff --git a/client/src/com/vaadin/client/ui/table/TableConnector.java b/client/src/com/vaadin/client/ui/table/TableConnector.java index dedcab84fa..c967642059 100644 --- a/client/src/com/vaadin/client/ui/table/TableConnector.java +++ b/client/src/com/vaadin/client/ui/table/TableConnector.java @@ -165,12 +165,19 @@ public class TableConnector extends AbstractHasComponentsConnector implements UIDL partialRowAdditions = uidl.getChildByTagName("prows"); UIDL partialRowUpdates = uidl.getChildByTagName("urows"); if (partialRowUpdates != null || partialRowAdditions != null) { + getWidget().postponeSanityCheckForLastRendered = true; // we may have pending cache row fetch, cancel it. See #2136 getWidget().rowRequestHandler.cancel(); getWidget().updateRowsInBody(partialRowUpdates); getWidget().addAndRemoveRows(partialRowAdditions); + + // sanity check (in case the value has slipped beyond the total + // amount of rows) + getWidget().scrollBody.setLastRendered(getWidget().scrollBody + .getLastRendered()); } else { + getWidget().postponeSanityCheckForLastRendered = false; UIDL rowData = uidl.getChildByTagName("rows"); if (rowData != null) { // we may have pending cache row fetch, cancel it. See #2136 |