Change-Id: Id630861d5089b0deabbccffe66d971252c44f46btags/7.6.0.alpha3
@@ -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 |
@@ -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> |
@@ -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() { |
@@ -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() { |
@@ -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); | |||
} | |||
} |
@@ -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 |
@@ -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; |
@@ -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); |
@@ -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); | |||
}-*/; | |||
@@ -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); |
@@ -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%"); | |||
} | |||
} |
@@ -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%"); | |||
} | |||
} |
@@ -159,7 +159,7 @@ public class GridLayoutConnector extends AbstractComponentContainerConnector | |||
for (ComponentConnector componentConnector : getChildComponents()) { | |||
Cell cell = getCell(componentConnector); | |||
cell.setComponent(componentConnector); | |||
cell.setComponent(componentConnector, getChildComponents()); | |||
} | |||
} |
@@ -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(); |
@@ -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) |
@@ -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) |
@@ -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) |
@@ -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 | |||
@@ -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) |
@@ -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) |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
@@ -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; |
@@ -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. | |||
* |
@@ -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"; |
@@ -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(); | |||
} | |||
} |
@@ -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() { |
@@ -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; | |||
} |
@@ -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. |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -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 |
@@ -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()); | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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,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()); | |||
} | |||
} |
@@ -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(); |
@@ -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)); | |||
} | |||
} |
@@ -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"); | |||
} |
@@ -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); | |||
} | |||
})); | |||
} | |||
} |
@@ -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")); | |||
} | |||
} |
@@ -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 |
@@ -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 + "']")); | |||
} | |||
} |
@@ -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."; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
})); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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 |
@@ -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)) { |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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" /> |