From 7112abe944259a615e26342de17d0302ddec3562 Mon Sep 17 00:00:00 2001 From: Fabian Lange Date: Wed, 26 Feb 2014 19:17:21 +0100 Subject: Preventing premature start of drag due to Chrome move event #13381 The drag only actually starts when the mouse move or touch move event is more than 3 pixel away. The purpose is twofold: a) it fixes the glitchy behaviour of Chrome which for some reason sometimes fires a move directly after the mousedown, which starts a drag immediately. b) it helps people with shaky hands or imprecise hardware, why might not want to drag but to select but slightly move the pointer. Some frameworks opted to make the distance configurable. Due to sub pixels (which might be the cause for a) in the first place), a distance of 1 or 2 pixel is not enough. Experiments showed that unaware users did not notice that 3 pixels movement are required for the drag to actually start (the ghost has already a delay of 300ms) Change-Id: I71b50b72486344a7dbe4ed927b34b1f8fab0db20 --- .../com/vaadin/client/ui/dd/VDragAndDropManager.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java index b911c28a07..7de40f9496 100644 --- a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java +++ b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java @@ -422,13 +422,20 @@ public class VDragAndDropManager { } case Event.ONMOUSEMOVE: case Event.ONTOUCHMOVE: - if (deferredStartRegistration != null) { - deferredStartRegistration.removeHandler(); - deferredStartRegistration = null; + // only start the drag if the mouse / touch has moved a minimum distance + int startX = Util.getTouchOrMouseClientX(currentDrag.getCurrentGwtEvent()); + int startY = Util.getTouchOrMouseClientY(currentDrag.getCurrentGwtEvent()); + int nowX = Util.getTouchOrMouseClientX(event.getNativeEvent()); + int nowY = Util.getTouchOrMouseClientY(event.getNativeEvent()); + if (Math.abs(startX - nowX) > 3 || Math.abs(startY - nowY) > 3) { + if (deferredStartRegistration != null) { + deferredStartRegistration.removeHandler(); + deferredStartRegistration = null; + } + currentDrag.setCurrentGwtEvent(event + .getNativeEvent()); + startDrag.execute(); } - currentDrag.setCurrentGwtEvent(event - .getNativeEvent()); - startDrag.execute(); break; default: // on any other events, clean up the -- cgit v1.2.3 From 7e7b6239ca8867d13e8d8b279a0541bfd71466f7 Mon Sep 17 00:00:00 2001 From: Fabian Lange Date: Wed, 12 Mar 2014 12:47:00 +0100 Subject: reduce frequency of session locking and StreamingProgressEvents (#13155) This change introduces throttling of streaming progress events. Before a event was fired once a buffer was filled. However as the buffer is only 4kb in size, fast uploads would trigger massive amounts of events. This change is backwards incompatible on a logical level. Before this change, a listener would get contentLength/4kb events, while after this change the amount is limited to one progress event per 500ms. Change-Id: I5da092ec4488971b8554b68b44c346057bfcc0e0 --- .../server/communication/FileUploadHandler.java | 49 ++++++++++++++++------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java index 3f6bfd9267..88f2e4b120 100644 --- a/server/src/com/vaadin/server/communication/FileUploadHandler.java +++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java @@ -227,6 +227,9 @@ public class FileUploadHandler implements RequestHandler { /* Same as in apache commons file upload library that was previously used. */ private static final int MAX_UPLOAD_BUFFER_SIZE = 4 * 1024; + /* Minimum interval which will be used for streaming progress events. */ + public static final int DEFAULT_STREAMING_PROGRESS_EVENT_INTERVAL_MS = 500; + @Override public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { @@ -537,26 +540,35 @@ public class FileUploadHandler implements RequestHandler { } final byte buffer[] = new byte[MAX_UPLOAD_BUFFER_SIZE]; + long lastStreamingEvent = 0; int bytesReadToBuffer = 0; - while ((bytesReadToBuffer = in.read(buffer)) > 0) { - out.write(buffer, 0, bytesReadToBuffer); - totalBytes += bytesReadToBuffer; + do { + bytesReadToBuffer = in.read(buffer); + if (bytesReadToBuffer > 0) { + out.write(buffer, 0, bytesReadToBuffer); + totalBytes += bytesReadToBuffer; + } if (listenProgress) { - // update progress if listener set and contentLength - // received - session.lock(); - try { - StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl( - filename, type, contentLength, totalBytes); - streamVariable.onProgress(progressEvent); - } finally { - session.unlock(); + long now = System.currentTimeMillis(); + // to avoid excessive session locking and event storms, + // events are sent in intervals, or at the end of the file. + if (lastStreamingEvent + getProgressEventInterval() <= now + || bytesReadToBuffer <= 0) { + lastStreamingEvent = now; + session.lock(); + try { + StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl( + filename, type, contentLength, totalBytes); + streamVariable.onProgress(progressEvent); + } finally { + session.unlock(); + } } } if (streamVariable.isInterrupted()) { throw new UploadInterruptedException(); } - } + } while (bytesReadToBuffer > 0); // upload successful out.close(); @@ -599,6 +611,17 @@ public class FileUploadHandler implements RequestHandler { return startedEvent.isDisposed(); } + /** + * To prevent event storming, streaming progress events are sent in this + * interval rather than every time the buffer is filled. This fixes #13155. + * To adjust this value override the method, and register your own handler + * in VaadinService.createRequestHandlers(). The default is 500ms, and + * setting it to 0 effectively restores the old behavior. + */ + protected int getProgressEventInterval() { + return DEFAULT_STREAMING_PROGRESS_EVENT_INTERVAL_MS; + } + static void tryToCloseStream(OutputStream out) { try { // try to close output stream (e.g. file handle) -- cgit v1.2.3 From 7cab7fd80f85b9a7846b1d771aa3dce592ae5d42 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 13 Mar 2014 13:23:21 +0200 Subject: Improve error message when reusing UI instance (#13457) Change-Id: I49ec1e837a1a2a04dfadef5fd5fb5b6fd10ffcbc --- server/src/com/vaadin/ui/UI.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 746fa194ac..0412cb1882 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -601,7 +601,18 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ public void doInit(VaadinRequest request, int uiId) { if (this.uiId != -1) { - throw new IllegalStateException("UI id has already been defined"); + String message = "This UI instance is already initialized (as UI id " + + this.uiId + + ") and can therefore not be initialized again (as UI id " + + uiId + "). "; + + if (getSession() != null + && !getSession().equals(VaadinSession.getCurrent())) { + message += "Furthermore, it is already attached to another VaadinSession. "; + } + message += "Please make sure you are not accidentally reusing an old UI instance."; + + throw new IllegalStateException(message); } this.uiId = uiId; -- cgit v1.2.3 From 3e53fa6d15edb11f938095f70ba4bc292d422b5c Mon Sep 17 00:00:00 2001 From: Teemu Pöntelin Date: Fri, 14 Mar 2014 00:41:42 +0200 Subject: Fixed "EEE" in DateField's date pattern (#13443) Change-Id: Ib82d901fbf65dc39c06b117c68bb0191f0fd8e68 --- client/src/com/vaadin/client/DateTimeService.java | 2 +- .../components/datefield/CustomDateFormatEEE.java | 59 ++++++++++++++++++++++ .../datefield/CustomDateFormatEEETest.java | 36 +++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 uitest/src/com/vaadin/tests/components/datefield/CustomDateFormatEEE.java create mode 100644 uitest/src/com/vaadin/tests/components/datefield/CustomDateFormatEEETest.java diff --git a/client/src/com/vaadin/client/DateTimeService.java b/client/src/com/vaadin/client/DateTimeService.java index 5fd0574d3e..2388bd38fb 100644 --- a/client/src/com/vaadin/client/DateTimeService.java +++ b/client/src/com/vaadin/client/DateTimeService.java @@ -344,7 +344,7 @@ public class DateTimeService { if (formatStr.contains("EEE")) { - String dayName = getShortDay(date.getMonth()); + String dayName = getShortDay(date.getDay()); if (dayName != null) { /* diff --git a/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormatEEE.java b/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormatEEE.java new file mode 100644 index 0000000000..ce9d021c79 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormatEEE.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2013 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.tests.components.datefield; + +import java.util.Calendar; +import java.util.Locale; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.datefield.Resolution; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.DateField; +import com.vaadin.ui.VerticalLayout; + +public class CustomDateFormatEEE extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + Calendar cal = Calendar.getInstance(); + cal.set(2014, 2, 14); // Friday + + DateField df = new DateField("Should display 14/03/2014 Fri"); + df.setResolution(Resolution.DAY); + df.setLocale(new Locale("en", "US")); + + String pattern = "dd/MM/yyyy EEE"; + df.setDateFormat(pattern); + df.setValue(cal.getTime()); + df.setWidth("200px"); + + VerticalLayout layout = new VerticalLayout(); + layout.addComponent(df); + layout.setMargin(true); + setContent(layout); + } + + @Override + protected String getTestDescription() { + return "Verifies that \"EEE\" works as a part of custom date pattern"; + } + + @Override + protected Integer getTicketNumber() { + return 13443; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormatEEETest.java b/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormatEEETest.java new file mode 100644 index 0000000000..286da85f06 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormatEEETest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2013 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.tests.components.datefield; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.openqa.selenium.By; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class CustomDateFormatEEETest extends MultiBrowserTest { + + @Test + public void verifyDatePattern() { + openTestURL(); + + String dateValue = driver.findElement( + By.className("v-datefield-textfield")).getAttribute("value"); + assertEquals("14/03/2014 Fri", dateValue); + } + +} -- cgit v1.2.3 From 1881ea8afd23e79a6ebbc9ce051944e14c696fd1 Mon Sep 17 00:00:00 2001 From: Teemu Pöntelin Date: Tue, 11 Mar 2014 19:45:38 +0200 Subject: Fix for width issue of TabSheet (#12805) Width of v-tabsheet-tabcontainer was set by copying the width from the ComponentConnector. This produced an incorrect result when a relative width (other than 100%) was used. Fixed by assigning the width to 100% when the TabSheet has a defined width. Change-Id: I7f128f87406e6e00ceda9ee6e75dcc5539e283b6 --- client/src/com/vaadin/client/ui/VTabsheet.java | 4 +- .../tests/components/tabsheet/TabBarWidth.java | 105 +++++++++++++++++++++ .../tests/components/tabsheet/TabBarWidthTest.java | 41 ++++++++ 3 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/tabsheet/TabBarWidth.java create mode 100644 uitest/src/com/vaadin/tests/components/tabsheet/TabBarWidthTest.java diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java index a3d96983e8..7d87650e24 100644 --- a/client/src/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/com/vaadin/client/ui/VTabsheet.java @@ -955,9 +955,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, */ private void updateTabScroller() { if (!isDynamicWidth()) { - ComponentConnector paintable = ConnectorMap.get(client) - .getConnector(this); - DOM.setStyleAttribute(tabs, "width", paintable.getState().width); + DOM.setStyleAttribute(tabs, "width", "100%"); } // Make sure scrollerIndex is valid diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabBarWidth.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabBarWidth.java new file mode 100644 index 0000000000..01bce334db --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabBarWidth.java @@ -0,0 +1,105 @@ +/* + * Copyright 2000-2013 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.tests.components.tabsheet; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Component; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.VerticalLayout; + +/** + * Tests the width of the tab bar, especially when using relative width for the + * {@link TabSheet}. + * + * Created for ticket #12805. + */ +public class TabBarWidth extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final VerticalLayout layout = new VerticalLayout(); + layout.setMargin(true); + layout.setSpacing(true); + layout.setWidth("500px"); + setContent(layout); + + // Add a Button to toggle between the widths and undefined. + Button toggle = new Button("Toggle widths", new Button.ClickListener() { + + private boolean removeWidths = true; + + @Override + public void buttonClick(ClickEvent event) { + restoreOrRemoveWidths(layout, removeWidths); + removeWidths = !removeWidths; + } + }); + toggle.setId("toggleWidths"); + layout.addComponent(toggle); + + // Add TabSheets with different widths specified. + layout.addComponent(newTabSheet(null)); + layout.addComponent(newTabSheet("100%")); + layout.addComponent(newTabSheet("75%")); + layout.addComponent(newTabSheet("50%")); + layout.addComponent(newTabSheet("150px")); + } + + @Override + protected String getTestDescription() { + return "Tests the width of the tab bar."; + } + + @Override + protected Integer getTicketNumber() { + return 12805; + } + + private void restoreOrRemoveWidths(VerticalLayout layout, + boolean removeWidths) { + for (Component component : layout) { + if (component instanceof TabSheet) { + if (removeWidths) { + component.setWidth(null); + component.setCaption("Width: undefined"); + } else { + String originalWidth = (String) ((TabSheet) component) + .getData(); + component.setWidth(originalWidth); + component.setCaption("Width: " + + (originalWidth == null ? "undefined" + : originalWidth)); + } + } + } + } + + private TabSheet newTabSheet(String width) { + TabSheet tabSheet = new TabSheet(); + tabSheet.setCaption("Width: " + (width == null ? "undefined" : width)); + tabSheet.setWidth(width); + tabSheet.setData(width); + + // Add dummy components to fill the TabSheet. + for (int i = 1; i <= 10; i++) { + tabSheet.addComponent(new Button(i + ". tab")); + } + return tabSheet; + } +} diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabBarWidthTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabBarWidthTest.java new file mode 100644 index 0000000000..f09a68d576 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabBarWidthTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2013 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.tests.components.tabsheet; + +import org.junit.Test; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TabBarWidthTest extends MultiBrowserTest { + + @Test + public void testWidths() throws Exception { + openTestURL(); + + // Initial rendering. + compareScreen("tab-bar-width-init"); + + // Remove all widths. + vaadinElementById("toggleWidths").click(); + compareScreen("tab-bar-width-undefined"); + + // Restore all widths. This should restore the rendering to the same + // point as the initial rendering. + vaadinElementById("toggleWidths").click(); + compareScreen("tab-bar-width-restored"); + } + +} -- cgit v1.2.3 From 396820e96208a783ed51f718b4c9a152c3a99ba5 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 7 Mar 2014 21:21:03 +0200 Subject: Test for streaming reconnect issue (#13435) Change-Id: Ibf04105a1ffe2c22726d628a0aba4668569d45d2 --- .../tests/push/StreamingReconnectWhilePushing.java | 75 ++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/push/StreamingReconnectWhilePushing.java diff --git a/uitest/src/com/vaadin/tests/push/StreamingReconnectWhilePushing.java b/uitest/src/com/vaadin/tests/push/StreamingReconnectWhilePushing.java new file mode 100644 index 0000000000..5a3460a290 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/StreamingReconnectWhilePushing.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2013 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.tests.push; + +import com.vaadin.annotations.Push; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.ui.Transport; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Label; + +@Push(transport = Transport.STREAMING) +public class StreamingReconnectWhilePushing extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + + Button button = new Button("Click Me"); + button.addClickListener(new Button.ClickListener() { + private Label label; + + @Override + public void buttonClick(ClickEvent event) { + if (label == null) { + label = new Label(); + label.setValue(getString(1000000)); + addComponent(label); + } else { + label.setValue("." + label.getValue()); + } + + } + }); + addComponent(button); + + } + + protected String getString(int len) { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < len; i++) { + if (i % 100 == 0) { + b.append("\n"); + } else { + b.append('A'); + } + + } + return b.toString(); + } + + @Override + protected String getTestDescription() { + return "Each push of the button sends about 1MB to the client. Press it a couple of times and a spinner will appear forever if reconnecting does not work."; + } + + @Override + protected Integer getTicketNumber() { + return 13435; + } + +} -- cgit v1.2.3 From 2f9318610ca83902060173bf0caae1a2fe385f21 Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Fri, 14 Mar 2014 12:20:08 +0200 Subject: Eliminate .v-caption memory leak (#13346) Change-Id: I6577dabaaf5d9fa4c73158d3391dfcd28dd0629e --- .../AbstractOrderedLayoutConnector.java | 3 +- .../components/orderedlayout/CaptionLeak.java | 62 ++++++++++++++++++++ .../components/orderedlayout/CaptionLeakTest.java | 68 ++++++++++++++++++++++ 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeak.java create mode 100644 uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java index 8ee1921ed7..ce73627c88 100644 --- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java +++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -267,8 +267,7 @@ public abstract class AbstractOrderedLayoutConnector extends if (slot.hasCaption()) { CaptionPosition pos = slot.getCaptionPosition(); - getLayoutManager().addElementResizeListener( - slot.getCaptionElement(), slotCaptionResizeListener); + slot.setCaptionResizeListener(slotCaptionResizeListener); if (child.isRelativeHeight() && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) { getWidget().updateCaptionOffset(slot.getCaptionElement()); diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeak.java b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeak.java new file mode 100644 index 0000000000..7d347d6180 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeak.java @@ -0,0 +1,62 @@ +package com.vaadin.tests.components.orderedlayout; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.ui.Button; +import com.vaadin.ui.ComponentContainer; +import com.vaadin.ui.CssLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.Panel; +import com.vaadin.ui.TextField; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; + +/** + * HorizontalLayout and VerticalLayout should not leak caption elements via + * listeners when removing components from a layout. + * + * @since 7.1.13 + * @author Vaadin Ltd + */ +public class CaptionLeak extends UI { + + public static final String USAGE = "Open this UI with ?debug and count" + + " measured non-connector elements after setting leaky and non leaky" + + " content."; + + @Override + public void init(VaadinRequest req) { + final VerticalLayout root = new VerticalLayout(); + setContent(root); + Label usage = new Label(USAGE); + Panel parent = new Panel(); + Button setLeakyContent = makeButton("Set leaky content", parent, + VerticalLayout.class); + Button setNonLeakyContent = makeButton("Set non leaky content", parent, + CssLayout.class); + root.addComponents(usage, setLeakyContent, setNonLeakyContent, parent); + } + + private Button makeButton(String caption, final Panel parent, + final Class targetClass) { + Button btn = new Button(caption); + btn.setId(caption); + btn.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(Button.ClickEvent event) { + try { + ComponentContainer target = targetClass.newInstance(); + for (int i = 0; i < 61; i++) { + target.addComponent(new TextField("Test")); + } + parent.setContent(target); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + }); + return btn; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java new file mode 100644 index 0000000000..142ca00ba7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2000-2013 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.tests.components.orderedlayout; + +import org.junit.Test; +import org.openqa.selenium.By; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class CaptionLeakTest extends MultiBrowserTest { + + @Test + public void testCaptionLeak() throws Exception { + setDebug(true); + openTestURL(); + + // this should be present + // 3 general non-connector elements, none accumulated on click + getDriver() + .findElement( + By.xpath("//span[text() = 'Measured 3 non connector elements']")); + + getDriver().findElement(By.xpath("//button[@title = 'Clear log']")) + .click(); + getDriver().findElement(By.id("Set leaky content")).click(); + + getDriver() + .findElement( + By.xpath("//span[text() = 'Measured 3 non connector elements']")); + + // nothing accumulates over clicks + getDriver().findElement(By.xpath("//button[@title = 'Clear log']")) + .click(); + getDriver().findElement(By.id("Set leaky content")).click(); + getDriver() + .findElement( + By.xpath("//span[text() = 'Measured 3 non connector elements']")); + } + + @Test + public void testNoCaptionLeak() throws Exception { + setDebug(true); + openTestURL(); + + getDriver().findElement(By.xpath("//button[@title = 'Clear log']")) + .click(); + getDriver().findElement(By.id("Set non leaky content")).click(); + + // this should be present + // 3 general non-connector elements, none accumulated on click + getDriver() + .findElement( + By.xpath("//span[text() = 'Measured 3 non connector elements']")); + } +} -- cgit v1.2.3 From 0c7cbc73dba97ad0b95cb11f4b4eabb37046fe61 Mon Sep 17 00:00:00 2001 From: Pekka Hyvönen Date: Fri, 14 Mar 2014 16:17:27 +0200 Subject: Fixes a memory leak on IE8 in LayoutManagerIE8 (#12688) Change-Id: Ieae3b1d82e92fadf5ab517c1c878fc82bcc0ecbd --- client/src/com/vaadin/client/LayoutManager.java | 9 ++ client/src/com/vaadin/client/LayoutManagerIE8.java | 15 ++- .../extensions/LayoutMemoryUsageIE8Extension.java | 36 +++++++ .../tests/layouts/IE8MeasuredSizeMemoryLeak.java | 111 +++++++++++++++++++++ .../layouts/IE8MeasuredSizeMemoryLeakTest.java | 54 ++++++++++ .../LayoutMemoryUsageIE8ExtensionConnector.java | 45 +++++++++ 6 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/extensions/LayoutMemoryUsageIE8Extension.java create mode 100644 uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeak.java create mode 100644 uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeakTest.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/LayoutMemoryUsageIE8ExtensionConnector.java diff --git a/client/src/com/vaadin/client/LayoutManager.java b/client/src/com/vaadin/client/LayoutManager.java index 1ced003146..5b27031a29 100644 --- a/client/src/com/vaadin/client/LayoutManager.java +++ b/client/src/com/vaadin/client/LayoutManager.java @@ -74,6 +74,15 @@ public class LayoutManager { this.connection = connection; } + /** + * Returns the application connection for this layout manager. + * + * @return connection + */ + protected ApplicationConnection getConnection() { + return connection; + } + /** * Gets the layout manager associated with the given * {@link ApplicationConnection}. diff --git a/client/src/com/vaadin/client/LayoutManagerIE8.java b/client/src/com/vaadin/client/LayoutManagerIE8.java index a692f126a2..97e3059a22 100644 --- a/client/src/com/vaadin/client/LayoutManagerIE8.java +++ b/client/src/com/vaadin/client/LayoutManagerIE8.java @@ -21,6 +21,7 @@ import java.util.Map; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Node; import com.google.gwt.user.client.ui.RootPanel; /** @@ -39,6 +40,12 @@ public class LayoutManagerIE8 extends LayoutManager { private Map measuredSizes = new HashMap(); + // this method is needed to test for memory leaks (see + // LayoutMemoryUsageIE8ExtensionConnector) but can be private + private int getMeasuredSizesMapSize() { + return measuredSizes.size(); + } + @Override protected void setMeasuredSize(Element element, MeasuredSize measuredSize) { if (measuredSize != null) { @@ -62,12 +69,16 @@ public class LayoutManagerIE8 extends LayoutManager { @Override protected void cleanMeasuredSizes() { Profiler.enter("LayoutManager.cleanMeasuredSizes"); - Document document = RootPanel.get().getElement().getOwnerDocument(); + + // #12688: IE8 was leaking memory when adding&removing components. + // Uses IE specific logic to figure if an element has been removed from + // DOM or not. For removed elements the measured size is discarded. + Node rootNode = Document.get().getBody(); Iterator i = measuredSizes.keySet().iterator(); while (i.hasNext()) { Element e = i.next(); - if (e.getOwnerDocument() != document) { + if (!rootNode.isOrHasChild(e)) { i.remove(); } } diff --git a/uitest/src/com/vaadin/tests/extensions/LayoutMemoryUsageIE8Extension.java b/uitest/src/com/vaadin/tests/extensions/LayoutMemoryUsageIE8Extension.java new file mode 100644 index 0000000000..c69c2b4d30 --- /dev/null +++ b/uitest/src/com/vaadin/tests/extensions/LayoutMemoryUsageIE8Extension.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2013 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.tests.extensions; + +import com.vaadin.server.AbstractExtension; +import com.vaadin.ui.UI; + +/** + * Test extension for finding out the size of the measuredSizes map of + * LayoutManagerIE8. + * + * This UI extension uses JSNI to register a JavaScript method + * window.vaadin.getMeasuredSizesCount() that can be used to query the size of + * the internal map of the layout manager. It should only be used on IE8. + * + * @since 7.1.13 + * @author Vaadin Ltd + */ +public class LayoutMemoryUsageIE8Extension extends AbstractExtension { + public void extend(UI target) { + super.extend(target); + } +} diff --git a/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeak.java b/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeak.java new file mode 100644 index 0000000000..7da9e46653 --- /dev/null +++ b/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeak.java @@ -0,0 +1,111 @@ +/* + * Copyright 2000-2013 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.tests.layouts; + +import com.vaadin.annotations.Widgetset; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.extensions.LayoutMemoryUsageIE8Extension; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.HasComponents; +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; + +@Widgetset("com.vaadin.tests.widgetset.TestingWidgetSet") +public class IE8MeasuredSizeMemoryLeak extends AbstractTestUI { + + private boolean state = false; + + private HasComponents component1 = new VerticalLayout() { + { + for (int i = 1; i <= 200; i++) { + String idText = "ID:" + i; + Label c = new Label(idText); + c.setId(idText); + addComponent(c); + } + } + }; + + private HasComponents component2 = new VerticalLayout() { + { + for (int i = 201; i <= 400; i++) { + String idText = "ID:" + i; + Label c = new Label(idText); + c.setId(idText); + addComponent(c); + } + } + }; + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + new LayoutMemoryUsageIE8Extension().extend(this); + + VerticalLayout layout = new VerticalLayout(); + setContent(layout); + + final VerticalLayout contentLayout = new VerticalLayout(); + + Button button = new Button("Toggle"); + button.setId("toggle"); + button.addClickListener(new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + contentLayout.removeAllComponents(); + if (state) { + contentLayout.addComponent(component1); + } else { + contentLayout.addComponent(component2); + } + state = !state; + } + + }); + + layout.addComponent(button); + layout.addComponent(contentLayout); + + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "IE8 leaks memory when components are added and removed"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 12688; + } +} diff --git a/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeakTest.java b/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeakTest.java new file mode 100644 index 0000000000..c9bd64c881 --- /dev/null +++ b/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeakTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2013 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.tests.layouts; + +import java.util.Collections; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class IE8MeasuredSizeMemoryLeakTest extends MultiBrowserTest { + + @Test + public void testMeasuredSizesMapCleaned() { + openTestURL(); + Assert.assertEquals("No extra measured sizes in the beginning", 3, + getMeasuredSizesMapSize()); + vaadinElementById("toggle").click(); + Assert.assertEquals("Measured sizes after single toggle", 204, + getMeasuredSizesMapSize()); + vaadinElementById("toggle").click(); + Assert.assertEquals("Measured sizes cleaned on toggle", 204, + getMeasuredSizesMapSize()); + } + + private int getMeasuredSizesMapSize() { + JavascriptExecutor jsExec = (JavascriptExecutor) getDriver(); + Number result = (Number) jsExec + .executeScript("return window.vaadin.getMeasuredSizesCount();"); + return result.intValue(); + } + + @Override + public List getBrowsersToTest() { + return Collections.singletonList(Browser.IE8.getDesiredCapabilities()); + } +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/LayoutMemoryUsageIE8ExtensionConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/LayoutMemoryUsageIE8ExtensionConnector.java new file mode 100644 index 0000000000..c92e688520 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/LayoutMemoryUsageIE8ExtensionConnector.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2013 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.tests.widgetset.client; + +import com.vaadin.client.BrowserInfo; +import com.vaadin.client.LayoutManager; +import com.vaadin.client.LayoutManagerIE8; +import com.vaadin.client.ServerConnector; +import com.vaadin.client.extensions.AbstractExtensionConnector; +import com.vaadin.shared.ui.Connect; +import com.vaadin.tests.extensions.LayoutMemoryUsageIE8Extension; + +@Connect(LayoutMemoryUsageIE8Extension.class) +public class LayoutMemoryUsageIE8ExtensionConnector extends + AbstractExtensionConnector { + + @Override + protected void extend(ServerConnector target) { + if (BrowserInfo.get().isIE8()) { + LayoutManagerIE8 manager = (LayoutManagerIE8) LayoutManager + .get(getConnection()); + configureGetMapSizeJS(manager); + } + } + + private native void configureGetMapSizeJS(LayoutManagerIE8 manager) + /*-{ + $wnd.vaadin.getMeasuredSizesCount = function() { + return manager.@com.vaadin.client.LayoutManagerIE8::getMeasuredSizesMapSize()(); + }; + }-*/; +} -- cgit v1.2.3 From 5441ef061e4b3bf1f6545f829121bcefcb256ef9 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 20 Feb 2014 22:56:43 +0200 Subject: Merged IntegrationTestRunner into TB3Runner Change-Id: I9e14a75b8446623d8995ee907bd95a1b2452cefd --- .../tests/integration/AbstractIntegrationTest.java | 17 +------ .../tests/integration/IntegrationTestRunner.java | 54 ---------------------- uitest/src/com/vaadin/tests/tb3/TB3Runner.java | 44 ++++++++++++++++-- .../src/com/vaadin/tests/tb3/TestNameSuffix.java | 29 ++++++++++++ 4 files changed, 72 insertions(+), 72 deletions(-) delete mode 100644 uitest/src/com/vaadin/tests/integration/IntegrationTestRunner.java create mode 100644 uitest/src/com/vaadin/tests/tb3/TestNameSuffix.java diff --git a/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java b/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java index cbb3a8b8e4..0266a9d892 100644 --- a/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java +++ b/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java @@ -15,15 +15,8 @@ */ package com.vaadin.tests.integration; -import java.util.Collection; -import java.util.Collections; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized.Parameters; -import org.openqa.selenium.remote.DesiredCapabilities; - -import com.vaadin.tests.tb3.MultiBrowserTest.Browser; import com.vaadin.tests.tb3.PrivateTB3Configuration; +import com.vaadin.tests.tb3.TestNameSuffix; /** * Base class for integration tests. Integration tests use the @@ -32,7 +25,7 @@ import com.vaadin.tests.tb3.PrivateTB3Configuration; * * @author Vaadin Ltd */ -@RunWith(IntegrationTestRunner.class) +@TestNameSuffix(property = "server-name") public abstract class AbstractIntegrationTest extends PrivateTB3Configuration { @Override protected String getBaseURL() { @@ -41,13 +34,7 @@ public abstract class AbstractIntegrationTest extends PrivateTB3Configuration { throw new RuntimeException( "Deployment url must be given as deployment.url"); } - return deploymentUrl; } - @Parameters - public static Collection getBrowsersForTest() { - return Collections.singleton(Browser.FIREFOX.getDesiredCapabilities()); - } - } diff --git a/uitest/src/com/vaadin/tests/integration/IntegrationTestRunner.java b/uitest/src/com/vaadin/tests/integration/IntegrationTestRunner.java deleted file mode 100644 index f5042b54b6..0000000000 --- a/uitest/src/com/vaadin/tests/integration/IntegrationTestRunner.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2000-2013 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.tests.integration; - -import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.InitializationError; - -import com.vaadin.tests.tb3.TB3Runner; - -/** - * JUnit runner for integration tests. Replaces the actual method name with the - * server-name property when generating the test name. - * - * @author Vaadin Ltd - */ -public class IntegrationTestRunner extends TB3Runner { - - private Class testClass; - - public IntegrationTestRunner(Class klass) throws InitializationError { - super(klass); - testClass = klass; - } - - /* - * (non-Javadoc) - * - * @see - * org.junit.runners.BlockJUnit4ClassRunner#testName(org.junit.runners.model - * .FrameworkMethod) - */ - @Override - protected String testName(FrameworkMethod method) { - if (AbstractIntegrationTest.class.isAssignableFrom(testClass)) { - return System.getProperty("server-name"); - } else { - return super.testName(method); - } - } -} diff --git a/uitest/src/com/vaadin/tests/tb3/TB3Runner.java b/uitest/src/com/vaadin/tests/tb3/TB3Runner.java index eaffa80d09..54bb2d86a5 100644 --- a/uitest/src/com/vaadin/tests/tb3/TB3Runner.java +++ b/uitest/src/com/vaadin/tests/tb3/TB3Runner.java @@ -16,6 +16,7 @@ package com.vaadin.tests.tb3; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; @@ -83,12 +84,21 @@ public class TB3Runner extends BlockJUnit4ClassRunner { .getAnnotation(RunLocally.class).value() .getDesiredCapabilities()); } - for (DesiredCapabilities capabilities : desiredCapabilites) { + TestNameSuffix testNameSuffixProperty = findAnnotation( + testClassInstance.getClass(), TestNameSuffix.class); + for (DesiredCapabilities capabilities : desiredCapabilites) { // Find any methods marked with @Test. for (FrameworkMethod m : getTestClass().getAnnotatedMethods( Test.class)) { - tests.add(new TB3Method(m.getMethod(), capabilities)); + TB3Method method = new TB3Method(m.getMethod(), + capabilities); + if (testNameSuffixProperty != null) { + method.setTestNameSuffix("-" + + System.getProperty(testNameSuffixProperty + .property())); + } + tests.add(method); } } } catch (Exception e) { @@ -98,6 +108,27 @@ public class TB3Runner extends BlockJUnit4ClassRunner { return tests; } + /** + * Finds the given annotation in the given class or one of its super + * classes. Return the first found annotation + * + * @param searchClass + * @param annotationClass + * @return + */ + private T findAnnotation(Class searchClass, + Class annotationClass) { + if (searchClass == Object.class) { + return null; + } + + if (searchClass.getAnnotation(annotationClass) != null) { + return searchClass.getAnnotation(annotationClass); + } + + return findAnnotation(searchClass.getSuperclass(), annotationClass); + } + /* * (non-Javadoc) * @@ -141,12 +172,17 @@ public class TB3Runner extends BlockJUnit4ClassRunner { private static class TB3Method extends FrameworkMethod { private DesiredCapabilities capabilities; + private String testNameSuffix = ""; public TB3Method(Method method, DesiredCapabilities capabilities) { super(method); this.capabilities = capabilities; } + public void setTestNameSuffix(String testNameSuffix) { + this.testNameSuffix = testNameSuffix; + } + @Override public Object invokeExplosively(final Object target, Object... params) throws Throwable { @@ -156,9 +192,11 @@ public class TB3Runner extends BlockJUnit4ClassRunner { @Override public String getName() { - return String.format("%s[%s]", getMethod().getName(), + return String.format("%s[%s]", getMethod().getName() + + testNameSuffix, BrowserUtil.getUniqueIdentifier(capabilities)); } } + } diff --git a/uitest/src/com/vaadin/tests/tb3/TestNameSuffix.java b/uitest/src/com/vaadin/tests/tb3/TestNameSuffix.java new file mode 100644 index 0000000000..9f9bb07a13 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/TestNameSuffix.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2013 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.tests.tb3; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Defines a system property to be used as part of the test name + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface TestNameSuffix { + + String property(); + +} -- cgit v1.2.3 From 3545db2a19397509db1c3fa4ed6f4cc3f85ec1e4 Mon Sep 17 00:00:00 2001 From: Sauli Tähkäpää Date: Mon, 17 Mar 2014 10:25:15 +0200 Subject: Added User-Agent and Screen Width + Height labels to portlet test. Change-Id: Ic51e0fde622b3075c6956b4c6f3700fbb281c7ba --- .../src/com/vaadin/tests/integration/JSR286Portlet.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java b/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java index 859175394d..dab19498ab 100644 --- a/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java +++ b/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java @@ -50,6 +50,9 @@ public class JSR286Portlet extends UI { Link portletEdit = new Link(); Link portletMax = new Link(); Link someAction = null; + Label userAgent = new Label(); + Label screenWidth = new Label(); + Label screenHeight = new Label(); private VerticalLayout main = new VerticalLayout(); @Override @@ -69,6 +72,15 @@ public class JSR286Portlet extends UI { userInfo.setContentMode(ContentMode.PREFORMATTED); main.addComponent(userInfo); + userAgent.setCaption("User Agent"); + main.addComponent(userAgent); + + screenWidth.setCaption("Screen width"); + main.addComponent(screenWidth); + + screenHeight.setCaption("Screen height"); + main.addComponent(screenHeight); + tf.setEnabled(false); tf.setImmediate(true); main.addComponent(tf); @@ -100,6 +112,11 @@ public class JSR286Portlet extends UI { VaadinPortletRequest request = (VaadinPortletRequest) VaadinPortletService .getCurrentRequest(); + userAgent.setValue(getPage().getWebBrowser().getBrowserApplication()); + screenWidth.setValue(String.valueOf(getPage().getBrowserWindowWidth())); + screenHeight.setValue(String + .valueOf(getPage().getBrowserWindowHeight())); + boolean inViewMode = (request.getPortletMode() == PortletMode.VIEW); boolean inNormalState = (request.getWindowState() == WindowState.NORMAL); // Portlet up-and-running, enable stuff -- cgit v1.2.3 From c5aaf938f797f8c657ff3b9d7c02489eaf2526e9 Mon Sep 17 00:00:00 2001 From: Sauli Tähkäpää Date: Tue, 18 Mar 2014 08:40:14 +0200 Subject: Refactored JSR286 portlet test. Change-Id: I1830ebca5e23890636ade0bab2eca2cefe6ee1ac --- .../com/vaadin/tests/integration/JSR286Portlet.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java b/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java index dab19498ab..37f8e21c50 100644 --- a/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java +++ b/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java @@ -72,15 +72,6 @@ public class JSR286Portlet extends UI { userInfo.setContentMode(ContentMode.PREFORMATTED); main.addComponent(userInfo); - userAgent.setCaption("User Agent"); - main.addComponent(userAgent); - - screenWidth.setCaption("Screen width"); - main.addComponent(screenWidth); - - screenHeight.setCaption("Screen height"); - main.addComponent(screenHeight); - tf.setEnabled(false); tf.setImmediate(true); main.addComponent(tf); @@ -100,6 +91,16 @@ public class JSR286Portlet extends UI { main.addComponent(upload); possiblyChangedModeOrState(); + + userAgent.setCaption("User Agent"); + main.addComponent(userAgent); + + screenWidth.setCaption("Screen width"); + main.addComponent(screenWidth); + + screenHeight.setCaption("Screen height"); + main.addComponent(screenHeight); + getSession().addPortletListener(new DemoPortletListener()); } -- cgit v1.2.3 From 52dcbaaf056631d98715f39b1038d1abc81f5476 Mon Sep 17 00:00:00 2001 From: Teemu Pöntelin Date: Sun, 16 Mar 2014 23:39:04 +0200 Subject: Pressing ESC now closes the DateField popup when using month or year resolutions. (#12317) Change-Id: Icf7b8da00e80ea4dc4843bcd28b005b5e91b866f --- .../src/com/vaadin/client/ui/VCalendarPanel.java | 2 + .../components/datefield/PopupClosingWithEsc.java | 57 ++++++++++++++++++ .../datefield/PopupClosingWithEscTest.java | 67 ++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/datefield/PopupClosingWithEsc.java create mode 100644 uitest/src/com/vaadin/tests/components/datefield/PopupClosingWithEscTest.java diff --git a/client/src/com/vaadin/client/ui/VCalendarPanel.java b/client/src/com/vaadin/client/ui/VCalendarPanel.java index e584a21563..d1a94ffb9a 100644 --- a/client/src/com/vaadin/client/ui/VCalendarPanel.java +++ b/client/src/com/vaadin/client/ui/VCalendarPanel.java @@ -1193,6 +1193,7 @@ public class VCalendarPanel extends FocusableFlexTable implements } else if (keycode == getCloseKey()) { // TODO fire listener, on users responsibility?? + onCancel(); return true; } return false; @@ -1244,6 +1245,7 @@ public class VCalendarPanel extends FocusableFlexTable implements return true; } else if (keycode == getCloseKey() || keycode == KeyCodes.KEY_TAB) { + onCancel(); // TODO fire close event diff --git a/uitest/src/com/vaadin/tests/components/datefield/PopupClosingWithEsc.java b/uitest/src/com/vaadin/tests/components/datefield/PopupClosingWithEsc.java new file mode 100644 index 0000000000..af43f143c1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/PopupClosingWithEsc.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2013 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.tests.components.datefield; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.datefield.Resolution; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.DateField; +import com.vaadin.ui.VerticalLayout; + +public class PopupClosingWithEsc extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + DateField df1 = new DateField("Day"); + df1.setId("day"); + df1.setResolution(Resolution.DAY); + + DateField df2 = new DateField("Month"); + df2.setId("month"); + df2.setResolution(Resolution.MONTH); + + DateField df3 = new DateField("Year"); + df3.setId("year"); + df3.setResolution(Resolution.YEAR); + + VerticalLayout layout = new VerticalLayout(); + layout.setMargin(true); + layout.setSpacing(true); + layout.addComponents(df1, df2, df3); + setContent(layout); + } + + @Override + protected String getTestDescription() { + return "Testing that the DateField popup can be closed with ESC key."; + } + + @Override + protected Integer getTicketNumber() { + return 12317; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/datefield/PopupClosingWithEscTest.java b/uitest/src/com/vaadin/tests/components/datefield/PopupClosingWithEscTest.java new file mode 100644 index 0000000000..4c4b894b2b --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/PopupClosingWithEscTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2013 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.tests.components.datefield; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class PopupClosingWithEscTest extends MultiBrowserTest { + + @Test + public void testPopupClosingDayResolution() { + testPopupClosing("day"); + } + + @Test + public void testPopupClosingMonthResolution() { + testPopupClosing("month"); + } + + @Test + public void testPopupClosingYearResolution() { + testPopupClosing("year"); + } + + private void testPopupClosing(String dateFieldId) { + openTestURL(); + + driver.findElement( + vaadinLocator("PID_S" + dateFieldId + "#popupButton")).click(); + assertTrue(isPopupVisible()); + sendEsc(); + assertFalse(isPopupVisible()); + } + + private boolean isPopupVisible() { + return !(driver.findElements(By.cssSelector(".v-datefield-popup")) + .isEmpty()); + } + + private void sendEsc() { + WebElement elem = driver.findElement(By + .cssSelector(".v-datefield-calendarpanel")); + new Actions(driver).sendKeys(elem, Keys.ESCAPE).perform(); + } + +} -- cgit v1.2.3 From e45294f717f920a6dfbcf36aff68d25d9b00cca3 Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Wed, 19 Mar 2014 10:36:41 +0000 Subject: Revert "Preventing premature start of drag due to Chrome move event #13381" This reverts commit 7112abe944259a615e26342de17d0302ddec3562. Change-Id: I2bc231ec20c27b508570c6358fb2d8128beb2735 --- .../com/vaadin/client/ui/dd/VDragAndDropManager.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java index 7de40f9496..b911c28a07 100644 --- a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java +++ b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java @@ -422,20 +422,13 @@ public class VDragAndDropManager { } case Event.ONMOUSEMOVE: case Event.ONTOUCHMOVE: - // only start the drag if the mouse / touch has moved a minimum distance - int startX = Util.getTouchOrMouseClientX(currentDrag.getCurrentGwtEvent()); - int startY = Util.getTouchOrMouseClientY(currentDrag.getCurrentGwtEvent()); - int nowX = Util.getTouchOrMouseClientX(event.getNativeEvent()); - int nowY = Util.getTouchOrMouseClientY(event.getNativeEvent()); - if (Math.abs(startX - nowX) > 3 || Math.abs(startY - nowY) > 3) { - if (deferredStartRegistration != null) { - deferredStartRegistration.removeHandler(); - deferredStartRegistration = null; - } - currentDrag.setCurrentGwtEvent(event - .getNativeEvent()); - startDrag.execute(); + if (deferredStartRegistration != null) { + deferredStartRegistration.removeHandler(); + deferredStartRegistration = null; } + currentDrag.setCurrentGwtEvent(event + .getNativeEvent()); + startDrag.execute(); break; default: // on any other events, clean up the -- cgit v1.2.3