Browse Source

Merge remote-tracking branch 'origin/master' into grid-unbuffered-editor

Change-Id: Id630861d5089b0deabbccffe66d971252c44f46b
tags/7.6.0.alpha3
Teemu Suo-Anttila 9 years ago
parent
commit
ae5793ae46
59 changed files with 2033 additions and 632 deletions
  1. 5
    0
      .gitignore
  2. 1
    0
      WebContent/release-notes.html
  3. 4
    4
      client/src/com/vaadin/client/ComputedStyle.java
  4. 3
    3
      client/src/com/vaadin/client/WidgetUtil.java
  5. 25
    11
      client/src/com/vaadin/client/connectors/GridConnector.java
  6. 15
    4
      client/src/com/vaadin/client/extensions/ResponsiveConnector.java
  7. 8
    4
      client/src/com/vaadin/client/ui/AbstractComponentConnector.java
  8. 38
    1
      client/src/com/vaadin/client/ui/VAbstractSplitPanel.java
  9. 3
    0
      client/src/com/vaadin/client/ui/VDragAndDropWrapper.java
  10. 16
    2
      client/src/com/vaadin/client/ui/VGridLayout.java
  11. 23
    0
      client/src/com/vaadin/client/ui/VSplitPanelHorizontal.java
  12. 23
    0
      client/src/com/vaadin/client/ui/VSplitPanelVertical.java
  13. 1
    1
      client/src/com/vaadin/client/ui/gridlayout/GridLayoutConnector.java
  14. 105
    96
      client/src/com/vaadin/client/widgets/Grid.java
  15. 47
    20
      scripts/BuildArchetypes.py
  16. 60
    18
      scripts/BuildDemos.py
  17. 60
    45
      scripts/BuildHelpers.py
  18. 82
    0
      scripts/DeployHelpers.py
  19. 48
    0
      scripts/GenerateBuildReport.py
  20. 40
    0
      scripts/GenerateStagingReport.py
  21. 18
    0
      server/src/com/vaadin/data/RpcDataProviderExtension.java
  22. 1
    3
      server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java
  23. 9
    1
      server/src/com/vaadin/server/AbstractClientConnector.java
  24. 0
    44
      server/src/com/vaadin/server/CustomizedSystemMessages.java
  25. 0
    11
      server/src/com/vaadin/server/SystemMessages.java
  26. 23
    29
      server/src/com/vaadin/ui/ConnectorTracker.java
  27. 5
    0
      server/src/com/vaadin/ui/Grid.java
  28. 10
    0
      server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java
  29. 6
    2
      shared/src/com/vaadin/shared/ui/ui/UIState.java
  30. 77
    0
      uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemoval.java
  31. 52
    0
      uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemovalTest.java
  32. 14
    0
      uitest/src/com/vaadin/tests/components/AbstractTestUI.java
  33. 60
    0
      uitest/src/com/vaadin/tests/components/embedded/EmbeddedAltTextTest.java
  34. 9
    4
      uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java
  35. 86
    0
      uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinatesTest.java
  36. 91
    0
      uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplay.java
  37. 72
    0
      uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplayTest.java
  38. 149
    0
      uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java
  39. 73
    0
      uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java
  40. 23
    0
      uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java
  41. 0
    12
      uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java
  42. 13
    0
      uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java
  43. 30
    0
      uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java
  44. 108
    0
      uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChild.java
  45. 88
    0
      uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChildTest.java
  46. 1
    5
      uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java
  47. 130
    0
      uitest/src/com/vaadin/tests/components/tree/TreeContextMenuAndIconsTest.java
  48. 153
    0
      uitest/src/com/vaadin/tests/components/upload/DragAndDropUploadAndInteractions.java
  49. 34
    0
      uitest/src/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContentTest.java
  50. 37
    0
      uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStyles.java
  51. 34
    0
      uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStylesTest.java
  52. 3
    1
      uitest/src/com/vaadin/tests/fieldgroup/BasicPersonForm.java
  53. 9
    0
      uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java
  54. 7
    0
      uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java
  55. 0
    47
      uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedAltText.html
  56. 0
    51
      uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html
  57. 0
    156
      uitest/tb2/com/vaadin/tests/components/tree/TreeContextMenuAndIcons.html
  58. 0
    57
      uitest/tb2/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContent.html
  59. 1
    0
      widgets/build.xml

+ 5
- 0
.gitignore View File

@@ -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

+ 1
- 0
WebContent/release-notes.html View File

@@ -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>

+ 4
- 4
client/src/com/vaadin/client/ComputedStyle.java View File

@@ -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() {

+ 3
- 3
client/src/com/vaadin/client/WidgetUtil.java View File

@@ -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() {

+ 25
- 11
client/src/com/vaadin/client/connectors/GridConnector.java View File

@@ -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) {
@@ -944,6 +951,13 @@ public class GridConnector extends AbstractHasComponentsConnector implements
layout();
}

@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);
}
}

+ 15
- 4
client/src/com/vaadin/client/extensions/ResponsiveConnector.java View File

@@ -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

+ 8
- 4
client/src/com/vaadin/client/ui/AbstractComponentConnector.java View File

@@ -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;

+ 38
- 1
client/src/com/vaadin/client/ui/VAbstractSplitPanel.java View File

@@ -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);

+ 3
- 0
client/src/com/vaadin/client/ui/VDragAndDropWrapper.java View File

@@ -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);
}-*/;


+ 16
- 2
client/src/com/vaadin/client/ui/VGridLayout.java View File

@@ -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);

+ 23
- 0
client/src/com/vaadin/client/ui/VSplitPanelHorizontal.java View File

@@ -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%");
}
}

+ 23
- 0
client/src/com/vaadin/client/ui/VSplitPanelVertical.java View File

@@ -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%");
}
}

+ 1
- 1
client/src/com/vaadin/client/ui/gridlayout/GridLayoutConnector.java View File

@@ -159,7 +159,7 @@ public class GridLayoutConnector extends AbstractComponentContainerConnector
for (ComponentConnector componentConnector : getChildComponents()) {
Cell cell = getCell(componentConnector);

cell.setComponent(componentConnector);
cell.setComponent(componentConnector, getChildComponents());
}

}

+ 105
- 96
client/src/com/vaadin/client/widgets/Grid.java View File

@@ -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();
}

/**
@@ -7781,6 +7780,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();

+ 47
- 20
scripts/BuildArchetypes.py View File

@@ -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)

+ 60
- 18
scripts/BuildDemos.py View File

@@ -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)

+ 60
- 45
scripts/BuildHelpers.py View File

@@ -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)

+ 82
- 0
scripts/DeployHelpers.py View File

@@ -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

+ 48
- 0
scripts/GenerateBuildReport.py View File

@@ -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)

+ 40
- 0
scripts/GenerateStagingReport.py View File

@@ -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)

+ 18
- 0
server/src/com/vaadin/data/RpcDataProviderExtension.java View File

@@ -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();
}
}

+ 1
- 3
server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java View File

@@ -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;
}


+ 9
- 1
server/src/com/vaadin/server/AbstractClientConnector.java View File

@@ -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;

+ 0
- 44
server/src/com/vaadin/server/CustomizedSystemMessages.java View File

@@ -239,50 +239,6 @@ public class CustomizedSystemMessages extends SystemMessages implements
this.internalErrorMessage = internalErrorMessage;
}

/**
* 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.
*

+ 0
- 11
server/src/com/vaadin/server/SystemMessages.java View File

@@ -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";

+ 23
- 29
server/src/com/vaadin/ui/ConnectorTracker.java View File

@@ -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();
}
}

+ 5
- 0
server/src/com/vaadin/ui/Grid.java View File

@@ -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() {

+ 10
- 0
server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java View File

@@ -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;
}

+ 6
- 2
shared/src/com/vaadin/shared/ui/ui/UIState.java View File

@@ -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.

+ 77
- 0
uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemoval.java View File

@@ -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);
}
}
}

+ 52
- 0
uitest/src/com/vaadin/tests/application/ResynchronizeAfterAsyncRemovalTest.java View File

@@ -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));
}
}

+ 14
- 0
uitest/src/com/vaadin/tests/components/AbstractTestUI.java View File

@@ -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();
}
}

+ 60
- 0
uitest/src/com/vaadin/tests/components/embedded/EmbeddedAltTextTest.java View File

@@ -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");
}
}

+ 9
- 4
uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java View File

@@ -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

+ 86
- 0
uitest/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinatesTest.java View File

@@ -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());
}

}

+ 91
- 0
uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplay.java View File

@@ -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;
}
}

}

+ 72
- 0
uitest/src/com/vaadin/tests/components/grid/GridCheckBoxDisplayTest.java View File

@@ -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();
}
}

+ 149
- 0
uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java View File

@@ -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;
}

}

}

+ 73
- 0
uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java View File

@@ -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());
}
}

+ 23
- 0
uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java View File

@@ -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());

}

}

+ 0
- 12
uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java View File

@@ -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();

+ 13
- 0
uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java View File

@@ -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));

}
}

+ 30
- 0
uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java View File

@@ -270,6 +270,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");
}

+ 108
- 0
uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChild.java View File

@@ -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);
}
}));
}
}

+ 88
- 0
uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutFocusOrderAfterShowChildTest.java View File

@@ -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"));
}
}

+ 1
- 5
uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java View File

@@ -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

+ 130
- 0
uitest/src/com/vaadin/tests/components/tree/TreeContextMenuAndIconsTest.java View File

@@ -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 + "']"));
}

}

+ 153
- 0
uitest/src/com/vaadin/tests/components/upload/DragAndDropUploadAndInteractions.java View File

@@ -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.";
}
}

+ 34
- 0
uitest/src/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContentTest.java View File

@@ -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);
}

}

+ 37
- 0
uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStyles.java View File

@@ -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);
}
}));
}

}

+ 34
- 0
uitest/src/com/vaadin/tests/extensions/ResponsiveWithCrossDomainStylesTest.java View File

@@ -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();
}

}

+ 3
- 1
uitest/src/com/vaadin/tests/fieldgroup/BasicPersonForm.java View File

@@ -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);

}

+ 9
- 0
uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java View File

@@ -235,6 +235,15 @@ public abstract class AbstractTB3Test extends ParallelTest {
waitUntilRowIsVisible(table, rowToWait);
}

/**
* 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() {
openTestURL(new String[0]);
}

/**
* Opens the given test (defined by {@link #getTestUrl()}, optionally with
* debug window and/or push (depending on {@link #isDebug()} and

+ 7
- 0
uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java View File

@@ -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)) {

+ 0
- 47
uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedAltText.html View File

@@ -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>

+ 0
- 51
uitest/tb2/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html View File

@@ -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>

+ 0
- 156
uitest/tb2/com/vaadin/tests/components/tree/TreeContextMenuAndIcons.html View File

@@ -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>

+ 0
- 57
uitest/tb2/com/vaadin/tests/components/window/UndefinedHeightSubWindowAndContent.html View File

@@ -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>

+ 1
- 0
widgets/build.xml View File

@@ -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" />

Loading…
Cancel
Save