summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--WebContent/release-notes.html1
-rw-r--r--client/src/com/vaadin/client/ComputedStyle.java8
-rw-r--r--client/src/com/vaadin/client/WidgetUtil.java6
-rw-r--r--client/src/com/vaadin/client/connectors/GridConnector.java36
-rw-r--r--client/src/com/vaadin/client/extensions/ResponsiveConnector.java19
-rw-r--r--client/src/com/vaadin/client/ui/AbstractComponentConnector.java12
-rw-r--r--client/src/com/vaadin/client/ui/VAbstractSplitPanel.java39
-rw-r--r--client/src/com/vaadin/client/ui/VDragAndDropWrapper.java3
-rw-r--r--client/src/com/vaadin/client/ui/VGridLayout.java18
-rw-r--r--client/src/com/vaadin/client/ui/VSplitPanelHorizontal.java23
-rw-r--r--client/src/com/vaadin/client/ui/VSplitPanelVertical.java23
-rw-r--r--client/src/com/vaadin/client/ui/gridlayout/GridLayoutConnector.java2
-rw-r--r--client/src/com/vaadin/client/widgets/Grid.java201
-rw-r--r--scripts/BuildArchetypes.py67
-rw-r--r--scripts/BuildDemos.py78
-rw-r--r--scripts/BuildHelpers.py105
-rw-r--r--scripts/DeployHelpers.py82
-rw-r--r--scripts/GenerateBuildReport.py48
-rw-r--r--scripts/GenerateStagingReport.py40
-rw-r--r--server/src/com/vaadin/data/RpcDataProviderExtension.java18
-rw-r--r--server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java4
-rw-r--r--server/src/com/vaadin/server/AbstractClientConnector.java10
-rw-r--r--server/src/com/vaadin/server/CustomizedSystemMessages.java44
-rw-r--r--server/src/com/vaadin/server/SystemMessages.java11
-rw-r--r--server/src/com/vaadin/ui/ConnectorTracker.java52
-rw-r--r--server/src/com/vaadin/ui/Grid.java5
-rw-r--r--server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java10
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/UIState.java8
-rw-r--r--uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemoval.java77
-rw-r--r--uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemovalTest.java52
-rw-r--r--uitest/src/com/vaadin/tests/components/AbstractTestUI.java14
-rw-r--r--uitest/src/com/vaadin/tests/components/embedded/EmbeddedAltTextTest.java60
-rw-r--r--uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java13
-rw-r--r--uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinatesTest.java86
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplay.java91
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplayTest.java72
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java149
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java73
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java23
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java12
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java13
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java30
-rw-r--r--uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChild.java108
-rw-r--r--uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChildTest.java88
-rw-r--r--uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java6
-rw-r--r--uitest/src/com/vaadin/tests/components/tree/TreeContextMenuAndIconsTest.java130
-rw-r--r--uitest/src/com/vaadin/tests/components/upload/DragAndDropUploadAndInteractions.java153
-rw-r--r--uitest/src/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContentTest.java34
-rw-r--r--uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStyles.java37
-rw-r--r--uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStylesTest.java34
-rw-r--r--uitest/src/com/vaadin/tests/fieldgroup/BasicPersonForm.java4
-rw-r--r--uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java9
-rw-r--r--uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java7
-rw-r--r--uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedAltText.html47
-rw-r--r--uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html51
-rw-r--r--uitest/tb2/com/vaadin/tests/components/tree/TreeContextMenuAndIcons.html156
-rw-r--r--uitest/tb2/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContent.html57
-rw-r--r--widgets/build.xml1
59 files changed, 2033 insertions, 632 deletions
diff --git a/.gitignore b/.gitignore
index 1433651abc..4b28bcd6e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,8 @@
WebContent/VAADIN/vaadinPush.js
WebContent/VAADIN/vaadinPush.debug.js
+WebContent/VAADIN/vaadinPush.js.gz
+WebContent/VAADIN/vaadinPush.debug.js.gz
# /WebContent/WEB-INF/
/WebContent/WEB-INF/classes
@@ -75,6 +77,9 @@ WebContent/VAADIN/vaadinPush.debug.js
# Mac
*.DS_Store
+# Python
+scripts/*.pyc
+
# build result folders
*/result
result
diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html
index ea65948baa..b7cdba7887 100644
--- a/WebContent/release-notes.html
+++ b/WebContent/release-notes.html
@@ -113,6 +113,7 @@
<li>Widgetset files and other pre-compressed resources are sent as gzip to compatible browsers.
This may interfere with custom response compression solutions that do not respect the Content-Encoding response header.</li>
<li>Unused methods related to the "out of sync" message have been removed from SystemMessages class.</li>
+ <li>All notifications use the WAI-ARIA alert role to be compatible with Jaws</li>
</ul>
<h3 id="knownissues">Known Issues and Limitations</h3>
<ul>
diff --git a/client/src/com/vaadin/client/ComputedStyle.java b/client/src/com/vaadin/client/ComputedStyle.java
index 7a04296b4b..61cb3c2eb6 100644
--- a/client/src/com/vaadin/client/ComputedStyle.java
+++ b/client/src/com/vaadin/client/ComputedStyle.java
@@ -131,7 +131,7 @@ public class ComputedStyle {
/**
* Retrieves the given computed property as an integer
- *
+ *
* Returns 0 if the property cannot be converted to an integer
*
* @param name
@@ -148,7 +148,7 @@ public class ComputedStyle {
/**
* Retrieves the given computed property as a double
- *
+ *
* Returns NaN if the property cannot be converted to a double
*
* @param name
@@ -205,7 +205,7 @@ public class ComputedStyle {
/**
* Returns the current width from the DOM.
*
- * @since
+ * @since 7.5.1
* @return the computed width
*/
public double getWidth() {
@@ -215,7 +215,7 @@ public class ComputedStyle {
/**
* Returns the current height from the DOM.
*
- * @since
+ * @since 7.5.1
* @return the computed height
*/
public double getHeight() {
diff --git a/client/src/com/vaadin/client/WidgetUtil.java b/client/src/com/vaadin/client/WidgetUtil.java
index b9d22193de..4906197b29 100644
--- a/client/src/com/vaadin/client/WidgetUtil.java
+++ b/client/src/com/vaadin/client/WidgetUtil.java
@@ -1641,7 +1641,7 @@ public class WidgetUtil {
* Firefox uses 1/60th of a pixel because it is divisible by three
* (https://bugzilla.mozilla.org/show_bug.cgi?id=1070940)
*
- * @since
+ * @since 7.5.1
* @param size
* the value to round
* @return the rounded value
@@ -1661,7 +1661,7 @@ public class WidgetUtil {
*
* IE9+ uses 1/100th of a pixel
*
- * @since
+ * @since 7.5.1
* @param size
* the value to round
* @return the rounded value
@@ -1694,7 +1694,7 @@ public class WidgetUtil {
/**
* Returns the factor used by browsers to round subpixel values
*
- * @since
+ * @since 7.5.1
* @return the factor N used by the browser when storing subpixels as X+Y/N
*/
private static double getSubPixelRoundingFactor() {
diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java
index bee9cedc43..d42041670e 100644
--- a/client/src/com/vaadin/client/connectors/GridConnector.java
+++ b/client/src/com/vaadin/client/connectors/GridConnector.java
@@ -735,13 +735,20 @@ public class GridConnector extends AbstractHasComponentsConnector implements
private final DetailsListener detailsListener = new DetailsListener() {
@Override
- public void reapplyDetailsVisibility(int rowIndex, JsonObject row) {
- if (hasDetailsOpen(row)) {
- getWidget().setDetailsVisible(rowIndex, true);
- detailsConnectorFetcher.schedule();
- } else {
- getWidget().setDetailsVisible(rowIndex, false);
- }
+ public void reapplyDetailsVisibility(final int rowIndex,
+ final JsonObject row) {
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ if (hasDetailsOpen(row)) {
+ getWidget().setDetailsVisible(rowIndex, true);
+ detailsConnectorFetcher.schedule();
+ } else {
+ getWidget().setDetailsVisible(rowIndex, false);
+ }
+ }
+ });
}
private boolean hasDetailsOpen(JsonObject row) {
@@ -945,6 +952,13 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
@Override
+ public void onUnregister() {
+ customDetailsGenerator.indexToDetailsMap.clear();
+
+ super.onUnregister();
+ }
+
+ @Override
public void onStateChanged(final StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
@@ -1061,6 +1075,10 @@ public class GridConnector extends AbstractHasComponentsConnector implements
for (RowState rowState : state.rows) {
HeaderRow row = getWidget().appendHeaderRow();
+ if (rowState.defaultRow) {
+ getWidget().setDefaultHeaderRow(row);
+ }
+
for (CellState cellState : rowState.cells) {
CustomGridColumn column = columnIdToColumn
.get(cellState.columnId);
@@ -1082,10 +1100,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements
updateHeaderCellFromState(row.join(columns), cellState);
}
- if (rowState.defaultRow) {
- getWidget().setDefaultHeaderRow(row);
- }
-
row.setStyleName(rowState.styleName);
}
}
diff --git a/client/src/com/vaadin/client/extensions/ResponsiveConnector.java b/client/src/com/vaadin/client/extensions/ResponsiveConnector.java
index 2e1e75f6cd..621c69788c 100644
--- a/client/src/com/vaadin/client/extensions/ResponsiveConnector.java
+++ b/client/src/com/vaadin/client/extensions/ResponsiveConnector.java
@@ -84,6 +84,10 @@ public class ResponsiveConnector extends AbstractExtensionConnector implements
getLogger().log(Level.SEVERE, message);
}
+ private static void warning(String message) {
+ getLogger().warning(message);
+ }
+
@Override
protected void extend(ServerConnector target) {
this.target = (AbstractComponentConnector) target;
@@ -204,10 +208,17 @@ public class ResponsiveConnector extends AbstractExtensionConnector implements
var IE = @com.vaadin.client.BrowserInfo::get()().@com.vaadin.client.BrowserInfo::isIE()();
var IE8 = @com.vaadin.client.BrowserInfo::get()().@com.vaadin.client.BrowserInfo::isIE8()();
- if (sheet.cssRules) {
- theRules = sheet.cssRules
- } else if (sheet.rules) {
- theRules = sheet.rules
+ try {
+ if (sheet.cssRules) {
+ theRules = sheet.cssRules
+ } else if (sheet.rules) {
+ theRules = sheet.rules
+ }
+ } catch (e) {
+ // FF spews if trying to access rules for cross domain styles
+ @ResponsiveConnector::warning(*)("Can't process styles from " + sheet.href +
+ ", probably because of cross domain issues: " + e);
+ return;
}
// Special import handling for IE8
diff --git a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java
index 24a0438476..1f09c14fb0 100644
--- a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java
+++ b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java
@@ -103,11 +103,15 @@ public abstract class AbstractComponentConnector extends AbstractConnector
@Override
public Widget getWidget() {
if (widget == null) {
- Profiler.enter("AbstractComponentConnector.createWidget for "
- + getClass().getSimpleName());
+ if (Profiler.isEnabled()) {
+ Profiler.enter("AbstractComponentConnector.createWidget for "
+ + getClass().getSimpleName());
+ }
widget = createWidget();
- Profiler.leave("AbstractComponentConnector.createWidget for "
- + getClass().getSimpleName());
+ if (Profiler.isEnabled()) {
+ Profiler.leave("AbstractComponentConnector.createWidget for "
+ + getClass().getSimpleName());
+ }
}
return widget;
diff --git a/client/src/com/vaadin/client/ui/VAbstractSplitPanel.java b/client/src/com/vaadin/client/ui/VAbstractSplitPanel.java
index 5565daf19b..6c11783d34 100644
--- a/client/src/com/vaadin/client/ui/VAbstractSplitPanel.java
+++ b/client/src/com/vaadin/client/ui/VAbstractSplitPanel.java
@@ -49,7 +49,7 @@ import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
import com.vaadin.client.ui.VAbstractSplitPanel.SplitterMoveHandler.SplitterMoveEvent;
import com.vaadin.shared.ui.Orientation;
-public class VAbstractSplitPanel extends ComplexPanel {
+public abstract class VAbstractSplitPanel extends ComplexPanel {
private boolean enabled = false;
@@ -571,6 +571,7 @@ public class VAbstractSplitPanel extends ComplexPanel {
}
break;
case Event.ONCLICK:
+ stopResize();
resizing = false;
break;
}
@@ -590,6 +591,7 @@ public class VAbstractSplitPanel extends ComplexPanel {
}
final Element trg = event.getEventTarget().cast();
if (trg == splitter || trg == DOM.getChild(splitter, 0)) {
+ startResize();
resizing = true;
DOM.setCapture(getElement());
origX = DOM.getElementPropertyInt(splitter, "offsetLeft");
@@ -601,6 +603,40 @@ public class VAbstractSplitPanel extends ComplexPanel {
}
}
+ /**
+ * Called when starting drag resize
+ *
+ * @since 7.5.1
+ */
+ abstract protected void startResize();
+
+ /**
+ * Called when stopping drag resize
+ *
+ * @since 7.5.1
+ */
+ abstract protected void stopResize();
+
+ /**
+ * Gets the first container
+ *
+ * @since 7.5.1
+ * @return the firstContainer
+ */
+ protected Element getFirstContainer() {
+ return firstContainer;
+ }
+
+ /**
+ * Gets the second container
+ *
+ * @since 7.5.1
+ * @return the secondContainer
+ */
+ protected Element getSecondContainer() {
+ return secondContainer;
+ }
+
public void onMouseMove(Event event) {
switch (orientation) {
case HORIZONTAL:
@@ -685,6 +721,7 @@ public class VAbstractSplitPanel extends ComplexPanel {
public void onMouseUp(Event event) {
DOM.releaseCapture(getElement());
hideDraggingCurtain();
+ stopResize();
resizing = false;
if (!WidgetUtil.isTouchEvent(event)) {
onMouseMove(event);
diff --git a/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java b/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java
index defa27fbac..f3905f9e46 100644
--- a/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java
+++ b/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java
@@ -472,6 +472,9 @@ public class VDragAndDropWrapper extends VCustomComponent implements
/*-{
this.setRequestHeader('Content-Type', 'multipart/form-data');
+ // Seems like IE10 will loose the file if we don't keep a reference to it...
+ this.fileBeingUploaded = file;
+
this.send(file);
}-*/;
diff --git a/client/src/com/vaadin/client/ui/VGridLayout.java b/client/src/com/vaadin/client/ui/VGridLayout.java
index 0c1d4cec90..42bcb5060a 100644
--- a/client/src/com/vaadin/client/ui/VGridLayout.java
+++ b/client/src/com/vaadin/client/ui/VGridLayout.java
@@ -734,7 +734,8 @@ public class VGridLayout extends ComplexPanel {
setAlignment(new AlignmentInfo(childComponentData.alignment));
}
- public void setComponent(ComponentConnector component) {
+ public void setComponent(ComponentConnector component,
+ List<ComponentConnector> ordering) {
if (slot == null || slot.getChild() != component) {
slot = new ComponentConnectorLayoutSlot(CLASSNAME, component,
getConnector());
@@ -743,7 +744,20 @@ public class VGridLayout extends ComplexPanel {
slot.getWrapperElement().getStyle().setWidth(100, Unit.PCT);
}
Element slotWrapper = slot.getWrapperElement();
- getElement().appendChild(slotWrapper);
+ int childIndex = ordering.indexOf(component);
+ // insert new slot by proper index
+ // do not break default focus order
+ com.google.gwt.user.client.Element element = getElement();
+ if (childIndex == ordering.size()) {
+ element.appendChild(slotWrapper);
+ } else if (childIndex == 0) {
+ element.insertAfter(slotWrapper, spacingMeasureElement);
+ } else {
+ // here we use childIndex - 1 + 1(spacingMeasureElement)
+ Element previousSlot = (Element) element
+ .getChild(childIndex);
+ element.insertAfter(slotWrapper, previousSlot);
+ }
Widget widget = component.getWidget();
insert(widget, slotWrapper, getWidgetCount(), false);
diff --git a/client/src/com/vaadin/client/ui/VSplitPanelHorizontal.java b/client/src/com/vaadin/client/ui/VSplitPanelHorizontal.java
index c6919d456b..1a3e699b20 100644
--- a/client/src/com/vaadin/client/ui/VSplitPanelHorizontal.java
+++ b/client/src/com/vaadin/client/ui/VSplitPanelHorizontal.java
@@ -16,6 +16,8 @@
package com.vaadin.client.ui;
+import com.google.gwt.dom.client.Style.Overflow;
+import com.google.gwt.user.client.ui.Widget;
import com.vaadin.shared.ui.Orientation;
public class VSplitPanelHorizontal extends VAbstractSplitPanel {
@@ -23,4 +25,25 @@ public class VSplitPanelHorizontal extends VAbstractSplitPanel {
public VSplitPanelHorizontal() {
super(Orientation.HORIZONTAL);
}
+
+ @Override
+ protected void startResize() {
+ if (getFirstWidget() != null && isWidgetFullWidth(getFirstWidget())) {
+ getFirstContainer().getStyle().setOverflow(Overflow.HIDDEN);
+ }
+
+ if (getSecondWidget() != null && isWidgetFullWidth(getSecondWidget())) {
+ getSecondContainer().getStyle().setOverflow(Overflow.HIDDEN);
+ }
+ }
+
+ @Override
+ protected void stopResize() {
+ getFirstContainer().getStyle().clearOverflow();
+ getSecondContainer().getStyle().clearOverflow();
+ }
+
+ private boolean isWidgetFullWidth(Widget w) {
+ return w.getElement().getStyle().getWidth().equals("100%");
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VSplitPanelVertical.java b/client/src/com/vaadin/client/ui/VSplitPanelVertical.java
index b008e5d3f0..7baed03ca3 100644
--- a/client/src/com/vaadin/client/ui/VSplitPanelVertical.java
+++ b/client/src/com/vaadin/client/ui/VSplitPanelVertical.java
@@ -16,6 +16,8 @@
package com.vaadin.client.ui;
+import com.google.gwt.dom.client.Style.Overflow;
+import com.google.gwt.user.client.ui.Widget;
import com.vaadin.shared.ui.Orientation;
public class VSplitPanelVertical extends VAbstractSplitPanel {
@@ -23,4 +25,25 @@ public class VSplitPanelVertical extends VAbstractSplitPanel {
public VSplitPanelVertical() {
super(Orientation.VERTICAL);
}
+
+ @Override
+ protected void startResize() {
+ if (getFirstWidget() != null && isWidgetFullHeight(getFirstWidget())) {
+ getFirstContainer().getStyle().setOverflow(Overflow.HIDDEN);
+ }
+
+ if (getSecondWidget() != null && isWidgetFullHeight(getSecondWidget())) {
+ getSecondContainer().getStyle().setOverflow(Overflow.HIDDEN);
+ }
+ }
+
+ @Override
+ protected void stopResize() {
+ getFirstContainer().getStyle().clearOverflow();
+ getSecondContainer().getStyle().clearOverflow();
+ }
+
+ private boolean isWidgetFullHeight(Widget w) {
+ return w.getElement().getStyle().getHeight().equals("100%");
+ }
}
diff --git a/client/src/com/vaadin/client/ui/gridlayout/GridLayoutConnector.java b/client/src/com/vaadin/client/ui/gridlayout/GridLayoutConnector.java
index 3102af8da9..4d1ce692ad 100644
--- a/client/src/com/vaadin/client/ui/gridlayout/GridLayoutConnector.java
+++ b/client/src/com/vaadin/client/ui/gridlayout/GridLayoutConnector.java
@@ -159,7 +159,7 @@ public class GridLayoutConnector extends AbstractComponentContainerConnector
for (ComponentConnector componentConnector : getChildComponents()) {
Cell cell = getCell(componentConnector);
- cell.setComponent(componentConnector);
+ cell.setComponent(componentConnector, getChildComponents());
}
}
diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java
index a0b0b08aaa..86d2ed5f00 100644
--- a/client/src/com/vaadin/client/widgets/Grid.java
+++ b/client/src/com/vaadin/client/widgets/Grid.java
@@ -867,6 +867,7 @@ public class Grid<T> extends ResizeComposite implements
if (row != null) {
row.setDefault(true);
}
+
defaultRow = row;
requestSectionRefresh();
}
@@ -917,6 +918,16 @@ public class Grid<T> extends ResizeComposite implements
BrowserEvents.TOUCHMOVE, BrowserEvents.TOUCHEND,
BrowserEvents.TOUCHCANCEL, BrowserEvents.CLICK);
}
+
+ @Override
+ protected void addColumn(Column<?, ?> column) {
+ super.addColumn(column);
+
+ // Add default content for new columns.
+ if (defaultRow != null) {
+ column.setDefaultHeaderContent(defaultRow.getCell(column));
+ }
+ }
}
/**
@@ -929,6 +940,11 @@ public class Grid<T> extends ResizeComposite implements
protected void setDefault(boolean isDefault) {
this.isDefault = isDefault;
+ if (isDefault) {
+ for (Column<?, ?> column : getSection().grid.getColumns()) {
+ column.setDefaultHeaderContent(getCell(column));
+ }
+ }
}
public boolean isDefault() {
@@ -2437,8 +2453,6 @@ public class Grid<T> extends ResizeComposite implements
}
void initDone() {
- addSelectAllToDefaultHeader();
-
setWidth(-1);
setEditable(false);
@@ -2446,62 +2460,52 @@ public class Grid<T> extends ResizeComposite implements
initDone = true;
}
- protected void addSelectAllToDefaultHeader() {
- if (getSelectionModel() instanceof SelectionModel.Multi
- && header.getDefaultRow() != null) {
- // If selection cell already contains a widget do not
- // create a new CheckBox
- HeaderCell selectionCell = header.getDefaultRow().getCell(this);
- if (selectionCell.getType().equals(GridStaticCellType.WIDGET)
- && selectionCell.getWidget() instanceof CheckBox) {
- return;
- }
- /*
- * TODO: Currently the select all check box is shown when multi
- * selection is in use. This might result in malfunctions if no
- * SelectAllHandlers are present.
- *
- * Later on this could be fixed so that it check such handlers
- * exist.
- */
- final SelectionModel.Multi<T> model = (Multi<T>) getSelectionModel();
- final CheckBox checkBox = GWT.create(CheckBox.class);
- checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
+ @Override
+ protected void setDefaultHeaderContent(HeaderCell selectionCell) {
+ /*
+ * TODO: Currently the select all check box is shown when multi
+ * selection is in use. This might result in malfunctions if no
+ * SelectAllHandlers are present.
+ *
+ * Later on this could be fixed so that it check such handlers
+ * 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;
- }
+ @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 (event.getFocusedCell().getColumn() == SelectionColumn.this) {
- // Send events to ensure row selection state is
- // updated
- checkBox.setValue(!checkBox.getValue(), true);
- }
+ }
+ });
+ 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 (event.getFocusedCell().getColumn() == SelectionColumn.this) {
+ // Send events to ensure row selection state is
+ // updated
+ checkBox.setValue(!checkBox.getValue(), true);
+ }
+ }
+ });
}
@Override
@@ -4300,7 +4304,6 @@ public class Grid<T> extends ResizeComposite implements
this.grid = grid;
if (this.grid != null) {
this.grid.recalculateColumnWidths();
- updateHeader();
}
}
@@ -4838,6 +4841,17 @@ public class Grid<T> extends ResizeComposite implements
*/
}
}
+
+ /**
+ * Resets the default header cell contents to column header captions.
+ *
+ * @since 7.5.1
+ * @param cell
+ * default header cell for this column
+ */
+ protected void setDefaultHeaderContent(HeaderCell cell) {
+ cell.setText(headerCaption);
+ }
}
protected class BodyUpdater implements EscalatorUpdater {
@@ -5091,35 +5105,29 @@ public class Grid<T> extends ResizeComposite implements
final StaticSection.StaticCell metadata = staticRow
.getCell(columns.get(cell.getColumn()));
- boolean updateCellData = true;
// Decorate default row with sorting indicators
if (staticRow instanceof HeaderRow) {
addSortingIndicatorsToHeaderRow((HeaderRow) staticRow, cell);
-
- if (isHeaderSelectionColumn(row, cell)) {
- updateCellData = false;
- }
}
// Assign colspan to cell before rendering
cell.setColSpan(metadata.getColspan());
TableCellElement element = cell.getElement();
- if (updateCellData) {
- switch (metadata.getType()) {
- case TEXT:
- element.setInnerText(metadata.getText());
- break;
- case HTML:
- element.setInnerHTML(metadata.getHtml());
- break;
- case WIDGET:
- preDetach(row, Arrays.asList(cell));
- element.setInnerHTML("");
- postAttach(row, Arrays.asList(cell));
- break;
- }
+ switch (metadata.getType()) {
+ case TEXT:
+ element.setInnerText(metadata.getText());
+ break;
+ case HTML:
+ element.setInnerHTML(metadata.getHtml());
+ break;
+ case WIDGET:
+ preDetach(row, Arrays.asList(cell));
+ element.setInnerHTML("");
+ postAttach(row, Arrays.asList(cell));
+ break;
}
+
setCustomStyleName(element, metadata.getStyleName());
cellFocusHandler.updateFocusedCellStyle(cell, container);
@@ -5178,27 +5186,6 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach) {
- // Add select all checkbox if needed on rebuild.
- for (FlyweightCell cell : cellsToAttach) {
- if (isHeaderSelectionColumn(row, cell)) {
- selectionColumn.addSelectAllToDefaultHeader();
- }
- }
- }
-
- /**
- * Check if selectionColumn in the default header row
- */
- private boolean isHeaderSelectionColumn(Row row, FlyweightCell cell) {
- return selectionColumn != null && isDefaultHeaderRow(row)
- && getColumn(cell.getColumn()).equals(selectionColumn);
- }
-
- /**
- * Row is the default header row.
- */
- private boolean isDefaultHeaderRow(Row row) {
- return section.getRow(row.getRow()).equals(header.getDefaultRow());
}
@Override
@@ -5827,6 +5814,9 @@ public class Grid<T> extends ResizeComposite implements
/**
* Sets the default row of the header. The default row is a special header
* row providing a user interface for sorting columns.
+ * <p>
+ * Note: Setting the default header row will reset all cell contents to
+ * Column defaults.
*
* @param row
* the new default row, or null for no default row
@@ -6081,6 +6071,12 @@ public class Grid<T> extends ResizeComposite implements
RowContainer body = escalator.getBody();
int oldSize = body.getRowCount();
+ // Hide all details.
+ Set<Integer> oldDetails = new HashSet<Integer>(visibleDetails);
+ for (int i : oldDetails) {
+ setDetailsVisible(i, false);
+ }
+
if (newSize > oldSize) {
body.insertRows(oldSize, newSize - oldSize);
cellFocusHandler.rowsAddedToBody(Range.withLength(oldSize,
@@ -6946,6 +6942,9 @@ public class Grid<T> extends ResizeComposite implements
selectionModel.setGrid(this);
setSelectColumnRenderer(this.selectionModel
.getSelectionColumnRenderer());
+
+ // Refresh rendered rows to update selection, if it has changed
+ refreshBody();
}
/**
@@ -7782,6 +7781,16 @@ public class Grid<T> extends ResizeComposite implements
}
@Override
+ protected void onDetach() {
+ Set<Integer> details = new HashSet<Integer>(visibleDetails);
+ for (int row : details) {
+ setDetailsVisible(row, false);
+ }
+
+ super.onDetach();
+ }
+
+ @Override
public void onResize() {
super.onResize();
/*
diff --git a/scripts/BuildArchetypes.py b/scripts/BuildArchetypes.py
index 80dd745bfb..fa6dba2c56 100644
--- a/scripts/BuildArchetypes.py
+++ b/scripts/BuildArchetypes.py
@@ -7,11 +7,11 @@
# Python3 is required as this script uses some Python3 specific features.
# Might work with Python2, haven't tested.
#
-# python BuildArchetypes.py version fw-repo-id archetype-repo-id plugin-repo-id
+# python BuildArchetypes.py version --repo staging-repo-url
#
-import subprocess
-from BuildHelpers import mavenValidate, copyWarFiles, repo, getLogFile, parseArgs, mavenCmd, updateRepositories
+import subprocess, sys
+from os.path import join
## DEFAULT VARIABLES ##
@@ -22,7 +22,7 @@ archetypeGroup = "com.vaadin"
archetypes = [
"vaadin-archetype-widget",
"vaadin-archetype-application",
- "vaadin-archetype-application-example",
+ "vaadin-archetype-application-example",
"vaadin-archetype-application-multimodule"
]
@@ -35,35 +35,62 @@ args = None
## BUILDING METHODS ##
# Generates and modifies a maven pom file
-def generateArchetype(archetype):
- artifactId = "test-%s-%s" % (archetype, args.version.replace(".", "-"))
-
+def generateArchetype(archetype, artifactId, repo):
# Generate the required command line for archetype generation
cmd = [mavenCmd, "archetype:generate"]
cmd.append("-DarchetypeGroupId=%s" % (archetypeGroup))
cmd.append("-DarchetypeArtifactId=%s" % (archetype))
cmd.append("-DarchetypeVersion=%s" % (args.version))
- if hasattr(args, "archetype") and args.archetype != None:
- cmd.append("-DarchetypeRepository=%s" % (repo % (args.archetype)))
+ if hasattr(args, "repo") and args.repo != None:
+ cmd.append("-DarchetypeRepository=%s" % repo)
cmd.append("-DgroupId=%s" % (group))
cmd.append("-DartifactId=%s" % (artifactId))
cmd.append("-Dversion=1.0-SNAPSHOT")
cmd.append("-DinteractiveMode=false")
+ if hasattr(args, "maven") and args.maven is not None:
+ cmd.extend(args.maven.strip('"').split(" "))
# Generate pom.xml
print("Generating pom.xml for archetype %s" % (archetype))
- subprocess.check_call(cmd, stdout=log)
-
- # Return the artifactId so we know the name in the future
- return artifactId
+ subprocess.check_call(cmd, cwd=resultPath, stdout=log)
+def getDeploymentContext(archetype, version):
+ return "%s-%s" % (archetype.split("-", 2)[2], version)
+
## DO THIS IF RUN AS A SCRIPT (not import) ##
if __name__ == "__main__":
- args = parseArgs()
- for archetype in archetypes:
- log = getLogFile(archetype)
- artifactId = generateArchetype(archetype)
- updateRepositories(artifactId)
- mavenValidate(artifactId, logFile=log)
- copyWarFiles(artifactId, name=archetype)
+ from BuildHelpers import mavenValidate, copyWarFiles, getLogFile, mavenCmd, updateRepositories, getArgs, removeDir, parser, resultPath
+ from DeployHelpers import deployWar
+
+ # Add command line arguments for staging repos
+ parser.add_argument("--repo", type=str, help="Staging repository URL", required=True)
+ archetypesFailed = False
+
+ # Parse the arguments
+ args = getArgs()
+
+ if hasattr(args, "artifactPath") and args.artifactPath is not None:
+ raise Exception("Archetype validation build does not support artifactPath")
+
+ for archetype in archetypes:
+ artifactId = "test-%s-%s" % (archetype, args.version.replace(".", "-"))
+ try:
+ log = getLogFile(archetype)
+ generateArchetype(archetype, artifactId, args.repo)
+ updateRepositories(join(resultPath, artifactId), args.repo)
+ mavenValidate(artifactId, logFile=log)
+ warFiles = copyWarFiles(artifactId, name=archetype)
+ for war in warFiles:
+ try:
+ deployWar(war, "%s.war" % (getDeploymentContext(archetype, args.version)))
+ except Exception as e:
+ print("War %s failed to deploy: %s" % (war, e))
+ archetypesFailed = True
+ except Exception as e:
+ print("Archetype %s build failed:" % (archetype), e)
+ archetypesFailed = True
+# removeDir(artifactId)
+ print("")
+ if archetypesFailed:
+ sys.exit(1)
diff --git a/scripts/BuildDemos.py b/scripts/BuildDemos.py
index f9f2ed1b48..ac161fc517 100644
--- a/scripts/BuildDemos.py
+++ b/scripts/BuildDemos.py
@@ -4,38 +4,80 @@
# BuildDemos needs git in PATH and depends on gitpython library
# gitpython can be installed with python installer script "pip":
# pip install gitpython
+#
+# Deployment dependency: requests
+# pip install requests
+# Deploy depends on .deployUrl and .deployCredentials files in home folder
-from git import Repo
-from BuildHelpers import updateRepositories, mavenValidate, copyWarFiles, VersionObject, getLogFile, parseArgs
-
-## Example of a non-staging test.
-#version = VersionObject()
-#version.version = "7.4.8"
-
-# Uncomment lines before this, and comment following line to make a non-staging test
-version = None
+import sys, os
+from os.path import join, isfile
+from fnmatch import fnmatch
+from xml.etree.ElementTree import ElementTree
+# Validated demos. name -> git url
demos = {
"dashboard" : "https://github.com/vaadin/dashboard-demo.git",
"parking" : "https://github.com/vaadin/parking-demo.git",
"addressbook" : "https://github.com/vaadin/addressbook.git",
- "confirmdialog" : "https://github.com/samie/Vaadin-ConfirmDialog.git"
+ "grid-gwt" : "https://github.com/vaadin/grid-gwt.git"
}
def checkout(folder, url):
- Repo.clone_from(url, folder)
+ Repo.clone_from(url, join(resultPath, folder))
if __name__ == "__main__":
- if version is None:
- version = parseArgs()
+ # Do imports.
+ try:
+ from git import Repo
+ except:
+ print("BuildDemos depends on gitpython. Install it with `pip install gitpython`")
+ sys.exit(1)
+ from BuildHelpers import updateRepositories, mavenValidate, copyWarFiles, getLogFile, removeDir, getArgs, mavenInstall, resultPath, readPomFile, parser
+ from DeployHelpers import deployWar
+
+ # Add command line arguments for staging repos
+ parser.add_argument("--repo", type=str, help="Staging repository URL", default=None)
+
+ args = getArgs()
+ if hasattr(args, "artifactPath") and args.artifactPath is not None:
+ version = False
+ basePath = args.artifactPath
+ poms = []
+ for root, dirs, files in os.walk(basePath):
+ for name in files:
+ if fnmatch(name, "*.pom"):
+ poms.append(join(root, name))
+ for pom in poms:
+ jarFile = pom.replace(".pom", ".jar")
+ if isfile(jarFile):
+ mavenInstall(pom, jarFile)
+ else:
+ mavenInstall(pom)
+ if "vaadin-server" in pom:
+ pomXml, nameSpace = readPomFile(pom)
+ for version in pomXml.getroot().findall("./{%s}version" % (nameSpace)):
+ args.version = version.text
+ demosFailed = False
+
for demo in demos:
print("Validating demo %s" % (demo))
try:
checkout(demo, demos[demo])
- updateRepositories(demo, repoIds = version)
- mavenValidate(demo, repoIds = version, logFile = getLogFile(demo))
- copyWarFiles(demo)
+ if hasattr(args, "repo") and args.repo is not None:
+ updateRepositories(join(resultPath, demo), args.repo)
+ mavenValidate(demo, logFile=getLogFile(demo))
+ resultWars = copyWarFiles(demo)
+ for war in resultWars:
+ try:
+ deployWar(war)
+ except Exception as e:
+ print("War %s failed to deploy: %s" % (war, e))
+ demosFailed = True
print("%s demo validation succeeded!" % (demo))
- except:
- print("%s demo validation failed" % (demo))
+ except Exception as e:
+ print("%s demo validation failed: %s" % (demo, e))
+ demosFailed = True
+ removeDir(demo)
print("")
+ if demosFailed:
+ sys.exit(1)
diff --git a/scripts/BuildHelpers.py b/scripts/BuildHelpers.py
index be21c0f721..7545467f98 100644
--- a/scripts/BuildHelpers.py
+++ b/scripts/BuildHelpers.py
@@ -5,43 +5,37 @@
import sys, argparse, subprocess, platform
from xml.etree import ElementTree
from os.path import join, isdir, isfile, basename, exists
-from os import listdir, getcwd, mkdir
-from shutil import copy
+from os import listdir, makedirs
+from shutil import copy, rmtree
from glob import glob
-class VersionObject(object):
- pass
-
-# Staging repo base url
-repo = "http://oss.sonatype.org/content/repositories/comvaadin-%d"
-
# Directory where the resulting war files are stored
# TODO: deploy results
-resultPath = "result"
+resultPath = join("result", "demos")
if not exists(resultPath):
- mkdir(resultPath)
+ makedirs(resultPath)
elif not isdir(resultPath):
print("Result path is not a directory.")
sys.exit(1)
args = None
-# Parse command line arguments <version> <framework-repo-id> <archetype-repo-id> <plugin-repo-id>
+# Default argument parser
+parser = argparse.ArgumentParser(description="Automated staging validation")
+group = parser.add_mutually_exclusive_group(required=True)
+group.add_argument("--version", help="Vaadin version to use")
+group.add_argument("--artifactPath", help="Path to local folder with Vaadin artifacts")
+
+parser.add_argument("--maven", help="Additional maven command line parameters", default=None)
+
+# Parse command line arguments <version>
def parseArgs():
- # Command line arguments for this script
- parser = argparse.ArgumentParser(description="Automated staging validation")
- parser.add_argument("version", type=str, help="Vaadin version to use")
- parser.add_argument("framework", type=int, help="Framework repo id (comvaadin-XXXX)", nargs='?')
- parser.add_argument("archetype", type=int, help="Archetype repo id (comvaadin-XXXX)", nargs='?')
- parser.add_argument("plugin", type=int, help="Maven Plugin repo id (comvaadin-XXXX)", nargs='?')
-
# If no args, give help
if len(sys.argv) == 1:
args = parser.parse_args(["-h"])
else:
args = parser.parse_args()
-
return args
# Function for determining the path for maven executable
@@ -73,48 +67,58 @@ def getArgs():
return args
# Maven Package and Validation
-def mavenValidate(artifactId, mvnCmd = mavenCmd, logFile = sys.stdout, repoIds = None):
- if repoIds is None:
- repoIds = getArgs()
+def mavenValidate(artifactId, mvnCmd = mavenCmd, logFile = sys.stdout, version = None, mavenParams = None):
+ if version is None:
+ version = getArgs().version
+ if mavenParams is None:
+ mavenParams = getArgs().maven
print("Do maven clean package validate")
cmd = [mvnCmd]
- if hasattr(repoIds, "version") and repoIds.version is not None:
- cmd.append("-Dvaadin.version=%s" % (repoIds.version))
+ cmd.append("-Dvaadin.version=%s" % (version))
+ if mavenParams is not None:
+ cmd.extend(mavenParams.strip('"').split(" "))
cmd.extend(["clean", "package", "validate"])
print("executing: %s" % (" ".join(cmd)))
- subprocess.check_call(cmd, cwd=join(getcwd(), artifactId), stdout=logFile)
+ subprocess.check_call(cmd, cwd=join(resultPath, artifactId), stdout=logFile)
# Collect .war files to given folder with given naming
def copyWarFiles(artifactId, resultDir = resultPath, name = None):
if name is None:
name = artifactId
- warFiles = glob(join(getcwd(), artifactId, "target", "*.war"))
- warFiles.extend(glob(join(getcwd(), artifactId, "*", "target", "*.war")))
+ copiedWars = []
+ warFiles = glob(join(resultDir, artifactId, "target", "*.war"))
+ warFiles.extend(glob(join(resultDir, artifactId, "*", "target", "*.war")))
for warFile in warFiles:
if len(warFiles) == 1:
deployName = "%s.war" % (name)
else:
deployName = "%s-%d.war" % (name, warFiles.index(warFile))
print("Copying .war file %s as %s to result folder" % (basename(warFile), deployName))
- copy(warFile, join(resultDir, "%s" % (deployName)))
+ copy(warFile, join(resultDir, deployName))
+ copiedWars.append(join(resultDir, deployName))
+ return copiedWars
+
+def readPomFile(pomFile):
+ # pom.xml namespace workaround
+ root = ElementTree.parse(pomFile).getroot()
+ nameSpace = root.tag[1:root.tag.index('}')]
+ ElementTree.register_namespace('', nameSpace)
+
+ # Read the pom.xml correctly
+ return ElementTree.parse(pomFile), nameSpace
# Recursive pom.xml update script
-def updateRepositories(path, repoIds = None, repoUrl = repo):
+def updateRepositories(path, repoUrl = None, version = None):
# If versions are not supplied, parse arguments
- if repoIds is None:
- repoIds = getArgs()
-
+ if version is None:
+ version = getArgs().version
+
# Read pom.xml
pomXml = join(path, "pom.xml")
if isfile(pomXml):
- # pom.xml namespace workaround
- root = ElementTree.parse(pomXml).getroot()
- nameSpace = root.tag[1:root.tag.index('}')]
- ElementTree.register_namespace('', nameSpace)
-
# Read the pom.xml correctly
- tree = ElementTree.parse(pomXml)
+ tree, nameSpace = readPomFile(pomXml)
# NameSpace needed for finding the repositories node
repoNode = tree.getroot().find("{%s}repositories" % (nameSpace))
@@ -124,9 +128,8 @@ def updateRepositories(path, repoIds = None, repoUrl = repo):
if repoNode is not None:
print("Add staging repositories to " + pomXml)
- if hasattr(repoIds, "framework") and repoIds.framework is not None:
- # Add framework staging repository
- addRepo(repoNode, "repository", "vaadin-%s-staging" % (repoIds.version), repoUrl % (repoIds.framework))
+ # Add framework staging repository
+ addRepo(repoNode, "repository", "vaadin-%s-staging" % (version), repoUrl)
# Find the correct pluginRepositories node
pluginRepo = tree.getroot().find("{%s}pluginRepositories" % (nameSpace))
@@ -134,9 +137,8 @@ def updateRepositories(path, repoIds = None, repoUrl = repo):
# Add pluginRepositories node if needed
pluginRepo = ElementTree.SubElement(tree.getroot(), "pluginRepositories")
- if hasattr(repoIds, "plugin") and repoIds.plugin is not None:
- # Add plugin staging repository
- addRepo(pluginRepo, "pluginRepository", "vaadin-%s-plugin-staging" % (repoIds.version), repoUrl % (repoIds.plugin))
+ # Add plugin staging repository
+ addRepo(pluginRepo, "pluginRepository", "vaadin-%s-plugin-staging" % (version), repoUrl)
# Overwrite the modified pom.xml
tree.write(pomXml, encoding='UTF-8')
@@ -145,7 +147,7 @@ def updateRepositories(path, repoIds = None, repoUrl = repo):
for i in listdir(path):
file = join(path, i)
if isdir(file):
- updateRepositories(join(path, i), repoIds, repoUrl)
+ updateRepositories(join(path, i), repoUrl, version)
# Add a repository of repoType to given repoNode with id and URL
def addRepo(repoNode, repoType, id, url):
@@ -158,3 +160,16 @@ def addRepo(repoNode, repoType, id, url):
# Get a logfile for given artifact
def getLogFile(artifact, resultDir = resultPath):
return open(join(resultDir, "%s.log" % (artifact)), 'w')
+
+def removeDir(subdir):
+ if '..' in subdir or '/' in subdir:
+ # Dangerous relative paths.
+ return
+ rmtree(join(resultPath, subdir))
+
+def mavenInstall(pomFile, jarFile = None, mvnCmd = mavenCmd, logFile = sys.stdout):
+ cmd = [mvnCmd, "install:install-file"]
+ cmd.append("-Dfile=%s" % (jarFile if jarFile is not None else pomFile))
+ cmd.append("-DpomFile=%s" % (pomFile))
+ print("executing: %s" % (" ".join(cmd)))
+ subprocess.check_call(cmd, stdout=logFile)
diff --git a/scripts/DeployHelpers.py b/scripts/DeployHelpers.py
new file mode 100644
index 0000000000..2c879088ff
--- /dev/null
+++ b/scripts/DeployHelpers.py
@@ -0,0 +1,82 @@
+#coding=UTF-8
+
+### Helper class for wildfly deployments. ###
+# Related files $HOME/.deploy-url $HOME/.deploy-credentials
+
+import sys, json
+try:
+ import requests
+except Exception as e:
+ print("DeployHelpers depends on requests library. Install it with `pip install requests`")
+ sys.exit(1)
+from requests.auth import HTTPDigestAuth
+from os.path import join, expanduser, basename
+from BuildHelpers import parser, getArgs
+
+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)
+
+# Helper for handling the full deployment
+# name should end with .war
+def deployWar(warFile, name=None):
+ if name is None:
+ name = basename(warFile).replace('.war', "-%s.war" % (getArgs().version.split('-')[0]))
+
+ print("Deploying to context %s" % (name[:-4]))
+ # Undeploy/Remove old version if needed
+ if deploymentExists(name):
+ removeDeployment(name)
+ # Do upload war file
+ hash = doUploadWarFile(warFile)
+ # Do deployment under name
+ doDeploy(hash, name)
+
+def deploymentExists(name):
+ # Deployment existence check data
+ data = {"operation" : "read-attribute", "name": "runtime-name", "address": [{"deployment" : name}]}
+ result = doPostJson(url=getUrl(), auth=getAuth(), data=json.dumps(data))
+ return result.json()["outcome"] == "success"
+
+def doDeploy(hash, name):
+ # Deployment data
+ data = {}
+ data["content"] = [{"hash" : hash}]
+ data["address"] = [{"deployment" : name}]
+ data["operation"] = "add"
+ data["enabled"] = True
+ return doPostJson(data=json.dumps(data), auth=getAuth(), url=getUrl())
+
+# Helper for adding Content-Type to headers
+def doPostJson(**kwargs):
+ r = requests.post(headers={"Content-Type" : "application/json"}, **kwargs)
+ # Wildfly gives code 500 when asking for a non-existent deployment
+ if r.status_code == requests.codes.ok or r.status_code == 500:
+ return r
+ r.raise_for_status()
+
+def doUploadWarFile(warFile):
+ # Upload request, just see the outcome
+ result = requests.post("%s/add-content" % (getUrl()), files={"file" : open(warFile, 'rb')}, auth=getAuth()).json()
+ if "outcome" not in result or result["outcome"] != "success":
+ raise Exception("File upload failed.", result)
+ return result["result"]
+
+# Method for removing an existing deployment
+def removeDeployment(name):
+ data = {}
+ data["address"] = [{"deployment" : name}]
+ for i in ["undeploy", "remove"]:
+ print("%s old deployment of %s" % (i, name))
+ data["operation"] = i
+ doPostJson(data=json.dumps(data), auth=getAuth(), url=getUrl())
+
+# Read credentials file and return a HTTPDigestAuth object
+def getAuth():
+ args = getArgs()
+ return HTTPDigestAuth(args.deployUser, args.deployPass)
+
+# Read the deploy url file and return the url
+def getUrl():
+ return getArgs().deployUrl
+
diff --git a/scripts/GenerateBuildReport.py b/scripts/GenerateBuildReport.py
new file mode 100644
index 0000000000..8ee2472133
--- /dev/null
+++ b/scripts/GenerateBuildReport.py
@@ -0,0 +1,48 @@
+#coding=UTF-8
+
+from BuildDemos import demos
+import argparse, subprocess
+
+parser = argparse.ArgumentParser(description="Build report generator")
+parser.add_argument("version", type=str, help="Vaadin version that was just built")
+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")
+
+args = parser.parse_args()
+
+content = """<html>
+<head></head>
+<body>
+<table>
+<tr><td><a href="https://dev.vaadin.com/milestone?action=new">Create milestone for next release</a></td></tr>
+<tr><td><a href="https://dev.vaadin.com/query?status=closed&component=Core+Framework&resolution=fixed&milestone=Vaadin {version}&col=id&col=summary&col=component&col=milestone&col=status&col=type">Closed tickets with milestone {version}</a></td></tr>
+<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">Pending-release tickets with milestone {version}</a></td></tr>
+<tr><td><a href="https://dev.vaadin.com/query?status=pending-release&milestone=">Pending-release tickets without milestone</a></td></tr>
+<tr><td><a href="apidiff/changes.html">API Diff</a></td></tr>
+<tr><td><a href="release-notes/release-notes.html">Release Notes</a></td></tr>
+""".format(version=args.version)
+
+try:
+ p1 = subprocess.Popen(['find', '.', '-name', '*.java'], stdout=subprocess.PIPE)
+ p2 = subprocess.Popen(['xargs', 'egrep', '@since ?$'], stdin=p1.stdout, stdout=subprocess.PIPE)
+ missing = subprocess.check_output(['grep', '-v', 'tests'], stdin=p2.stdout)
+ content += "<tr><td>Empty @since:<br>\n<pre>%s</pre></td></tr>\n" % (missing)
+except subprocess.CalledProcessError as e:
+ if e.returncode == 1:
+ content += "<tr><td>No empty @since</td></tr>\n"
+ else:
+ raise e
+
+content += "<tr><td>Try demos<ul>"
+
+for demo in demos:
+ content += "<li><a href='{url}/{demoName}-{version}'>{demoName}</a></li>\n".format(url=args.deployUrl, demoName=demo, version=args.version)
+
+content += """</ul></td></tr>
+<tr><td><a href="{url}">Build result page (See test results, pin and tag build and dependencies)</a></td></tr>
+</table>
+</body>
+</html>""".format(url=args.buildResultUrl)
+
+f = open("result/report.html", 'w')
+f.write(content)
diff --git a/scripts/GenerateStagingReport.py b/scripts/GenerateStagingReport.py
new file mode 100644
index 0000000000..fdcdc93fdb
--- /dev/null
+++ b/scripts/GenerateStagingReport.py
@@ -0,0 +1,40 @@
+#coding=UTF-8
+
+from BuildArchetypes import archetypes, getDeploymentContext
+import argparse, cgi
+
+parser = argparse.ArgumentParser(description="Build report generator")
+parser.add_argument("version", type=str, help="Vaadin version that was just built")
+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")
+
+args = parser.parse_args()
+
+content = """<html>
+<head></head>
+<body>
+<table>
+"""
+
+content += "<tr><td>Try archetype demos<ul>"
+
+for archetype in archetypes:
+ content += "<li><a href='{url}/{context}'>{demo}</a></li>\n".format(url=args.deployUrl, demo=archetype, context=getDeploymentContext(archetype, args.version))
+
+content += """</ul></td></tr>
+<tr><td><a href="{repoUrl}">Staging repository</a></td></tr>
+<tr><td>Eclipse Ivy Settings:<br><pre>""".format(repoUrl=args.stagingRepo)
+content += cgi.escape(""" <ibiblio name="vaadin-staging" usepoms="true" m2compatible="true"
+ 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/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>
+</table>
+</body>
+</html>""".format(url=args.buildResultUrl, repoUrl=args.stagingRepo, version=args.version)
+
+f = open("result/report.html", 'w')
+f.write(content)
diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java
index 71b597ff1d..55947c98d1 100644
--- a/server/src/com/vaadin/data/RpcDataProviderExtension.java
+++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java
@@ -947,6 +947,14 @@ public class RpcDataProviderExtension extends AbstractExtension {
listener.removeListener();
}
+ // Wipe clean all details.
+ HashSet<Object> detailItemIds = new HashSet<Object>(
+ detailComponentManager.visibleDetailsComponents
+ .keySet());
+ for (Object itemId : detailItemIds) {
+ detailComponentManager.destroyDetails(itemId);
+ }
+
listeners.clear();
activeRowHandler.activeRange = Range.withLength(0, 0);
@@ -1387,4 +1395,14 @@ public class RpcDataProviderExtension extends AbstractExtension {
public DetailComponentManager getDetailComponentManager() {
return detailComponentManager;
}
+
+ @Override
+ public void detach() {
+ for (Object itemId : ImmutableSet
+ .copyOf(detailComponentManager.visibleDetails)) {
+ detailComponentManager.destroyDetails(itemId);
+ }
+
+ super.detach();
+ }
}
diff --git a/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java b/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java
index 495bed74f8..b86fec5558 100644
--- a/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java
+++ b/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java
@@ -155,9 +155,7 @@ public class StringToCollectionConverter implements
previous = index + delimiter.length();
index = value.indexOf(delimiter, previous);
}
- if (result.size() > 0) {
- collectToken(value.substring(previous), result, converter, locale);
- }
+ collectToken(value.substring(previous), result, converter, locale);
return result;
}
diff --git a/server/src/com/vaadin/server/AbstractClientConnector.java b/server/src/com/vaadin/server/AbstractClientConnector.java
index 0655b482ed..b6bcebd167 100644
--- a/server/src/com/vaadin/server/AbstractClientConnector.java
+++ b/server/src/com/vaadin/server/AbstractClientConnector.java
@@ -30,6 +30,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import com.vaadin.event.EventRouter;
@@ -91,6 +92,8 @@ public abstract class AbstractClientConnector implements ClientConnector,
private ErrorHandler errorHandler = null;
+ private static final ConcurrentHashMap<Class<? extends AbstractClientConnector>, Class<? extends SharedState>> stateTypeCache = new ConcurrentHashMap<Class<? extends AbstractClientConnector>, Class<? extends SharedState>>();
+
@Override
public void addAttachListener(AttachListener listener) {
addListener(AttachEvent.ATTACH_EVENT_IDENTIFIER, AttachEvent.class,
@@ -296,7 +299,12 @@ public abstract class AbstractClientConnector implements ClientConnector,
// Lazy load because finding type can be expensive because of the
// exceptions flying around
if (stateType == null) {
- stateType = findStateType();
+ // Cache because we don't need to do this once per instance
+ stateType = stateTypeCache.get(this.getClass());
+ if (stateType == null) {
+ stateType = findStateType();
+ stateTypeCache.put(this.getClass(), stateType);
+ }
}
return stateType;
diff --git a/server/src/com/vaadin/server/CustomizedSystemMessages.java b/server/src/com/vaadin/server/CustomizedSystemMessages.java
index f7049e3688..9aef4f5cf3 100644
--- a/server/src/com/vaadin/server/CustomizedSystemMessages.java
+++ b/server/src/com/vaadin/server/CustomizedSystemMessages.java
@@ -240,50 +240,6 @@ public class CustomizedSystemMessages extends SystemMessages implements
}
/**
- * Sets the URL to go to when the client is out-of-sync.
- *
- * @param outOfSyncURL
- * the URL to go to, or null to reload current
- */
- public void setOutOfSyncURL(String outOfSyncURL) {
- this.outOfSyncURL = outOfSyncURL;
- }
-
- /**
- * Enables or disables the notification. If disabled, the set URL (or
- * current) is loaded directly.
- *
- * @param outOfSyncNotificationEnabled
- * true = enabled, false = disabled
- */
- public void setOutOfSyncNotificationEnabled(
- boolean outOfSyncNotificationEnabled) {
- this.outOfSyncNotificationEnabled = outOfSyncNotificationEnabled;
- }
-
- /**
- * Sets the caption of the notification. Set to null for no caption. If both
- * caption and message is null, the notification is disabled;
- *
- * @param outOfSyncCaption
- * the caption
- */
- public void setOutOfSyncCaption(String outOfSyncCaption) {
- this.outOfSyncCaption = outOfSyncCaption;
- }
-
- /**
- * Sets the message of the notification. Set to null for no message. If both
- * caption and message is null, the notification is disabled;
- *
- * @param outOfSyncMessage
- * the message
- */
- public void setOutOfSyncMessage(String outOfSyncMessage) {
- this.outOfSyncMessage = outOfSyncMessage;
- }
-
- /**
* Sets the URL to redirect to when the browser has cookies disabled.
*
* @param cookiesDisabledURL
diff --git a/server/src/com/vaadin/server/SystemMessages.java b/server/src/com/vaadin/server/SystemMessages.java
index 51cc7d497d..3bcf0a90fa 100644
--- a/server/src/com/vaadin/server/SystemMessages.java
+++ b/server/src/com/vaadin/server/SystemMessages.java
@@ -43,12 +43,6 @@ import java.io.Serializable;
* <li><b>internalErrorCaption</b> = "Internal error"</li>
* <li><b>internalErrorMessage</b> = "Please notify the administrator.<br/>
* Take note of any unsaved data, and <u>click here</u> to continue."</li>
- * <li><b>outOfSyncURL</b> = null</li>
- * <li><b>outOfSyncNotificationEnabled</b> = true</li>
- * <li><b>outOfSyncCaption</b> = "Out of sync"</li>
- * <li><b>outOfSyncMessage</b> = "Something has caused us to be out of sync with
- * the server.<br/>
- * Take note of any unsaved data, and <u>click here</u> to re-sync."</li>
* <li><b>cookiesDisabledURL</b> = null</li>
* <li><b>cookiesDisabledNotificationEnabled</b> = true</li>
* <li><b>cookiesDisabledCaption</b> = "Cookies disabled"</li>
@@ -80,11 +74,6 @@ public class SystemMessages implements Serializable {
protected String internalErrorCaption = "Internal error";
protected String internalErrorMessage = "Please notify the administrator.<br/>Take note of any unsaved data, and <u>click here</u> or press ESC to continue.";
- protected String outOfSyncURL = null;
- protected boolean outOfSyncNotificationEnabled = true;
- protected String outOfSyncCaption = "Out of sync";
- protected String outOfSyncMessage = "Something has caused us to be out of sync with the server.<br/>Take note of any unsaved data, and <u>click here</u> or press ESC to re-sync.";
-
protected String cookiesDisabledURL = null;
protected boolean cookiesDisabledNotificationEnabled = true;
protected String cookiesDisabledCaption = "Cookies disabled";
diff --git a/server/src/com/vaadin/ui/ConnectorTracker.java b/server/src/com/vaadin/ui/ConnectorTracker.java
index 95a80b7be0..eba248fb00 100644
--- a/server/src/com/vaadin/ui/ConnectorTracker.java
+++ b/server/src/com/vaadin/ui/ConnectorTracker.java
@@ -24,6 +24,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
+import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
@@ -591,8 +592,8 @@ public class ConnectorTracker implements Serializable {
* <p>
* This method has a side-effect of incrementing the sync id by one (see
* {@link #getCurrentSyncId()}), if {@link #isWritingResponse()} returns
- * <code>false</code> and <code>writingResponse</code> is set to
- * <code>true</code>.
+ * <code>true</code> and <code>writingResponse</code> is set to
+ * <code>false</code>.
*
* @param writingResponse
* the new response status.
@@ -616,7 +617,9 @@ public class ConnectorTracker implements Serializable {
* the right hand side of the && is unnecessary here because of the
* if-clause above, but rigorous coding is always rigorous coding.
*/
- if (writingResponse && !this.writingResponse) {
+ if (!writingResponse && this.writingResponse) {
+ // Bump sync id when done writing - the client is not expected to
+ // know about anything happening after this moment.
currentSyncId++;
}
this.writingResponse = writingResponse;
@@ -784,34 +787,25 @@ public class ConnectorTracker implements Serializable {
*/
public boolean connectorWasPresentAsRequestWasSent(String connectorId,
long lastSyncIdSeenByClient) {
-
assert getConnector(connectorId) == null : "Connector " + connectorId
+ " is still attached";
- boolean clientRequestIsTooOld = lastSyncIdSeenByClient < currentSyncId
- && lastSyncIdSeenByClient != -1;
- if (clientRequestIsTooOld) {
- /*
- * The headMap call is present here because we're only interested in
- * connectors removed "in the past" (i.e. the server has removed
- * them before the client ever knew about that), since those are the
- * ones that we choose to handle as a special case.
- */
- /*-
- * Server Client
- * [#1 add table] ---------.
- * \
- * [push: #2 remove table]-. `--> [adding table, storing #1]
- * \ .- [table from request #1 needs more data]
- * \/
- * /`-> [removing table, storing #2]
- * [#1 < #2 - ignoring] <---´
- */
- for (Set<String> unregisteredConnectors : syncIdToUnregisteredConnectorIds
- .headMap(currentSyncId).values()) {
- if (unregisteredConnectors.contains(connectorId)) {
- return true;
- }
+ if (lastSyncIdSeenByClient == -1) {
+ // Ignore potential problems
+ return true;
+ }
+
+ /*
+ * Use non-inclusive tail map to find all connectors that were removed
+ * after the reported sync id was sent to the client.
+ */
+ NavigableMap<Integer, Set<String>> unregisteredAfter = syncIdToUnregisteredConnectorIds
+ .tailMap(Integer.valueOf((int) lastSyncIdSeenByClient), false);
+ for (Set<String> unregisteredIds : unregisteredAfter.values()) {
+ if (unregisteredIds.contains(connectorId)) {
+ // Removed with a higher sync id, so it was most likely present
+ // when this sync id was sent.
+ return true;
}
}
@@ -877,7 +871,7 @@ public class ConnectorTracker implements Serializable {
* conflicts. In any case, it's better to clean up too little than too
* much, especially as the data will hardly grow into the kilobytes.
*/
- syncIdToUnregisteredConnectorIds.headMap(lastSyncIdSeenByClient)
+ syncIdToUnregisteredConnectorIds.headMap(lastSyncIdSeenByClient, true)
.clear();
}
}
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index af89064411..251ec0f678 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -6084,10 +6084,15 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
editorActive = false;
editorFieldGroup.discard();
editorFieldGroup.setItemDataSource(null);
+
if (datasource instanceof ItemSetChangeNotifier) {
((ItemSetChangeNotifier) datasource)
.removeItemSetChangeListener(editorClosingItemSetListener);
}
+
+ // Mark Grid as dirty so the client side gets to know that the editors
+ // are no longer attached
+ markAsDirty();
}
void resetEditor() {
diff --git a/server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java b/server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java
index 977985c6cb..bcd0dc15bd 100644
--- a/server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java
+++ b/server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java
@@ -141,6 +141,16 @@ public class StringToCollectionConverterTest {
Assert.assertEquals("Z,Y", presentation);
}
+ @Test
+ public void convertToModel_singleItem() {
+ StringToCollectionConverter converter = new StringToCollectionConverter();
+ Collection<?> model = converter.convertToModel("a", List.class, null);
+ Iterator<?> iterator = model.iterator();
+ Assert.assertEquals("Incorrect fist token", "a", iterator.next());
+ Assert.assertFalse("More than one item detected after conversation",
+ iterator.hasNext());
+ }
+
public enum TestEnum {
X, Y, Z;
}
diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java
index 2f51fef6ee..6f7a531eb6 100644
--- a/shared/src/com/vaadin/shared/ui/ui/UIState.java
+++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java
@@ -43,12 +43,16 @@ public class UIState extends TabIndexState {
notificationConfigurations.put("humanized",
new NotificationTypeConfiguration("Info: ", null,
NotificationRole.ALERT));
+
+ // We use alert instead of status for all notifications because
+ // (at least) Jaws 16 and earlier fail to announce any role=status
+ // message in Chrome/Firefox
notificationConfigurations.put("tray",
new NotificationTypeConfiguration("Status: ", null,
- NotificationRole.STATUS));
+ NotificationRole.ALERT));
notificationConfigurations.put("assistive",
new NotificationTypeConfiguration("Note: ", null,
- NotificationRole.STATUS));
+ NotificationRole.ALERT));
}
/**
* State related to the Page class.
diff --git a/uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemoval.java b/uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemoval.java
new file mode 100644
index 0000000000..d8f7fface3
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemoval.java
@@ -0,0 +1,77 @@
+package com.vaadin.tests.application;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.Set;
+
+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.ConnectorTracker;
+import com.vaadin.ui.Window;
+
+public class ResynchronizeAfterAsyncRemoval extends AbstractTestUIWithLog {
+
+ @Override
+ public void setup(VaadinRequest vaadinRequest) {
+ final Window window = new Window("Asynchronously removed window");
+ window.center();
+
+ // The window will enqueue a non-immediate message reporting its current
+ // position.
+ addWindow(window);
+
+ // Remove window immediately when the current response is sent
+ runAfterResponse(new Runnable() {
+ @Override
+ public void run() {
+ removeWindow(window);
+ }
+ });
+
+ // Clicking the button will trigger sending the window coordinates, but
+ // the window is already removed at that point.
+ addComponent(new Button("Am I dirty?", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ log("Window removed: " + (window.getParent() == null));
+
+ boolean dirty = getUI().getConnectorTracker().isDirty(
+ event.getButton());
+ log("Dirty: " + dirty);
+ }
+ }));
+ addComponent(new Button("Log unregistered connector count",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ logUnregisteredConnectorCount();
+ }
+ }));
+ }
+
+ private void logUnregisteredConnectorCount() {
+ int count = 0;
+
+ Map<Integer, Set<String>> unregisterIdMap = getUnregisterIdMap();
+ for (Set<String> set : unregisterIdMap.values()) {
+ count += set.size();
+ }
+ log("syncId: " + getConnectorTracker().getCurrentSyncId());
+ log("Unregistered connector count: " + count);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map<Integer, Set<String>> getUnregisterIdMap() {
+ try {
+ ConnectorTracker tracker = getConnectorTracker();
+ Field field = tracker.getClass().getDeclaredField(
+ "syncIdToUnregisteredConnectorIds");
+ field.setAccessible(true);
+ return (Map<Integer, Set<String>>) field.get(tracker);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemovalTest.java b/uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemovalTest.java
new file mode 100644
index 0000000000..7f2dabe9f1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemovalTest.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.application;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+public class ResynchronizeAfterAsyncRemovalTest extends SingleBrowserTest {
+ @Test
+ public void noResyncAfterAsyncRemoval() {
+ openTestURL();
+
+ $(ButtonElement.class).first().click();
+
+ Assert.assertEquals("Timing issue in the test?",
+ "1. Window removed: true", getLogRow(1));
+
+ Assert.assertEquals(
+ "Removing window should not cause button to be marked as dirty",
+ "2. Dirty: false", getLogRow(0));
+
+ ButtonElement logCountButton = $(ButtonElement.class).all().get(1);
+ logCountButton.click();
+
+ Assert.assertEquals("Sanity check", "3. syncId: 2", getLogRow(1));
+ Assert.assertEquals("Sanity check",
+ "4. Unregistered connector count: 1", getLogRow(0));
+
+ logCountButton.click();
+
+ Assert.assertEquals("Sanity check", "5. syncId: 3", getLogRow(1));
+ Assert.assertEquals(
+ "Unregistered connector map should have been cleared",
+ "6. Unregistered connector count: 0", getLogRow(0));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/AbstractTestUI.java b/uitest/src/com/vaadin/tests/components/AbstractTestUI.java
index dba055a65a..98b0f63ce1 100644
--- a/uitest/src/com/vaadin/tests/components/AbstractTestUI.java
+++ b/uitest/src/com/vaadin/tests/components/AbstractTestUI.java
@@ -205,4 +205,18 @@ public abstract class AbstractTestUI extends UI {
return getSession().getBrowser();
}
+ /**
+ * Execute the provided runnable on the UI thread as soon as the current
+ * request has been sent.
+ */
+ protected void runAfterResponse(final Runnable runnable) {
+ // Immediately start a thread that will start waiting for the session to
+ // get unlocked.
+ new Thread() {
+ @Override
+ public void run() {
+ accessSynchronously(runnable);
+ }
+ }.start();
+ }
}
diff --git a/uitest/src/com/vaadin/tests/components/embedded/EmbeddedAltTextTest.java b/uitest/src/com/vaadin/tests/components/embedded/EmbeddedAltTextTest.java
new file mode 100644
index 0000000000..23dcddd8d0
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/embedded/EmbeddedAltTextTest.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.embedded;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.EmbeddedElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class EmbeddedAltTextTest extends MultiBrowserTest {
+
+ @Before
+ @Override
+ public void setup() throws Exception {
+ super.setup();
+ openTestURL();
+ waitForElementPresent(By.className("v-embedded"));
+ }
+
+ @Test
+ public void testEmbeddedAltText() {
+ EmbeddedElement embedded = $(EmbeddedElement.class).first();
+
+ Assert.assertEquals("Alt text of the image", getAltText(embedded));
+ assertHtmlSource("Alt text of the object");
+
+ $(ButtonElement.class).first().click();
+
+ Assert.assertEquals("New alt text of the image!", getAltText(embedded));
+ assertHtmlSource("New alt text of the object!");
+ }
+
+ private void assertHtmlSource(String html) {
+ String pageSource = driver.getPageSource();
+ Assert.assertTrue("Page source does not contain '" + html + "'",
+ pageSource.contains(html));
+ }
+
+ private String getAltText(EmbeddedElement embedded) {
+ return embedded.findElement(By.vaadin("/domChild[0]")).getAttribute(
+ "alt");
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java b/uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java
index 3c5801e90e..28ffebcf56 100644
--- a/uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java
+++ b/uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java
@@ -5,6 +5,7 @@ import com.vaadin.event.MouseEvents.ClickListener;
import com.vaadin.server.ThemeResource;
import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.Embedded;
+import com.vaadin.ui.Label;
public class EmbeddedClickListenerRelativeCoordinates extends TestBase {
@@ -12,17 +13,21 @@ public class EmbeddedClickListenerRelativeCoordinates extends TestBase {
protected void setup() {
Embedded e = new Embedded("Embedded caption", new ThemeResource(
"../runo/icons/64/ok.png"));
+ final Label xLabel = new Label();
+ xLabel.setId("x");
+ final Label yLabel = new Label();
+ yLabel.setId("y");
e.addListener(new ClickListener() {
@Override
public void click(ClickEvent event) {
- getMainWindow()
- .showNotification(
- "" + event.getRelativeX() + ", "
- + event.getRelativeY());
+ xLabel.setValue("" + event.getRelativeX());
+ yLabel.setValue("" + event.getRelativeY());
}
});
addComponent(e);
+ addComponent(xLabel);
+ addComponent(yLabel);
}
@Override
diff --git a/uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinatesTest.java b/uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinatesTest.java
new file mode 100644
index 0000000000..6bed0117f8
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinatesTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.embedded;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.By;
+
+import com.vaadin.testbench.elements.EmbeddedElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.testbench.parallel.BrowserUtil;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class EmbeddedClickListenerRelativeCoordinatesTest extends
+ MultiBrowserTest {
+
+ @Before
+ @Override
+ public void setup() throws Exception {
+ super.setup();
+ openTestURL();
+ waitForElementPresent(By.className("v-embedded"));
+ }
+
+ @Test
+ public void testRelativeClick() {
+ clickAt(41, 22);
+ checkLocation(41, 22);
+
+ clickAt(0, 0);
+ checkLocation(0, 0);
+ }
+
+ private void clickAt(int x, int y) {
+ EmbeddedElement embedded = $(EmbeddedElement.class).first();
+
+ // IE8 consistently clicks two pixels left and above of the given
+ // position
+ if (isIE8()) {
+ x += 2;
+ y += 2;
+ }
+ embedded.click(x, y);
+ }
+
+ private void checkLocation(int expectedX, int expectedY) {
+ LabelElement xLabel = $(LabelElement.class).id("x");
+ LabelElement yLabel = $(LabelElement.class).id("y");
+
+ int x = Integer.parseInt(xLabel.getText());
+ int y = Integer.parseInt(yLabel.getText());
+
+ Assert.assertEquals(
+ "Reported X-coordinate from Embedded does not match click location",
+ expectedX, x);
+
+ // IE10 and IE11 sometimes click one pixel below the given position
+ int tolerance = isIE() ? 1 : 0;
+ Assert.assertTrue(
+ "Reported Y-coordinate from Embedded does not match click location",
+ Math.abs(expectedY - y) <= tolerance);
+ }
+
+ private boolean isIE() {
+ return BrowserUtil.isIE(getDesiredCapabilities());
+ }
+
+ private boolean isIE8() {
+ return BrowserUtil.isIE8(getDesiredCapabilities());
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplay.java b/uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplay.java
new file mode 100644
index 0000000000..e6aff73532
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplay.java
@@ -0,0 +1,91 @@
+/*
+ * 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 java.io.Serializable;
+
+import com.vaadin.data.util.BeanItemContainer;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Grid;
+
+public class GridCheckBoxDisplay extends AbstractTestUI {
+
+ private static final long serialVersionUID = -5575892909354637168L;
+ private BeanItemContainer<Todo> todoContainer = new BeanItemContainer<Todo>(
+ Todo.class);
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ todoContainer.addBean(new Todo("Done task", true));
+ todoContainer.addBean(new Todo("Not done", false));
+
+ Grid grid = new Grid(todoContainer);
+ grid.setSizeFull();
+
+ grid.setColumnOrder("done", "task");
+ grid.getColumn("done").setWidth(75);
+ grid.getColumn("task").setExpandRatio(1);
+
+ grid.setSelectionMode(Grid.SelectionMode.SINGLE);
+
+ grid.setEditorEnabled(true);
+ grid.setImmediate(true);
+
+ getLayout().addComponent(grid);
+ getLayout().setExpandRatio(grid, 1);
+
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 16976;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Verify that checkbox state is correct for all items in editor";
+ }
+
+ public class Todo implements Serializable {
+ private static final long serialVersionUID = -5961103142478316018L;
+
+ private boolean done;
+ private String task = "";
+
+ public Todo(String task, boolean done) {
+ this.task = task;
+ this.done = done;
+ }
+
+ public boolean isDone() {
+ return done;
+ }
+
+ public void setDone(boolean done) {
+ this.done = done;
+ }
+
+ public String getTask() {
+ return task;
+ }
+
+ public void setTask(String task) {
+ this.task = task;
+ }
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplayTest.java b/uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplayTest.java
new file mode 100644
index 0000000000..c430821534
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplayTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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 org.openqa.selenium.By;
+
+import com.vaadin.testbench.elements.CheckBoxElement;
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.parallel.TestCategory;
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+@TestCategory("grid")
+public class GridCheckBoxDisplayTest extends SingleBrowserTest {
+ @Test
+ public void testAddRow() {
+ openTestURL();
+
+ GridElement grid = $(GridElement.class).first();
+
+ Assert.assertEquals("First item had wrong value", "true",
+ grid.getCell(0, 0).getText());
+ Assert.assertEquals("Second item had wrong value", "false", grid
+ .getCell(1, 0).getText());
+
+ // First edit false item and see that the CheckBox is unchecked
+ grid.getCell(1, 0).doubleClick();
+
+ CheckBoxElement checkbox = $(CheckBoxElement.class).first();
+ Assert.assertEquals("CheckBox was checked", "unchecked",
+ checkbox.getValue());
+
+ closeEditor();
+
+ // Edit true item and see that the CheckBox is checked
+ grid.getCell(0, 0).doubleClick();
+
+ checkbox = $(CheckBoxElement.class).first();
+ Assert.assertEquals("CheckBox was not checked.", "checked",
+ checkbox.getValue());
+
+ closeEditor();
+
+ // Edit false item and confirm that the CheckBox is unchecked again
+ grid.getCell(1, 0).doubleClick();
+
+ checkbox = $(CheckBoxElement.class).first();
+ Assert.assertEquals("CheckBox was checked", "unchecked",
+ checkbox.getValue());
+ }
+
+ /**
+ * Closes the grids editor using the cancel button
+ */
+ private void closeEditor() {
+ findElement(By.className("v-grid-editor-cancel")).click();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java
new file mode 100644
index 0000000000..1032378a2d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java
@@ -0,0 +1,149 @@
+/*
+ * 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.data.util.BeanItemContainer;
+import com.vaadin.event.ItemClickEvent;
+import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.DetailsGenerator;
+import com.vaadin.ui.Grid.RowReference;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+
+public class GridDetailsDetach extends AbstractTestUI {
+
+ private Grid currentGrid;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ VerticalLayout layout = new VerticalLayout();
+ layout.setSizeFull();
+
+ Button button = new Button("Test");
+ layout.addComponent(button);
+ layout.setExpandRatio(button, 0f);
+
+ currentGrid = generateGrid();
+ final VerticalLayout gridContainer = new VerticalLayout();
+ gridContainer.addComponent(currentGrid);
+
+ button.addClickListener(new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ gridContainer.replaceComponent(currentGrid, new Label("Foo"));
+ }
+ });
+
+ layout.addComponent(new Button("Reattach Grid",
+ new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ gridContainer.removeAllComponents();
+ gridContainer.addComponent(currentGrid);
+ }
+ }));
+
+ layout.addComponent(gridContainer);
+ layout.setExpandRatio(gridContainer, 1f);
+
+ addComponent(layout);
+ }
+
+ private Grid generateGrid() {
+ BeanItemContainer<GridExampleBean> container = new BeanItemContainer<GridExampleBean>(
+ GridExampleBean.class);
+ for (int i = 0; i < 1000; i++) {
+ container.addItem(new GridExampleBean("Bean " + i, i * i, i / 10d));
+ }
+
+ final Grid grid = new Grid(container);
+ grid.setColumnOrder("name", "amount", "count");
+ grid.setSizeFull();
+
+ grid.setDetailsGenerator(new DetailsGenerator() {
+ @Override
+ public Component getDetails(RowReference rowReference) {
+ final GridExampleBean bean = (GridExampleBean) rowReference
+ .getItemId();
+ VerticalLayout layout = new VerticalLayout(new Label(
+ "Extra data for " + bean.getName()));
+ layout.setMargin(true);
+ return layout;
+ }
+ });
+
+ grid.addItemClickListener(new ItemClickListener() {
+ @Override
+ public void itemClick(ItemClickEvent event) {
+ Object itemId = event.getItemId();
+ grid.setDetailsVisible(itemId, !grid.isDetailsVisible(itemId));
+ }
+ });
+ return grid;
+ }
+
+ public class GridExampleBean {
+
+ private String name;
+
+ private int count;
+
+ private double amount;
+
+ public GridExampleBean() {
+ }
+
+ public GridExampleBean(String name, int count, double amount) {
+ this.name = name;
+ this.count = count;
+ this.amount = amount;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public double getAmount() {
+ return amount;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public void setAmount(double amount) {
+ this.amount = amount;
+ }
+
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java
new file mode 100644
index 0000000000..fc79fd1b68
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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 java.util.List;
+
+import org.junit.Assert;
+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.GridElement;
+import com.vaadin.testbench.parallel.TestCategory;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+@TestCategory("grid")
+public class GridDetailsDetachTest extends MultiBrowserTest {
+
+ @Test
+ public void testDetachGridWithDetailsOpen() {
+ setDebug(true);
+ openTestURL();
+
+ $(GridElement.class).first().getCell(3, 0).click();
+ $(GridElement.class).first().getCell(5, 0).click();
+
+ assertNoErrorNotifications();
+
+ $(ButtonElement.class).first().click();
+
+ assertNoErrorNotifications();
+ }
+
+ @Test
+ public void testDetachAndReattachGridWithDetailsOpen() {
+ setDebug(true);
+ openTestURL();
+
+ $(GridElement.class).first().getCell(3, 0).click();
+ $(GridElement.class).first().getCell(5, 0).click();
+
+ assertNoErrorNotifications();
+
+ $(ButtonElement.class).first().click();
+
+ assertNoErrorNotifications();
+
+ $(ButtonElement.class).get(1).click();
+
+ assertNoErrorNotifications();
+
+ List<WebElement> spacers = findElements(By.className("v-grid-spacer"));
+ Assert.assertEquals("Not enough spacers in DOM", 2, spacers.size());
+ Assert.assertEquals("Spacer content not visible",
+ "Extra data for Bean 3", spacers.get(0).getText());
+ Assert.assertEquals("Spacer content not visible",
+ "Extra data for Bean 5", spacers.get(1).getText());
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java
index 41838b427b..2def2d0279 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java
@@ -23,6 +23,7 @@ import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.elements.GridElement.GridCellElement;
import com.vaadin.testbench.parallel.TestCategory;
import com.vaadin.tests.tb3.SingleBrowserTest;
@@ -66,4 +67,26 @@ public class GridDetailsWidthTest extends SingleBrowserTest {
}
}
+ @Test
+ public void testDetailsOnSort() {
+ openTestURL();
+ GridElement grid = $(GridElement.class).first();
+
+ // Open a details rows
+ grid.getCell(0, 0).click();
+
+ GridCellElement cell = grid.getHeaderCell(0, 0);
+ cell.click();
+ cell.click();
+
+ cell = grid.getCell(2, 0);
+ WebElement spacer = findElement(By.className("v-grid-spacer"));
+ Assert.assertEquals("Grid was not sorted correctly", "Hello 0",
+ cell.getText());
+ Assert.assertEquals("Details row was not in correct location", cell
+ .getLocation().getY() + cell.getSize().getHeight(), spacer
+ .getLocation().getY());
+
+ }
+
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java
index 319cf3b8b8..4368fda158 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java
@@ -15,30 +15,18 @@
*/
package com.vaadin.tests.components.grid;
-import java.util.List;
-
import org.junit.Assert;
import org.junit.Test;
-import org.openqa.selenium.remote.DesiredCapabilities;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.GridElement;
import com.vaadin.testbench.elements.GridElement.GridRowElement;
-import com.vaadin.testbench.parallel.Browser;
import com.vaadin.testbench.parallel.TestCategory;
import com.vaadin.tests.tb3.MultiBrowserTest;
@TestCategory("grid")
public class GridSubPixelProblemWrappingTest extends MultiBrowserTest {
- @Override
- public List<DesiredCapabilities> getBrowsersToTest() {
- List<DesiredCapabilities> l = super.getBrowsersToTest();
- // Currently broken because of #18214
- l.remove(Browser.IE9.getDesiredCapabilities());
- return l;
- }
-
@Test
public void addedRowShouldNotWrap() {
openTestURL();
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java
index a341e39b74..d1d7b21e11 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java
@@ -195,4 +195,17 @@ public class GridClientSelectionTest extends GridBasicClientFeaturesTest {
isRowSelected(1));
}
+ @Test
+ public void testChangeSelectionModelUpdatesUI() {
+ openTestURL();
+
+ setSelectionModelSingle(true);
+ getGridElement().getCell(5, 1).click();
+ assertTrue("Row 5 should be selected after clicking", isRowSelected(5));
+ setSelectionModelNone();
+ assertFalse(
+ "Row 5 should not be selected after changing selection model",
+ isRowSelected(5));
+
+ }
}
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 b4eb473d4b..9953bbcae0 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
@@ -271,6 +271,20 @@ public class GridSelectionTest extends GridBasicFeaturesTest {
}
@Test
+ public void testSelectAllCheckboxWithHeaderOperations() {
+ openTestURL();
+
+ setSelectionModelMulti();
+ selectMenuPath("Component", "Header", "Prepend row");
+ selectMenuPath("Component", "Header", "Append row");
+
+ GridCellElement header = getGridElement().getHeaderCell(1, 0);
+ assertTrue("Multi Selection Model should have select all checkbox",
+ header.isElementPresent(By.tagName("input")));
+
+ }
+
+ @Test
public void testToggleDeselectAllowed() {
openTestURL();
@@ -305,6 +319,22 @@ public class GridSelectionTest extends GridBasicFeaturesTest {
.isSelected());
}
+ @Test
+ public void testChangeSelectionModelUpdatesUI() {
+ openTestURL();
+
+ setSelectionModelSingle();
+
+ getGridElement().getCell(5, 1).click();
+ assertTrue("Row should be selected after clicking", getRow(5)
+ .isSelected());
+
+ setSelectionModelNone();
+ assertFalse(
+ "Row should not be selected after changing selection model",
+ getRow(5).isSelected());
+ }
+
private void setSelectionModelMulti() {
selectMenuPath("Component", "State", "Selection mode", "multi");
}
diff --git a/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChild.java b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChild.java
new file mode 100644
index 0000000000..034ff024d0
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChild.java
@@ -0,0 +1,108 @@
+/*
+ * 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.gridlayout;
+
+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.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+
+public class GridLayoutFocusOrderAfterShowChild extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ GridLayout gl = new GridLayout(2, 5);
+ gl.setId("grid");
+ gl.setMargin(true);
+ gl.setSpacing(true);
+
+ final Label l1 = new Label("First");
+ l1.setWidthUndefined();
+ l1.setVisible(false);
+ gl.addComponent(l1);
+
+ final TextField t1 = new TextField();
+ t1.setId("t1");
+ t1.setVisible(false);
+ t1.setWidthUndefined();
+ gl.addComponent(t1);
+
+ Label l2 = new Label("Second");
+ l2.setWidthUndefined();
+ gl.addComponent(l2);
+
+ TextField t2 = new TextField();
+ t2.setId("t2");
+ gl.addComponent(t2);
+
+ final Label l3 = new Label("Third");
+ l3.setWidthUndefined();
+ l3.setVisible(false);
+ gl.addComponent(l3);
+
+ final TextField t3 = new TextField();
+ t3.setId("t3");
+ t3.setVisible(false);
+ gl.addComponent(t3);
+
+ Label l4 = new Label("Fourth");
+ l4.setWidthUndefined();
+ gl.addComponent(l4);
+
+ TextField t4 = new TextField();
+ t4.setId("t4");
+ gl.addComponent(t4);
+
+ final Label l5 = new Label("Fifth");
+ l5.setWidthUndefined();
+ l5.setVisible(false);
+ gl.addComponent(l5);
+
+ final TextField t5 = new TextField();
+ t5.setId("t5");
+ t5.setVisible(false);
+ gl.addComponent(t5);
+
+ addComponent(gl);
+
+ addComponent(new Button("Show first", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ t1.setVisible(true);
+ l1.setVisible(true);
+ }
+ }));
+
+ addComponent(new Button("Show third", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ t3.setVisible(true);
+ l3.setVisible(true);
+ }
+ }));
+
+ addComponent(new Button("Show fifth", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ t5.setVisible(true);
+ l5.setVisible(true);
+ }
+ }));
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChildTest.java b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChildTest.java
new file mode 100644
index 0000000000..1913fbfdf9
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChildTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.gridlayout;
+
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.GridLayoutElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.testbench.elements.TextFieldElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class GridLayoutFocusOrderAfterShowChildTest extends MultiBrowserTest {
+
+ @Test
+ public void showComponentBreaksFocusOrderFirst()
+ throws IOException, Exception {
+ openTestURL();
+
+ GridLayoutElement grid = $(GridLayoutElement.class).id("grid");
+
+ $(ButtonElement.class).first().click();
+
+ Assert.assertEquals("First",
+ grid.$(LabelElement.class).first().getText());
+ grid.$(TextFieldElement.class).first().focus();
+
+ grid.$(TextFieldElement.class).first().sendKeys(Keys.TAB);
+
+ Assert.assertEquals("t2",
+ driver.switchTo().activeElement().getAttribute("id"));
+ }
+
+ @Test
+ public void showComponentBreaksFocusOrderMiddle()
+ throws IOException, Exception {
+ openTestURL();
+
+ GridLayoutElement grid = $(GridLayoutElement.class).id("grid");
+
+ $(ButtonElement.class).get(1).click();
+
+ Assert.assertEquals("Third",
+ grid.$(LabelElement.class).get(1).getText());
+ grid.$(TextFieldElement.class).first().focus();
+
+ grid.$(TextFieldElement.class).first().sendKeys(Keys.TAB);
+
+ Assert.assertEquals("t3",
+ driver.switchTo().activeElement().getAttribute("id"));
+ }
+
+ @Test
+ public void showComponentBreaksFocusOrderLast()
+ throws IOException, Exception {
+ openTestURL();
+
+ GridLayoutElement grid = $(GridLayoutElement.class).id("grid");
+
+ $(ButtonElement.class).get(2).click();
+
+ Assert.assertEquals("Fifth",
+ grid.$(LabelElement.class).get(2).getText());
+ grid.$(TextFieldElement.class).get(1).focus();
+
+ grid.$(TextFieldElement.class).get(1).sendKeys(Keys.TAB);
+
+ Assert.assertEquals("t5",
+ driver.switchTo().activeElement().getAttribute("id"));
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java b/uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java
index e6b3ca2af4..e5e5163442 100644
--- a/uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java
+++ b/uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java
@@ -27,7 +27,6 @@ import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.DesiredCapabilities;
-import com.vaadin.testbench.parallel.Browser;
import com.vaadin.tests.tb3.MultiBrowserTest;
/**
@@ -39,10 +38,7 @@ public class ContextMenuSizeTest extends MultiBrowserTest {
@Override
public List<DesiredCapabilities> getBrowsersToTest() {
- // context menu doesn't work in phantom JS and works weirdly with IE8
- // and selenium.
- return getBrowserCapabilities(Browser.IE9, Browser.IE10, Browser.IE11,
- Browser.FIREFOX, Browser.CHROME);
+ return getBrowsersSupportingContextMenu();
}
@Override
diff --git a/uitest/src/com/vaadin/tests/components/tree/TreeContextMenuAndIconsTest.java b/uitest/src/com/vaadin/tests/components/tree/TreeContextMenuAndIconsTest.java
new file mode 100644
index 0000000000..81d906bec3
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/tree/TreeContextMenuAndIconsTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.tree;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.Dimension;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.remote.DesiredCapabilities;
+
+import com.vaadin.testbench.By;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class TreeContextMenuAndIconsTest extends MultiBrowserTest {
+
+ @Override
+ protected Class<?> getUIClass() {
+ return Trees.class;
+ }
+
+ @Override
+ public List<DesiredCapabilities> getBrowsersToTest() {
+ return getBrowsersSupportingContextMenu();
+ }
+
+ @Test
+ public void testSimpleContextMenu() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Settings", "Show event log");
+ selectMenuPath("Component", "Features", "Context menu",
+ "Item without icon");
+
+ openContextMenu(getTreeNodeByCaption("Item 1"));
+
+ compareScreen("contextmenu-noicon");
+
+ closeContextMenu();
+ }
+
+ @Test
+ public void testContextMenuWithAndWithoutIcon() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Settings", "Show event log");
+ selectMenuPath("Component", "Features", "Context menu",
+ "With and without icon");
+
+ openContextMenu(getTreeNodeByCaption("Item 1"));
+
+ compareScreen("caption-only-and-has-icon");
+
+ closeContextMenu();
+ }
+
+ @Test
+ public void testContextLargeIcon() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Settings", "Show event log");
+ selectMenuPath("Component", "Features", "Context menu",
+ "Only one large icon");
+
+ WebElement menu = openContextMenu(getTreeNodeByCaption("Item 1"));
+
+ // reindeer doesn't support menu with larger row height, so the
+ // background image contains parts of other sprites =>
+ // just check that the menu is of correct size
+ Dimension size = menu.getSize();
+ Assert.assertEquals("Menu height with large icons", 74, size.height);
+
+ closeContextMenu();
+ }
+
+ @Test
+ public void testContextRemoveIcon() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Settings", "Show event log");
+ selectMenuPath("Component", "Features", "Context menu",
+ "Only one large icon");
+
+ openContextMenu(getTreeNodeByCaption("Item 1"));
+ closeContextMenu();
+
+ selectMenuPath("Component", "Features", "Context menu",
+ "Item without icon");
+
+ openContextMenu(getTreeNodeByCaption("Item 1"));
+
+ compareScreen("contextmenu-noicon");
+
+ closeContextMenu();
+ }
+
+ private WebElement openContextMenu(WebElement element) {
+ Actions actions = new Actions(getDriver());
+ // Note: on Firefox, the first menu item does not get focus; on other
+ // browsers it does
+ actions.contextClick(element);
+ actions.perform();
+ return findElement(By.className("v-contextmenu"));
+ }
+
+ private void closeContextMenu() {
+ findElement(By.className("v-app")).click();
+ }
+
+ private WebElement getTreeNodeByCaption(String caption) {
+ return getDriver().findElement(
+ By.xpath("//span[text() = '" + caption + "']"));
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/upload/DragAndDropUploadAndInteractions.java b/uitest/src/com/vaadin/tests/components/upload/DragAndDropUploadAndInteractions.java
new file mode 100644
index 0000000000..952fe08b79
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/upload/DragAndDropUploadAndInteractions.java
@@ -0,0 +1,153 @@
+package com.vaadin.tests.components.upload;
+
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.server.StreamVariable;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.Html5File;
+import com.vaadin.ui.Panel;
+
+public class DragAndDropUploadAndInteractions extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ ComboBox comboBox = new ComboBox();
+ for (int i = 0; i < 10; i++) {
+ comboBox.addItem("Test " + i);
+ }
+ addComponent(comboBox);
+ Button b = new Button("Dummy");
+ addComponent(b);
+ Panel p = new Panel();
+ p.setHeight(200, Unit.PIXELS);
+ p.setWidth(200, Unit.PIXELS);
+ MyUploadPanel myUploadPanel = new MyUploadPanel(p);
+ addComponent(myUploadPanel);
+ }
+
+ class MyUploadPanel extends DragAndDropWrapper implements DropHandler {
+ private static final long serialVersionUID = 1L;
+
+ public MyUploadPanel(Component root) {
+ super(root);
+ setDropHandler(this);
+ }
+
+ @Override
+ public void drop(DragAndDropEvent event) {
+ WrapperTransferable tr = (WrapperTransferable) event
+ .getTransferable();
+ Html5File[] files = tr.getFiles();
+
+ if (files != null) {
+ List<Html5File> filesToUpload = Arrays.asList(files);
+ for (Html5File file : filesToUpload) {
+ file.setStreamVariable(new MyStreamVariable());
+ }
+ }
+ }
+
+ @Override
+ public AcceptCriterion getAcceptCriterion() {
+ return AcceptAll.get();
+ }
+
+ }
+
+ class MyStreamVariable implements StreamVariable {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public OutputStream getOutputStream() {
+ return new ByteArrayOutputStream();
+ }
+
+ @Override
+ public boolean listenProgress() {
+ return true;
+ }
+
+ long lastEvent = 0;
+ long lastTime = 0;
+
+ @Override
+ public void onProgress(StreamingProgressEvent event) {
+ long received = event.getBytesReceived() - lastEvent;
+ long now = new Date().getTime();
+ long time = now - lastTime;
+ lastTime = now;
+ lastEvent = event.getBytesReceived();
+ if (time == 0) {
+ return;
+ }
+ log("Received " + received + " bytes in " + time + "ms: "
+ + formatSize(received / (time / 1000.0)) + "/s");
+ log("Streaming OnProgress - ContentLength: "
+ + formatSize(event.getContentLength())
+ + " - Bytes Received: "
+ + formatSize(event.getBytesReceived()));
+ }
+
+ @Override
+ public void streamingStarted(StreamingStartEvent event) {
+ lastEvent = 0;
+ lastTime = new Date().getTime();
+ log("Streaming Started - ContentLength: "
+ + formatSize(event.getContentLength())
+ + " - Bytes Received: "
+ + formatSize(event.getBytesReceived()));
+ }
+
+ @Override
+ public void streamingFinished(StreamingEndEvent event) {
+ log("Streaming Finished - ContentLength: "
+ + formatSize(event.getContentLength())
+ + " - Bytes Received: "
+ + formatSize(event.getBytesReceived()));
+ }
+
+ @Override
+ public void streamingFailed(StreamingErrorEvent event) {
+ log("Streaming Failed - ContentLength: "
+ + formatSize(event.getContentLength())
+ + " - Bytes Received: "
+ + formatSize(event.getBytesReceived()));
+ }
+
+ @Override
+ public boolean isInterrupted() {
+ return false;
+ }
+
+ }
+
+ protected String formatSize(double contentLength) {
+ double d = contentLength;
+ int suffix = 0;
+ String[] suffixes = new String[] { "B", "KB", "MB", "GB", "TB" };
+ while (d > 1024) {
+ suffix++;
+ d /= 1024.0;
+ }
+ return String.format("%.1f %s", d, suffixes[suffix]);
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Drop a large (100 MB) file using IE10 and interact with the application while uploading. Ensure the uploads succeeds even though you are interacting with the app.";
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContentTest.java b/uitest/src/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContentTest.java
new file mode 100644
index 0000000000..057a43f495
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContentTest.java
@@ -0,0 +1,34 @@
+package com.vaadin.tests.components.window;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+
+import com.vaadin.testbench.elements.TextFieldElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+import com.vaadin.tests.tb3.newelements.WindowElement;
+
+public class UndefinedHeightSubWindowAndContentTest extends MultiBrowserTest {
+
+ @Test
+ public void testUndefinedHeight() {
+ openTestURL();
+
+ TextFieldElement textField = $(TextFieldElement.class).first();
+
+ textField.click();
+ textField.sendKeys("invalid", Keys.ENTER);
+
+ WindowElement window = $(WindowElement.class).first();
+ int height = window.getSize().getHeight();
+ Assert.assertTrue("Window height with validation failure",
+ 161 <= height && height <= 164);
+
+ textField.setValue("valid");
+ textField.sendKeys(Keys.ENTER);
+ height = window.getSize().getHeight();
+ Assert.assertTrue("Window height with validation success",
+ 136 <= height && height <= 139);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStyles.java b/uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStyles.java
new file mode 100644
index 0000000000..9f9453d505
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStyles.java
@@ -0,0 +1,37 @@
+/*
+ * 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.extensions;
+
+import com.vaadin.annotations.StyleSheet;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+
+@StyleSheet("http://fonts.googleapis.com/css?family=Cabin+Sketch")
+public class ResponsiveWithCrossDomainStyles extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ addComponent(new Button("Make responsive", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ event.getButton().setResponsive(true);
+ }
+ }));
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStylesTest.java b/uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStylesTest.java
new file mode 100644
index 0000000000..4089618635
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStylesTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.extensions;
+
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class ResponsiveWithCrossDomainStylesTest extends MultiBrowserTest {
+ @Test
+ public void testResponsive() {
+ setDebug(true);
+ openTestURL();
+
+ $(ButtonElement.class).first().click();
+
+ assertNoErrorNotifications();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonForm.java b/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonForm.java
index a223cea6a0..52d3e60af5 100644
--- a/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonForm.java
+++ b/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonForm.java
@@ -131,7 +131,9 @@ public class BasicPersonForm extends AbstractTestUIWithLog {
} catch (CommitException e) {
msg = "Commit failed: " + e.getMessage();
}
- Notification.show(msg);
+ Notification notification = new Notification(msg);
+ notification.setDelayMsec(Notification.DELAY_FOREVER);
+ notification.show(getPage());
log(msg);
}
diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java
index edcd07ee89..842fcbb859 100644
--- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java
+++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java
@@ -240,6 +240,15 @@ public abstract class AbstractTB3Test extends ParallelTest {
* debug window and/or push (depending on {@link #isDebug()} and
* {@link #isPush()}.
*/
+ protected void openTestURL() {
+ openTestURL(new String[0]);
+ }
+
+ /**
+ * Opens the given test (defined by {@link #getTestUrl()}, optionally with
+ * debug window and/or push (depending on {@link #isDebug()} and
+ * {@link #isPush()}.
+ */
protected void openTestURL(String... parameters) {
openTestURL(getUIClass(), parameters);
}
diff --git a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java
index 678b38c4f1..a678009d85 100644
--- a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java
+++ b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java
@@ -80,6 +80,13 @@ public abstract class MultiBrowserTest extends PrivateTB3Configuration {
Browser.IE11);
}
+ protected List<DesiredCapabilities> getBrowsersSupportingContextMenu() {
+ // context menu doesn't work in phantom JS and works weirdly with IE8
+ // and selenium.
+ return getBrowserCapabilities(Browser.IE9, Browser.IE10, Browser.IE11,
+ Browser.FIREFOX, Browser.CHROME);
+ }
+
@Override
public void setDesiredCapabilities(DesiredCapabilities desiredCapabilities) {
if (BrowserUtil.isIE(desiredCapabilities)) {
diff --git a/uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedAltText.html b/uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedAltText.html
deleted file mode 100644
index 066c55fe55..0000000000
--- a/uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedAltText.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="http://localhost:8068" />
-<title>EmbeddedAltText</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">EmbeddedAltText</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/com.vaadin.tests.components.embedded.EmbeddedAltText?restartApplication</td>
- <td></td>
-</tr>
-<tr>
- <td>assertAttribute</td>
- <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedAltText::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VEmbedded[0]/domChild[0]@alt</td>
- <td>Alt text of the image</td>
-</tr>
-<tr>
- <td>assertHtmlSource</td>
- <td>*Alt text of the object*</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedAltText::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>assertAttribute</td>
- <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedAltText::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VEmbedded[0]/domChild[0]@alt</td>
- <td>New alt text of the image!</td>
-</tr>
-<tr>
- <td>assertHtmlSource</td>
- <td>*New alt text of the object!*</td>
- <td></td>
-</tr>
-
-</tbody></table>
-</body>
-</html>
diff --git a/uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html b/uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html
deleted file mode 100644
index ae81cfe61c..0000000000
--- a/uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="" />
-<title>EmbeddedClickListenerRelativeCoordinates</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">EmbeddedClickListenerRelativeCoordinates</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/com.vaadin.tests.components.embedded.EmbeddedClickListenerRelativeCoordinates?restartApplication</td>
- <td></td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VEmbedded[0]/domChild[0]</td>
- <td>41,22</td>
-</tr>
-<tr>
- <td>assertText</td>
- <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::Root/VNotification[0]/HTML[0]/domChild[1]</td>
- <td>41, 22</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::Root/VNotification[0]</td>
- <td>0,0</td>
-</tr>
-<tr>
- <td>waitForElementNotPresent</td>
- <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::Root/VNotification[0]/HTML[0]/domChild[1]</td>
- <td></td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VEmbedded[0]/domChild[0]</td>
- <td>0,0</td>
-</tr>
-<tr>
- <td>assertText</td>
- <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::Root/VNotification[0]/HTML[0]/domChild[1]</td>
- <td>0, 0</td>
-</tr>
-</tbody></table>
-</body>
-</html>
diff --git a/uitest/tb2/com/vaadin/tests/components/tree/TreeContextMenuAndIcons.html b/uitest/tb2/com/vaadin/tests/components/tree/TreeContextMenuAndIcons.html
deleted file mode 100644
index 6f9b5e81c3..0000000000
--- a/uitest/tb2/com/vaadin/tests/components/tree/TreeContextMenuAndIcons.html
+++ /dev/null
@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="http://localhost:8888/" />
-<title>New Test</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">New Test</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/com.vaadin.tests.components.tree.Trees?restartApplication</td>
- <td></td>
-</tr>
-<!--Hide event log-->
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_Smenu#item1</td>
- <td>19,7</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[0]/VMenuBar[0]#item0</td>
- <td>32,7</td>
-</tr>
-<!--Simple context menu-->
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_Smenu#item0</td>
- <td>28,7</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[0]/VMenuBar[0]#item6</td>
- <td>57,11</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[1]/VMenuBar[0]#item4</td>
- <td>68,4</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[2]/VMenuBar[0]#item1</td>
- <td>69,7</td>
-</tr>
-<tr>
- <td>contextMenuAt</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]</td>
- <td></td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>contextmenu-noicon</td>
-</tr>
-<!--Two actions, without and with icon-->
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_Smenu#item0</td>
- <td>42,7</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[0]/VMenuBar[0]#item6</td>
- <td>52,6</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[1]/VMenuBar[0]#item4</td>
- <td>53,3</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[2]/VMenuBar[0]#item2</td>
- <td>31,4</td>
-</tr>
-<tr>
- <td>contextMenuAt</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]</td>
- <td></td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>caption-only-and-has-icon</td>
-</tr>
-<!--Large icon-->
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_Smenu#item0</td>
- <td>42,7</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[0]/VMenuBar[0]#item6</td>
- <td>52,6</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[1]/VMenuBar[0]#item4</td>
- <td>53,3</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[2]/VMenuBar[0]#item3</td>
- <td>31,4</td>
-</tr>
-<tr>
- <td>contextMenuAt</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]</td>
- <td></td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>large-icon</td>
-</tr>
-<!--Simple context menu again to ensure it is properly updated (icons removed)-->
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_Smenu#item0</td>
- <td>28,7</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[0]/VMenuBar[0]#item6</td>
- <td>57,11</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[1]/VMenuBar[0]#item4</td>
- <td>68,4</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::Root/VOverlay[2]/VMenuBar[0]#item1</td>
- <td>69,7</td>
-</tr>
-<tr>
- <td>contextMenuAt</td>
- <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]</td>
- <td></td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>contextmenu-noicon</td>
-</tr>
-</tbody></table>
-</body>
-</html>
diff --git a/uitest/tb2/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContent.html b/uitest/tb2/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContent.html
deleted file mode 100644
index a3b56cd12a..0000000000
--- a/uitest/tb2/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContent.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="" />
-<title>UndefinedHeightSubWindowAndContent</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">UndefinedHeightSubWindowAndContent</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/com.vaadin.tests.components.window.UndefinedHeightSubWindowAndContent?restartApplication</td>
- <td></td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentswindowUndefinedHeightSubWindowAndContent::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
- <td>52,11</td>
-</tr>
-<tr>
- <td>enterCharacter</td>
- <td>vaadin=runcomvaadintestscomponentswindowUndefinedHeightSubWindowAndContent::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
- <td>invalid</td>
-</tr>
-<tr>
- <td>pressSpecialKey</td>
- <td>vaadin=runcomvaadintestscomponentswindowUndefinedHeightSubWindowAndContent::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
- <td>enter</td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>form_full_width_1_error</td>
-</tr>
-<tr>
- <td>enterCharacter</td>
- <td>vaadin=runcomvaadintestscomponentswindowUndefinedHeightSubWindowAndContent::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
- <td>valid</td>
-</tr>
-<tr>
- <td>pressSpecialKey</td>
- <td>vaadin=runcomvaadintestscomponentswindowUndefinedHeightSubWindowAndContent::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
- <td>enter</td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>form_full_width_2_valid</td>
-</tr>
-
-</tbody></table>
-</body>
-</html>
diff --git a/widgets/build.xml b/widgets/build.xml
index 63317fb5ad..a437fd1940 100644
--- a/widgets/build.xml
+++ b/widgets/build.xml
@@ -45,6 +45,7 @@
<fileset dir="${result.deps}">
<include name="com/vaadin/*.gwt.xml" />
<include name="com/vaadin/client/BrowserInfo.java" />
+ <include name="com/vaadin/client/ComputedStyle.java" />
<include name="com/vaadin/client/DeferredWorker.java" />
<include name="com/vaadin/client/Profiler.java" />
<include name="com/vaadin/client/StyleConstants.java" />