diff options
author | Leif Åstrand <leif@vaadin.com> | 2013-08-30 13:43:34 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2013-08-30 13:43:34 +0300 |
commit | be3953c0686a4bd59fe9df2c401d882104a7afac (patch) | |
tree | dcefc03352e742a41d3551d781651bfbe19875d6 /client | |
parent | d827a1760da477575294f0105933e868c1bf3ad3 (diff) | |
parent | ad669c39c603650cc8193eef83fe1b6a39be0e45 (diff) | |
download | vaadin-framework-be3953c0686a4bd59fe9df2c401d882104a7afac.tar.gz vaadin-framework-be3953c0686a4bd59fe9df2c401d882104a7afac.zip |
Merge changes from origin/7.1
4f3e81a Use <code> instead of {@code} for sample containing { and } (#12311)
c7a48ae Delay sending DateField popup value to server until popup is closed #6252
dc491a4 Reset waitingForFilteringResponse flag to false inside onBlur (#12325)
4fb775a Fixed a typo in FieldGroup.isModified() JavaDoc. (#12172)
aa47197 Add a chapter on installing IvyDE (for #12359)
eaec281 GWT requires max 1.6 compiler compliance level currently - #12345
f72be69 Terminate JVM if server.close() has no effect (#12363)
36413cb Make sure that no fileIds are replayed to the client (#12330)
7182665 Fix scrollbar for Window under WebKit browsers (#11994)
61dbe9c Search only remaining message for delimiter (#12404)
b5a212a Report min and max times from Profiler (#12409)
7220ca8 Fixed DragAndDropWrapper using wrong drop target in IE8 #12406
c87772b Escape markup in CustomLayout's JavaDoc (#12410)
f5b67af Optimize ComputedStyle.getIntProperty() (#12411)
0473036 Add more detailed profiling for some client side hotspots (#12418)
7dfe5ae Fixed test broken by fixes to drag&drop #12406
234ed1c Fixed test broken by PopupDateField communication change #6252
c7a8c3f Fixed failing TabKeyboardNavigation test #12433
fac9ff6 Optimize resetting of state when detaching components (#10899, #11284)
af995de Optimize large Vertical/HorizontalLayout client side (#12420, #10899)
39fd5fc Fix bug for spacing on first widget (#12420)
bd4442b Fixed broken test due to changes in drop position by #12406
b83240f Optimize CssLayout hierarchy update (#11284)
a52b286 Added controlDirective to ifContentStatement. Fixes ticket #12105.
8ce45c7 Disable slow sanity check when not in debug mode (#12463)
232eb42 Enable use of profiler without debug window (#12465)
6dc46c5 Use the add() path of CssLayout only when appending to the end (#11284)
bea7fa3 Only consider caption tooltips for own slots (#12469)
dce63d1 Allow creating session for Portlet UI init request (#12473)
ad669c3 Adds junit to the ide configuration for the theme-compiler module.
Change-Id: Icd734d6849cc4f4014e1268f4fabe1ed92f72e38
Diffstat (limited to 'client')
17 files changed, 353 insertions, 59 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 0b64f56c3e..0d9c859ee8 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -1686,8 +1686,15 @@ public class ApplicationConnection { for (int i = 0; i < size; i++) { ServerConnector c = currentConnectors.get(i); if (c.getParent() != null) { - if (!c.getParent().getChildren().contains(c)) { - VConsole.error("ERROR: Connector is connected to a parent but the parent does not contain the connector"); + // only do this check if debug mode is active + if (ApplicationConfiguration.isDebugMode()) { + Profiler.enter("unregisterRemovedConnectors check parent - this is only performed in debug mode"); + // this is slow for large layouts, 25-30% of total + // time for some operations even on modern browsers + if (!c.getParent().getChildren().contains(c)) { + VConsole.error("ERROR: Connector is connected to a parent but the parent does not contain the connector"); + } + Profiler.leave("unregisterRemovedConnectors check parent - this is only performed in debug mode"); } } else if (c == getUIConnector()) { // UIConnector for this connection, leave as-is @@ -1701,7 +1708,9 @@ public class ApplicationConnection { // hierarchy, unregister it and any possible // children. The UIConnector should never be // unregistered even though it has no parent. + Profiler.enter("unregisterRemovedConnectors unregisterConnector"); connectorMap.unregisterConnector(c); + Profiler.leave("unregisterRemovedConnectors unregisterConnector"); unregistered++; } @@ -1984,6 +1993,8 @@ public class ApplicationConnection { JsArrayString hierarchyKeys = hierarchies.getKeyArray(); for (int i = 0; i < hierarchyKeys.length(); i++) { try { + Profiler.enter("updateConnectorHierarchy hierarchy entry"); + String connectorId = hierarchyKeys.get(i); ServerConnector parentConnector = connectorMap .getConnector(connectorId); @@ -1991,6 +2002,8 @@ public class ApplicationConnection { .getJSStringArray(connectorId); int childConnectorSize = childConnectorIds.length(); + Profiler.enter("updateConnectorHierarchy find new connectors"); + List<ServerConnector> newChildren = new ArrayList<ServerConnector>(); List<ComponentConnector> newComponents = new ArrayList<ComponentConnector>(); for (int connectorIndex = 0; connectorIndex < childConnectorSize; connectorIndex++) { @@ -2029,6 +2042,8 @@ public class ApplicationConnection { } } + Profiler.leave("updateConnectorHierarchy find new connectors"); + // TODO This check should be done on the server side in // the future so the hierarchy update is only sent when // something actually has changed @@ -2041,6 +2056,8 @@ public class ApplicationConnection { continue; } + Profiler.enter("updateConnectorHierarchy handle HasComponentsConnector"); + if (parentConnector instanceof HasComponentsConnector) { HasComponentsConnector ccc = (HasComponentsConnector) parentConnector; List<ComponentConnector> oldComponents = ccc @@ -2062,7 +2079,13 @@ public class ApplicationConnection { + " has component children even though it isn't a HasComponentsConnector"); } + Profiler.leave("updateConnectorHierarchy handle HasComponentsConnector"); + + Profiler.enter("updateConnectorHierarchy setChildren"); parentConnector.setChildren(newChildren); + Profiler.leave("updateConnectorHierarchy setChildren"); + + Profiler.enter("updateConnectorHierarchy find removed children"); /* * Find children removed from this parent and mark for @@ -2084,11 +2107,17 @@ public class ApplicationConnection { maybeDetached.add(oldChild.getConnectorId()); } } + + Profiler.leave("updateConnectorHierarchy find removed children"); } catch (final Throwable e) { VConsole.error(e); + } finally { + Profiler.leave("updateConnectorHierarchy hierarchy entry"); } } + Profiler.enter("updateConnectorHierarchy detach removed connectors"); + /* * Connector is in maybeDetached at this point if it has been * removed from its parent but not added to any other parent @@ -2100,6 +2129,8 @@ public class ApplicationConnection { recursivelyDetach(removed, result.events); } + Profiler.leave("updateConnectorHierarchy detach removed connectors"); + Profiler.leave("updateConnectorHierarchy"); return result; @@ -2116,27 +2147,44 @@ public class ApplicationConnection { * is the closest we can get without data from the server. * #10151 */ + Profiler.enter("ApplicationConnection recursivelyDetach reset state"); try { + Profiler.enter("ApplicationConnection recursivelyDetach reset state - getStateType"); Type stateType = AbstractConnector.getStateType(connector); + Profiler.leave("ApplicationConnection recursivelyDetach reset state - getStateType"); // Empty state instance to get default property values from + Profiler.enter("ApplicationConnection recursivelyDetach reset state - createInstance"); Object defaultState = stateType.createInstance(); + Profiler.leave("ApplicationConnection recursivelyDetach reset state - createInstance"); - SharedState state = connector.getState(); - - JsArrayObject<Property> properties = stateType - .getPropertiesAsArray(); - int size = properties.size(); - for (int i = 0; i < size; i++) { - Property property = properties.get(i); - property.setValue(state, - property.getValue(defaultState)); + if (connector instanceof AbstractConnector) { + // optimization as the loop setting properties is very + // slow, especially on IE8 + replaceState((AbstractConnector) connector, + defaultState); + } else { + SharedState state = connector.getState(); + + Profiler.enter("ApplicationConnection recursivelyDetach reset state - properties"); + JsArrayObject<Property> properties = stateType + .getPropertiesAsArray(); + int size = properties.size(); + for (int i = 0; i < size; i++) { + Property property = properties.get(i); + property.setValue(state, + property.getValue(defaultState)); + } + Profiler.leave("ApplicationConnection recursivelyDetach reset state - properties"); } } catch (NoDataException e) { throw new RuntimeException("Can't reset state for " + Util.getConnectorString(connector), e); + } finally { + Profiler.leave("ApplicationConnection recursivelyDetach reset state"); } + Profiler.enter("ApplicationConnection recursivelyDetach perform detach"); /* * Recursively detach children to make sure they get * setParent(null) and hierarchy change events as needed. @@ -2153,18 +2201,22 @@ public class ApplicationConnection { } recursivelyDetach(child, events); } + Profiler.leave("ApplicationConnection recursivelyDetach perform detach"); /* * Clear child list and parent */ + Profiler.enter("ApplicationConnection recursivelyDetach clear children and parent"); connector .setChildren(Collections.<ServerConnector> emptyList()); connector.setParent(null); + Profiler.leave("ApplicationConnection recursivelyDetach clear children and parent"); /* * Create an artificial hierarchy event for containers to give * it a chance to clean up after its children if it has any */ + Profiler.enter("ApplicationConnection recursivelyDetach create hierarchy event"); if (connector instanceof HasComponentsConnector) { HasComponentsConnector ccc = (HasComponentsConnector) connector; List<ComponentConnector> oldChildren = ccc @@ -2185,8 +2237,15 @@ public class ApplicationConnection { events.add(event); } } + Profiler.leave("ApplicationConnection recursivelyDetach create hierarchy event"); } + private native void replaceState(AbstractConnector connector, + Object defaultState) + /*-{ + connector.@com.vaadin.client.ui.AbstractConnector::state = defaultState; + }-*/; + private void handleRpcInvocations(ValueMap json) { if (json.containsKey("rpc")) { Profiler.enter("handleRpcInvocations"); diff --git a/client/src/com/vaadin/client/ComputedStyle.java b/client/src/com/vaadin/client/ComputedStyle.java index 499d9cd2d6..db8ed037bf 100644 --- a/client/src/com/vaadin/client/ComputedStyle.java +++ b/client/src/com/vaadin/client/ComputedStyle.java @@ -130,11 +130,11 @@ public class ComputedStyle { }-*/; public final int getIntProperty(String name) { - Integer parsed = parseInt(getProperty(name)); - if (parsed != null) { - return parsed.intValue(); - } - return 0; + Profiler.enter("ComputedStyle.getIntProperty"); + String value = getProperty(name); + int result = parseIntNative(value); + Profiler.leave("ComputedStyle.getIntProperty"); + return result; } /** @@ -177,14 +177,20 @@ public class ComputedStyle { } /** - * Takes a String value e.g. "12px" and parses that to int 12. + * Takes a String value e.g. "12px" and parses that to Integer 12. * * @param String * a value starting with a number - * @return int the value from the string before any non-numeric characters. - * If the value cannot be parsed to a number, returns + * @return Integer the value from the string before any non-numeric + * characters. If the value cannot be parsed to a number, returns * <code>null</code>. + * + * @deprecated Since 7.1.4, the method {@link #parseIntNative(String)} is + * used internally and this method does not belong in the public + * API of {@link ComputedStyle}. {@link #parseInt(String)} might + * be removed or moved to a utility class in future versions. */ + @Deprecated public static native Integer parseInt(final String value) /*-{ var number = parseInt(value, 10); @@ -195,4 +201,24 @@ public class ComputedStyle { return @java.lang.Integer::valueOf(I)(number); }-*/; + /** + * Takes a String value e.g. "12px" and parses that to int 12. + * + * <p> + * This method returns 0 for <code>NaN</code>. + * + * @param String + * a value starting with a number + * @return int the value from the string before any non-numeric characters. + * If the value cannot be parsed to a number, returns 0. + */ + private static native int parseIntNative(final String value) + /*-{ + var number = parseInt(value, 10); + if (isNaN(number)) + return 0; + else + return number; + }-*/; + } diff --git a/client/src/com/vaadin/client/LayoutManager.java b/client/src/com/vaadin/client/LayoutManager.java index 1f9884de67..5d27527793 100644 --- a/client/src/com/vaadin/client/LayoutManager.java +++ b/client/src/com/vaadin/client/LayoutManager.java @@ -322,17 +322,22 @@ public class LayoutManager { Collection<ElementResizeListener> listeners = elementResizeListeners .get(element); if (listeners != null) { + Profiler.enter("Layout fire resize events - listeners not null"); + Profiler.enter("ElementResizeListener.onElementResize copy list"); ElementResizeListener[] array = listeners .toArray(new ElementResizeListener[listeners .size()]); + Profiler.leave("ElementResizeListener.onElementResize copy list"); ElementResizeEvent event = new ElementResizeEvent(this, element); for (ElementResizeListener listener : array) { try { String key = null; if (Profiler.isEnabled()) { - key = "ElementReizeListener.onElementReize for " + Profiler.enter("ElementResizeListener.onElementResize construct profiler key"); + key = "ElementResizeListener.onElementResize for " + Util.getSimpleName(listener); + Profiler.leave("ElementResizeListener.onElementResize construct profiler key"); Profiler.enter(key); } @@ -344,6 +349,7 @@ public class LayoutManager { VConsole.error(e); } } + Profiler.leave("Layout fire resize events - listeners not null"); } } listenersToFire.clear(); @@ -716,13 +722,19 @@ public class LayoutManager { private void onConnectorChange(ComponentConnector connector, boolean widthChanged, boolean heightChanged) { Profiler.enter("LayoutManager.onConnectorChange"); + Profiler.enter("LayoutManager.onConnectorChange setNeedsOverflowFix"); setNeedsOverflowFix(connector); + Profiler.leave("LayoutManager.onConnectorChange setNeedsOverflowFix"); + Profiler.enter("LayoutManager.onConnectorChange heightChanged"); if (heightChanged) { currentDependencyTree.markHeightAsChanged(connector); } + Profiler.leave("LayoutManager.onConnectorChange heightChanged"); + Profiler.enter("LayoutManager.onConnectorChange widthChanged"); if (widthChanged) { currentDependencyTree.markWidthAsChanged(connector); } + Profiler.leave("LayoutManager.onConnectorChange widthChanged"); Profiler.leave("LayoutManager.onConnectorChange"); } diff --git a/client/src/com/vaadin/client/Profiler.java b/client/src/com/vaadin/client/Profiler.java index caa512b34e..083f2559b1 100644 --- a/client/src/com/vaadin/client/Profiler.java +++ b/client/src/com/vaadin/client/Profiler.java @@ -224,7 +224,7 @@ public class Profiler { && eventName.equals(stack.get(stack.size() - 2).getName()) && !isBeginEvent) { // back out of sub event - stackTop.addTime(gwtStatsEvent.getMillis()); + stackTop.leave(gwtStatsEvent.getMillis()); stack.removeLast(); stackTop = stack.getLast(); @@ -240,7 +240,7 @@ public class Profiler { return; } Node previousStackTop = stack.removeLast(); - previousStackTop.addTime(gwtStatsEvent.getMillis()); + previousStackTop.leave(gwtStatsEvent.getMillis()); } else { if (!inEvent) { stackTop = stackTop.enterChild(eventName, @@ -273,7 +273,9 @@ public class Profiler { } }); - getConsumer().addProfilerData(stack.getFirst(), totalList); + if (getConsumer() != null) { + getConsumer().addProfilerData(stack.getFirst(), totalList); + } } /** @@ -325,7 +327,9 @@ public class Profiler { return; } - getConsumer().addBootstrapData(timings); + if (getConsumer() != null) { + getConsumer().addBootstrapData(timings); + } } } @@ -386,11 +390,11 @@ public class Profiler { * <b>Warning!</b> This is internal API and should not be used by * applications or add-ons. * - * @since 7.1 + * @since 7.1.4 * @param profilerResultConsumer * the consumer that gets profiler data */ - public static void setProfilerResultConsuer( + public static void setProfilerResultConsumer( ProfilerResultConsumer profilerResultConsumer) { if (consumer != null) { throw new IllegalStateException("The consumer has already been set"); @@ -399,11 +403,7 @@ public class Profiler { } private static ProfilerResultConsumer getConsumer() { - if (consumer == null) { - throw new IllegalStateException("No consumer has been registered"); - } else { - return consumer; - } + return consumer; } private static Logger getLogger() { diff --git a/client/src/com/vaadin/client/debug/internal/ProfilerSection.java b/client/src/com/vaadin/client/debug/internal/ProfilerSection.java index aa40e8ff17..4a2a3a1c38 100644 --- a/client/src/com/vaadin/client/debug/internal/ProfilerSection.java +++ b/client/src/com/vaadin/client/debug/internal/ProfilerSection.java @@ -71,6 +71,9 @@ public class ProfilerSection implements Section { private final LinkedHashMap<String, Node> children = new LinkedHashMap<String, Node>(); private double time = 0; private int count = 0; + private double enterTime = 0; + private double minTime = 1000000000; + private double maxTime = 0; /** * Create a new node with the given name. @@ -96,17 +99,17 @@ public class ProfilerSection implements Section { * * @param name * the name of the child - * @param time + * @param timestamp * the timestamp for when the node is entered * @return the child node object */ - public Node enterChild(String name, double time) { + public Node enterChild(String name, double timestamp) { Node child = children.get(name); if (child == null) { child = new Node(name); children.put(name, child); } - child.time -= time; + child.enterTime = timestamp; child.count++; return child; } @@ -122,6 +125,26 @@ public class ProfilerSection implements Section { } /** + * Gets the minimum time spent for one invocation of this node, + * including time spent in sub nodes + * + * @return the time spent for the fastest invocation, in milliseconds + */ + public double getMinTimeSpent() { + return minTime; + } + + /** + * Gets the maximum time spent for one invocation of this node, + * including time spent in sub nodes + * + * @return the time spent for the slowest invocation, in milliseconds + */ + public double getMaxTimeSpent() { + return maxTime; + } + + /** * Gets the number of times this node has been entered * * @return the number of times the node has been entered @@ -180,7 +203,11 @@ public class ProfilerSection implements Section { + getCount() + " times (" + roundToSignificantFigures(getTimeSpent() / getCount()) - + " ms per time)."; + + " ms per time, min " + + roundToSignificantFigures(getMinTimeSpent()) + + " ms, max " + + roundToSignificantFigures(getMaxTimeSpent()) + + " ms)."; } if (!children.isEmpty()) { double ownTime = getOwnTime(); @@ -221,6 +248,10 @@ public class ProfilerSection implements Section { totalNode.time += getOwnTime(); totalNode.count += getCount(); + totalNode.minTime = Math.min(totalNode.minTime, + getMinTimeSpent()); + totalNode.maxTime = Math.max(totalNode.maxTime, + getMaxTimeSpent()); } for (Node node : children.values()) { node.sumUpTotals(totals); @@ -228,11 +259,18 @@ public class ProfilerSection implements Section { } /** - * @since - * @param time + * @param timestamp */ - public void addTime(double time) { - this.time += time; + public void leave(double timestamp) { + double elapsed = (timestamp - enterTime); + time += elapsed; + enterTime = 0; + if (elapsed < minTime) { + minTime = elapsed; + } + if (elapsed > maxTime) { + maxTime = elapsed; + } } } @@ -245,7 +283,7 @@ public class ProfilerSection implements Section { private final FlowPanel content = new FlowPanel(); public ProfilerSection() { - Profiler.setProfilerResultConsuer(new ProfilerResultConsumer() { + Profiler.setProfilerResultConsumer(new ProfilerResultConsumer() { @Override public void addProfilerData(Node rootNode, List<Node> totals) { double totalTime = 0; diff --git a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java index d384549ee3..6f98e29d03 100644 --- a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java +++ b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java @@ -150,17 +150,23 @@ public abstract class AbstractComponentConnector extends AbstractConnector } Profiler.leave("AbstractComponentConnector.onStateChanged update tab index"); + Profiler.enter("AbstractComponentConnector.onStateChanged AbstractConnector.onStateChanged()"); super.onStateChanged(stateChangeEvent); + Profiler.leave("AbstractComponentConnector.onStateChanged AbstractConnector.onStateChanged()"); // Style names + Profiler.enter("AbstractComponentConnector.onStateChanged updateWidgetStyleNames"); updateWidgetStyleNames(); + Profiler.leave("AbstractComponentConnector.onStateChanged updateWidgetStyleNames"); /* * updateComponentSize need to be after caption update so caption can be * taken into account */ + Profiler.enter("AbstractComponentConnector.onStateChanged updateComponentSize"); updateComponentSize(); + Profiler.leave("AbstractComponentConnector.onStateChanged updateComponentSize"); Profiler.enter("AbstractComponentContainer.onStateChanged check tooltip"); if (!tooltipListenersAttached && hasTooltip()) { diff --git a/client/src/com/vaadin/client/ui/VCssLayout.java b/client/src/com/vaadin/client/ui/VCssLayout.java index 4357116707..e4fac6acb3 100644 --- a/client/src/com/vaadin/client/ui/VCssLayout.java +++ b/client/src/com/vaadin/client/ui/VCssLayout.java @@ -44,13 +44,25 @@ public class VCssLayout extends FlowPanel { public void addOrMove(Widget child, int index) { Profiler.enter("VCssLayout.addOrMove"); if (child.getParent() == this) { + Profiler.enter("VCssLayout.addOrMove getWidgetIndex"); int currentIndex = getWidgetIndex(child); + Profiler.leave("VCssLayout.addOrMove getWidgetIndex"); if (index == currentIndex) { Profiler.leave("VCssLayout.addOrMove"); return; } + } else if (index == getWidgetCount()) { + // optimized path for appending components - faster especially for + // initial rendering + Profiler.enter("VCssLayout.addOrMove add"); + add(child); + Profiler.leave("VCssLayout.addOrMove add"); + Profiler.leave("VCssLayout.addOrMove"); + return; } + Profiler.enter("VCssLayout.addOrMove insert"); insert(child, index); + Profiler.leave("VCssLayout.addOrMove insert"); Profiler.leave("VCssLayout.addOrMove"); } } diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index a5c1e566ca..7aac581008 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -1803,6 +1803,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, || suggestionPopup.isJustClosed()) { // typing so fast the popup was never opened, or it's just // closed + waitingForFilteringResponse = false; suggestionPopup.menu.doSelectedItemAction(); } if (selectedOptionKey == null) { diff --git a/client/src/com/vaadin/client/ui/VPopupCalendar.java b/client/src/com/vaadin/client/ui/VPopupCalendar.java index e431da127d..57a0222118 100644 --- a/client/src/com/vaadin/client/ui/VPopupCalendar.java +++ b/client/src/com/vaadin/client/ui/VPopupCalendar.java @@ -217,9 +217,6 @@ public class VPopupCalendar extends VTextualDate implements Field, } } } - if (isImmediate()) { - getClient().sendPendingVariableChanges(); - } } } diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java index fd28e4137e..18df2222a4 100644 --- a/client/src/com/vaadin/client/ui/VWindow.java +++ b/client/src/com/vaadin/client/ui/VWindow.java @@ -536,6 +536,37 @@ public class VWindow extends VWindowOverlay implements if (!visibilityChangesDisabled) { super.setVisible(visible); } + + if (visible && BrowserInfo.get().isWebkit()) { + + /* + * Shake up the DOM a bit to make the window shed unnecessary + * scrollbars and resize correctly afterwards. This resulting code + * took over a week to summon forth, and involved some pretty hairy + * black magic. Don't touch it unless you know what you're doing! + * Fixes ticket #11994 + */ + Scheduler.get().scheduleFinally(new ScheduledCommand() { + @Override + public void execute() { + final com.google.gwt.dom.client.Element scrollable = contents + .getFirstChildElement(); + final String oldWidth = scrollable.getStyle().getWidth(); + final String oldHeight = scrollable.getStyle().getHeight(); + + scrollable.getStyle().setWidth(110, Unit.PCT); + scrollable.getOffsetWidth(); + scrollable.getStyle().setProperty("width", oldWidth); + + scrollable.getStyle().setHeight(110, Unit.PCT); + scrollable.getOffsetHeight(); + scrollable.getStyle().setProperty("height", oldHeight); + + updateContentsSize(); + positionOrSizeUpdated(); + } + }); + } } /** For internal use only. May be removed or replaced in the future. */ diff --git a/client/src/com/vaadin/client/ui/csslayout/CssLayoutConnector.java b/client/src/com/vaadin/client/ui/csslayout/CssLayoutConnector.java index 4c8d1a3ecc..45e52c890e 100644 --- a/client/src/com/vaadin/client/ui/csslayout/CssLayoutConnector.java +++ b/client/src/com/vaadin/client/ui/csslayout/CssLayoutConnector.java @@ -22,6 +22,7 @@ import com.vaadin.client.BrowserInfo; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.FastStringMap; +import com.vaadin.client.Profiler; import com.vaadin.client.Util; import com.vaadin.client.VCaption; import com.vaadin.client.communication.StateChangeEvent; @@ -120,6 +121,8 @@ public class CssLayoutConnector extends AbstractLayoutConnector { */ @Override public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + Profiler.enter("CssLayoutConnector.onConnectorHierarchyChange"); + Profiler.enter("CssLayoutConnector.onConnectorHierarchyChange add children"); int index = 0; for (ComponentConnector child : getChildComponents()) { VCaption childCaption = childIdToCaption @@ -129,8 +132,10 @@ public class CssLayoutConnector extends AbstractLayoutConnector { } getWidget().addOrMove(child.getWidget(), index++); } + Profiler.leave("CssLayoutConnector.onConnectorHierarchyChange add children"); // Detach old child widgets and possibly their caption + Profiler.enter("CssLayoutConnector.onConnectorHierarchyChange remove old children"); for (ComponentConnector child : event.getOldChildren()) { if (child.getParent() == this) { // Skip current children @@ -143,6 +148,8 @@ public class CssLayoutConnector extends AbstractLayoutConnector { getWidget().remove(vCaption); } } + Profiler.leave("CssLayoutConnector.onConnectorHierarchyChange remove old children"); + Profiler.leave("CssLayoutConnector.onConnectorHierarchyChange"); } /** diff --git a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java index 7257af4a08..627478ebe5 100644 --- a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java +++ b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java @@ -18,6 +18,9 @@ package com.vaadin.client.ui.datefield; import java.util.Date; +import com.google.gwt.event.logical.shared.CloseEvent; +import com.google.gwt.event.logical.shared.CloseHandler; +import com.google.gwt.user.client.ui.PopupPanel; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.DateTimeService; import com.vaadin.client.UIDL; @@ -36,6 +39,35 @@ public class PopupDateFieldConnector extends TextualDateConnector { /* * (non-Javadoc) * + * @see com.vaadin.client.ui.AbstractConnector#init() + */ + @Override + protected void init() { + getWidget().popup.addCloseHandler(new CloseHandler<PopupPanel>() { + + @Override + public void onClose(CloseEvent<PopupPanel> event) { + /* + * FIXME This is a hack so we do not have to rewrite half of the + * datefield so values are not sent while selecting a date + * (#6252). + * + * The datefield will now only set the date UIDL variables while + * the user is selecting year/month/date/time and not send them + * directly. Only when the user closes the popup (by clicking on + * a day/enter/clicking outside of popup) then the new value is + * communicated to the server. + */ + if (getWidget().isImmediate()) { + getConnection().sendPendingVariableChanges(); + } + } + }); + } + + /* + * (non-Javadoc) + * * @see com.vaadin.client.ui.VTextualDate#updateFromUIDL(com.vaadin * .client.UIDL, com.vaadin.client.ApplicationConnection) */ diff --git a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java index dd838fdeff..b4cf008a38 100644 --- a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java +++ b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java @@ -93,9 +93,7 @@ public class VDragAndDropManager { targetElement = targetNode.getParentElement(); } - if (Util.isTouchEvent(nativeEvent) - || (dragElement != null && dragElement - .isOrHasChild(targetElement))) { + if (Util.isTouchEvent(nativeEvent) || dragElement != null) { // to detect the "real" target, hide dragelement temporary and // use elementFromPoint String display = dragElement.getStyle().getDisplay(); diff --git a/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java b/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java index 2ce45623d0..e148742b0b 100644 --- a/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java +++ b/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java @@ -26,6 +26,7 @@ import com.vaadin.client.FastStringMap; import com.vaadin.client.FastStringSet; import com.vaadin.client.HasComponentsConnector; import com.vaadin.client.JsArrayObject; +import com.vaadin.client.Profiler; import com.vaadin.client.ServerConnector; import com.vaadin.client.Util; import com.vaadin.client.VConsole; @@ -267,6 +268,7 @@ public class LayoutDependencyTree { } public void markSizeAsChanged() { + Profiler.enter("LayoutDependency.markSizeAsChanged phase 1"); // When the size has changed, all that use that size should be // layouted JsArrayString needsSizeForLayout = getNeedsSizeForLayout(); @@ -276,14 +278,20 @@ public class LayoutDependencyTree { LayoutDependency layoutDependency = getDependency(connectorId, direction); if (layoutDependency.connector instanceof ManagedLayout) { + Profiler.enter("LayoutDependency.markSizeAsChanged setNeedsLayout"); layoutDependency.setNeedsLayout(true); + Profiler.leave("LayoutDependency.markSizeAsChanged setNeedsLayout"); } else { + Profiler.enter("LayoutDependency.markSizeAsChanged propagatePostLayoutMeasure"); // Should simulate setNeedsLayout(true) + markAsLayouted -> // propagate needs measure layoutDependency.propagatePostLayoutMeasure(); + Profiler.leave("LayoutDependency.markSizeAsChanged propagatePostLayoutMeasure"); } } + Profiler.leave("LayoutDependency.markSizeAsChanged phase 1"); + Profiler.enter("LayoutDependency.markSizeAsChanged scrollbars"); // Should also go through the hierarchy to discover appeared or // disappeared scrollbars ComponentConnector scrollingBoundary = getScrollingBoundary(connector); @@ -291,6 +299,7 @@ public class LayoutDependencyTree { getDependency(scrollingBoundary.getConnectorId(), getOppositeDirection()).setNeedsMeasure(true); } + Profiler.leave("LayoutDependency.markSizeAsChanged scrollbars"); } @@ -332,22 +341,28 @@ public class LayoutDependencyTree { } private void propagatePostLayoutMeasure() { + Profiler.enter("LayoutDependency.propagatePostLayoutMeasure getResizedByLayout"); JsArrayString resizedByLayout = getResizedByLayout(); + Profiler.leave("LayoutDependency.propagatePostLayoutMeasure getResizedByLayout"); int length = resizedByLayout.length(); for (int i = 0; i < length; i++) { + Profiler.enter("LayoutDependency.propagatePostLayoutMeasure setNeedsMeasure"); String resizedId = resizedByLayout.get(i); LayoutDependency layoutDependency = getDependency(resizedId, direction); layoutDependency.setNeedsMeasure(true); + Profiler.leave("LayoutDependency.propagatePostLayoutMeasure setNeedsMeasure"); } // Special case for e.g. wrapping texts + Profiler.enter("LayoutDependency.propagatePostLayoutMeasure horizontal case"); if (direction == HORIZONTAL && !connector.isUndefinedWidth() && connector.isUndefinedHeight()) { LayoutDependency dependency = getDependency( connector.getConnectorId(), VERTICAL); dependency.setNeedsMeasure(true); } + Profiler.leave("LayoutDependency.propagatePostLayoutMeasure horizontal case"); } @Override diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java index cea993310f..e0dc0d51df 100644 --- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java +++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -294,7 +294,11 @@ public abstract class AbstractOrderedLayoutConnector extends int currentIndex = 0; VAbstractOrderedLayout layout = getWidget(); - layout.setSpacing(getState().spacing); + // remove spacing as it is exists as separate elements that cannot be + // removed easily after reordering the contents + Profiler.enter("AOLC.onConnectorHierarchyChange addOrMoveSlot temporarily remove spacing"); + layout.setSpacing(false); + Profiler.leave("AOLC.onConnectorHierarchyChange addOrMoveSlot temporarily remove spacing"); for (ComponentConnector child : getChildComponents()) { Profiler.enter("AOLC.onConnectorHierarchyChange add children"); @@ -305,12 +309,20 @@ public abstract class AbstractOrderedLayoutConnector extends Profiler.leave("AOLC.onConnectorHierarchyChange add state change handler"); } Profiler.enter("AOLC.onConnectorHierarchyChange addOrMoveSlot"); - layout.addOrMoveSlot(slot, currentIndex++); + layout.addOrMoveSlot(slot, currentIndex++, false); Profiler.leave("AOLC.onConnectorHierarchyChange addOrMoveSlot"); Profiler.leave("AOLC.onConnectorHierarchyChange add children"); } + // re-add spacing for the elements that should have it + Profiler.enter("AOLC.onConnectorHierarchyChange addOrMoveSlot setSpacing"); + // spacings were removed above + if (getState().spacing) { + layout.setSpacing(true); + } + Profiler.leave("AOLC.onConnectorHierarchyChange addOrMoveSlot setSpacing"); + for (ComponentConnector child : previousChildren) { Profiler.enter("AOLC.onConnectorHierarchyChange remove children"); if (child.getParent() != this) { @@ -325,7 +337,7 @@ public abstract class AbstractOrderedLayoutConnector extends child.removeStateChangeHandler(childStateChangeHandler); layout.removeWidget(child.getWidget()); } - Profiler.leave("AOL.onConnectorHierarchyChange remove children"); + Profiler.leave("AOLC.onConnectorHierarchyChange remove children"); } Profiler.leave("AOLC.onConnectorHierarchyChange"); @@ -363,6 +375,7 @@ public abstract class AbstractOrderedLayoutConnector extends Slot slot = Util.findWidget( (com.google.gwt.user.client.Element) element, Slot.class); if (slot != null && slot.getCaptionElement() != null + && slot.getParent() == getWidget() && slot.getCaptionElement().isOrHasChild(element)) { ComponentConnector connector = Util.findConnectorFor(slot .getWidget()); diff --git a/client/src/com/vaadin/client/ui/orderedlayout/VAbstractOrderedLayout.java b/client/src/com/vaadin/client/ui/orderedlayout/VAbstractOrderedLayout.java index b5a6262693..54c9eb6c68 100644 --- a/client/src/com/vaadin/client/ui/orderedlayout/VAbstractOrderedLayout.java +++ b/client/src/com/vaadin/client/ui/orderedlayout/VAbstractOrderedLayout.java @@ -31,6 +31,7 @@ import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.BrowserInfo; import com.vaadin.client.LayoutManager; +import com.vaadin.client.Profiler; import com.vaadin.client.Util; import com.vaadin.shared.ui.MarginInfo; @@ -63,6 +64,23 @@ public class VAbstractOrderedLayout extends FlowPanel { } /** + * See the method {@link #addOrMoveSlot(Slot, int, boolean)}. + * + * <p> + * This method always adjusts spacings for the whole layout. + * + * @param slot + * The slot to move or add + * @param index + * The index where the slot should be placed. + * @deprecated since 7.1.4, use {@link #addOrMoveSlot(Slot, int, boolean)} + */ + @Deprecated + public void addOrMoveSlot(Slot slot, int index) { + addOrMoveSlot(slot, index, true); + } + + /** * Add or move a slot to another index. * <p> * For internal use only. May be removed or replaced in the future. @@ -83,27 +101,42 @@ public class VAbstractOrderedLayout extends FlowPanel { * </pre> * * When using this method never account for spacings. + * <p> + * The caller should remove all spacings before calling this method and + * re-add them (if necessary) after this method. This can be done before and + * after all slots have been added/moved. * </p> * + * @since 7.1.4 + * * @param slot * The slot to move or add * @param index * The index where the slot should be placed. + * @param adjustSpacing + * true to recalculate spacings for the whole layout after the + * operation */ - public void addOrMoveSlot(Slot slot, int index) { + public void addOrMoveSlot(Slot slot, int index, boolean adjustSpacing) { + Profiler.enter("VAOL.onConnectorHierarchyChange addOrMoveSlot find index"); if (slot.getParent() == this) { int currentIndex = getWidgetIndex(slot); if (index == currentIndex) { + Profiler.leave("VAOL.onConnectorHierarchyChange addOrMoveSlot find index"); return; } } + Profiler.leave("VAOL.onConnectorHierarchyChange addOrMoveSlot find index"); + Profiler.enter("VAOL.onConnectorHierarchyChange addOrMoveSlot insert"); insert(slot, index); + Profiler.leave("VAOL.onConnectorHierarchyChange addOrMoveSlot insert"); - /* - * We need to confirm spacings are correctly applied after each insert. - */ - setSpacing(spacing); + if (adjustSpacing) { + Profiler.enter("VAOL.onConnectorHierarchyChange addOrMoveSlot setSpacing"); + setSpacing(spacing); + Profiler.leave("VAOL.onConnectorHierarchyChange addOrMoveSlot setSpacing"); + } } /** @@ -329,14 +362,18 @@ public class VAbstractOrderedLayout extends FlowPanel { * True if spacing should be used, false if not */ public void setSpacing(boolean spacing) { + Profiler.enter("VAOL.onConnectorHierarchyChange setSpacing"); this.spacing = spacing; + // first widget does not have spacing on + // optimization to avoid looking up widget indices on every iteration + Widget firstSlot = null; + if (getWidgetCount() > 0) { + firstSlot = getWidget(0); + } for (Slot slot : widgetToSlot.values()) { - if (getWidgetIndex(slot) > 0) { - slot.setSpacing(spacing); - } else { - slot.setSpacing(false); - } + slot.setSpacing(spacing && firstSlot != slot); } + Profiler.leave("VAOL.onConnectorHierarchyChange setSpacing"); } /** diff --git a/client/src/com/vaadin/client/ui/panel/PanelConnector.java b/client/src/com/vaadin/client/ui/panel/PanelConnector.java index fe211901c9..4011f86c76 100644 --- a/client/src/com/vaadin/client/ui/panel/PanelConnector.java +++ b/client/src/com/vaadin/client/ui/panel/PanelConnector.java @@ -23,6 +23,7 @@ import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.LayoutManager; import com.vaadin.client.Paintable; +import com.vaadin.client.Profiler; import com.vaadin.client.UIDL; import com.vaadin.client.ui.AbstractSingleComponentContainerConnector; import com.vaadin.client.ui.ClickEventHandler; @@ -194,22 +195,31 @@ public class PanelConnector extends AbstractSingleComponentContainerConnector VPanel panel = getWidget(); LayoutManager layoutManager = getLayoutManager(); + Profiler.enter("PanelConnector.layout getHeights"); int top = layoutManager.getOuterHeight(panel.captionNode); int bottom = layoutManager.getInnerHeight(panel.bottomDecoration); + Profiler.leave("PanelConnector.layout getHeights"); + Profiler.enter("PanelConnector.layout modify style"); Style style = panel.getElement().getStyle(); panel.captionNode.getParentElement().getStyle() .setMarginTop(-top, Unit.PX); panel.bottomDecoration.getStyle().setMarginBottom(-bottom, Unit.PX); style.setPaddingTop(top, Unit.PX); style.setPaddingBottom(bottom, Unit.PX); + Profiler.leave("PanelConnector.layout modify style"); // Update scroll positions + Profiler.enter("PanelConnector.layout update scroll positions"); panel.contentNode.setScrollTop(panel.scrollTop); panel.contentNode.setScrollLeft(panel.scrollLeft); + Profiler.leave("PanelConnector.layout update scroll positions"); + // Read actual value back to ensure update logic is correct + Profiler.enter("PanelConnector.layout read scroll positions"); panel.scrollTop = panel.contentNode.getScrollTop(); panel.scrollLeft = panel.contentNode.getScrollLeft(); + Profiler.leave("PanelConnector.layout read scroll positions"); } @Override |