From: Denis Date: Thu, 15 Dec 2016 10:40:54 +0000 (+0200) Subject: Migrate 7.7.5 branch patches to v8. (#7969) X-Git-Tag: 8.0.0.alpha10~13 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=809a486c60a680d31308ffd078e6f8036252a990;p=vaadin-framework.git Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 --- diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java index 7d906fc4af..828c795777 100644 --- a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java +++ b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java @@ -53,9 +53,7 @@ import com.vaadin.client.widget.grid.sort.SortEvent; import com.vaadin.client.widget.grid.sort.SortOrder; import com.vaadin.client.widgets.Grid; import com.vaadin.client.widgets.Grid.Column; -import com.vaadin.client.widgets.Grid.FooterCell; import com.vaadin.client.widgets.Grid.FooterRow; -import com.vaadin.client.widgets.Grid.HeaderCell; import com.vaadin.client.widgets.Grid.HeaderRow; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.data.sort.SortDirection; @@ -212,6 +210,11 @@ public class GridConnector extends AbstractListingConnector .map(this::getColumn).toArray(size -> new Column[size])); } + @OnStateChange("columnResizeMode") + void updateColumnResizeMode() { + getWidget().setColumnResizeMode(getState().columnResizeMode); + } + /** * Updates the grid header section on state change. */ @@ -235,18 +238,21 @@ public class GridConnector extends AbstractListingConnector } } - private void updateStaticRow(RowState rowState, Grid.StaticSection.StaticRow row) { + private void updateStaticRow(RowState rowState, + Grid.StaticSection.StaticRow row) { rowState.cells.forEach((columnId, cellState) -> { updateStaticCellFromState(row.getCell(getColumn(columnId)), cellState); }); - for (Map.Entry> cellGroupEntry : rowState.cellGroups.entrySet()) { + for (Map.Entry> cellGroupEntry : rowState.cellGroups + .entrySet()) { Set group = cellGroupEntry.getValue(); - Grid.Column[] columns = - group.stream().map(idToColumn::get).toArray(size->new Grid.Column[size]); + Grid.Column[] columns = group.stream().map(idToColumn::get) + .toArray(size -> new Grid.Column[size]); // Set state to be the same as first in group. - updateStaticCellFromState(row.join(columns), cellGroupEntry.getKey()); + updateStaticCellFromState(row.join(columns), + cellGroupEntry.getKey()); } } diff --git a/client/src/main/java/com/vaadin/client/ui/VTextField.java b/client/src/main/java/com/vaadin/client/ui/VTextField.java index 1eb499505a..1ed84ab274 100644 --- a/client/src/main/java/com/vaadin/client/ui/VTextField.java +++ b/client/src/main/java/com/vaadin/client/ui/VTextField.java @@ -72,4 +72,5 @@ public class VTextField extends TextBoxBase public void onFocus(FocusEvent event) { addStyleDependentName(CLASSNAME_FOCUS); } + } diff --git a/client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java b/client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java index b800c5e53b..c5a9475d39 100644 --- a/client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java +++ b/client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java @@ -37,14 +37,14 @@ import com.vaadin.client.ui.dd.DragAndDropHandler.DragAndDropCallback; public class DragHandle { /** - * Callback interface for the DragHandle event life cycle + * Callback interface for the DragHandle event life cycle. */ public interface DragHandleCallback { /** - * Called when dragging starts + * Called when dragging starts. */ - public void onStart(); + void onStart(); /** * Called when the drag handle has moved. @@ -54,18 +54,18 @@ public class DragHandle { * @param deltaY * change in Y direction since start */ - public void onUpdate(double deltaX, double deltaY); + void onUpdate(double deltaX, double deltaY); /** * Called when the drag operation has been cancelled (usually by - * pressing ESC) + * pressing ESC). */ - public void onCancel(); + void onCancel(); /** - * Called when the drag operation completes successfully + * Called when the drag operation completes successfully. */ - public void onComplete(); + void onComplete(); } @@ -78,6 +78,20 @@ public class DragHandle { private DragHandleCallback userCallback; + /** + * Creates a new DragHandle. + * + * @param baseName + * CSS style name to use for this DragHandle element. This + * parameter is supplied to the constructor (rather than added + * later) both to provide the "-dragged" style and to make sure + * that the drag handle can be properly styled (it's otherwise + * invisible) + */ + public DragHandle(String baseName) { + this(baseName, null); + } + /** * Creates a new DragHandle. * @@ -106,22 +120,28 @@ public class DragHandle { @Override public void onDrop() { removeDraggingStyle(); - userCallback.onComplete(); + if (userCallback != null) { + userCallback.onComplete(); + } } @Override public void onDragUpdate(Event e) { - double dx = WidgetUtil.getTouchOrMouseClientX(e) - startX; - double dy = WidgetUtil.getTouchOrMouseClientY(e) - startY; - userCallback.onUpdate(dx, dy); + if (userCallback != null) { + double dx = WidgetUtil.getTouchOrMouseClientX(e) - startX; + double dy = WidgetUtil.getTouchOrMouseClientY(e) - startY; + userCallback.onUpdate(dx, dy); + } } @Override public boolean onDragStart(Event e) { addDraggingStyle(); - startX = WidgetUtil.getTouchOrMouseClientX(e); - startY = WidgetUtil.getTouchOrMouseClientY(e); - userCallback.onStart(); + if (userCallback != null) { + startX = WidgetUtil.getTouchOrMouseClientX(e); + startY = WidgetUtil.getTouchOrMouseClientY(e); + userCallback.onStart(); + } return true; } @@ -133,7 +153,9 @@ public class DragHandle { @Override public void onDragCancel() { removeDraggingStyle(); - userCallback.onCancel(); + if (userCallback != null) { + userCallback.onCancel(); + } } private void addDraggingStyle() { @@ -156,6 +178,18 @@ public class DragHandle { }); } + /** + * Sets the user-facing drag handle callback method. This allows code using + * the DragHandle to react to the situations where a drag handle first + * touched, when it's moved and when it's released. + * + * @param dragHandleCallback + * the callback object to use (can be null) + */ + public void setCallback(DragHandleCallback dragHandleCallback) { + userCallback = dragHandleCallback; + } + /** * Returns the current parent element for this drag handle. May be null. * diff --git a/client/src/main/java/com/vaadin/client/ui/dd/VHtml5DragEvent.java b/client/src/main/java/com/vaadin/client/ui/dd/VHtml5DragEvent.java index 581d9263ac..830f668a00 100644 --- a/client/src/main/java/com/vaadin/client/ui/dd/VHtml5DragEvent.java +++ b/client/src/main/java/com/vaadin/client/ui/dd/VHtml5DragEvent.java @@ -90,8 +90,11 @@ public class VHtml5DragEvent extends NativeEvent { // Chrome >= v21 and Opera >= v? if (this.dataTransfer.items) { var item = this.dataTransfer.items[fileIndex]; - if (item.webkitGetAsEntry) { - return item.webkitGetAsEntry().isFile; + if (typeof item.webkitGetAsEntry == "function") { + var entry = item.webkitGetAsEntry(); + if (typeof entry !== "undefined" && entry !== null) { + return entry.isFile; + } } } diff --git a/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java b/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java index 2b615ebdb7..ed8d3cd57b 100644 --- a/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java +++ b/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java @@ -436,6 +436,9 @@ public abstract class ScrollbarBundle implements DeferredWorker { boolean offsetSizeBecomesGreaterThanScrollSize = showsScrollHandle() && newOffsetSizeIsGreaterThanScrollSize; if (offsetSizeBecomesGreaterThanScrollSize && getScrollPos() != 0) { + if (offsetSizeTemporaryScrollHandler != null) { + offsetSizeTemporaryScrollHandler.removeHandler(); + } // must be a field because Java insists. offsetSizeTemporaryScrollHandler = addScrollHandler( new ScrollHandler() { @@ -661,6 +664,9 @@ public abstract class ScrollbarBundle implements DeferredWorker { */ boolean delayedSizeSet = !BrowserInfo.get().isFirefox(); if (delayedSizeSet) { + if (scrollSizeTemporaryScrollHandler != null) { + scrollSizeTemporaryScrollHandler.removeHandler(); + } scrollSizeTemporaryScrollHandler = addScrollHandler( new ScrollHandler() { @Override diff --git a/client/src/main/java/com/vaadin/client/widgets/Escalator.java b/client/src/main/java/com/vaadin/client/widgets/Escalator.java index e3e0dfa0e4..e3953b436a 100644 --- a/client/src/main/java/com/vaadin/client/widgets/Escalator.java +++ b/client/src/main/java/com/vaadin/client/widgets/Escalator.java @@ -307,6 +307,8 @@ public class Escalator extends Widget static class JsniUtil { public static class TouchHandlerBundle { + public static final String POINTER_EVENT_TYPE_TOUCH = "touch"; + /** * A a = event.getNativeEvent().getTouches(); return vertical ? a.get(0).getPageY() : a.get(0).getPageX(); } @@ -495,7 +511,7 @@ public class Escalator extends Widget }; public void touchStart(final CustomTouchEvent event) { - if (event.getNativeEvent().getTouches().length() == 1) { + if (allowTouch(event)) { if (yMov == null) { yMov = new Movement(true); xMov = new Movement(false); @@ -543,6 +559,18 @@ public class Escalator extends Widget } } + // Allow touchStart for IE11 and Edge even though there is no touch + // (#18737), + // otherwise allow touch only if there is a single touch in the + // event + private boolean allowTouch(final TouchHandlerBundle.CustomTouchEvent event) { + if (isCurrentBrowserIE11OrEdge()) { + return (POINTER_EVENT_TYPE_TOUCH.equals(event.getPointerType())); + } else { + return (event.getNativeEvent().getTouches().length() == 1); + } + } + private double easingInOutCos(double val, double max) { return 0.5 - 0.5 * Math.cos(Math.PI * Math.signum(val) * Math.min(Math.abs(val), max) / max); @@ -881,7 +909,7 @@ public class Escalator extends Widget public native void detachScrollListener(Element element) /* - * Attaching events with JSNI instead of the GWT event mechanism because + * Detaching events with JSNI instead of the GWT event mechanism because * GWT didn't provide enough details in events, or triggering the event * handlers with GWT bindings was unsuccessful. Maybe, with more time * and skill, it could be done with better success. JavaScript overlay @@ -958,6 +986,50 @@ public class Escalator extends Widget element.removeEventListener("touchcancel", this.@com.vaadin.client.widgets.JsniWorkaround::touchEndFunction); }-*/; + /** + * Using pointerdown, pointermove, pointerup, and pointercancel for IE11 and Edge instead of + * touch* listeners (#18737) + * + * @param element + */ + public native void attachPointerEventListeners(Element element) + /* + * Attaching events with JSNI instead of the GWT event mechanism because + * GWT didn't provide enough details in events, or triggering the event + * handlers with GWT bindings was unsuccessful. Maybe, with more time + * and skill, it could be done with better success. JavaScript overlay + * types might work. This might also get rid of the JsniWorkaround + * class. + */ + /*-{ + element.addEventListener("pointerdown", this.@com.vaadin.client.widgets.JsniWorkaround::touchStartFunction); + element.addEventListener("pointermove", this.@com.vaadin.client.widgets.JsniWorkaround::touchMoveFunction); + element.addEventListener("pointerup", this.@com.vaadin.client.widgets.JsniWorkaround::touchEndFunction); + element.addEventListener("pointercancel", this.@com.vaadin.client.widgets.JsniWorkaround::touchEndFunction); + }-*/; + + /** + * Using pointerdown, pointermove, pointerup, and pointercancel for IE11 and Edge instead of + * touch* listeners (#18737) + * + * @param element + */ + public native void detachPointerEventListeners(Element element) + /* + * Detaching events with JSNI instead of the GWT event mechanism because + * GWT didn't provide enough details in events, or triggering the event + * handlers with GWT bindings was unsuccessful. Maybe, with more time + * and skill, it could be done with better success. JavaScript overlay + * types might work. This might also get rid of the JsniWorkaround + * class. + */ + /*-{ + element.removeEventListener("pointerdown", this.@com.vaadin.client.widgets.JsniWorkaround::touchStartFunction); + element.removeEventListener("pointermove", this.@com.vaadin.client.widgets.JsniWorkaround::touchMoveFunction); + element.removeEventListener("pointerup", this.@com.vaadin.client.widgets.JsniWorkaround::touchEndFunction); + element.removeEventListener("pointercancel", this.@com.vaadin.client.widgets.JsniWorkaround::touchEndFunction); + }-*/; + public void scrollToColumn(final int columnIndex, final ScrollDestination destination, final int padding) { assert columnIndex >= columnConfiguration.frozenColumns : "Can't scroll to a frozen column"; @@ -5717,7 +5789,13 @@ public class Escalator extends Widget scroller.attachScrollListener(verticalScrollbar.getElement()); scroller.attachScrollListener(horizontalScrollbar.getElement()); scroller.attachMousewheelListener(getElement()); - scroller.attachTouchListeners(getElement()); + + if (isCurrentBrowserIE11OrEdge()) { + // Touch listeners doesn't work for IE11 and Edge (#18737) + scroller.attachPointerEventListeners(getElement()); + } else { + scroller.attachTouchListeners(getElement()); + } } @Override @@ -5726,7 +5804,13 @@ public class Escalator extends Widget scroller.detachScrollListener(verticalScrollbar.getElement()); scroller.detachScrollListener(horizontalScrollbar.getElement()); scroller.detachMousewheelListener(getElement()); - scroller.detachTouchListeners(getElement()); + + if (isCurrentBrowserIE11OrEdge()) { + // Touch listeners doesn't work for IE11 and Edge (#18737) + scroller.detachPointerEventListeners(getElement()); + } else { + scroller.detachTouchListeners(getElement()); + } /* * We can call paintRemoveRows here, because static ranges are simple to @@ -6772,4 +6856,12 @@ public class Escalator extends Widget double getMinCellWidth(int colIndex) { return columnConfiguration.getMinCellWidth(colIndex); } + + /** + * Internal method for checking whether the browser is IE11 or Edge + * @return true only if the current browser is IE11, or Edge + */ + private static boolean isCurrentBrowserIE11OrEdge() { + return BrowserInfo.get().isIE11() || BrowserInfo.get().isEdge(); + } } diff --git a/client/src/main/java/com/vaadin/client/widgets/Grid.java b/client/src/main/java/com/vaadin/client/widgets/Grid.java index 368ad8693b..1ffda08ef7 100644 --- a/client/src/main/java/com/vaadin/client/widgets/Grid.java +++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java @@ -37,6 +37,7 @@ import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.EventTarget; import com.google.gwt.dom.client.NativeEvent; @@ -174,6 +175,7 @@ import com.vaadin.client.widgets.Grid.StaticSection.StaticRow; import com.vaadin.shared.Range; import com.vaadin.shared.Registration; import com.vaadin.shared.data.sort.SortDirection; +import com.vaadin.shared.ui.grid.ColumnResizeMode; import com.vaadin.shared.ui.grid.GridConstants; import com.vaadin.shared.ui.grid.GridConstants.Section; import com.vaadin.shared.ui.grid.GridStaticCellType; @@ -4140,6 +4142,8 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, private AutoScroller autoScroller = new AutoScroller(this); + private ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; + private DragAndDropHandler.DragAndDropCallback headerCellDndCallback = new DragAndDropCallback() { private final AutoScrollerCallback autoScrollerCallback = new AutoScrollerCallback() { @@ -5684,63 +5688,164 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, && staticRow instanceof HeaderRow && ((HeaderRow) staticRow).isDefault()) { + final DivElement resizeElement = Document.get() + .createDivElement(); + resizeElement.addClassName(getStylePrimaryName() + + "-column-resize-simple-indicator"); + final int column = cell.getColumn(); - DragHandle dragger = new DragHandle( - getStylePrimaryName() + "-column-resize-handle", - new DragHandleCallback() { - - private Column col = getVisibleColumn( - column); - private double initialWidth = 0; - private double minCellWidth; - - @Override - public void onUpdate(double deltaX, - double deltaY) { - col.setWidth(Math.max(minCellWidth, - initialWidth + deltaX)); - } + final DragHandle dragger = new DragHandle( + getStylePrimaryName() + "-column-resize-handle"); + dragger.addTo(td); - @Override - public void onStart() { - initialWidth = col.getWidthActual(); - - minCellWidth = escalator.getMinCellWidth( - getVisibleColumns().indexOf(col)); - for (Column c : getVisibleColumns()) { - if (selectionColumn == c) { - // Don't modify selection column. - continue; - } - - if (c.getWidth() < 0) { - c.setWidth(c.getWidthActual()); - fireEvent( - new ColumnResizeEvent<>(c)); - } - } + // Common functionality for drag handle callback + // implementations + abstract class AbstractDHCallback + implements DragHandleCallback { + protected Column col = getVisibleColumn(column); + protected double initialWidth = 0; + protected double minCellWidth; + protected double width; + + protected void dragStarted() { + initialWidth = col.getWidthActual(); + width = initialWidth; + + minCellWidth = escalator.getMinCellWidth( + getVisibleColumns().indexOf(col)); + for (Column c : getVisibleColumns()) { + if (selectionColumn == c) { + // Don't modify selection column. + continue; + } - WidgetUtil.setTextSelectionEnabled( - getElement(), false); + if (c.getWidth() < 0) { + c.setWidth(c.getWidthActual()); + fireEvent(new ColumnResizeEvent<>(c)); } + } - @Override - public void onComplete() { - fireEvent(new ColumnResizeEvent<>(col)); + WidgetUtil.setTextSelectionEnabled(getElement(), + false); + } - WidgetUtil.setTextSelectionEnabled( - getElement(), true); - } + protected void dragEnded() { + WidgetUtil.setTextSelectionEnabled(getElement(), + true); + } + } - @Override - public void onCancel() { - col.setWidth(initialWidth); + final DragHandleCallback simpleResizeMode = new AbstractDHCallback() { + @Override + protected void dragEnded() { + super.dragEnded(); + dragger.getElement().removeChild(resizeElement); + } - WidgetUtil.setTextSelectionEnabled( - getElement(), true); - } - }); - dragger.addTo(td); + @Override + public void onStart() { + dragStarted(); + dragger.getElement().appendChild(resizeElement); + resizeElement.getStyle().setLeft( + (dragger.getElement().getOffsetWidth() + - resizeElement.getOffsetWidth()) + * .5, + Unit.PX); + resizeElement.getStyle().setHeight( + col.grid.getOffsetHeight(), Unit.PX); + } + + @Override + public void onUpdate(double deltaX, double deltaY) { + width = Math.max(minCellWidth, + initialWidth + deltaX); + resizeElement.getStyle().setLeft( + (dragger.getElement().getOffsetWidth() + - resizeElement.getOffsetWidth()) + * .5 + (width - initialWidth), + Unit.PX); + } + + @Override + public void onCancel() { + dragEnded(); + } + + @Override + public void onComplete() { + dragEnded(); + + col.setWidth(width); + fireEvent(new ColumnResizeEvent<>(col)); + } + }; + + final DragHandleCallback animatedResizeMode = new AbstractDHCallback() { + @Override + public void onStart() { + dragStarted(); + } + + @Override + public void onUpdate(double deltaX, double deltaY) { + width = Math.max(minCellWidth, + initialWidth + deltaX); + col.setWidth(width); + } + + @Override + public void onCancel() { + dragEnded(); + col.setWidth(initialWidth); + } + + @Override + public void onComplete() { + dragEnded(); + col.setWidth(width); + fireEvent(new ColumnResizeEvent<>(col)); + } + }; + + // DragHandle gets assigned a 'master callback' that + // delegates + // functionality to the correct case-specific implementation + dragger.setCallback(new DragHandleCallback() { + + private DragHandleCallback currentCallback; + + @Override + public void onStart() { + switch (getColumnResizeMode()) { + case SIMPLE: + currentCallback = simpleResizeMode; + break; + case ANIMATED: + currentCallback = animatedResizeMode; + break; + default: + throw new UnsupportedOperationException( + "Support for current column resize mode is not yet implemented"); + } + + currentCallback.onStart(); + } + + @Override + public void onUpdate(double deltaX, double deltaY) { + currentCallback.onUpdate(deltaX, deltaY); + } + + @Override + public void onCancel() { + currentCallback.onCancel(); + } + + @Override + public void onComplete() { + currentCallback.onComplete(); + } + }); } cellFocusHandler.updateFocusedCellStyle(cell, container); @@ -5996,6 +6101,27 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, fireEvent(new GridEnabledEvent(enabled)); } + /** + * Sets the column resize mode to use. The default mode is + * {@link ColumnResizeMode.ANIMATED}. + * + * @param mode + * a ColumnResizeMode value + */ + public void setColumnResizeMode(ColumnResizeMode mode) { + columnResizeMode = mode; + } + + /** + * Returns the current column resize mode. The default mode is + * {@link ColumnResizeMode.ANIMATED}. + * + * @return a ColumnResizeMode value + */ + public ColumnResizeMode getColumnResizeMode() { + return columnResizeMode; + } + @Override public void setStylePrimaryName(String style) { super.setStylePrimaryName(style); diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java b/compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java index cf48586d01..cba6fc6565 100644 --- a/compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java +++ b/compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java @@ -389,7 +389,7 @@ public class GridConnector extends AbstractHasComponentsConnector } else { Collection> errorColumns; if (errorColumnsIds != null) { - errorColumns = new ArrayList>(); + errorColumns = new ArrayList<>(); for (String colId : errorColumnsIds) { errorColumns.add(columnIdToColumn.get(colId)); } @@ -435,7 +435,7 @@ public class GridConnector extends AbstractHasComponentsConnector public void onColumnReorder(ColumnReorderEvent event) { if (!columnsUpdatedFromState) { List> columns = getWidget().getColumns(); - final List newColumnOrder = new ArrayList(); + final List newColumnOrder = new ArrayList<>(); for (Column column : columns) { if (column instanceof CustomGridColumn) { newColumnOrder.add(((CustomGridColumn) column).id); @@ -494,8 +494,8 @@ public class GridConnector extends AbstractHasComponentsConnector private class CustomDetailsGenerator implements HeightAwareDetailsGenerator { - private final Map idToDetailsMap = new HashMap(); - private final Map idToRowIndex = new HashMap(); + private final Map idToDetailsMap = new HashMap<>(); + private final Map idToRowIndex = new HashMap<>(); @Override public Widget getDetails(int rowIndex) { @@ -544,7 +544,7 @@ public class GridConnector extends AbstractHasComponentsConnector } public void updateConnectorHierarchy(List children) { - Set connectorIds = new HashSet(); + Set connectorIds = new HashSet<>(); for (ServerConnector child : children) { if (child instanceof ComponentConnector) { connectorIds.add(child.getConnectorId()); @@ -553,7 +553,7 @@ public class GridConnector extends AbstractHasComponentsConnector } } - Set removedDetails = new HashSet(); + Set removedDetails = new HashSet<>(); for (Entry entry : idToDetailsMap .entrySet()) { ComponentConnector connector = entry.getValue(); @@ -626,9 +626,9 @@ public class GridConnector extends AbstractHasComponentsConnector /** * Maps a generated column id to a grid column instance */ - private Map columnIdToColumn = new HashMap(); + private Map columnIdToColumn = new HashMap<>(); - private List columnOrder = new ArrayList(); + private List columnOrder = new ArrayList<>(); /** * {@link #columnsUpdatedFromState} is set to true when @@ -642,7 +642,7 @@ public class GridConnector extends AbstractHasComponentsConnector private RpcDataSource dataSource; /* Used to track Grid editor columns with validation errors */ - private final Map, String> columnToErrorMessage = new HashMap, String>(); + private final Map, String> columnToErrorMessage = new HashMap<>(); private ItemClickHandler itemClickHandler = new ItemClickHandler(); @@ -839,6 +839,11 @@ public class GridConnector extends AbstractHasComponentsConnector } } + // Column resize mode + if (stateChangeEvent.hasPropertyChanged("columnResizeMode")) { + getWidget().setColumnResizeMode(getState().columnResizeMode); + } + // Header and footer if (stateChangeEvent.hasPropertyChanged("header")) { updateHeaderFromState(getState().header); @@ -1101,7 +1106,7 @@ public class GridConnector extends AbstractHasComponentsConnector private void purgeRemovedColumns() { // Get columns still registered in the state - Set columnsInState = new HashSet(); + Set columnsInState = new HashSet<>(); for (GridColumnState columnState : getState().columns) { columnsInState.add(columnState.id); } @@ -1126,7 +1131,7 @@ public class GridConnector extends AbstractHasComponentsConnector } private void onSortStateChange() { - List sortOrder = new ArrayList(); + List sortOrder = new ArrayList<>(); String[] sortColumns = getState().sortColumns; SortDirection[] sortDirs = getState().sortDirs; @@ -1283,7 +1288,7 @@ public class GridConnector extends AbstractHasComponentsConnector * @return displayed error string */ private String getColumnErrors() { - List errors = new ArrayList(); + List errors = new ArrayList<>(); for (Grid.Column c : getWidget().getColumns()) { if (!(c instanceof CustomGridColumn)) { diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/VTextField.java b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/VTextField.java index ffaec8ad20..8357a7649a 100644 --- a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/VTextField.java +++ b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/VTextField.java @@ -34,6 +34,7 @@ import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.TextBoxBase; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.BrowserInfo; +import com.vaadin.client.DeferredWorker; import com.vaadin.client.WidgetUtil; import com.vaadin.client.ui.Field; import com.vaadin.shared.EventId; @@ -47,7 +48,7 @@ import com.vaadin.v7.shared.ui.textfield.TextFieldConstants; */ @Deprecated public class VTextField extends TextBoxBase implements Field, ChangeHandler, - FocusHandler, BlurHandler, KeyDownHandler { + FocusHandler, BlurHandler, KeyDownHandler, DeferredWorker { /** * The input node CSS classname. @@ -530,4 +531,9 @@ public class VTextField extends TextBoxBase implements Field, ChangeHandler, } possibleInputError = false; } + + @Override + public boolean isWorkPending() { + return scheduled; + } } diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java b/compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java index 49a6c6b986..0ea348553a 100644 --- a/compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java +++ b/compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java @@ -36,6 +36,7 @@ import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.EventTarget; import com.google.gwt.dom.client.NativeEvent; @@ -179,6 +180,7 @@ import com.vaadin.v7.client.widgets.Escalator.SubPartArguments; import com.vaadin.v7.client.widgets.Grid.Editor.State; import com.vaadin.v7.client.widgets.Grid.StaticSection.StaticCell; import com.vaadin.v7.client.widgets.Grid.StaticSection.StaticRow; +import com.vaadin.v7.shared.ui.grid.ColumnResizeMode; import com.vaadin.v7.shared.ui.grid.GridConstants; import com.vaadin.v7.shared.ui.grid.GridConstants.Section; import com.vaadin.v7.shared.ui.grid.GridStaticCellType; @@ -4105,6 +4107,8 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, private AutoScroller autoScroller = new AutoScroller(this); + private ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; + private DragAndDropHandler.DragAndDropCallback headerCellDndCallback = new DragAndDropCallback() { private final AutoScrollerCallback autoScrollerCallback = new AutoScrollerCallback() { @@ -5691,63 +5695,164 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, && staticRow instanceof HeaderRow && ((HeaderRow) staticRow).isDefault()) { + final DivElement resizeElement = Document.get() + .createDivElement(); + resizeElement.addClassName(getStylePrimaryName() + + "-column-resize-simple-indicator"); + final int column = cell.getColumn(); - DragHandle dragger = new DragHandle( - getStylePrimaryName() + "-column-resize-handle", - new DragHandleCallback() { - - private Column col = getVisibleColumn( - column); - private double initialWidth = 0; - private double minCellWidth; - - @Override - public void onUpdate(double deltaX, - double deltaY) { - col.setWidth(Math.max(minCellWidth, - initialWidth + deltaX)); - } + final DragHandle dragger = new DragHandle( + getStylePrimaryName() + "-column-resize-handle"); + dragger.addTo(td); - @Override - public void onStart() { - initialWidth = col.getWidthActual(); - - minCellWidth = escalator.getMinCellWidth( - getVisibleColumns().indexOf(col)); - for (Column c : getVisibleColumns()) { - if (selectionColumn == c) { - // Don't modify selection column. - continue; - } - - if (c.getWidth() < 0) { - c.setWidth(c.getWidthActual()); - fireEvent( - new ColumnResizeEvent<>(c)); - } - } + // Common functionality for drag handle callback + // implementations + abstract class AbstractDHCallback + implements DragHandleCallback { + protected Column col = getVisibleColumn(column); + protected double initialWidth = 0; + protected double minCellWidth; + protected double width; + + protected void dragStarted() { + initialWidth = col.getWidthActual(); + width = initialWidth; + + minCellWidth = escalator.getMinCellWidth( + getVisibleColumns().indexOf(col)); + for (Column c : getVisibleColumns()) { + if (selectionColumn == c) { + // Don't modify selection column. + continue; + } - WidgetUtil.setTextSelectionEnabled( - getElement(), false); + if (c.getWidth() < 0) { + c.setWidth(c.getWidthActual()); + fireEvent(new ColumnResizeEvent<>(c)); } + } - @Override - public void onComplete() { - fireEvent(new ColumnResizeEvent<>(col)); + WidgetUtil.setTextSelectionEnabled(getElement(), + false); + } - WidgetUtil.setTextSelectionEnabled( - getElement(), true); - } + protected void dragEnded() { + WidgetUtil.setTextSelectionEnabled(getElement(), + true); + } + } - @Override - public void onCancel() { - col.setWidth(initialWidth); + final DragHandleCallback simpleResizeMode = new AbstractDHCallback() { + @Override + protected void dragEnded() { + super.dragEnded(); + dragger.getElement().removeChild(resizeElement); + } - WidgetUtil.setTextSelectionEnabled( - getElement(), true); - } - }); - dragger.addTo(td); + @Override + public void onStart() { + dragStarted(); + dragger.getElement().appendChild(resizeElement); + resizeElement.getStyle().setLeft( + (dragger.getElement().getOffsetWidth() + - resizeElement.getOffsetWidth()) + * .5, + Unit.PX); + resizeElement.getStyle().setHeight( + col.grid.getOffsetHeight(), Unit.PX); + } + + @Override + public void onUpdate(double deltaX, double deltaY) { + width = Math.max(minCellWidth, + initialWidth + deltaX); + resizeElement.getStyle().setLeft( + (dragger.getElement().getOffsetWidth() + - resizeElement.getOffsetWidth()) + * .5 + (width - initialWidth), + Unit.PX); + } + + @Override + public void onCancel() { + dragEnded(); + } + + @Override + public void onComplete() { + dragEnded(); + + col.setWidth(width); + fireEvent(new ColumnResizeEvent<>(col)); + } + }; + + final DragHandleCallback animatedResizeMode = new AbstractDHCallback() { + @Override + public void onStart() { + dragStarted(); + } + + @Override + public void onUpdate(double deltaX, double deltaY) { + width = Math.max(minCellWidth, + initialWidth + deltaX); + col.setWidth(width); + } + + @Override + public void onCancel() { + dragEnded(); + col.setWidth(initialWidth); + } + + @Override + public void onComplete() { + dragEnded(); + col.setWidth(width); + fireEvent(new ColumnResizeEvent<>(col)); + } + }; + + // DragHandle gets assigned a 'master callback' that + // delegates + // functionality to the correct case-specific implementation + dragger.setCallback(new DragHandleCallback() { + + private DragHandleCallback currentCallback; + + @Override + public void onStart() { + switch (getColumnResizeMode()) { + case SIMPLE: + currentCallback = simpleResizeMode; + break; + case ANIMATED: + currentCallback = animatedResizeMode; + break; + default: + throw new UnsupportedOperationException( + "Support for current column resize mode is not yet implemented"); + } + + currentCallback.onStart(); + } + + @Override + public void onUpdate(double deltaX, double deltaY) { + currentCallback.onUpdate(deltaX, deltaY); + } + + @Override + public void onCancel() { + currentCallback.onCancel(); + } + + @Override + public void onComplete() { + currentCallback.onComplete(); + } + }); } cellFocusHandler.updateFocusedCellStyle(cell, container); @@ -5979,6 +6084,27 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, return enabled; } + /** + * Sets the column resize mode to use. The default mode is + * {@link ColumnResizeMode.ANIMATED}. + * + * @param mode + * a ColumnResizeMode value + */ + public void setColumnResizeMode(ColumnResizeMode mode) { + columnResizeMode = mode; + } + + /** + * Returns the current column resize mode. The default mode is + * {@link ColumnResizeMode.ANIMATED}. + * + * @return a ColumnResizeMode value + */ + public ColumnResizeMode getColumnResizeMode() { + return columnResizeMode; + } + @Override public void setEnabled(boolean enabled) { if (enabled == this.enabled) { diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/fieldgroup/FieldGroup.java b/compatibility-server/src/main/java/com/vaadin/v7/data/fieldgroup/FieldGroup.java index 1055d1921d..553bbc753c 100644 --- a/compatibility-server/src/main/java/com/vaadin/v7/data/fieldgroup/FieldGroup.java +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/fieldgroup/FieldGroup.java @@ -99,6 +99,13 @@ public class FieldGroup implements Serializable { public void setItemDataSource(Item itemDataSource) { this.itemDataSource = itemDataSource; + bindFields(); + } + + /** + * Binds all fields to the properties in the item in use. + */ + protected void bindFields() { for (Field f : fieldToPropertyId.keySet()) { bind(f, fieldToPropertyId.get(f)); } @@ -254,20 +261,7 @@ public class FieldGroup implements Serializable { fieldToPropertyId.put(field, propertyId); propertyIdToField.put(propertyId, field); if (itemDataSource == null) { - // Clear any possible existing binding to clear the field - field.setPropertyDataSource(null); - boolean fieldReadOnly = field.isReadOnly(); - if (!fieldReadOnly) { - field.clear(); - } else { - // Temporarily make the field read-write so we can clear the - // value. Needed because setPropertyDataSource(null) does not - // currently clear the field - // (https://dev.vaadin.com/ticket/14733) - field.setReadOnly(false); - field.clear(); - field.setReadOnly(true); - } + clearField(field); // Will be bound when data source is set return; @@ -278,6 +272,29 @@ public class FieldGroup implements Serializable { configureField(field); } + /** + * Clears field and any possible existing binding. + * + * @param field + * The field to be cleared + */ + protected void clearField(Field field) { + // Clear any possible existing binding to clear the field + field.setPropertyDataSource(null); + boolean fieldReadOnly = field.isReadOnly(); + if (!fieldReadOnly) { + field.clear(); + } else { + // Temporarily make the field read-write so we can clear the + // value. Needed because setPropertyDataSource(null) does not + // currently clear the field + // (https://dev.vaadin.com/ticket/14733) + field.setReadOnly(false); + field.clear(); + field.setReadOnly(true); + } + } + /** * Wrap property to transactional property. */ diff --git a/compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java b/compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java index f5399f60ce..e48e58824f 100644 --- a/compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java +++ b/compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java @@ -104,6 +104,7 @@ import com.vaadin.v7.event.SelectionEvent.SelectionListener; import com.vaadin.v7.event.SelectionEvent.SelectionNotifier; import com.vaadin.v7.server.communication.data.DataGenerator; import com.vaadin.v7.server.communication.data.RpcDataProviderExtension; +import com.vaadin.v7.shared.ui.grid.ColumnResizeMode; import com.vaadin.v7.shared.ui.grid.EditorClientRpc; import com.vaadin.v7.shared.ui.grid.EditorServerRpc; import com.vaadin.v7.shared.ui.grid.GridClientRpc; @@ -566,6 +567,35 @@ public class Grid extends AbstractComponent } return field; } + + @Override + protected void bindFields() { + List> fields = new ArrayList<>(getFields()); + Item itemDataSource = getItemDataSource(); + + if (itemDataSource == null) { + unbindFields(fields); + } else { + bindFields(fields, itemDataSource); + } + } + + private void unbindFields(List> fields) { + for (Field field : fields) { + clearField(field); + unbind(field); + field.setParent(null); + } + } + + private void bindFields(List> fields, Item itemDataSource) { + for (Field field : fields) { + if (itemDataSource + .getItemProperty(getPropertyId(field)) != null) { + bind(field, getPropertyId(field)); + } + } + } } /** @@ -2242,8 +2272,9 @@ public class Grid extends AbstractComponent Renderer renderer = column.getRenderer(); Item item = cell.getItem(); - Object modelValue = item.getItemProperty(cell.getPropertyId()) - .getValue(); + Property itemProperty = item.getItemProperty(cell.getPropertyId()); + Object modelValue = itemProperty == null ? null + : itemProperty.getValue(); data.put(columnKeys.key(cell.getPropertyId()), AbstractRenderer .encodeValue(modelValue, renderer, converter, getLocale())); @@ -4583,6 +4614,12 @@ public class Grid extends AbstractComponent private boolean editorSaving = false; private FieldGroup editorFieldGroup = new CustomFieldGroup(); + /** + * Poperty ID to Field mapping that stores editor fields set by + * {@link #setEditorField(Object, Field)}. + */ + private Map> editorFields = new HashMap<>(); + private CellStyleGenerator cellStyleGenerator; private RowStyleGenerator rowStyleGenerator; @@ -5285,6 +5322,27 @@ public class Grid extends AbstractComponent return (GridState) super.getState(markAsDirty); } + /** + * Sets the column resize mode to use. The default mode is + * {@link ColumnResizeMode#ANIMATED}. + * + * @param mode + * a ColumnResizeMode value + */ + public void setColumnResizeMode(ColumnResizeMode mode) { + getState().columnResizeMode = mode; + } + + /** + * Returns the current column resize mode. The default mode is + * {@link ColumnResizeMode#ANIMATED}. + * + * @return a ColumnResizeMode value + */ + public ColumnResizeMode getColumnResizeMode() { + return getState(false).columnResizeMode; + } + /** * Creates a new column based on a property id and appends it as the last * column. @@ -6868,6 +6926,16 @@ public class Grid extends AbstractComponent Field editor = editorFieldGroup.getField(propertyId); + // If field group has no field for this property, see if we have it + // stored + if (editor == null) { + editor = editorFields.get(propertyId); + if (editor != null) { + editorFieldGroup.bind(editor, propertyId); + } + } + + // Otherwise try to build one try { if (editor == null) { editor = editorFieldGroup.buildAndBind(propertyId); @@ -6923,8 +6991,9 @@ public class Grid extends AbstractComponent editorFieldGroup.setItemDataSource(item); for (Column column : getColumns()) { - column.getState().editorConnector = getEditorField( - column.getPropertyId()); + column.getState().editorConnector = item + .getItemProperty(column.getPropertyId()) == null ? null + : getEditorField(column.getPropertyId()); } editorActive = true; @@ -6953,6 +7022,9 @@ public class Grid extends AbstractComponent field.setParent(this); editorFieldGroup.bind(field, propertyId); } + + // Store field for this property for future reference + editorFields.put(propertyId, field); } /** diff --git a/compatibility-server/src/test/java/com/vaadin/v7/tests/server/component/grid/GridEditorMissingPropertyTest.java b/compatibility-server/src/test/java/com/vaadin/v7/tests/server/component/grid/GridEditorMissingPropertyTest.java new file mode 100644 index 0000000000..be6334f8cc --- /dev/null +++ b/compatibility-server/src/test/java/com/vaadin/v7/tests/server/component/grid/GridEditorMissingPropertyTest.java @@ -0,0 +1,334 @@ +/* + * Copyright 2000-2016 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.v7.tests.server.component.grid; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.v7.data.Item; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.fieldgroup.FieldGroup; +import com.vaadin.v7.data.util.AbstractInMemoryContainer; +import com.vaadin.v7.data.util.BeanItem; +import com.vaadin.v7.ui.Field; +import com.vaadin.v7.ui.PasswordField; +import com.vaadin.v7.ui.TextField; + +public class GridEditorMissingPropertyTest { + + private static final String PROPERTY_NAME = "name"; + private static final String PROPERTY_SIZE = "size"; + + private static final String FOLDER_NAME_BEFORE = "Folder name"; + private static final String FOLDER_NAME_AFTER = "Modified folder name"; + private static final String FILE_NAME_BEFORE = "File name"; + private static final String FILE_NAME_AFTER = "Modified file name"; + private static final String FILE_SIZE_BEFORE = "10kB"; + private static final String FILE_SIZE_AFTER = "20MB"; + + private final Grid grid = new Grid(); + + // Test items + private final Folder folder = new Folder(FOLDER_NAME_BEFORE); + private final File file = new File(FILE_NAME_BEFORE, FILE_SIZE_BEFORE); + + @Before + public void setup() throws SecurityException, NoSuchMethodException { + final BeanItem folderItem = new BeanItem<>(folder); + final BeanItem childItem = new BeanItem<>(file); + + @SuppressWarnings("unchecked") + TestContainer container = new TestContainer( + Arrays.asList(folderItem, childItem), + Arrays.asList(PROPERTY_NAME, PROPERTY_SIZE)); + + grid.setContainerDataSource(container); + grid.setSelectionMode(Grid.SelectionMode.SINGLE); + grid.setEditorEnabled(true); + } + + @Test + public void testBindFields() { + FieldGroup fieldGroup = grid.getEditorFieldGroup(); + + // Item with incomplete property set + fieldGroup.setItemDataSource( + grid.getContainerDataSource().getItem(folder)); + grid.getColumn(PROPERTY_NAME).getEditorField(); // called in + // grid.doEditItem + assertTrue("Properties in item should be bound", + fieldGroup.getBoundPropertyIds().contains(PROPERTY_NAME)); + assertFalse("Properties not present in item should not be bound", + fieldGroup.getBoundPropertyIds().contains(PROPERTY_SIZE)); + assertTrue("All of item's properties should be bound", + fieldGroup.getUnboundPropertyIds().isEmpty()); + + // Unbind all fields + fieldGroup.setItemDataSource(null); + assertTrue("No properties should be bound", + fieldGroup.getBoundPropertyIds().isEmpty()); + assertTrue("No unbound properties should exist", + fieldGroup.getUnboundPropertyIds().isEmpty()); + + // Item with complete property set + fieldGroup + .setItemDataSource(grid.getContainerDataSource().getItem(file)); + grid.getColumn(PROPERTY_NAME).getEditorField(); + grid.getColumn(PROPERTY_SIZE).getEditorField(); + assertTrue("Properties in item should be bound", + fieldGroup.getBoundPropertyIds().contains(PROPERTY_NAME)); + assertTrue("Properties in item should be bound", + fieldGroup.getBoundPropertyIds().contains(PROPERTY_SIZE)); + assertTrue("All of item's properties should be bound", + fieldGroup.getUnboundPropertyIds().isEmpty()); + + // Unbind all fields + fieldGroup.setItemDataSource(null); + assertTrue("No properties should be bound", + fieldGroup.getBoundPropertyIds().isEmpty()); + assertTrue("No unbound properties should exist", + fieldGroup.getUnboundPropertyIds().isEmpty()); + } + + @Test + public void testSetEditorField() { + FieldGroup fieldGroup = grid.getEditorFieldGroup(); + Field editorField = new PasswordField(); + + // Explicitly set editor field + fieldGroup.setItemDataSource( + grid.getContainerDataSource().getItem(folder)); + grid.getColumn(PROPERTY_NAME).setEditorField(editorField); + assertTrue("Editor field should be the one that was previously set", + grid.getColumn(PROPERTY_NAME).getEditorField() == editorField); + + // Reset item + fieldGroup.setItemDataSource(null); + fieldGroup + .setItemDataSource(grid.getContainerDataSource().getItem(file)); + assertTrue("Editor field should be the one that was previously set", + grid.getColumn(PROPERTY_NAME).getEditorField() == editorField); + } + + @Test + public void testEditCell() { + // Row with missing property + startEdit(folder); + assertEquals(folder, grid.getEditedItemId()); + assertEquals(getEditedItem(), + grid.getEditorFieldGroup().getItemDataSource()); + + assertEquals(FOLDER_NAME_BEFORE, + grid.getColumn(PROPERTY_NAME).getEditorField().getValue()); + try { + grid.getColumn(PROPERTY_SIZE).getEditorField(); + fail("Grid.editorFieldGroup should throw BindException by default"); + } catch (FieldGroup.BindException e) { + // BindException is thrown using the default FieldGroup + } + grid.cancelEditor(); + + // Row with all properties + startEdit(file); + assertEquals(file, grid.getEditedItemId()); + assertEquals(getEditedItem(), + grid.getEditorFieldGroup().getItemDataSource()); + + assertEquals(FILE_NAME_BEFORE, + grid.getColumn(PROPERTY_NAME).getEditorField().getValue()); + assertEquals(FILE_SIZE_BEFORE, + grid.getColumn(PROPERTY_SIZE).getEditorField().getValue()); + grid.cancelEditor(); + } + + @Test + public void testCancelEditor() { + // Row with all properties + testCancel(file, PROPERTY_NAME, FILE_NAME_BEFORE, FILE_NAME_AFTER); + testCancel(file, PROPERTY_SIZE, FILE_SIZE_BEFORE, FILE_SIZE_AFTER); + + // Row with missing property + testCancel(folder, PROPERTY_NAME, FOLDER_NAME_BEFORE, + FOLDER_NAME_AFTER); + } + + private void testCancel(Object itemId, String propertyId, + String valueBefore, String valueAfter) { + startEdit(itemId); + + TextField field = (TextField) grid.getColumn(propertyId) + .getEditorField(); + field.setValue(valueAfter); + + Property datasource = field.getPropertyDataSource(); + + grid.cancelEditor(); + assertFalse(grid.isEditorActive()); + assertNull(grid.getEditedItemId()); + assertFalse(field.isModified()); + assertEquals("", field.getValue()); + assertEquals(valueBefore, datasource.getValue()); + assertNull(field.getPropertyDataSource()); + assertNull(grid.getEditorFieldGroup().getItemDataSource()); + } + + @Test + public void testSaveEditor() throws Exception { + // Row with all properties + testSave(file, PROPERTY_SIZE, FILE_SIZE_BEFORE, FILE_SIZE_AFTER); + + // Row with missing property + testSave(folder, PROPERTY_NAME, FOLDER_NAME_BEFORE, FOLDER_NAME_AFTER); + } + + private void testSave(Object itemId, String propertyId, String valueBefore, + String valueAfter) throws Exception { + startEdit(itemId); + TextField field = (TextField) grid.getColumn(propertyId) + .getEditorField(); + + field.setValue(valueAfter); + assertEquals(valueBefore, field.getPropertyDataSource().getValue()); + + grid.saveEditor(); + assertTrue(grid.isEditorActive()); + assertFalse(field.isModified()); + assertEquals(valueAfter, field.getValue()); + assertEquals(valueAfter, getEditedProperty(propertyId).getValue()); + grid.cancelEditor(); + } + + private Item getEditedItem() { + assertNotNull(grid.getEditedItemId()); + return grid.getContainerDataSource().getItem(grid.getEditedItemId()); + } + + private Property getEditedProperty(Object propertyId) { + return getEditedItem().getItemProperty(propertyId); + } + + private void startEdit(Object itemId) { + grid.setEditorEnabled(true); + grid.editItem(itemId); + // Simulate succesful client response to actually start the editing. + grid.doEditItem(); + } + + private class TestContainer + extends AbstractInMemoryContainer { + + private final List> items; + private final List pids; + + public TestContainer(List> items, List pids) { + this.items = items; + this.pids = pids; + } + + @Override + protected List getAllItemIds() { + List ids = new ArrayList<>(); + for (BeanItem item : items) { + ids.add(item.getBean()); + } + return ids; + } + + @Override + protected BeanItem getUnfilteredItem(Object itemId) { + for (BeanItem item : items) { + if (item.getBean().equals(itemId)) { + return item; + } + } + return null; + } + + @Override + public Collection getContainerPropertyIds() { + return pids; + } + + @Override + public Property getContainerProperty(Object itemId, Object propertyId) { + return getItem(itemId).getItemProperty(propertyId); + } + + @Override + public Class getType(Object propertyId) { + return String.class; + } + } + + public class Entry { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Entry(String name) { + this.name = name; + } + } + + public class Folder extends Entry { + + public Folder(String name) { + super(name); + } + } + + public class File extends Entry { + private String size; + + public File(String name, String size) { + super(name); + this.size = size; + } + + public String getSize() { + return size; + } + + public void setSize(String size) { + this.size = size; + } + } + + private class Grid extends com.vaadin.v7.ui.Grid { + @Override + protected void doEditItem() { + super.doEditItem(); + } + } +} diff --git a/compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/ColumnResizeMode.java b/compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/ColumnResizeMode.java new file mode 100644 index 0000000000..6f3de6a185 --- /dev/null +++ b/compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/ColumnResizeMode.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2016 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.v7.shared.ui.grid; + +/** + * Collection of modes used for resizing columns in the Grid. + */ +public enum ColumnResizeMode { + + /** + * When column resize mode is set to Animated, columns are resized as they + * are dragged. + */ + ANIMATED, + + /** + * When column resize mode is set to Simple, dragging to resize a column + * will show a marker, and the column will resize only after the mouse + * button or touch is released. + */ + SIMPLE + +} \ No newline at end of file diff --git a/compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/GridState.java b/compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/GridState.java index 4befc1fe09..a4c701c64b 100644 --- a/compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/GridState.java +++ b/compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/GridState.java @@ -141,15 +141,20 @@ public class GridState extends TabIndexState { primaryStyleName = "v-grid"; } + /** + * Column resize mode in grid. + */ + public ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; + /** * Columns in grid. */ - public List columns = new ArrayList(); + public List columns = new ArrayList<>(); /** * Column order in grid. */ - public List columnOrder = new ArrayList(); + public List columnOrder = new ArrayList<>(); public GridStaticSectionState header = new GridStaticSectionState(); diff --git a/compatibility-themes/src/main/themes/VAADIN/themes/base/escalator/escalator.scss b/compatibility-themes/src/main/themes/VAADIN/themes/base/escalator/escalator.scss index 1abf754584..10a21c65d9 100644 --- a/compatibility-themes/src/main/themes/VAADIN/themes/base/escalator/escalator.scss +++ b/compatibility-themes/src/main/themes/VAADIN/themes/base/escalator/escalator.scss @@ -75,6 +75,8 @@ } .#{$primaryStyleName}-body { + -ms-touch-action: none; + touch-action: none; z-index: 0; top: 0; diff --git a/compatibility-themes/src/main/themes/VAADIN/themes/base/grid/grid.scss b/compatibility-themes/src/main/themes/VAADIN/themes/base/grid/grid.scss index fdbf2a0cf5..2cbb1c8616 100644 --- a/compatibility-themes/src/main/themes/VAADIN/themes/base/grid/grid.scss +++ b/compatibility-themes/src/main/themes/VAADIN/themes/base/grid/grid.scss @@ -276,6 +276,22 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co -ms-user-select: none; user-select: none; } + + .#{$primaryStyleName}-column-resize-simple-indicator { + position: absolute; + width: 3px; + top: 0px; + left: $v-grid-cell-padding-horizontal; + z-index: 9001; + background: #fff; + box-shadow: 0px 0px 5px #000; + + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } // Footer diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java index 120640bd53..7b868ee542 100644 --- a/server/src/main/java/com/vaadin/ui/Grid.java +++ b/server/src/main/java/com/vaadin/ui/Grid.java @@ -68,6 +68,7 @@ import com.vaadin.shared.Registration; import com.vaadin.shared.data.DataCommunicatorConstants; import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.ui.grid.AbstractGridExtensionState; +import com.vaadin.shared.ui.grid.ColumnResizeMode; import com.vaadin.shared.ui.grid.ColumnState; import com.vaadin.shared.ui.grid.DetailsManagerState; import com.vaadin.shared.ui.grid.GridConstants; @@ -79,6 +80,7 @@ import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.SectionState; import com.vaadin.shared.util.SharedUtil; import com.vaadin.ui.Grid.FooterRow; +import com.vaadin.ui.Grid.SelectionMode; import com.vaadin.ui.components.grid.AbstractSelectionModel; import com.vaadin.ui.components.grid.EditorComponentGenerator; import com.vaadin.ui.components.grid.EditorImpl; @@ -845,7 +847,6 @@ public class Grid extends AbstractListing if (column != null && column.isResizable()) { column.getState().width = pixels; fireColumnResizeEvent(column, true); - markAsDirty(); } } } @@ -3465,6 +3466,27 @@ public class Grid extends AbstractListing return (GridState) super.getState(markAsDirty); } + /** + * Sets the column resize mode to use. The default mode is + * {@link ColumnResizeMode#ANIMATED}. + * + * @param mode + * a ColumnResizeMode value + */ + public void setColumnResizeMode(ColumnResizeMode mode) { + getState().columnResizeMode = mode; + } + + /** + * Returns the current column resize mode. The default mode is + * {@link ColumnResizeMode#ANIMATED}. + * + * @return a ColumnResizeMode value + */ + public ColumnResizeMode getColumnResizeMode() { + return getState(false).columnResizeMode; + } + /** * Creates a new Editor instance. Can be overridden to create a custom * Editor. If the Editor is a {@link AbstractGridExtension}, it will be @@ -3744,7 +3766,6 @@ public class Grid extends AbstractListing getDataCommunicator().setInMemorySorting(null); return; } - sortOrder.addAll(order); sort(userOriginated); } diff --git a/server/src/main/java/com/vaadin/ui/GridLayout.java b/server/src/main/java/com/vaadin/ui/GridLayout.java index f56a90be95..e4562f81ce 100644 --- a/server/src/main/java/com/vaadin/ui/GridLayout.java +++ b/server/src/main/java/com/vaadin/ui/GridLayout.java @@ -740,7 +740,7 @@ public class GridLayout extends AbstractLayout // Forget expands for removed columns if (columns < getColumns()) { - for (int i = columns - 1; i < getColumns(); i++) { + for (int i = columns; i < getColumns(); i++) { columnExpandRatio.remove(i); getState().explicitColRatios.remove(i); } @@ -790,7 +790,7 @@ public class GridLayout extends AbstractLayout } // Forget expands for removed rows if (rows < getRows()) { - for (int i = rows - 1; i < getRows(); i++) { + for (int i = rows; i < getRows(); i++) { rowExpandRatio.remove(i); getState().explicitRowRatios.remove(i); } diff --git a/server/src/test/java/com/vaadin/tests/server/component/gridlayout/GridLayoutTest.java b/server/src/test/java/com/vaadin/tests/server/component/gridlayout/GridLayoutTest.java index 1eabf2fb62..64b466612f 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/gridlayout/GridLayoutTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/gridlayout/GridLayoutTest.java @@ -75,6 +75,30 @@ public class GridLayoutTest { assertOrder(grid, new int[] { 0, 1, 2, 3 }); } + @Test + public void removeRowsExpandRatiosPreserved() { + GridLayout gl = new GridLayout(3, 3); + gl.setRowExpandRatio(0, 0); + gl.setRowExpandRatio(1, 1); + gl.setRowExpandRatio(2, 2); + + gl.setRows(2); + assertEquals(0, gl.getRowExpandRatio(0), 0); + assertEquals(1, gl.getRowExpandRatio(1), 0); + } + + @Test + public void removeColsExpandRatiosPreserved() { + GridLayout gl = new GridLayout(3, 3); + gl.setColumnExpandRatio(0, 0); + gl.setColumnExpandRatio(1, 1); + gl.setColumnExpandRatio(2, 2); + + gl.setColumns(2); + assertEquals(0, gl.getColumnExpandRatio(0), 0); + assertEquals(1, gl.getColumnExpandRatio(1), 0); + } + private void assertContentPositions(GridLayout grid) { assertEquals(grid.getComponentCount(), children.length); int c = 0; diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/ColumnResizeMode.java b/shared/src/main/java/com/vaadin/shared/ui/grid/ColumnResizeMode.java new file mode 100644 index 0000000000..a19a2bb9eb --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/ui/grid/ColumnResizeMode.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2016 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.shared.ui.grid; + +/** + * Collection of modes used for resizing columns in the Grid. + */ +public enum ColumnResizeMode { + + /** + * When column resize mode is set to Animated, columns + * are resized as they are dragged. + */ + ANIMATED, + + /** + * When column resize mode is set to Simple, dragging to resize + * a column will show a marker, and the column will resize only + * after the mouse button or touch is released. + */ + SIMPLE + +} diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java b/shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java index a8abf82c75..1074b181d8 100644 --- a/shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java @@ -99,6 +99,11 @@ public class GridState extends AbstractSingleSelectState { primaryStyleName = "v-grid"; } + /** + * Column resize mode in grid. + */ + public ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; + /** The state of the header section. */ public SectionState header = new SectionState(); diff --git a/themes/src/main/themes/VAADIN/themes/valo/components/_escalator.scss b/themes/src/main/themes/VAADIN/themes/valo/components/_escalator.scss index c91c301fa7..895d9ab975 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/components/_escalator.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/components/_escalator.scss @@ -75,6 +75,8 @@ } .#{$primaryStyleName}-body { + -ms-touch-action: none; + touch-action: none; z-index: 0; top: 0; diff --git a/themes/src/main/themes/VAADIN/themes/valo/components/_grid.scss b/themes/src/main/themes/VAADIN/themes/valo/components/_grid.scss index 849ff7a1e4..b0279ecea2 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/components/_grid.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/components/_grid.scss @@ -306,6 +306,22 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co -ms-user-select: none; user-select: none; } + + .#{$primaryStyleName}-column-resize-simple-indicator { + position: absolute; + width: 3px; + top: 0px; + left: $v-grid-cell-padding-horizontal; + z-index: 9001; + background: #fff; + box-shadow: 0px 0px 5px #000; + + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } // Footer diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResize.java b/uitest/src/main/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResize.java new file mode 100644 index 0000000000..580f2d3a30 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResize.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2016 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.stream.IntStream; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Grid; + +/** + * @author Vaadin Ltd + * + */ +public class HorizontalScrollAfterResize extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final Grid grid = new Grid<>(); + grid.setWidth("100%"); + grid.setHeight("350px"); + grid.setCaption("My Grid"); + + for (int i = 0; i < 10; i++) { + char ch = (char) ('a' + i); + grid.addColumn(item -> "test").setCaption("" + ch); + } + + grid.setItems(IntStream.of(0, 100).mapToObj(Integer::valueOf)); + + addComponents(grid); + } + + @Override + protected String getTestDescription() { + return "Don't add more than one scroll handler"; + } + + @Override + protected Integer getTicketNumber() { + return 19189; // also 20254, 19622 + } + +} diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java index c074bd4d14..e7ab23961b 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java @@ -22,6 +22,7 @@ import com.vaadin.event.selection.SingleSelectionEvent; import com.vaadin.server.VaadinRequest; import com.vaadin.shared.Registration; import com.vaadin.shared.data.sort.SortDirection; +import com.vaadin.shared.ui.grid.ColumnResizeMode; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.tests.components.AbstractTestUIWithLog; import com.vaadin.ui.Button; @@ -233,6 +234,10 @@ public class GridBasics extends AbstractTestUIWithLog { .getSelectionModel()) .addSingleSelectionListener(this::onSingleSelect); + grid.addColumnResizeListener( + event -> log("ColumnResizeEvent: isUserOriginated? " + + event.isUserOriginated())); + layout.addComponent(createMenu()); layout.addComponent(grid); addComponent(layout); @@ -345,6 +350,11 @@ public class GridBasics extends AbstractTestUIWithLog { item -> grid.sort(col, SortDirection.DESCENDING)); } columnsMenu.addItem("Clear sort", item -> grid.clearSortOrder()); + + columnsMenu.addItem("Simple resize mode", + item -> grid.setColumnResizeMode(item.isChecked() + ? ColumnResizeMode.SIMPLE : ColumnResizeMode.ANIMATED)) + .setCheckable(true); } private void createSizeMenu(MenuItem sizeMenu) { diff --git a/uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java b/uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java new file mode 100644 index 0000000000..3db3e208af --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java @@ -0,0 +1,125 @@ +package com.vaadin.tests.components.textfield; + +import com.vaadin.data.HasValue; +import com.vaadin.data.HasValue.ValueChangeListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.ValueChangeMode; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.tests.util.TestUtils; +import com.vaadin.ui.AbstractTextField; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.TextField; + +public class TextChangeEvents extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + + TextField textField = new TextField("Default"); + + ValueChangeListener listener = event -> log( + "Text change event for " + event.getComponent().getCaption() + + ", text content currently:'" + event.getValue() + + "' Cursor at index:" + + ((AbstractTextField) event.getSource()) + .getCursorPosition()); + + textField.addValueChangeListener(listener); + addComponent(textField); + + TextField eager = new TextField("Eager"); + eager.addValueChangeListener(listener); + eager.setValueChangeMode(ValueChangeMode.EAGER); + addComponent(eager); + + TextField timeout = new TextField("Timeout 3s"); + timeout.addValueChangeListener(listener); + timeout.setValueChangeMode(ValueChangeMode.EAGER); + timeout.setValueChangeTimeout(3000); + addComponent(timeout); + + TextArea textArea = new TextArea("Default text area"); + textArea.addValueChangeListener(listener); + addComponent(textArea); + + TextArea textAreaTimeout = new TextArea("Timeout 3s"); + textAreaTimeout.addValueChangeListener(listener); + textAreaTimeout.setValueChangeMode(ValueChangeMode.TIMEOUT); + textAreaTimeout.setValueChangeTimeout(3000); + addComponent(textAreaTimeout); + + VaadinDeveloperNameField vd = new VaadinDeveloperNameField(); + vd.addValueChangeListener(listener); + addComponent(vd); + } + + @Override + protected String getTestDescription() { + return "Simple TextChangeEvent test cases."; + } + + /** + * "Autosuggest" + * + * Known issue is timing if suggestion comes while typing more content. IMO + * we will not support this kind of features in default TextField, but + * hopefully make it easily extendable to perfect suggest feature. MT + * 2010-10 + * + */ + private class VaadinDeveloperNameField extends TextField + implements HasValue.ValueChangeListener { + private String[] names = new String[] { "Matti Tahvonen", + "Marc Englund", "Joonas Lehtinen", "Jouni Koivuviita", + "Marko Grönroos", "Artur Signell" }; + + public VaadinDeveloperNameField() { + setCaption("Start typing 'old' Vaadin developers."); + addValueChangeListener(this); + setStyleName("nomatch"); + } + + @Override + public void attach() { + super.attach(); + TestUtils.injectCSS(getUI(), ".match { background:green ;} " + + ".nomatch {background:red;}"); + } + + @Override + public void valueChange(HasValue.ValueChangeEvent event) { + boolean atTheEndOfText = event.getValue() + .length() == getCursorPosition(); + String match = findMatch(event.getValue()); + if (match != null) { + setStyleName("match"); + String curText = event.getValue(); + int matchlenght = curText.length(); + // autocomplete if garret is at the end of the text + if (atTheEndOfText) { + suggest(match, matchlenght); + } + } else { + setStyleName("nomatch"); + } + } + + private void suggest(String match, int matchlenght) { + setValue(match); + setSelection(matchlenght, match.length() - matchlenght); + } + + private String findMatch(String currentTextContent) { + if (currentTextContent.length() > 0) { + for (int i = 0; i < names.length; i++) { + if (names[i].startsWith(currentTextContent)) { + return names[i]; + } + } + } + return null; + } + + } + +} diff --git a/uitest/src/main/java/com/vaadin/v7/tests/components/grid/GridMissingProperty.java b/uitest/src/main/java/com/vaadin/v7/tests/components/grid/GridMissingProperty.java new file mode 100644 index 0000000000..99b2a53aad --- /dev/null +++ b/uitest/src/main/java/com/vaadin/v7/tests/components/grid/GridMissingProperty.java @@ -0,0 +1,129 @@ +package com.vaadin.v7.tests.components.grid; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.util.AbstractInMemoryContainer; +import com.vaadin.v7.data.util.BeanItem; +import com.vaadin.v7.ui.Grid; + +public class GridMissingProperty extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final Grid grid = new Grid(); + + final Folder folder = new Folder("Folder name"); + final BeanItem folderItem = new BeanItem<>(folder); + + final File file = new File("File name", "10kB"); + final BeanItem fileItem = new BeanItem<>(file); + + @SuppressWarnings("unchecked") + TestContainer container = new TestContainer( + Arrays.asList(folderItem, fileItem), + Arrays.asList("name", "size")); + + grid.setContainerDataSource(container); + grid.setSelectionMode(Grid.SelectionMode.SINGLE); + grid.setEditorEnabled(true); + + addComponent(grid); + } + + @Override + protected String getTestDescription() { + return "Grid Editor should not throw exception even when items are missing properties."; + } + + private class TestContainer + extends AbstractInMemoryContainer { + + private final List> items; + private final List pids; + + public TestContainer(List> items, List pids) { + this.items = items; + this.pids = pids; + } + + @Override + protected List getAllItemIds() { + List ids = new ArrayList<>(); + for (BeanItem item : items) { + ids.add(item.getBean()); + } + return ids; + } + + @Override + protected BeanItem getUnfilteredItem(Object itemId) { + for (BeanItem item : items) { + if (item.getBean().equals(itemId)) { + return item; + } + } + return null; + } + + @Override + public Collection getContainerPropertyIds() { + return pids; + } + + @Override + public Property getContainerProperty(Object itemId, Object propertyId) { + return getItem(itemId).getItemProperty(propertyId); + } + + @Override + public Class getType(Object propertyId) { + return String.class; + } + } + + public class Entry { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Entry(String name) { + this.name = name; + } + } + + public class Folder extends Entry { + + public Folder(String name) { + super(name); + } + } + + public class File extends Entry { + private String size; + + public File(String name, String size) { + super(name); + this.size = size; + } + + public String getSize() { + return size; + } + + public void setSize(String size) { + this.size = size; + } + } +} diff --git a/uitest/src/main/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/main/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridBasicFeatures.java index 0e8f16889c..5c5acf0054 100644 --- a/uitest/src/main/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/main/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -51,9 +51,10 @@ import com.vaadin.v7.data.Property.ValueChangeListener; import com.vaadin.v7.data.fieldgroup.FieldGroup.CommitException; import com.vaadin.v7.data.util.IndexedContainer; import com.vaadin.v7.event.ItemClickEvent; -import com.vaadin.v7.event.SelectionEvent; import com.vaadin.v7.event.ItemClickEvent.ItemClickListener; +import com.vaadin.v7.event.SelectionEvent; import com.vaadin.v7.event.SelectionEvent.SelectionListener; +import com.vaadin.v7.shared.ui.grid.ColumnResizeMode; import com.vaadin.v7.shared.ui.grid.GridStaticCellType; import com.vaadin.v7.shared.ui.grid.HeightMode; import com.vaadin.v7.ui.Field; @@ -1267,6 +1268,14 @@ public class GridBasicFeatures extends AbstractComponentTest { grid.getColumns().get(0).setMaximumWidth(30); } }, null); + createBooleanAction("Simple resize mode", "Columns", false, + new Command() { + @Override + public void execute(Grid g, Boolean value, Object data) { + g.setColumnResizeMode(value ? ColumnResizeMode.SIMPLE + : ColumnResizeMode.ANIMATED); + } + }); } private static String getColumnProperty(int c) { diff --git a/uitest/src/main/java/com/vaadin/v7/tests/components/textfield/TextChangeEvents.java b/uitest/src/main/java/com/vaadin/v7/tests/components/textfield/TextChangeEvents.java new file mode 100644 index 0000000000..fc9ccfe04f --- /dev/null +++ b/uitest/src/main/java/com/vaadin/v7/tests/components/textfield/TextChangeEvents.java @@ -0,0 +1,136 @@ +package com.vaadin.v7.tests.components.textfield; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Log; +import com.vaadin.tests.util.TestUtils; +import com.vaadin.v7.event.FieldEvents.TextChangeEvent; +import com.vaadin.v7.event.FieldEvents.TextChangeListener; +import com.vaadin.v7.ui.AbstractTextField.TextChangeEventMode; +import com.vaadin.v7.ui.TextArea; +import com.vaadin.v7.ui.TextField; + +public class TextChangeEvents extends TestBase { + Log l = new Log(10); + + @Override + protected void setup() { + + TextField tf = new TextField("Default"); + + TextChangeListener inputEventListener = new TextChangeListener() { + + @Override + public void textChange(TextChangeEvent event) { + l.log("Text change event for " + + event.getComponent().getCaption() + + ", text content currently:'" + event.getText() + + "' Cursor at index:" + event.getCursorPosition()); + } + }; + + tf.addListener(inputEventListener); + + getLayout().addComponent(tf); + + TextField eager = new TextField("Eager"); + eager.addListener(inputEventListener); + eager.setTextChangeEventMode(TextChangeEventMode.EAGER); + getLayout().addComponent(eager); + + TextField to = new TextField("Timeout 3s"); + to.addListener(inputEventListener); + to.setTextChangeEventMode(TextChangeEventMode.TIMEOUT); + to.setTextChangeTimeout(3000); + getLayout().addComponent(to); + + TextArea ta = new TextArea("Default text area"); + ta.addListener(inputEventListener); + getLayout().addComponent(ta); + + TextArea tat = new TextArea("Timeout 3s"); + tat.addListener(inputEventListener); + tat.setTextChangeEventMode(TextChangeEventMode.TIMEOUT); + tat.setTextChangeTimeout(3000); + getLayout().addComponent(tat); + + VaadinDeveloperNameField vd = new VaadinDeveloperNameField(); + vd.addListener(inputEventListener); + getLayout().addComponent(vd); + + getLayout().addComponent(l); + } + + @Override + protected String getDescription() { + return "Simple TextChangeEvent test cases."; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + + /** + * "Autosuggest" + * + * Known issue is timing if suggestion comes while typing more content. IMO + * we will not support this kind of features in default TextField, but + * hopefully make it easily extendable to perfect suggest feature. MT + * 2010-10 + * + */ + private class VaadinDeveloperNameField extends TextField + implements TextChangeListener { + private String[] names = new String[] { "Matti Tahvonen", + "Marc Englund", "Joonas Lehtinen", "Jouni Koivuviita", + "Marko Grönroos", "Artur Signell" }; + + public VaadinDeveloperNameField() { + setCaption("Start typing 'old' Vaadin developers."); + addListener((TextChangeListener) this); + setStyleName("nomatch"); + } + + @Override + public void attach() { + super.attach(); + TestUtils.injectCSS(getUI(), ".match { background:green ;} " + + ".nomatch {background:red;}"); + } + + @Override + public void textChange(TextChangeEvent event) { + boolean atTheEndOfText = event.getText() + .length() == getCursorPosition(); + String match = findMatch(event.getText()); + if (match != null) { + setStyleName("match"); + String curText = event.getText(); + int matchlenght = curText.length(); + // autocomplete if garret is at the end of the text + if (atTheEndOfText) { + suggest(match, matchlenght); + } + } else { + setStyleName("nomatch"); + } + } + + private void suggest(String match, int matchlenght) { + setValue(match); + setSelectionRange(matchlenght, match.length() - matchlenght); + } + + private String findMatch(String currentTextContent) { + if (currentTextContent.length() > 0) { + for (int i = 0; i < names.length; i++) { + if (names[i].startsWith(currentTextContent)) { + return names[i]; + } + } + } + return null; + } + } + +} diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResizeTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResizeTest.java new file mode 100644 index 0000000000..fcc9681b61 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResizeTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2000-2016 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.Dimension; +import org.openqa.selenium.Point; + +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.v7.tests.components.grid.basicfeatures.GridBasicFeaturesTest; + +/** + * @author Vaadin Ltd + * + */ +public class HorizontalScrollAfterResizeTest extends GridBasicFeaturesTest { + + /** + * The behavior without the fix differs across different browsers but + * scenario should work everywhere. + */ + @Test + public void scrollAfterResize() { + getDriver().manage().window().setSize(new Dimension(600, 400)); + openTestURL(); + getDriver().manage().window().setSize(new Dimension(200, 400)); + + // First scroll to the right + scrollGridHorizontallyTo(600); + Point locationAfterFirstScroll = $(GridElement.class).first() + .getCell(0, 9).getLocation(); + + // resize back + getDriver().manage().window().setSize(new Dimension(600, 400)); + // shrink again + getDriver().manage().window().setSize(new Dimension(200, 400)); + + // second scroll to the right + scrollGridHorizontallyTo(600); + + Point lolocationAfterSecondScrollcation = $(GridElement.class).first() + .getCell(0, 9).getLocation(); + + // With the bug scrolling doesn't happen. Location should be the same as + // first time + Assert.assertEquals(locationAfterFirstScroll, + lolocationAfterSecondScrollcation); + } + + @Override + protected Class getUIClass() { + return HorizontalScrollAfterResize.class; + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java new file mode 100644 index 0000000000..f92366cdb4 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2016 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.basicfeatures; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.customelements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.components.grid.basics.GridBasicsTest; + +@TestCategory("grid") +public class GridColumnResizeModeTest extends GridBasicsTest { + + @Before + public void before() { + openTestURL(); + } + + @Test + public void testSimpleResizeModeToggle() throws Exception { + + GridElement grid = getGridElement(); + + List handles = grid + .findElements(By.className("v-grid-column-resize-handle")); + WebElement handle = handles.get(1); + + Actions drag1 = new Actions(getDriver()).moveToElement(handle) + .clickAndHold(); + Actions drag2 = new Actions(getDriver()).moveByOffset(-50, 0); + Actions drag3 = new Actions(getDriver()).moveByOffset(100, 0); + Actions dragEndAction = new Actions(getDriver()).release() + .moveToElement(grid); + + selectMenuPath("Component", "Columns", "Simple resize mode"); + sleep(250); + + drag1.perform(); + sleep(500); + drag2.perform(); + sleep(500); + drag3.perform(); + sleep(500); + + // Make sure we find at least one simple resize mode splitter + assertElementPresent( + By.className("v-grid-column-resize-simple-indicator")); + + dragEndAction.perform(); + + // Make sure it went away + assertElementNotPresent( + By.className("v-grid-column-resize-simple-indicator")); + + // See that we got a resize event + sleep(500); + Assert.assertTrue("Log shows resize event", getLogRow(0) + .contains("ColumnResizeEvent: isUserOriginated? true")); + + } + +} diff --git a/uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java b/uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java new file mode 100644 index 0000000000..5693400eba --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java @@ -0,0 +1,50 @@ +package com.vaadin.tests.components.textfield; + +import org.junit.Test; + +import com.vaadin.testbench.elements.TextAreaElement; +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class TextChangeEventsTest extends SingleBrowserTest { + + @Test + public void textAreaWaitsForTextChangeEvents() { + openTestURL(); + + TextAreaElement taDefault = $(TextAreaElement.class) + .caption("Default text area").first(); + taDefault.sendKeys("abc"); + waitUntil(driver -> getLogRow(0).equals( + "1. Text change event for Default text area, text content currently:'abc' Cursor at index:3")); + + TextAreaElement taTimeout = $(TextAreaElement.class) + .caption("Timeout 3s").first(); + taTimeout.sendKeys("abc"); + waitUntil(driver -> getLogRow(0).equals( + "2. Text change event for Timeout 3s, text content currently:'abc' Cursor at index:3")); + } + + @Test + public void textFieldWaitsForTextChangeEvents() { + openTestURL(); + + TextFieldElement tfDefault = $(TextFieldElement.class) + .caption("Default").first(); + tfDefault.sendKeys("abc"); + waitUntil(driver -> getLogRow(0).equals( + "1. Text change event for Default, text content currently:'abc' Cursor at index:3")); + + TextFieldElement tfEager = $(TextFieldElement.class).caption("Eager") + .first(); + tfEager.sendKeys("abc"); + waitUntil(driver -> getLogRow(0).contains( + "Text change event for Eager, text content currently:'abc' Cursor at index:3")); + + TextFieldElement tfTimeout = $(TextFieldElement.class) + .caption("Timeout 3s").first(); + tfTimeout.sendKeys("abc"); + waitUntil(driver -> getLogRow(0).contains( + "Text change event for Timeout 3s, text content currently:'abc' Cursor at index:3")); + } +} diff --git a/uitest/src/test/java/com/vaadin/v7/tests/components/grid/GridMissingPropertyTest.java b/uitest/src/test/java/com/vaadin/v7/tests/components/grid/GridMissingPropertyTest.java new file mode 100644 index 0000000000..88262dcfcc --- /dev/null +++ b/uitest/src/test/java/com/vaadin/v7/tests/components/grid/GridMissingPropertyTest.java @@ -0,0 +1,73 @@ +package com.vaadin.v7.tests.components.grid; + +import org.junit.Test; + +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.elements.GridElement.GridEditorElement; +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GridMissingPropertyTest extends SingleBrowserTest { + + @Test + public void testCellEditable() { + openTestURL(); + GridElement grid = $(GridElement.class).first(); + + // Row with missing property + grid.getCell(0, 0).doubleClick(); + GridEditorElement editor = grid.getEditor(); + + assertTrue("Cell with property should be editable", + editor.isEditable(0)); + assertFalse("Cell without property should not be editable", + editor.isEditable(1)); + + editor.cancel(); + + // Row with all properties + grid.getCell(1, 0).doubleClick(); + editor = grid.getEditor(); + + assertTrue("Cell with property should be editable", + editor.isEditable(0)); + assertTrue("Cell with property should be editable", + editor.isEditable(1)); + + editor.cancel(); + } + + @Test + public void testEditCell() { + openTestURL(); + GridElement grid = $(GridElement.class).first(); + + GridEditorElement editor; + TextFieldElement editorField; + + grid.getCell(0, 0).doubleClick(); + editor = grid.getEditor(); + editorField = editor.getField(0).wrap(TextFieldElement.class); + editorField.setValue("New Folder Name"); + editor.save(); + assertEquals("New Folder Name", grid.getCell(0, 0).getText()); + + grid.getCell(1, 0).doubleClick(); + editor = grid.getEditor(); + editorField = editor.getField(1).wrap(TextFieldElement.class); + editorField.setValue("10 MB"); + editor.save(); + assertEquals("10 MB", grid.getCell(1, 1).getText()); + + grid.getCell(1, 0).doubleClick(); + editor = grid.getEditor(); + editorField = editor.getField(0).wrap(TextFieldElement.class); + editorField.setValue("New File Name"); + editor.save(); + assertEquals("New File Name", grid.getCell(1, 0).getText()); + } +} diff --git a/uitest/src/test/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java b/uitest/src/test/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java new file mode 100644 index 0000000000..f287a2aaa2 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2016 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.v7.tests.components.grid.basicfeatures; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.customelements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; + +@TestCategory("grid") +public class GridColumnResizeModeTest extends GridBasicFeaturesTest { + + @Before + public void before() { + openTestURL(); + } + + @Test + public void testSimpleResizeModeToggle() throws Exception { + + GridElement grid = getGridElement(); + + List handles = grid + .findElements(By.className("v-grid-column-resize-handle")); + WebElement handle = handles.get(1); + + Actions drag1 = new Actions(getDriver()).moveToElement(handle) + .clickAndHold(); + Actions drag2 = new Actions(getDriver()).moveByOffset(-50, 0); + Actions drag3 = new Actions(getDriver()).moveByOffset(100, 0); + Actions dragEndAction = new Actions(getDriver()).release() + .moveToElement(grid); + + selectMenuPath("Component", "Columns", "Simple resize mode"); + sleep(250); + + drag1.perform(); + sleep(500); + drag2.perform(); + sleep(500); + drag3.perform(); + sleep(500); + + // Make sure we find at least one simple resize mode splitter + assertElementPresent( + By.className("v-grid-column-resize-simple-indicator")); + + dragEndAction.perform(); + + // Make sure it went away + assertElementNotPresent( + By.className("v-grid-column-resize-simple-indicator")); + + // See that we got a resize event + sleep(500); + Assert.assertEquals("Log shows resize event", getLogRow(0), + "3. ColumnResizeEvent: isUserOriginated? true"); + + } + +} \ No newline at end of file diff --git a/uitest/src/test/java/com/vaadin/v7/tests/components/textfield/TextChangeEventsTest.java b/uitest/src/test/java/com/vaadin/v7/tests/components/textfield/TextChangeEventsTest.java new file mode 100644 index 0000000000..c6880fc700 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/v7/tests/components/textfield/TextChangeEventsTest.java @@ -0,0 +1,58 @@ +package com.vaadin.v7.tests.components.textfield; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.elements.TextAreaElement; +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class TextChangeEventsTest extends SingleBrowserTest { + + @Test + public void textAreaWaitsForTextChangeEvents() { + openTestURL(); + + TextAreaElement taDefault = $(TextAreaElement.class) + .caption("Default text area").first(); + taDefault.sendKeys("abc"); + Assert.assertEquals( + "1. Text change event for Default text area, text content currently:'abc' Cursor at index:3", + getLogRow(0)); + + TextAreaElement taTimeout = $(TextAreaElement.class) + .caption("Timeout 3s").first(); + taTimeout.sendKeys("abc"); + Assert.assertEquals( + "2. Text change event for Timeout 3s, text content currently:'abc' Cursor at index:3", + getLogRow(0)); + + } + + @Test + public void textFieldWaitsForTextChangeEvents() { + openTestURL(); + + TextFieldElement tfDefault = $(TextFieldElement.class) + .caption("Default").first(); + tfDefault.sendKeys("abc"); + Assert.assertEquals( + "1. Text change event for Default, text content currently:'abc' Cursor at index:3", + getLogRow(0)); + + TextFieldElement tfEager = $(TextFieldElement.class).caption("Eager") + .first(); + tfEager.sendKeys("abc"); + Assert.assertEquals( + "2. Text change event for Eager, text content currently:'abc' Cursor at index:3", + getLogRow(0)); + + TextFieldElement tfTimeout = $(TextFieldElement.class) + .caption("Timeout 3s").first(); + tfTimeout.sendKeys("abc"); + Assert.assertEquals( + "3. Text change event for Timeout 3s, text content currently:'abc' Cursor at index:3", + getLogRow(0)); + + } +} \ No newline at end of file