diff options
69 files changed, 1698 insertions, 179 deletions
diff --git a/WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt b/WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt new file mode 100644 index 0000000000..dff31dd51f --- /dev/null +++ b/WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt @@ -0,0 +1 @@ +Just ordinary contents here
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/tests-tickets/ordinary.txt b/WebContent/VAADIN/themes/tests-tickets/ordinary.txt new file mode 100644 index 0000000000..dff31dd51f --- /dev/null +++ b/WebContent/VAADIN/themes/tests-tickets/ordinary.txt @@ -0,0 +1 @@ +Just ordinary contents here
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt b/WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt new file mode 100644 index 0000000000..dff31dd51f --- /dev/null +++ b/WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt @@ -0,0 +1 @@ +Just ordinary contents here
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/valo/components/_grid.scss b/WebContent/VAADIN/themes/valo/components/_grid.scss index 11134262eb..e9b4d249c7 100644 --- a/WebContent/VAADIN/themes/valo/components/_grid.scss +++ b/WebContent/VAADIN/themes/valo/components/_grid.scss @@ -21,6 +21,11 @@ $v-grid-details-marker-width: first-number($v-grid-border) * 2 !default; $v-grid-details-marker-color: $v-selection-color !default; $v-grid-details-border-top: valo-border($color: $v-grid-border-color-source, $strength: 0.3) !default; $v-grid-details-border-top-stripe: valo-border($color: $v-grid-row-stripe-background-color, $strength: 0.3) !default; + +$v-grid-border-size: 1px !default; +$v-grid-border: $v-grid-border-size solid #ddd !default; +$v-grid-cell-vertical-border: $v-grid-border !default; +$v-grid-cell-horizontal-border: $v-grid-cell-vertical-border !default; $v-grid-details-border-bottom: $v-grid-cell-horizontal-border !default; $v-grid-details-border-bottom-stripe: $v-grid-cell-horizontal-border !default; diff --git a/client/src/com/vaadin/client/BrowserInfo.java b/client/src/com/vaadin/client/BrowserInfo.java index 8b274623c1..8dcefddcf5 100644 --- a/client/src/com/vaadin/client/BrowserInfo.java +++ b/client/src/com/vaadin/client/BrowserInfo.java @@ -30,6 +30,7 @@ public class BrowserInfo { private static final String BROWSER_OPERA = "op"; private static final String BROWSER_IE = "ie"; + private static final String BROWSER_EDGE = "edge"; private static final String BROWSER_FIREFOX = "ff"; private static final String BROWSER_SAFARI = "sa"; @@ -171,6 +172,13 @@ public class BrowserInfo { minorVersionClass = majorVersionClass + browserDetails.getBrowserMinorVersion(); browserEngineClass = ENGINE_TRIDENT; + } else if (browserDetails.isEdge()) { + browserIdentifier = BROWSER_EDGE; + majorVersionClass = browserIdentifier + + getBrowserMajorVersion(); + minorVersionClass = majorVersionClass + + browserDetails.getBrowserMinorVersion(); + browserEngineClass = ""; } else if (browserDetails.isOpera()) { browserIdentifier = BROWSER_OPERA; majorVersionClass = browserIdentifier @@ -225,6 +233,10 @@ public class BrowserInfo { return browserDetails.isIE(); } + public boolean isEdge() { + return browserDetails.isEdge(); + } + public boolean isFirefox() { return browserDetails.isFirefox(); } @@ -245,6 +257,10 @@ public class BrowserInfo { return isIE() && getBrowserMajorVersion() == 10; } + public boolean isIE11() { + return isIE() && getBrowserMajorVersion() == 11; + } + public boolean isChrome() { return browserDetails.isChrome(); } diff --git a/client/src/com/vaadin/client/ComputedStyle.java b/client/src/com/vaadin/client/ComputedStyle.java index 61cb3c2eb6..cd90e0e78b 100644 --- a/client/src/com/vaadin/client/ComputedStyle.java +++ b/client/src/com/vaadin/client/ComputedStyle.java @@ -155,10 +155,10 @@ public class ComputedStyle { * the property to retrieve * @return the double value of the property */ - public final int getDoubleProperty(String name) { + public final double getDoubleProperty(String name) { Profiler.enter("ComputedStyle.getDoubleProperty"); String value = getProperty(name); - int result = parseDoubleNative(value); + double result = parseDoubleNative(value); Profiler.leave("ComputedStyle.getDoubleProperty"); return result; } @@ -275,9 +275,60 @@ public class ComputedStyle { * @return the value from the string before any non-numeric characters or * NaN if the value cannot be parsed as a number */ - private static native int parseDoubleNative(final String value) + private static native double parseDoubleNative(final String value) /*-{ return parseFloat(value); }-*/; + /** + * Returns the sum of the top and bottom border width + * + * @since 7.5.3 + * @return the sum of the top and bottom border + */ + public double getBorderHeight() { + double borderHeight = getDoubleProperty("borderTopWidth"); + borderHeight += getDoubleProperty("borderBottomWidth"); + + return borderHeight; + } + + /** + * Returns the sum of the left and right border width + * + * @since 7.5.3 + * @return the sum of the left and right border + */ + public double getBorderWidth() { + double borderWidth = getDoubleProperty("borderLeftWidth"); + borderWidth += getDoubleProperty("borderRightWidth"); + + return borderWidth; + } + + /** + * Returns the sum of the top and bottom padding + * + * @since 7.5.3 + * @return the sum of the top and bottom padding + */ + public double getPaddingHeight() { + double paddingHeight = getDoubleProperty("paddingTop"); + paddingHeight += getDoubleProperty("paddingBottom"); + + return paddingHeight; + } + + /** + * Returns the sum of the top and bottom padding + * + * @since 7.5.3 + * @return the sum of the left and right padding + */ + public double getPaddingWidth() { + double paddingWidth = getDoubleProperty("paddingLeft"); + paddingWidth += getDoubleProperty("paddingRight"); + + return paddingWidth; + } } diff --git a/client/src/com/vaadin/client/ResourceLoader.java b/client/src/com/vaadin/client/ResourceLoader.java index 9e9ce5ac49..559768d09c 100644 --- a/client/src/com/vaadin/client/ResourceLoader.java +++ b/client/src/com/vaadin/client/ResourceLoader.java @@ -283,8 +283,7 @@ public class ResourceLoader { * @since 7.2.4 */ public static boolean supportsInOrderScriptExecution() { - return BrowserInfo.get().isIE() - && BrowserInfo.get().getBrowserMajorVersion() >= 11; + return BrowserInfo.get().isIE11() || BrowserInfo.get().isEdge(); } /** @@ -486,10 +485,11 @@ public class ResourceLoader { addOnloadHandler(linkElement, new ResourceLoadListener() { @Override public void onLoad(ResourceLoadEvent event) { - // Chrome && IE fires load for errors, must check + // Chrome, IE, Edge all fire load for errors, must check // stylesheet data if (BrowserInfo.get().isChrome() - || BrowserInfo.get().isIE()) { + || BrowserInfo.get().isIE() + || BrowserInfo.get().isEdge()) { int styleSheetLength = getStyleSheetLength(url); // Error if there's an empty stylesheet if (styleSheetLength == 0) { diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index 62326c4b07..74f8a96bc0 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -34,6 +34,7 @@ import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; @@ -476,8 +477,7 @@ public class GridConnector extends AbstractHasComponentsConnector implements /** * Class for handling scrolling issues with open details. * - * @since - * @author Vaadin Ltd + * @since 7.5.2 */ private class LazyDetailsScroller implements DeferredWorker { @@ -507,7 +507,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements /** * Inform LazyDetailsScroller that a details row has opened on a row. * - * @since * @param rowIndex * index of row with details now open */ @@ -685,6 +684,26 @@ public class GridConnector extends AbstractHasComponentsConnector implements public void recalculateColumnWidths() { getWidget().recalculateColumnWidths(); } + + @Override + public void setSelectAll(boolean allSelected) { + if (selectionModel instanceof SelectionModel.Multi + && selectionModel.getSelectionColumnRenderer() != null) { + final Widget widget; + try { + HeaderRow defaultHeaderRow = getWidget() + .getDefaultHeaderRow(); + if (defaultHeaderRow != null) { + widget = defaultHeaderRow.getCell( + getWidget().getColumn(0)).getWidget(); + ((CheckBox) widget).setValue(allSelected, false); + } + } catch (Exception e) { + getLogger().warning( + "Problems finding select all checkbox."); + } + } + } }); getWidget().addSelectionHandler(internalSelectionChangeHandler); diff --git a/client/src/com/vaadin/client/ui/FocusableScrollPanel.java b/client/src/com/vaadin/client/ui/FocusableScrollPanel.java index 9dd9c17675..1ac5a08ccd 100644 --- a/client/src/com/vaadin/client/ui/FocusableScrollPanel.java +++ b/client/src/com/vaadin/client/ui/FocusableScrollPanel.java @@ -74,7 +74,7 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements style.setPosition(Position.FIXED); style.setTop(0, Unit.PX); style.setLeft(0, Unit.PX); - if (browserInfo.isIE()) { + if (browserInfo.isIE() || browserInfo.isEdge()) { // for #15294: artificially hide little bit more the // focusElement, otherwise IE will make the window to scroll // into it when focused diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index 8d9e30ac6e..d756c88f79 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -599,7 +599,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, + "]"); Element menuFirstChild = menu.getElement().getFirstChildElement(); - final int naturalMenuWidth = menuFirstChild.getOffsetWidth(); + final int naturalMenuWidth = WidgetUtil + .getRequiredWidth(menuFirstChild); if (popupOuterPadding == -1) { popupOuterPadding = WidgetUtil @@ -611,13 +612,20 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, menuFirstChild.getStyle().setWidth(100, Unit.PCT); } - if (BrowserInfo.get().isIE()) { + if (BrowserInfo.get().isIE() + && BrowserInfo.get().getBrowserMajorVersion() < 11) { + // Must take margin,border,padding manually into account for + // menu element as we measure the element child and set width to + // the element parent + int naturalMenuOuterWidth = naturalMenuWidth + + getMarginBorderPaddingWidth(menu.getElement()); + /* * IE requires us to specify the width for the container * element. Otherwise it will be 100% wide */ - int rootWidth = Math.max(desiredWidth, naturalMenuWidth) - - popupOuterPadding; + int rootWidth = Math.max(desiredWidth - popupOuterPadding, + naturalMenuOuterWidth); getContainerElement().getStyle().setWidth(rootWidth, Unit.PX); } @@ -1283,6 +1291,16 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, sinkEvents(Event.ONPASTE); } + private static int getMarginBorderPaddingWidth(Element element) { + final ComputedStyle s = new ComputedStyle(element); + int[] margin = s.getMargin(); + int[] border = s.getBorder(); + int[] padding = s.getPadding(); + return margin[1] + margin[3] + border[1] + border[3] + padding[1] + + padding[3]; + + } + /* * (non-Javadoc) * diff --git a/client/src/com/vaadin/client/ui/VFormLayout.java b/client/src/com/vaadin/client/ui/VFormLayout.java index 84a9b4f3dd..bcbb3ebf7b 100644 --- a/client/src/com/vaadin/client/ui/VFormLayout.java +++ b/client/src/com/vaadin/client/ui/VFormLayout.java @@ -22,7 +22,6 @@ import java.util.List; import com.google.gwt.aria.client.Roles; import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.DOM; @@ -327,22 +326,6 @@ public class VFormLayout extends SimplePanel { requiredFieldIndicator = null; } } - - // Workaround for IE weirdness, sometimes returns bad height in some - // circumstances when Caption is empty. See #1444 - // IE7 bugs more often. I wonder what happens when IE8 arrives... - // FIXME: This could be unnecessary for IE8+ - if (BrowserInfo.get().isIE()) { - if (isEmpty) { - setHeight("0px"); - getElement().getStyle().setOverflow(Overflow.HIDDEN); - } else { - setHeight(""); - getElement().getStyle().clearOverflow(); - } - - } - } /** diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java index e823e8ee80..3649afc74f 100644 --- a/client/src/com/vaadin/client/ui/VOverlay.java +++ b/client/src/com/vaadin/client/ui/VOverlay.java @@ -22,8 +22,6 @@ import java.util.logging.Logger; import com.google.gwt.animation.client.Animation; import com.google.gwt.aria.client.Roles; import com.google.gwt.core.client.JavaScriptObject; -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.IFrameElement; @@ -473,17 +471,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { if (isAnimationEnabled()) { new ResizeAnimation().run(POPUP_PANEL_ANIMATION_DURATION); } else { - if (BrowserInfo.get().isIE8()) { - Scheduler.get().scheduleFinally(new ScheduledCommand() { - - @Override - public void execute() { - positionOrSizeUpdated(1.0); - } - }); - } else { - positionOrSizeUpdated(1.0); - } + positionOrSizeUpdated(1.0); } current = null; } diff --git a/client/src/com/vaadin/client/ui/VRichTextArea.java b/client/src/com/vaadin/client/ui/VRichTextArea.java index 3f63f38067..cb4482f7cb 100644 --- a/client/src/com/vaadin/client/ui/VRichTextArea.java +++ b/client/src/com/vaadin/client/ui/VRichTextArea.java @@ -322,7 +322,7 @@ public class VRichTextArea extends Composite implements Field, KeyPressHandler, if ("<br>".equals(result)) { result = ""; } - } else if (browser.isWebkit()) { + } else if (browser.isWebkit() || browser.isEdge()) { if ("<br>".equals(result) || "<div><br></div>".equals(result)) { result = ""; } diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index e036725ceb..4e030b8e49 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -1295,8 +1295,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (uidl.hasVariable("selected")) { final Set<String> selectedKeys = uidl .getStringArrayVariableAsSet("selected"); - removeUnselectedRowKeys(selectedKeys); - + // Do not update focus if there is a single selected row + // that is the same as the previous selection. This prevents + // unwanted scrolling (#18247). + boolean rowsUnSelected = removeUnselectedRowKeys(selectedKeys); + boolean updateFocus = rowsUnSelected || selectedRowKeys.size() == 0 + || focusedRow == null; if (scrollBody != null) { Iterator<Widget> iterator = scrollBody.iterator(); while (iterator.hasNext()) { @@ -1313,7 +1317,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, selected = true; keyboardSelectionOverRowFetchInProgress = true; } - if (selected && selectedKeys.size() == 1) { + if (selected && selectedKeys.size() == 1 && updateFocus) { /* * If a single item is selected, move focus to the * selected row. (#10522) @@ -1338,14 +1342,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets, return keyboardSelectionOverRowFetchInProgress; } - private void removeUnselectedRowKeys(final Set<String> selectedKeys) { + private boolean removeUnselectedRowKeys(final Set<String> selectedKeys) { List<String> unselectedKeys = new ArrayList<String>(0); for (String key : selectedRowKeys) { if (!selectedKeys.contains(key)) { unselectedKeys.add(key); } } - selectedRowKeys.removeAll(unselectedKeys); + return selectedRowKeys.removeAll(unselectedKeys); } /** For internal use only. May be removed or replaced in the future. */ diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java index ded9977f5e..e196870348 100644 --- a/client/src/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/com/vaadin/client/ui/VTabsheet.java @@ -61,11 +61,12 @@ import com.google.gwt.user.client.ui.impl.FocusImpl; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.BrowserInfo; import com.vaadin.client.ComponentConnector; +import com.vaadin.client.ComputedStyle; import com.vaadin.client.Focusable; import com.vaadin.client.TooltipInfo; -import com.vaadin.client.WidgetUtil; import com.vaadin.client.VCaption; import com.vaadin.client.VTooltip; +import com.vaadin.client.WidgetUtil; import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.ComponentConstants; @@ -1227,8 +1228,13 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware public void updateContentNodeHeight() { if (!isDynamicHeight()) { int contentHeight = getOffsetHeight(); - contentHeight -= DOM.getElementPropertyInt(deco, "offsetHeight"); + contentHeight -= deco.getOffsetHeight(); contentHeight -= tb.getOffsetHeight(); + + ComputedStyle cs = new ComputedStyle(contentNode); + contentHeight -= Math.ceil(cs.getPaddingHeight()); + contentHeight -= Math.ceil(cs.getBorderHeight()); + if (contentHeight < 0) { contentHeight = 0; } diff --git a/client/src/com/vaadin/client/ui/VTextArea.java b/client/src/com/vaadin/client/ui/VTextArea.java index 50930f2fee..bb3d3a476b 100644 --- a/client/src/com/vaadin/client/ui/VTextArea.java +++ b/client/src/com/vaadin/client/ui/VTextArea.java @@ -224,16 +224,16 @@ public class VTextArea extends VTextField implements DragImageModifier { protected boolean browserSupportsMaxLengthAttribute() { BrowserInfo info = BrowserInfo.get(); - if (info.isFirefox() && info.isBrowserVersionNewerOrEqual(4, 0)) { + if (info.isFirefox()) { return true; } - if (info.isSafari() && info.isBrowserVersionNewerOrEqual(5, 0)) { + if (info.isSafari()) { return true; } - if (info.isIE() && info.isBrowserVersionNewerOrEqual(10, 0)) { + if (info.isIE10() || info.isIE11() || info.isEdge()) { return true; } - if (info.isAndroid() && info.isBrowserVersionNewerOrEqual(2, 3)) { + if (info.isAndroid()) { return true; } return false; diff --git a/client/src/com/vaadin/client/ui/VUI.java b/client/src/com/vaadin/client/ui/VUI.java index 0c1b83ab0f..963d83a6e6 100644 --- a/client/src/com/vaadin/client/ui/VUI.java +++ b/client/src/com/vaadin/client/ui/VUI.java @@ -18,7 +18,6 @@ package com.vaadin.client.ui; import java.util.ArrayList; -import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; import com.google.gwt.event.dom.client.HasScrollHandlers; @@ -44,8 +43,8 @@ import com.vaadin.client.ConnectorMap; import com.vaadin.client.Focusable; import com.vaadin.client.LayoutManager; import com.vaadin.client.Profiler; -import com.vaadin.client.WidgetUtil; import com.vaadin.client.VConsole; +import com.vaadin.client.WidgetUtil; import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler; import com.vaadin.client.ui.ui.UIConnector; @@ -515,13 +514,6 @@ public class VUI extends SimplePanel implements ResizeHandler, public void focusStoredElement() { if (storedFocus != null) { storedFocus.focus(); - - Scheduler.get().scheduleDeferred(new ScheduledCommand() { - @Override - public void execute() { - storedFocus.focus(); - } - }); } } diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java index c5cab8ff6b..e34e12a20b 100644 --- a/client/src/com/vaadin/client/ui/VWindow.java +++ b/client/src/com/vaadin/client/ui/VWindow.java @@ -562,17 +562,10 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, } private static void focusTopmostModalWindow() { - // If we call focus() directly without scheduling, it does not work in - // IE and FF. - Scheduler.get().scheduleDeferred(new ScheduledCommand() { - @Override - public void execute() { - VWindow topmost = getTopmostWindow(); - if ((topmost != null) && (topmost.vaadinModality)) { - topmost.focus(); - } - } - }); + VWindow topmost = getTopmostWindow(); + if ((topmost != null) && (topmost.vaadinModality)) { + topmost.focus(); + } } @Override @@ -762,11 +755,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, modalityCurtain.removeFromParent(); - if (BrowserInfo.get().isIE()) { - // IE leaks memory in certain cases unless we release the reference - // (#9197) - modalityCurtain = null; - } + // IE leaks memory in certain cases unless we release the reference + // (#9197) + modalityCurtain = null; } /* @@ -1375,7 +1366,11 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, @Override public void focus() { - contentPanel.focus(); + // We don't want to use contentPanel.focus() as that will use a timer in + // Chrome/Safari and ultimately run focus events in the wrong order when + // opening a modal window and focusing some other component at the same + // time + contentPanel.getElement().focus(); } private int getDecorationHeight() { diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java index 1a54fe0454..55834397d3 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java @@ -268,8 +268,13 @@ public class DateCellDayEvent extends FocusableHTML implements } int endX = event.getClientX(); int endY = event.getClientY(); - int xDiff = startX - endX; - int yDiff = startY - endY; + int xDiff = 0, yDiff = 0; + if (startX != -1 && startY != -1) { + // Drag started + xDiff = startX - endX; + yDiff = startY - endY; + } + startX = -1; startY = -1; mouseMoveStarted = false; diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java index 3bf6930933..158241337b 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java @@ -392,8 +392,11 @@ public class SimpleDayCell extends FocusableFlowPanel implements int endX = event.getClientX(); int endY = event.getClientY(); - int xDiff = startX - endX; - int yDiff = startY - endY; + int xDiff = 0, yDiff = 0; + if (startX != -1 && startY != -1) { + xDiff = startX - endX; + yDiff = startY - endY; + } startX = -1; startY = -1; prevDayDiff = 0; diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index 9d8aa5b877..bcd90437a4 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -72,6 +72,7 @@ import com.vaadin.client.ui.ShortcutActionHandler; import com.vaadin.client.ui.VNotification; import com.vaadin.client.ui.VOverlay; import com.vaadin.client.ui.VUI; +import com.vaadin.client.ui.VWindow; import com.vaadin.client.ui.layout.MayScrollChildren; import com.vaadin.client.ui.window.WindowConnector; import com.vaadin.server.Page.Styles; @@ -677,6 +678,19 @@ public class UIConnector extends AbstractSingleComponentContainerConnector if (c instanceof WindowConnector) { WindowConnector wc = (WindowConnector) c; wc.setWindowOrderAndPosition(); + VWindow window = wc.getWidget(); + if (!window.isAttached()) { + + // Attach so that all widgets inside the Window are attached + // when their onStateChange is run + + // Made invisible here for legacy reasons and made visible + // at the end of stateChange. This dance could probably be + // removed + window.setVisible(false); + window.show(); + } + } } diff --git a/client/src/com/vaadin/client/ui/window/WindowConnector.java b/client/src/com/vaadin/client/ui/window/WindowConnector.java index 9b710981d8..9ea3c8bb68 100644 --- a/client/src/com/vaadin/client/ui/window/WindowConnector.java +++ b/client/src/com/vaadin/client/ui/window/WindowConnector.java @@ -17,6 +17,8 @@ package com.vaadin.client.ui.window; import java.util.logging.Logger; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Node; @@ -354,10 +356,6 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector if (state.modal != window.vaadinModality) { window.setVaadinModality(!window.vaadinModality); } - if (!window.isAttached()) { - window.setVisible(false); // hide until possible centering - window.show(); - } boolean resizeable = state.resizable && state.windowMode == WindowMode.NORMAL; window.setResizable(resizeable); @@ -407,7 +405,13 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector window.centered = state.centered; // Ensure centering before setting visible (#16486) if (window.centered && getState().windowMode != WindowMode.MAXIMIZED) { - window.center(); + Scheduler.get().scheduleFinally(new ScheduledCommand() { + + @Override + public void execute() { + getWidget().center(); + } + }); } window.setVisible(true); diff --git a/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java index 1e47d3ad6b..c64908f24c 100644 --- a/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java @@ -56,6 +56,8 @@ import com.vaadin.client.widgets.Grid; public class MultiSelectionRenderer<T> extends ClickableRenderer<Boolean, CheckBox> { + private static final String SELECTION_CHECKBOX_CLASSNAME = "-selection-checkbox"; + /** The size of the autoscroll area, both top and bottom. */ private static final int SCROLL_AREA_GRADIENT_PX = 100; @@ -591,6 +593,8 @@ public class MultiSelectionRenderer<T> extends @Override public CheckBox createWidget() { final CheckBox checkBox = GWT.create(CheckBox.class); + checkBox.setStylePrimaryName(grid.getStylePrimaryName() + + SELECTION_CHECKBOX_CLASSNAME); CheckBoxEventHandler handler = new CheckBoxEventHandler(checkBox); // Sink events diff --git a/client/src/com/vaadin/client/widgets/Escalator.java b/client/src/com/vaadin/client/widgets/Escalator.java index a6247aee12..5b3d4e1b70 100644 --- a/client/src/com/vaadin/client/widgets/Escalator.java +++ b/client/src/com/vaadin/client/widgets/Escalator.java @@ -1475,6 +1475,9 @@ public class Escalator extends Widget implements RequiresResize, cellElem.addClassName("frozen"); position.set(cellElem, scroller.lastScrollLeft, 0); } + if (columnConfiguration.frozenColumns > 0 && col == columnConfiguration.frozenColumns - 1) { + cellElem.addClassName("last-frozen"); + } } referenceRow = paintInsertRow(referenceRow, tr, row); @@ -1732,6 +1735,14 @@ public class Escalator extends Widget implements RequiresResize, } public void setColumnFrozen(int column, boolean frozen) { + toggleFrozenColumnClass(column, frozen, "frozen"); + + if (frozen) { + updateFreezePosition(column, scroller.lastScrollLeft); + } + } + + private void toggleFrozenColumnClass(int column, boolean frozen, String className) { final NodeList<TableRowElement> childRows = root.getRows(); for (int row = 0; row < childRows.getLength(); row++) { @@ -1742,16 +1753,16 @@ public class Escalator extends Widget implements RequiresResize, TableCellElement cell = tr.getCells().getItem(column); if (frozen) { - cell.addClassName("frozen"); + cell.addClassName(className); } else { - cell.removeClassName("frozen"); + cell.removeClassName(className); position.reset(cell); } } + } - if (frozen) { - updateFreezePosition(column, scroller.lastScrollLeft); - } + public void setColumnLastFrozen(int column, boolean lastFrozen) { + toggleFrozenColumnClass(column, lastFrozen, "last-frozen"); } public void updateFreezePosition(int column, double scrollLeft) { @@ -4309,6 +4320,17 @@ public class Escalator extends Widget implements RequiresResize, firstUnaffectedCol = oldCount; } + if (oldCount > 0) { + header.setColumnLastFrozen(oldCount - 1, false); + body.setColumnLastFrozen(oldCount - 1, false); + footer.setColumnLastFrozen(oldCount - 1, false); + } + if (count > 0) { + header.setColumnLastFrozen(count - 1, true); + body.setColumnLastFrozen(count - 1, true); + footer.setColumnLastFrozen(count - 1, true); + } + for (int col = firstAffectedCol; col < firstUnaffectedCol; col++) { header.setColumnFrozen(col, frozen); body.setColumnFrozen(col, frozen); @@ -5619,14 +5641,29 @@ public class Escalator extends Widget implements RequiresResize, horizontalScrollbar.setScrollbarThickness(scrollbarThickness); horizontalScrollbar .addVisibilityHandler(new ScrollbarBundle.VisibilityHandler() { + + private boolean queued = false; + @Override public void visibilityChanged( ScrollbarBundle.VisibilityChangeEvent event) { + if (queued) { + return; + } + queued = true; + /* * We either lost or gained a scrollbar. In any case, we * need to change the height, if it's defined by rows. */ - applyHeightByRows(); + Scheduler.get().scheduleFinally(new ScheduledCommand() { + + @Override + public void execute() { + applyHeightByRows(); + queued = false; + } + }); } }); diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index a17c59c795..eb54f9c720 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -216,6 +216,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, SubPartAware, DeferredWorker, Focusable, com.google.gwt.user.client.ui.Focusable, HasWidgets, HasEnabled { + private static final String SELECT_ALL_CHECKBOX_CLASSNAME = "-select-all-checkbox"; + /** * Enum describing different sections of Grid. */ @@ -2535,6 +2537,7 @@ public class Grid<T> extends ResizeComposite implements private boolean initDone = false; private boolean selected = false; + private CheckBox selectAllCheckBox; SelectionColumn(final Renderer<Boolean> selectColumnRenderer) { super(selectColumnRenderer); @@ -2559,41 +2562,57 @@ public class Grid<T> extends ResizeComposite implements * exist. */ final SelectionModel.Multi<T> model = (Multi<T>) getSelectionModel(); - final CheckBox checkBox = GWT.create(CheckBox.class); - checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() { - @Override - public void onValueChange(ValueChangeEvent<Boolean> event) { - if (event.getValue()) { - fireEvent(new SelectAllEvent<T>(model)); - selected = true; - } else { - model.deselectAll(); - selected = false; - } - } - }); - checkBox.setValue(selected); - selectionCell.setWidget(checkBox); - // Select all with space when "select all" cell is active - addHeaderKeyUpHandler(new HeaderKeyUpHandler() { - @Override - public void onKeyUp(GridKeyUpEvent event) { - if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) { - return; - } - HeaderRow targetHeaderRow = getHeader().getRow( - event.getFocusedCell().getRowIndex()); - if (!targetHeaderRow.isDefault()) { - return; + if (selectAllCheckBox == null) { + selectAllCheckBox = GWT.create(CheckBox.class); + selectAllCheckBox.setStylePrimaryName(getStylePrimaryName() + + SELECT_ALL_CHECKBOX_CLASSNAME); + selectAllCheckBox + .addValueChangeHandler(new ValueChangeHandler<Boolean>() { + + @Override + public void onValueChange( + ValueChangeEvent<Boolean> event) { + if (event.getValue()) { + fireEvent(new SelectAllEvent<T>(model)); + selected = true; + } else { + model.deselectAll(); + selected = false; + } + } + }); + selectAllCheckBox.setValue(selected); + + // Select all with space when "select all" cell is active + addHeaderKeyUpHandler(new HeaderKeyUpHandler() { + @Override + public void onKeyUp(GridKeyUpEvent event) { + if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) { + return; + } + HeaderRow targetHeaderRow = getHeader().getRow( + event.getFocusedCell().getRowIndex()); + if (!targetHeaderRow.isDefault()) { + return; + } + if (event.getFocusedCell().getColumn() == SelectionColumn.this) { + // Send events to ensure state is updated + selectAllCheckBox.setValue( + !selectAllCheckBox.getValue(), true); + } } - if (event.getFocusedCell().getColumn() == SelectionColumn.this) { - // Send events to ensure row selection state is - // updated - checkBox.setValue(!checkBox.getValue(), true); + }); + } else { + for (HeaderRow row : header.getRows()) { + if (row.getCell(this).getType() == GridStaticCellType.WIDGET) { + // Detach from old header. + row.getCell(this).setText(""); } } - }); + } + + selectionCell.setWidget(selectAllCheckBox); } @Override @@ -2655,7 +2674,6 @@ public class Grid<T> extends ResizeComposite implements super.setEditable(editable); return this; } - } /** @@ -6927,11 +6945,21 @@ public class Grid<T> extends ResizeComposite implements if (args.getIndicesLength() == 0) { return editor.editorOverlay; - } else if (args.getIndicesLength() == 1 - && args.getIndex(0) < columns.size()) { - escalator - .scrollToColumn(args.getIndex(0), ScrollDestination.ANY, 0); - return editor.getWidget(columns.get(args.getIndex(0))).getElement(); + } else if (args.getIndicesLength() == 1) { + int index = args.getIndex(0); + if (index >= columns.size()) { + return null; + } + + escalator.scrollToColumn(index, ScrollDestination.ANY, 0); + Widget widget = editor.getWidget(columns.get(index)); + + if (widget != null) { + return widget.getElement(); + } + + // No widget for the column. + return null; } return null; diff --git a/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java b/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java index 62b727e5f5..24bf9b6558 100644 --- a/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java +++ b/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java @@ -56,6 +56,8 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { private static final String ANDROID_MOTOROLA_3_0 = "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13"; private static final String ANDROID_GALAXY_NEXUS_4_0_4_CHROME = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"; + private static final String EDGE_WINDOWS_10 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"; + public void testSafari3() { VBrowserDetails bd = new VBrowserDetails(SAFARI3_WINDOWS); assertWebKit(bd); @@ -423,6 +425,14 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertWindows(bd, true); } + public void testEdgeWindows10() { + VBrowserDetails bd = new VBrowserDetails(EDGE_WINDOWS_10); + assertEdge(bd); + assertBrowserMajorVersion(bd, 12); + assertBrowserMinorVersion(bd, 10240); + assertWindows(bd, false); + } + /* * Helper methods below */ @@ -484,6 +494,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertFalse(browserDetails.isIE()); assertFalse(browserDetails.isOpera()); assertFalse(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); } private void assertChrome(VBrowserDetails browserDetails) { @@ -493,6 +504,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertFalse(browserDetails.isIE()); assertFalse(browserDetails.isOpera()); assertFalse(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); } private void assertIE(VBrowserDetails browserDetails) { @@ -502,6 +514,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertTrue(browserDetails.isIE()); assertFalse(browserDetails.isOpera()); assertFalse(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); } private void assertOpera(VBrowserDetails browserDetails) { @@ -511,6 +524,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertFalse(browserDetails.isIE()); assertTrue(browserDetails.isOpera()); assertFalse(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); } private void assertSafari(VBrowserDetails browserDetails) { @@ -520,6 +534,17 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertFalse(browserDetails.isIE()); assertFalse(browserDetails.isOpera()); assertTrue(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); + } + + private void assertEdge(VBrowserDetails browserDetails) { + // Browser + assertFalse(browserDetails.isFirefox()); + assertFalse(browserDetails.isChrome()); + assertFalse(browserDetails.isIE()); + assertFalse(browserDetails.isOpera()); + assertFalse(browserDetails.isSafari()); + assertTrue(browserDetails.isEdge()); } private void assertMacOSX(VBrowserDetails browserDetails) { diff --git a/eclipse/Super Development Mode (vaadin).launch b/eclipse/Super Development Mode (vaadin).launch index 361a456e96..b03337e5ff 100644 --- a/eclipse/Super Development Mode (vaadin).launch +++ b/eclipse/Super Development Mode (vaadin).launch @@ -23,5 +23,5 @@ <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.codeserver.CodeServer"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-noprecompile -strict -bindAddress 0.0.0.0 com.vaadin.DefaultWidgetSet com.vaadin.tests.widgetset.TestingWidgetSet"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="vaadin"/> -<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx512M -XX:MaxPermSize=256M"/> +<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx1G -XX:MaxPermSize=256M"/> </launchConfiguration> diff --git a/scripts/DeployHelpers.py b/scripts/DeployHelpers.py index 2c879088ff..12c7baaaec 100644 --- a/scripts/DeployHelpers.py +++ b/scripts/DeployHelpers.py @@ -12,14 +12,51 @@ except Exception as e: from requests.auth import HTTPDigestAuth from os.path import join, expanduser, basename from BuildHelpers import parser, getArgs +from time import sleep parser.add_argument("--deployUrl", help="Wildfly management URL") parser.add_argument("--deployUser", help="Deployment user", default=None) parser.add_argument("--deployPass", help="Deployment password", default=None) +serverUp = None + +def testServer(): + global serverUp + + if serverUp is not None: + return serverUp + + print("Checking server status") + i = 0 + request = {"operation" : "read-attribute", "name" : "server-state"} + serverUp = False + while not serverUp and i < 2: + try: + print("Trying on url %s" % (getUrl())) + result = doPostJson(url=getUrl(), auth=getAuth(), data=json.dumps(request)) + response = result.json() + if "outcome" not in response or response["outcome"] != "success": + # Failure + raise Exception(response) + elif "result" not in response or response["result"] != "running": + # Another failure + raise Exception(response) + # All OK + serverUp = True + print("Got server connection.") + except Exception as e: + print("Exception while checking server state: ", e) + print("Server connection failed, retrying in 5 seconds.") + i = i + 1 + sleep(5) + return serverUp + # Helper for handling the full deployment # name should end with .war def deployWar(warFile, name=None): + if not testServer(): + raise Exception("Server not up. Skipping deployment.") + return if name is None: name = basename(warFile).replace('.war', "-%s.war" % (getArgs().version.split('-')[0])) diff --git a/scripts/GeneratePublishReport.py b/scripts/GeneratePublishReport.py new file mode 100644 index 0000000000..0293bdbb44 --- /dev/null +++ b/scripts/GeneratePublishReport.py @@ -0,0 +1,53 @@ +#coding=UTF-8 + +import argparse, cgi + +parser = argparse.ArgumentParser(description="Post-publish report generator") +parser.add_argument("version", type=str, help="Vaadin version that was just built") +parser.add_argument("buildResultUrl", type=str, help="URL for the build result page") + +args = parser.parse_args() + +(major, minor, maintenance) = args.version.split(".", 2) +prerelease = "." in maintenance +if prerelease: + maintenance = maintenance.split('.')[0] + +content = """<html> +<head></head> +<body> +<table> +""" + +if not prerelease: + content += "<tr><td><a href='http://vaadin.com/download/release/{maj}.{min}/{ver}/'>Check {ver} is published to vaadin.com/download</td></tr>".format(maj=major, min=minor, ver=args.version) +else: + content += "<tr><td><a href='http://vaadin.com/download/prerelease/{maj}.{min}/{maj}.{min}.{main}/{ver}'>Check {ver} is published as prerelease to vaadin.com/download</td></tr>".format(maj=major, min=minor, main=maintenance, ver=args.version) + +content += """ +<tr><td>Verify Latest Vaadin 7: <iframe src="http://vaadin.com/download/LATEST7"></iframe></td></tr> +<tr><td>Verify Vaadin 7 Version List: <iframe src="http://vaadin.com/download/VERSIONS_7"></iframe></td></tr> +<tr><td>Verify Latest Vaadin 7.5: <iframe src="http://vaadin.com/download/release/7.5/LATEST"></iframe></td></tr> +<tr><td>Verify Latest Vaadin 7.6: <iframe src="http://vaadin.com/download/release/7.6/LATEST"></iframe></td></tr> +<tr><td>Verify Latest Vaadin 6: <iframe src="http://vaadin.com/download/LATEST"></iframe></td></tr> +<tr><td>Verify Latest Vaadin 7 Prerelease: <iframe src="http://vaadin.com/download/PRERELEASES"></iframe></td></tr>""" + +if not prerelease: + content += '<tr><td><a href="https://dev.vaadin.com/admin/ticket/versions">Set latest version to default</a></td></tr>' + +content += """ +<tr><td><a href="http://test.vaadin.com/{version}/run/LabelModes?restartApplication">Verify uploaded to test.vaadin.com</a></td></tr> +<tr><td><a href="https://github.com/vaadin/vaadin/tags">Verify tags pushed to GitHub</a></td></tr>""".format(version=args.version) + +if not prerelease: + content += '<tr><td><a href="http://vaadin.com/api">Verify API version list updated</a></td></tr>' + +content += """ +<tr><td><a href="https://dev.vaadin.com/query?status=pending-release&component=Core+Framework&resolution=fixed&milestone=Vaadin {version}&col=id&col=summary&col=component&col=milestone&col=status&col=type">Batch update tickets in Trac</a></td></tr> +<tr><td><a href="{url}">Publish result page (See test results, pin and tag build and dependencies)</a></td></tr> +</table> +</body> +</html>""".format(url=args.buildResultUrl, version=args.version) + +f = open("result/report.html", 'w') +f.write(content) diff --git a/scripts/GenerateStagingReport.py b/scripts/GenerateStagingReport.py index cf53928379..23977aa933 100644 --- a/scripts/GenerateStagingReport.py +++ b/scripts/GenerateStagingReport.py @@ -9,6 +9,7 @@ parser.add_argument("version", type=str, help="Vaadin version that was just buil parser.add_argument("deployUrl", type=str, help="Base url of the deployment server") parser.add_argument("buildResultUrl", type=str, help="URL for the build result page") parser.add_argument("stagingRepo", type=str, help="URL for the staging repository") +parser.add_argument("tbapiUrl", type=str, help="URL for the TestBench API build") args = parser.parse_args() @@ -35,12 +36,48 @@ content += cgi.escape(""" <ibiblio name="vaadin-staging" usepoms="true" m2compat root="{repoUrl}" />""".format(repoUrl=args.stagingRepo)) content += """</pre> </td></tr> -<tr><td><a href="https://dev.vaadin.com/milestone/Vaadin {version}">Trac Milestone</a></td></tr> +<tr><td><a href="https://dev.vaadin.com/milestone/Vaadin {version}">Close Trac Milestone</a></td></tr> +<tr><td><a href="https://dev.vaadin.com/query?status=pending-release&component=Core+Framework&resolution=fixed&col=id&col=summary&col=component&col=milestone&col=status&col=type">Verify pending release tickets still have milestone {version}</a></td></tr> <tr><td><a href="https://dev.vaadin.com/admin/ticket/versions">Add version {version} to Trac</td></tr> <tr><td><a href="{url}">Staging result page (See test results, pin and tag build and dependencies)</a></td></tr> +<tr><td>Commands to tag all repositories (warning: do not run as a single script but set variables and check before any push commands - this has not been tested yet and the change IDs are missing)</td></tr> +<tr><td><pre> +VERSION={version} + +GERRIT_USER=[fill in your gerrit username] +FRAMEWORK_REVISION=[fill in framework revision] +SCREENSHOTS_REVISION=[fill in screenshot repository revision] +ARCHETYPES_REVISION=[fill in maven-integration repository revision] +PLUGIN_REVISION=[fill in maven plug-in repository revision] + +git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/vaadin +cd vaadin +git tag -a -m"$VERSION" $VERSION $FRAMEWORK_REVISION +git push --tags +cd .. + +git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/vaadin-screenshots +cd vaadin-screenshots +git tag -a -m"$VERSION" $VERSION $SCREENSHOTS_REVISION +git push --tags +cd .. + +git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/maven-integration +cd maven-integration +git tag -a -m"$VERSION" $VERSION $ARCHETYPES_REVISION +git push --tags +cd .. + +git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/maven-plugin +cd maven-plugin +git tag -a -m"$VERSION" $VERSION $PLUGIN_REVISION +git push --tags +cd .. +</pre></td></tr> +<tr><td><a href="{tbapi}">Build and publish TestBench API for version {version} if proceeding</a></td></tr> </table> </body> -</html>""".format(url=args.buildResultUrl, repoUrl=args.stagingRepo, version=args.version) +</html>""".format(url=args.buildResultUrl, repoUrl=args.stagingRepo, version=args.version, tbapi=args.tbapiUrl) f = open("result/report.html", 'w') f.write(content) diff --git a/server/ivy.xml b/server/ivy.xml index e9bc8b818d..0711b4b2ea 100644 --- a/server/ivy.xml +++ b/server/ivy.xml @@ -36,7 +36,7 @@ <!-- Google App Engine --> <dependency org="com.google.appengine" name="appengine-api-1.0-sdk" - rev="1.2.1" conf="build-provided,ide,test -> default" /> + rev="1.7.7" conf="build-provided,ide,test -> default" /> <!-- Bean Validation API --> <dependency org="javax.validation" name="validation-api" diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 7aada2402d..61df02feaa 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -28,6 +28,7 @@ import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; +import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -694,17 +695,20 @@ public class VaadinServlet extends HttpServlet implements Constants { return false; } + String decodedRequestURI = URLDecoder.decode(request.getRequestURI(), + "UTF-8"); if ((request.getContextPath() != null) - && (request.getRequestURI().startsWith("/VAADIN/"))) { - serveStaticResourcesInVAADIN(request.getRequestURI(), request, - response); + && (decodedRequestURI.startsWith("/VAADIN/"))) { + serveStaticResourcesInVAADIN(decodedRequestURI, request, response); return true; - } else if (request.getRequestURI().startsWith( - request.getContextPath() + "/VAADIN/")) { + } + + String decodedContextPath = URLDecoder.decode(request.getContextPath(), + "UTF-8"); + if (decodedRequestURI.startsWith(decodedContextPath + "/VAADIN/")) { serveStaticResourcesInVAADIN( - request.getRequestURI().substring( - request.getContextPath().length()), request, - response); + decodedRequestURI.substring(decodedContextPath.length()), + request, response); return true; } diff --git a/server/src/com/vaadin/server/WebBrowser.java b/server/src/com/vaadin/server/WebBrowser.java index 66018b02f2..9bf30cb3db 100644 --- a/server/src/com/vaadin/server/WebBrowser.java +++ b/server/src/com/vaadin/server/WebBrowser.java @@ -126,6 +126,20 @@ public class WebBrowser implements Serializable { } /** + * Tests whether the user is using Edge. + * + * @return true if the user is using Edge, false if the user is not using + * Edge or if no information on the browser is present + */ + public boolean isEdge() { + if (browserDetails == null) { + return false; + } + + return browserDetails.isEdge(); + } + + /** * Tests whether the user is using Safari. * * @return true if the user is using Safari, false if the user is not using diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java index 357278f411..a45d9aa059 100644 --- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java +++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java @@ -274,6 +274,13 @@ public class AtmospherePushConnection implements PushConnection { public void disconnect() { assert isConnected(); + if (resource == null) { + // Already disconnected. Should not happen but if it does, we don't + // want to cause NPEs + getLogger() + .fine("AtmospherePushConnection.disconnect() called twice, this should not happen"); + return; + } if (resource.isResumed()) { // This can happen for long polling because of // http://dev.vaadin.com/ticket/16919 diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java index 576cbd8411..532c7fe95b 100644 --- a/server/src/com/vaadin/server/communication/FileUploadHandler.java +++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java @@ -269,7 +269,7 @@ public class FileUploadHandler implements RequestHandler { streamVariable = uI.getConnectorTracker().getStreamVariable( connectorId, variableName); String secKey = uI.getConnectorTracker().getSeckey(streamVariable); - if (!secKey.equals(parts[3])) { + if (secKey == null || !secKey.equals(parts[3])) { // TODO Should rethink error handling return true; } diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index bee424e98f..c7ad9632fa 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -1167,6 +1167,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, private int selectionLimit = DEFAULT_MAX_SELECTIONS; + private boolean allSelected; + @Override public boolean select(final Object... itemIds) throws IllegalArgumentException { @@ -1212,6 +1214,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, } fireSelectionEvent(oldSelection, selection); } + + updateAllSelectedState(); + return selectionWillChange; } @@ -1277,6 +1282,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, selection.removeAll(itemIds); fireSelectionEvent(oldSelection, selection); } + + updateAllSelectedState(); + return hasCommonElements; } @@ -1357,6 +1365,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, fireSelectionEvent(oldSelection, selection); } + updateAllSelectedState(); + return changed; } @@ -1370,6 +1380,13 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, "Vararg array of itemIds may not be null"); } } + + private void updateAllSelectedState() { + if (allSelected != selection.size() >= selectionLimit) { + allSelected = selection.size() >= selectionLimit; + grid.getRpcProxy(GridClientRpc.class).setSelectAll(allSelected); + } + } } /** @@ -3648,10 +3665,21 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, safeConverter.getPresentationType(), locale); } - JsonValue encodedValue = renderer.encode(presentationValue); + JsonValue encodedValue; + try { + encodedValue = renderer.encode(presentationValue); + } catch (Exception e) { + getLogger().log(Level.SEVERE, "Unable to encode data", e); + encodedValue = renderer.encode(null); + } return encodedValue; } + + private static Logger getLogger() { + return Logger.getLogger(AbstractRenderer.class.getName()); + } + } /** diff --git a/server/src/com/vaadin/ui/HorizontalLayout.java b/server/src/com/vaadin/ui/HorizontalLayout.java index 54569570b9..616fa09225 100644 --- a/server/src/com/vaadin/ui/HorizontalLayout.java +++ b/server/src/com/vaadin/ui/HorizontalLayout.java @@ -15,6 +15,8 @@ */ package com.vaadin.ui; +import com.vaadin.shared.ui.orderedlayout.HorizontalLayoutState; + /** * Horizontal layout * @@ -48,4 +50,9 @@ public class HorizontalLayout extends AbstractOrderedLayout { addComponents(children); } + @Override + protected HorizontalLayoutState getState() { + return (HorizontalLayoutState) super.getState(); + } + } diff --git a/server/src/com/vaadin/ui/VerticalLayout.java b/server/src/com/vaadin/ui/VerticalLayout.java index 12819e50bc..7002fbc7e6 100644 --- a/server/src/com/vaadin/ui/VerticalLayout.java +++ b/server/src/com/vaadin/ui/VerticalLayout.java @@ -15,6 +15,8 @@ */ package com.vaadin.ui; +import com.vaadin.shared.ui.orderedlayout.VerticalLayoutState; + /** * Vertical layout * @@ -48,4 +50,9 @@ public class VerticalLayout extends AbstractOrderedLayout { this(); addComponents(children); } + + @Override + protected VerticalLayoutState getState() { + return (VerticalLayoutState) super.getState(); + } } diff --git a/server/src/com/vaadin/ui/renderers/ImageRenderer.java b/server/src/com/vaadin/ui/renderers/ImageRenderer.java index 2fb872583e..ad7d5cae2b 100644 --- a/server/src/com/vaadin/ui/renderers/ImageRenderer.java +++ b/server/src/com/vaadin/ui/renderers/ImageRenderer.java @@ -58,7 +58,7 @@ public class ImageRenderer extends ClickableRenderer<Resource> { if (!(resource == null || resource instanceof ExternalResource || resource instanceof ThemeResource)) { throw new IllegalArgumentException( "ImageRenderer only supports ExternalResource and ThemeResource (" - + resource.getClass().getSimpleName() + "given )"); + + resource.getClass().getSimpleName() + " given)"); } return encode(ResourceReference.create(resource, this, null), diff --git a/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java b/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java index 2cb4c3bf4d..286163541e 100644 --- a/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java +++ b/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java @@ -15,50 +15,136 @@ */ package com.vaadin.server.communication; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import com.vaadin.server.ClientConnector; +import com.vaadin.server.ServletPortletHelper; +import com.vaadin.server.StreamVariable; import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinResponse; +import com.vaadin.server.VaadinSession; +import com.vaadin.ui.ConnectorTracker; +import com.vaadin.ui.UI; -/** - * Tests whether we get infinite loop if InputStream is already read (#10096) - */ public class FileUploadHandlerTest { private FileUploadHandler handler; - private VaadinRequest request; + @Mock private VaadinResponse response; + @Mock private StreamVariable streamVariable; + @Mock private ClientConnector clientConnector; + @Mock private VaadinRequest request; + @Mock private UI ui; + @Mock private ConnectorTracker connectorTracker; + @Mock private VaadinSession session; + @Mock private OutputStream responseOutput; + + private int uiId = 123; + private final String connectorId = "connectorId"; + private final String variableName = "name"; + private final String expectedSecurityKey = "key"; @Before public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + handler = new FileUploadHandler(); - InputStream inputStream = new InputStream() { - private int counter = 0; + + mockRequest(); + mockConnectorTracker(); + mockUi(); + + when(clientConnector.isConnectorEnabled()).thenReturn(true); + when(streamVariable.getOutputStream()).thenReturn(mock(OutputStream.class)); + when(response.getOutputStream()).thenReturn(responseOutput); + } + + private void mockConnectorTracker() { + when(connectorTracker.getSeckey(streamVariable)).thenReturn(expectedSecurityKey); + when(connectorTracker.getStreamVariable(connectorId, variableName)).thenReturn(streamVariable); + when(connectorTracker.getConnector(connectorId)).thenReturn(clientConnector); + } + + private void mockRequest() throws IOException { + when(request.getPathInfo()).thenReturn("/" + ServletPortletHelper.UPLOAD_URL_PREFIX + uiId + "/"+ connectorId + "/" + variableName + "/" + expectedSecurityKey); + when(request.getInputStream()).thenReturn(createInputStream("foobar")); + when(request.getHeader("Content-Length")).thenReturn("6"); + when(request.getContentType()).thenReturn("foobar"); + } + + private InputStream createInputStream(final String content) { + return new InputStream() { + int counter = 0; + byte[] msg = content.getBytes(); @Override public int read() throws IOException { - counter++; - if (counter > 6) { - throw new RuntimeException( - "-1 is ignored by FileUploadHandler"); + if(counter > msg.length + 1) { + throw new AssertionError("-1 was ignored by FileUploadHandler."); + } + + if(counter >= msg.length) { + counter++; + return -1; } - return -1; - } + return msg[counter++]; + } }; - request = Mockito.mock(VaadinRequest.class); - Mockito.when(request.getInputStream()).thenReturn(inputStream); - Mockito.when(request.getHeader("Content-Length")).thenReturn("211"); } + private void mockUi() { + when(ui.getConnectorTracker()).thenReturn(connectorTracker); + when(session.getUIById(uiId)).thenReturn(ui); + } + + /** + * Tests whether we get infinite loop if InputStream is already read (#10096) + */ @Test(expected = IOException.class) - public void testStreamEnded() throws IOException { + public void exceptionIsThrownOnUnexpectedEnd() throws IOException { + when(request.getInputStream()).thenReturn(createInputStream("")); + when(request.getHeader("Content-Length")).thenReturn("1"); + handler.doHandleSimpleMultipartFileUpload(null, request, null, null, null, null, null); + } + + @Test + public void responseIsSentOnCorrectSecurityKey() throws IOException { + when(connectorTracker.getSeckey(streamVariable)).thenReturn(expectedSecurityKey); + + handler.handleRequest(session, request, response); + verify(responseOutput).close(); } + @Test + public void responseIsNotSentOnIncorrectSecurityKey() throws IOException { + when(connectorTracker.getSeckey(streamVariable)).thenReturn("another key expected"); + + handler.handleRequest(session, request, response); + + verifyZeroInteractions(responseOutput); + } + + @Test + public void responseIsNotSentOnMissingSecurityKey() throws IOException { + when(connectorTracker.getSeckey(streamVariable)).thenReturn(null); + + handler.handleRequest(session, request, response); + + verifyZeroInteractions(responseOutput); + } } diff --git a/shared/src/com/vaadin/shared/VBrowserDetails.java b/shared/src/com/vaadin/shared/VBrowserDetails.java index 561b6c76d0..d0de8ffb9f 100644 --- a/shared/src/com/vaadin/shared/VBrowserDetails.java +++ b/shared/src/com/vaadin/shared/VBrowserDetails.java @@ -41,6 +41,7 @@ public class VBrowserDetails implements Serializable { private boolean isFirefox = false; private boolean isOpera = false; private boolean isIE = false; + private boolean isEdge = false; private boolean isPhantomJS = false; private boolean isWindowsPhone; @@ -88,6 +89,16 @@ public class VBrowserDetails implements Serializable { isSafari = !isChrome && !isIE && userAgent.indexOf("safari") != -1; isFirefox = userAgent.indexOf(" firefox/") != -1; isPhantomJS = userAgent.indexOf("phantomjs/") != -1; + if (userAgent.indexOf(" edge/") != -1) { + isEdge = true; + isChrome = false; + isOpera = false; + isIE = false; + isSafari = false; + isFirefox = false; + isWebKit = false; + isGecko = false; + } // chromeframe isChromeFrameCapable = userAgent.indexOf("chromeframe") != -1; @@ -115,6 +126,8 @@ public class VBrowserDetails implements Serializable { tmp = tmp.replaceFirst("([0-9]+\\.[0-9]+).*", "$1"); browserEngineVersion = Float.parseFloat(tmp); } + } else if (isEdge) { + browserEngineVersion = 0; } } catch (Exception e) { // Browser engine version parsing failed @@ -158,6 +171,9 @@ public class VBrowserDetails implements Serializable { i = userAgent.indexOf("opera/") + 6; } parseVersionString(safeSubstring(userAgent, i, i + 5)); + } else if (isEdge) { + int i = userAgent.indexOf(" edge/") + 6; + parseVersionString(safeSubstring(userAgent, i, i + 8)); } } catch (Exception e) { // Browser version parsing failed @@ -373,6 +389,15 @@ public class VBrowserDetails implements Serializable { } /** + * Tests if the browser is Edge. + * + * @return true if it is Edge, false otherwise + */ + public boolean isEdge() { + return isEdge; + } + + /** * Tests if the browser is PhantomJS. * * @return true if it is PhantomJS, false otherwise diff --git a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java index ac1b1d5a78..8711a757a1 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java @@ -55,4 +55,15 @@ public interface GridClientRpc extends ClientRpc { * Command client Grid to recalculate column widths. */ public void recalculateColumnWidths(); + + /** + * Informs the Grid that all items have been selected or not selected on the + * server side. + * + * @since 7.5.3 + * @param allSelected + * <code>true</code> to check the select all checkbox, + * <code>false</code> to uncheck it. + */ + public void setSelectAll(boolean allSelected); } diff --git a/uitest/integration_tests.xml b/uitest/integration_tests.xml index d56ba2683f..bdbf1f2e5b 100644 --- a/uitest/integration_tests.xml +++ b/uitest/integration_tests.xml @@ -404,7 +404,8 @@ <antcall target="integration-test-osgi" /> <antcall target="integration-test-tomcat7apacheproxy" /> <antcall target="integration-test-websphere8" /> - <antcall target="integration-test-websphereportal8" /> + <!-- Currently the test system does not have a server for automatic testing of WebSphere Portal 8 --> + <!-- <antcall target="integration-test-websphereportal8" /> --> </parallel> </target> diff --git a/uitest/ivy.xml b/uitest/ivy.xml index 8f2765c7a4..281ba1ecdf 100644 --- a/uitest/ivy.xml +++ b/uitest/ivy.xml @@ -31,7 +31,7 @@ rev="4.2.0.Final" conf="build,ide -> default" /> <!-- Google App Engine --> <dependency org="com.google.appengine" name="appengine-api-1.0-sdk" - rev="1.2.1" conf="build-provided,ide -> default" /> + rev="1.7.7" conf="build-provided,ide -> default" /> <!-- LIBRARY DEPENDENCIES (compile time) --> <!-- Project modules --> diff --git a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java index c6ccd1bf4c..ed0f1a9b4f 100644 --- a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java +++ b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java @@ -40,7 +40,7 @@ public class VerifyBrowserVersionTest extends MultiBrowserTest { // Chrome version does not necessarily match the desired version // because of auto updates... browserIdentifier = getExpectedUserAgentString(getDesiredCapabilities()) - + "43"; + + "44"; } else { browserIdentifier = getExpectedUserAgentString(desiredCapabilities) + desiredCapabilities.getVersion(); diff --git a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java index c2dfdb26c1..40dd43abb2 100644 --- a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java +++ b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java @@ -5,17 +5,27 @@ import java.text.SimpleDateFormat; import java.util.Locale; import com.vaadin.server.VaadinRequest; -import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.components.AbstractTestUIWithLog; import com.vaadin.ui.Calendar; import com.vaadin.ui.components.calendar.CalendarComponentEvents; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClick; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClickHandler; import com.vaadin.ui.components.calendar.event.BasicEvent; -public class NullEventMoveHandler extends AbstractTestUI { +public class NullEventMoveHandler extends AbstractTestUIWithLog { @Override protected void setup(VaadinRequest request) { Calendar calendar = getCalendar(); calendar.setHandler((CalendarComponentEvents.EventMoveHandler) null); + calendar.setHandler(new EventClickHandler() { + + @Override + public void eventClick(EventClick event) { + log("Clicked on " + event.getCalendarEvent().getCaption()); + + } + }); addComponent(calendar); } diff --git a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java index c40cd9ce97..156100310c 100644 --- a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java +++ b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java @@ -3,6 +3,7 @@ package com.vaadin.tests.components.calendar; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; +import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; @@ -23,11 +24,25 @@ public class NullEventMoveHandlerTest extends DndActionsTest { } @Test + public void eventIsClickableWhenNotMovableInMonthView() { + getEvent().click(); + Assert.assertEquals("1. Clicked on foo", getLogRow(0)); + } + + @Test public void eventIsNotMovableInWeekView() { openWeekView(); assertEventCannotBeMoved(); } + @Test + public void eventIsClickableWhenNotMovableInWeekView() { + openWeekView(); + getEvent().findElement(By.className("v-calendar-event-caption")) + .click(); + Assert.assertEquals("1. Clicked on foo", getLogRow(0)); + } + private void assertEventCannotBeMoved() { int originalPosition = getEventXPosition(); diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java new file mode 100644 index 0000000000..9f1c4b9e03 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java @@ -0,0 +1,40 @@ +package com.vaadin.tests.components.combobox; + +import com.vaadin.annotations.Theme; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.HorizontalLayout; + +@Theme("valo") +public class ComboboxPopupScrolling extends AbstractTestUIWithLog { + @Override + protected void setup(VaadinRequest request) { + ComboBox combobox = new ComboBox("100px wide combobox"); + combobox.setWidth("100px"); + combobox.addItem("AMERICAN SAMOA"); + combobox.addItem("ANTIGUA AND BARBUDA"); + + ComboBox combobox2 = new ComboBox("250px wide combobox"); + combobox2.setWidth("250px"); + combobox2.addItem("AMERICAN SAMOA"); + combobox2.addItem("ANTIGUA AND BARBUDA"); + + ComboBox combobox3 = new ComboBox("Undefined wide combobox"); + combobox3.setWidth(null); + combobox3.addItem("AMERICAN SAMOA"); + combobox3.addItem("ANTIGUA AND BARBUDA"); + + ComboBox combobox4 = new ComboBox("Another 100px wide combobox"); + combobox4.setWidth("100px"); + for (int i = 0; i < 10; i++) { + combobox4.addItem("AMERICAN SAMOA " + i); + combobox4.addItem("ANTIGUA AND BARBUDA " + i); + } + + HorizontalLayout hl = new HorizontalLayout(combobox, combobox2, + combobox3, combobox4); + addComponent(hl); + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java new file mode 100644 index 0000000000..ec5bc088da --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2014 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.combobox; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class ComboboxPopupScrollingTest extends MultiBrowserTest { + + @Test + public void testNoScrollbarsValo() { + testNoScrollbars("valo"); + } + + @Test + public void testNoScrollbarsChameleon() { + testNoScrollbars("chameleon"); + } + + @Test + public void testNoScrollbarsRuno() { + testNoScrollbars("runo"); + } + + @Test + public void testNoScrollbarsReindeer() { + testNoScrollbars("reindeer"); + } + + private void testNoScrollbars(String theme) { + openTestURL("theme=" + theme); + + for (CustomComboBoxElement cb : $(CustomComboBoxElement.class).all()) { + String caption = cb.getCaption(); + cb.openPopup(); + WebElement popup = cb.getSuggestionPopup(); + WebElement scrollable = popup.findElement(By + .className("v-filterselect-suggestmenu")); + assertNoHorizontalScrollbar(scrollable, caption); + assertNoVerticalScrollbar(scrollable, caption); + } + } + +} diff --git a/uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java b/uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java new file mode 100644 index 0000000000..697d5eb932 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2014 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.combobox; + +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.ComboBoxElement; +import com.vaadin.testbench.elementsbase.ServerClass; + +@ServerClass("com.vaadin.ui.ComboBox") +public class CustomComboBoxElement extends ComboBoxElement { + private static org.openqa.selenium.By bySuggestionPopup = By + .vaadin("#popup"); + + public WebElement getSuggestionPopup() { + ensurePopupOpen(); + return findElement(bySuggestionPopup); + } + + private void ensurePopupOpen() { + if (!isElementPresent(bySuggestionPopup)) { + openPopup(); + } + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java index f20cc0f6f4..33f66d35be 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java @@ -23,7 +23,6 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; -import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Keys; import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.WebDriver; @@ -313,10 +312,6 @@ public class GridDetailsLocationTest extends MultiBrowserTest { checkBoxElement.click(5, 5); } - private Object executeScript(String string, Object... param) { - return ((JavascriptExecutor) getDriver()).executeScript(string, param); - } - private void scrollAndToggle(int row) { setRow(row); getScrollAndToggle().click(); diff --git a/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java new file mode 100644 index 0000000000..4d44eeb248 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 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.grid; + +import com.vaadin.server.ClassResource; +import com.vaadin.server.Resource; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.tests.integration.FlagSeResource; +import com.vaadin.ui.Grid; +import com.vaadin.ui.renderers.ImageRenderer; + +public class GridWithBrokenRenderer extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + final Grid grid = new Grid(); + grid.addColumn("short", String.class); + grid.addColumn("icon", Resource.class); + grid.addColumn("country", String.class); + + grid.getColumn("icon").setRenderer(new ImageRenderer()); + addComponent(grid); + + grid.addRow("FI", new ClassResource("fi.gif"), "Finland"); + grid.addRow("SE", new FlagSeResource(), "Sweden"); + + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java new file mode 100644 index 0000000000..011c8c92ce --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2014 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.grid; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class GridWithBrokenRendererTest extends SingleBrowserTest { + + @Test + public void ensureRendered() { + openTestURL(); + GridElement grid = $(GridElement.class).first(); + assertRow(grid, 0, "FI", "", "Finland"); + assertRow(grid, 1, "SE", "", "Sweden"); + } + + private void assertRow(GridElement grid, int row, String... texts) { + for (int column = 0; column < texts.length; column++) { + Assert.assertEquals("Cell " + row + "," + column, texts[column], + grid.getCell(row, column).getText()); + } + + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 33a54b1c9a..23226fb6cf 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -792,6 +792,26 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { c.setColumnReorderingAllowed(value); } }); + + createClickAction("Select all", "State", new Command<Grid, String>() { + @Override + public void execute(Grid c, String value, Object data) { + SelectionModel selectionModel = c.getSelectionModel(); + if (selectionModel instanceof SelectionModel.Multi) { + ((SelectionModel.Multi) selectionModel).selectAll(); + } + } + }, null); + + createClickAction("Select none", "State", new Command<Grid, String>() { + @Override + public void execute(Grid c, String value, Object data) { + SelectionModel selectionModel = c.getSelectionModel(); + if (selectionModel instanceof SelectionModel.Multi) { + ((SelectionModel.Multi) selectionModel).deselectAll(); + } + } + }, null); } protected void createHeaderActions() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index 0a77d690a4..0cba2ce34b 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -207,6 +207,8 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { assertTrue("Noneditable cell should contain v-grid-cell classname", classNames.contains("v-grid-cell")); + + assertNoErrorNotifications(); } @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java index 9953bbcae0..8bf8639d76 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java @@ -20,8 +20,10 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import org.openqa.selenium.Keys; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.ExpectedCondition; import com.vaadin.testbench.By; import com.vaadin.testbench.elements.GridElement; @@ -335,6 +337,62 @@ public class GridSelectionTest extends GridBasicFeaturesTest { getRow(5).isSelected()); } + @Test + public void testSelectionCheckBoxesHaveStyleNames() { + openTestURL(); + + setSelectionModelMulti(); + + assertTrue( + "Selection column CheckBox should have the proper style name set", + getGridElement().getCell(0, 0).findElement(By.tagName("span")) + .getAttribute("class") + .contains("v-grid-selection-checkbox")); + + GridCellElement header = getGridElement().getHeaderCell(0, 0); + assertTrue("Select all CheckBox should have the proper style name set", + header.findElement(By.tagName("span")).getAttribute("class") + .contains("v-grid-select-all-checkbox")); + } + + @Test + public void testServerSideSelectTogglesSelectAllCheckBox() { + openTestURL(); + + setSelectionModelMulti(); + GridCellElement header = getGridElement().getHeaderCell(0, 0); + + WebElement selectAll = header.findElement(By.tagName("input")); + + selectMenuPath("Component", "State", "Select all"); + waitUntilCheckBoxValue(selectAll, true); + assertTrue("Select all CheckBox wasn't selected as expected", + selectAll.isSelected()); + + selectMenuPath("Component", "State", "Select none"); + waitUntilCheckBoxValue(selectAll, false); + assertFalse("Select all CheckBox was selected unexpectedly", + selectAll.isSelected()); + + selectMenuPath("Component", "State", "Select all"); + waitUntilCheckBoxValue(selectAll, true); + getGridElement().getCell(5, 0).click(); + waitUntilCheckBoxValue(selectAll, false); + assertFalse("Select all CheckBox was selected unexpectedly", + selectAll.isSelected()); + } + + private void waitUntilCheckBoxValue(final WebElement checkBoxElememnt, + final boolean expectedValue) { + waitUntil(new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver input) { + return expectedValue ? checkBoxElememnt.isSelected() + : !checkBoxElememnt.isSelected(); + } + }, 5); + } + private void setSelectionModelMulti() { selectMenuPath("Component", "State", "Selection mode", "multi"); } diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java new file mode 100644 index 0000000000..b2313020a3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 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.annotations.Theme; +import com.vaadin.server.VaadinRequest; +import com.vaadin.ui.Label; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalSplitPanel; +import com.vaadin.ui.themes.ValoTheme; + +@Theme("valo") +public class TabSheetInSplitPanel extends UI { + + @Override + protected void init(VaadinRequest request) { + VerticalSplitPanel verticalSplitter = new VerticalSplitPanel(); + setContent(verticalSplitter); + verticalSplitter.setSizeFull(); + TabSheet t = new TabSheet(); + t.setHeight("100%"); + t.addTab(new Label("Hello in tab"), "Hello tab"); + t.setStyleName(ValoTheme.TABSHEET_FRAMED); + verticalSplitter.addComponent(t); + verticalSplitter.addComponent(new Label("Hello")); + + } + +} diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java new file mode 100644 index 0000000000..8070133bde --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 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 java.util.List; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.TabSheetElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TabSheetInSplitPanelTest extends MultiBrowserTest { + + @Test + public void ensureNoScrollbars() { + openTestURL(); + TabSheetElement ts = $(TabSheetElement.class).first(); + List<WebElement> scrollables = ts.findElements(By + .xpath("//*[contains(@class,'v-scrollable')]")); + for (WebElement scrollable : scrollables) { + assertNoHorizontalScrollbar(scrollable, + "Element should not have a horizontal scrollbar"); + assertNoVerticalScrollbar(scrollable, + "Element should not have a vertical scrollbar"); + } + } + +} diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java new file mode 100644 index 0000000000..07cf7f8c2e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 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.treetable; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.TreeTable; + +public class TreeTableScrollOnExpand extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + TreeTable t = new TreeTable(); + t.setSelectable(true); + t.setImmediate(true); + t.setSizeFull(); + t.addContainerProperty("Name", String.class, "null"); + for (int i = 1; i <= 100; i++) { + String parentID = "Item " + i; + Object parent = t.addItem(new Object[] { parentID }, parentID); + String childID = "Item " + (100 + i); + Object child = t.addItem(new Object[] { childID }, childID); + t.getContainerDataSource().setParent(childID, parentID); + } + addComponent(t); + } + + @Override + public Integer getTicketNumber() { + return 18247; + } + + @Override + public String getTestDescription() { + return "After selecting an item and scrolling it out of view, TreeTable should not scroll to the " + + "selected item when expanding an item."; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java new file mode 100644 index 0000000000..a17559cc81 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2014 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.treetable; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.TreeTableElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TreeTableScrollOnExpandTest extends MultiBrowserTest { + + @Test + public void testScrollOnExpand() throws InterruptedException, IOException { + openTestURL(); + TreeTableElement tt = $(TreeTableElement.class).first(); + tt.getRow(0).click(); + tt.scroll(300); + sleep(1000); + tt.getRow(20).toggleExpanded(); + // Need to wait a bit to avoid accepting the case where the TreeTable is + // in the desired state only for a short while. + sleep(1000); + WebElement focusedRow = getDriver().findElement( + By.className("v-table-focus")); + assertEquals("Item 21", focusedRow.getText()); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/window/GridInWindow.java b/uitest/src/com/vaadin/tests/components/window/GridInWindow.java new file mode 100644 index 0000000000..918a991cc1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/GridInWindow.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 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.window; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Window; + +public class GridInWindow extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + final Grid grid = new Grid(); + + grid.addColumn("Hidable column").setHidable(true); + grid.addRow("Close and reopen and it vanishes"); + + Button popupButton = new Button("Open PopUp", + new Button.ClickListener() { + @Override + public void buttonClick(Button.ClickEvent event) { + Window subWindow = new Window("Sub-window"); + subWindow.setContent(grid); + subWindow.setWidth(600, Unit.PIXELS); + subWindow.setWidth(400, Unit.PIXELS); + getUI().addWindow(subWindow); + } + }); + + addComponent(popupButton); + + } + +} diff --git a/uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java b/uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java new file mode 100644 index 0000000000..301a7c60e4 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 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.window; + +import org.junit.Test; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.SingleBrowserTest; +import com.vaadin.tests.tb3.newelements.WindowElement; + +public class GridInWindowTest extends SingleBrowserTest { + + @Test + public void ensureAttachInHierachyChange() { + openTestURL("debug"); + $(ButtonElement.class).first().click(); + assertNoErrorNotifications(); + $(WindowElement.class).first().close(); + assertNoErrorNotifications(); + $(ButtonElement.class).first().click(); + assertNoErrorNotifications(); + } +} diff --git a/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java new file mode 100644 index 0000000000..1c82a3de02 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2014 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.window; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.Window; + +public class OpenModalWindowAndFocusField extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + Button button = new Button("Open modal and focus textarea"); + button.setId("openFocus"); + button.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + open(true); + } + }); + addComponent(button); + + button = new Button("Only open modal"); + button.setId("open"); + button.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + open(false); + } + + }); + addComponent(button); + + } + + private void open(boolean focus) { + Window wind = new Window(); + wind.setModal(true); + TextArea ta = new TextArea(); + wind.setContent(ta); + addWindow(wind); + if (focus) { + ta.focus(); + } + } +} diff --git a/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java new file mode 100644 index 0000000000..5dba1c3285 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2014 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.window; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.TextAreaElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class OpenModalWindowAndFocusFieldTest extends MultiBrowserTest { + + @Test + public void openModalAndFocusField() { + openTestURL(); + $(ButtonElement.class).id("openFocus").click(); + TextAreaElement textArea = $(TextAreaElement.class).first(); + + assertElementsEquals(textArea, getActiveElement()); + } + + @Test + public void openModal() { + openTestURL(); + $(ButtonElement.class).id("open").click(); + // WindowElement window = $(WindowElement.class).first(); + WebElement windowFocusElement = findElement(By + .xpath("//div[@class='v-window-contents']/div[@class='v-scrollable']")); + + assertElementsEquals(windowFocusElement, getActiveElement()); + } + +} diff --git a/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java new file mode 100644 index 0000000000..190f6daa24 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java @@ -0,0 +1,94 @@ +/* + * Copyright 2000-2014 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 java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.vaadin.annotations.Push; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.Transport; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; + +@Push(value = PushMode.MANUAL, transport = Transport.LONG_POLLING) +public class ManualLongPollingPushUI extends AbstractTestUIWithLog { + + ExecutorService executor = Executors.newFixedThreadPool(1); + + @Override + protected void setup(VaadinRequest request) { + Button b = new Button("Manual push after 1s", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + executor.submit(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + access(new Runnable() { + + @Override + public void run() { + log("Logged after 1s, followed by manual push"); + push(); + } + }); + + } + }); + } + }); + addComponent(b); + + b = new Button("Double manual push after 1s", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + executor.submit(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + access(new Runnable() { + + @Override + public void run() { + log("First message logged after 1s, followed by manual push"); + push(); + log("Second message logged after 1s, followed by manual push"); + push(); + } + }); + + } + }); + } + }); + addComponent(b); + + } + +} diff --git a/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java new file mode 100644 index 0000000000..096204ff75 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2014 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 org.junit.Test; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class ManualLongPollingPushUITest extends SingleBrowserTest { + + @Test + public void doubleManualPushDoesNotFreezeApplication() { + openTestURL(); + $(ButtonElement.class).caption("Double manual push after 1s").first() + .click(); + waitUntilLogText("2. Second message logged after 1s, followed by manual push"); + $(ButtonElement.class).caption("Manual push after 1s").first().click(); + waitUntilLogText("3. Logged after 1s, followed by manual push"); + } + + private void waitUntilLogText(final String expected) { + waitUntil(new ExpectedCondition<Boolean>() { + private String actual; + + @Override + public Boolean apply(WebDriver arg0) { + actual = getLogRow(0); + return expected.equals(actual); + } + + @Override + public String toString() { + return String.format("log text to become '%s' (was: '%s')", + expected, actual); + } + }); + } +} diff --git a/uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java b/uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java new file mode 100644 index 0000000000..e584ec73cc --- /dev/null +++ b/uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2014 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.resources; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class SpecialCharsInThemeResources extends SingleBrowserTest { + + @Test + public void loadThemeResource() { + loadResource("/VAADIN/themes/tests-tickets/ordinary.txt"); + checkSource(); + } + + @Test + public void loadThemeResourceWithPercentage() { + loadResource("/VAADIN/themes/tests-tickets/percentagein%2520name.txt"); + checkSource(); + } + + @Test + public void loadThemeResourceWithSpecialChars() { + loadResource("/VAADIN/themes/tests-tickets/folder%20with%20space/resource%20with%20special%20$chars@.txt"); + checkSource(); + } + + private void loadResource(String path) { + getDriver().get(getBaseURL() + path); + } + + private void checkSource() { + String source = getDriver().getPageSource(); + Assert.assertTrue("Incorrect contents (was: " + source + ")", + source.contains("Just ordinary contents here")); + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java index 842fcbb859..2e3854cb2b 100644 --- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java @@ -50,6 +50,7 @@ import org.openqa.selenium.interactions.Keyboard; import org.openqa.selenium.interactions.Mouse; import org.openqa.selenium.interactions.internal.Coordinates; import org.openqa.selenium.internal.Locatable; +import org.openqa.selenium.internal.WrapsElement; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.HttpCommandExecutor; import org.openqa.selenium.remote.RemoteWebDriver; @@ -368,8 +369,8 @@ public abstract class AbstractTB3Test extends ParallelTest { * {@link org.openqa.selenium.JavascriptExecutor#executeScript(String, Object...)} * returns */ - protected Object executeScript(String script) { - return ((JavascriptExecutor) getDriver()).executeScript(script); + protected Object executeScript(String script, Object... args) { + return ((JavascriptExecutor) getDriver()).executeScript(script, args); } /** @@ -1105,4 +1106,93 @@ public abstract class AbstractTB3Test extends ParallelTest { return isElementPresent(By.className("v-debugwindow")); } + protected void assertNoHorizontalScrollbar(WebElement element, + String errorMessage) { + // IE rounds clientWidth/clientHeight down and scrollHeight/scrollWidth + // up, so using clientWidth/clientHeight will fail if the element height + // is not an integer + int clientWidth = getClientWidth(element); + int scrollWidth = getScrollWidth(element); + boolean hasScrollbar = scrollWidth > clientWidth; + + Assert.assertFalse( + "The element should not have a horizontal scrollbar (scrollWidth: " + + scrollWidth + ", clientWidth: " + clientWidth + "): " + + errorMessage, hasScrollbar); + } + + protected void assertNoVerticalScrollbar(WebElement element, + String errorMessage) { + // IE rounds clientWidth/clientHeight down and scrollHeight/scrollWidth + // up, so using clientWidth/clientHeight will fail if the element height + // is not an integer + int clientHeight = getClientHeight(element); + int scrollHeight = getScrollHeight(element); + boolean hasScrollbar = scrollHeight > clientHeight; + + Assert.assertFalse( + "The element should not have a vertical scrollbar (scrollHeight: " + + scrollHeight + ", clientHeight: " + clientHeight + + "): " + errorMessage, hasScrollbar); + } + + protected int getScrollHeight(WebElement element) { + return ((Number) executeScript("return arguments[0].scrollHeight;", + element)).intValue(); + } + + protected int getScrollWidth(WebElement element) { + return ((Number) executeScript("return arguments[0].scrollWidth;", + element)).intValue(); + } + + /** + * Returns client height rounded up instead of as double because of IE9 + * issues: https://dev.vaadin.com/ticket/18469 + */ + protected int getClientHeight(WebElement e) { + String script; + if (BrowserUtil.isIE8(getDesiredCapabilities())) { + script = "return arguments[0].clientHeight;"; // + } else { + script = "var cs = window.getComputedStyle(arguments[0]);" + + "return Math.ceil(parseFloat(cs.height)+parseFloat(cs.paddingTop)+parseFloat(cs.paddingBottom));"; + } + return ((Number) executeScript(script, e)).intValue(); + } + + /** + * Returns client width rounded up instead of as double because of IE9 + * issues: https://dev.vaadin.com/ticket/18469 + */ + protected int getClientWidth(WebElement e) { + String script; + if (BrowserUtil.isIE8(getDesiredCapabilities())) { + script = "return arguments[0].clientWidth;"; + } else { + script = "var cs = window.getComputedStyle(arguments[0]);" + + "var h = parseFloat(cs.width)+parseFloat(cs.paddingLeft)+parseFloat(cs.paddingRight);" + + "return Math.ceil(h);"; + } + + return ((Number) executeScript(script, e)).intValue(); + } + + protected void assertElementsEquals(WebElement expectedElement, + WebElement actualElement) { + while (expectedElement instanceof WrapsElement) { + expectedElement = ((WrapsElement) expectedElement) + .getWrappedElement(); + } + while (actualElement instanceof WrapsElement) { + actualElement = ((WrapsElement) actualElement).getWrappedElement(); + } + + Assert.assertEquals(expectedElement, actualElement); + } + + protected WebElement getActiveElement() { + return (WebElement) executeScript("return document.activeElement;"); + + } } diff --git a/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java b/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java index 34344324d0..784d203ab0 100644 --- a/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java +++ b/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java @@ -14,6 +14,7 @@ public class WindowElement extends com.vaadin.testbench.elements.WindowElement { private final String restoreBoxClass = "v-window-restorebox"; private final String maximizeBoxClass = "v-window-maximizebox"; + private final String closeBoxClass = "v-window-closebox"; public void restore() { if (isMaximized()) { @@ -63,4 +64,13 @@ public class WindowElement extends com.vaadin.testbench.elements.WindowElement { public String getCaption() { return findElement(By.className("v-window-header")).getText(); } + + private WebElement getCloseButton() { + return findElement(By.className(closeBoxClass)); + } + + public void close() { + getCloseButton().click(); + + } } |