Browse Source

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 8df27b952d.

* 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
tags/8.0.0.alpha10
Denis 7 years ago
parent
commit
809a486c60
36 changed files with 2034 additions and 165 deletions
  1. 13
    7
      client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
  2. 1
    0
      client/src/main/java/com/vaadin/client/ui/VTextField.java
  3. 50
    16
      client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java
  4. 5
    2
      client/src/main/java/com/vaadin/client/ui/dd/VHtml5DragEvent.java
  5. 6
    0
      client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java
  6. 96
    4
      client/src/main/java/com/vaadin/client/widgets/Escalator.java
  7. 175
    49
      client/src/main/java/com/vaadin/client/widgets/Grid.java
  8. 17
    12
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java
  9. 7
    1
      compatibility-client/src/main/java/com/vaadin/v7/client/ui/VTextField.java
  10. 175
    49
      compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java
  11. 31
    14
      compatibility-server/src/main/java/com/vaadin/v7/data/fieldgroup/FieldGroup.java
  12. 76
    4
      compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java
  13. 334
    0
      compatibility-server/src/test/java/com/vaadin/v7/tests/server/component/grid/GridEditorMissingPropertyTest.java
  14. 36
    0
      compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/ColumnResizeMode.java
  15. 7
    2
      compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/GridState.java
  16. 2
    0
      compatibility-themes/src/main/themes/VAADIN/themes/base/escalator/escalator.scss
  17. 16
    0
      compatibility-themes/src/main/themes/VAADIN/themes/base/grid/grid.scss
  18. 23
    2
      server/src/main/java/com/vaadin/ui/Grid.java
  19. 2
    2
      server/src/main/java/com/vaadin/ui/GridLayout.java
  20. 24
    0
      server/src/test/java/com/vaadin/tests/server/component/gridlayout/GridLayoutTest.java
  21. 36
    0
      shared/src/main/java/com/vaadin/shared/ui/grid/ColumnResizeMode.java
  22. 5
    0
      shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java
  23. 2
    0
      themes/src/main/themes/VAADIN/themes/valo/components/_escalator.scss
  24. 16
    0
      themes/src/main/themes/VAADIN/themes/valo/components/_grid.scss
  25. 57
    0
      uitest/src/main/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResize.java
  26. 10
    0
      uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java
  27. 125
    0
      uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java
  28. 129
    0
      uitest/src/main/java/com/vaadin/v7/tests/components/grid/GridMissingProperty.java
  29. 10
    1
      uitest/src/main/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridBasicFeatures.java
  30. 136
    0
      uitest/src/main/java/com/vaadin/v7/tests/components/textfield/TextChangeEvents.java
  31. 68
    0
      uitest/src/test/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResizeTest.java
  32. 82
    0
      uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java
  33. 50
    0
      uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java
  34. 73
    0
      uitest/src/test/java/com/vaadin/v7/tests/components/grid/GridMissingPropertyTest.java
  35. 81
    0
      uitest/src/test/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java
  36. 58
    0
      uitest/src/test/java/com/vaadin/v7/tests/components/textfield/TextChangeEventsTest.java

+ 13
- 7
client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java View File

@@ -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<CellState, Set<String>> cellGroupEntry : rowState.cellGroups.entrySet()) {
for (Map.Entry<CellState, Set<String>> cellGroupEntry : rowState.cellGroups
.entrySet()) {
Set<String> 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());
}
}


+ 1
- 0
client/src/main/java/com/vaadin/client/ui/VTextField.java View File

@@ -72,4 +72,5 @@ public class VTextField extends TextBoxBase
public void onFocus(FocusEvent event) {
addStyleDependentName(CLASSNAME_FOCUS);
}

}

+ 50
- 16
client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java View File

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

+ 5
- 2
client/src/main/java/com/vaadin/client/ui/dd/VHtml5DragEvent.java View File

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


+ 6
- 0
client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java View File

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

+ 96
- 4
client/src/main/java/com/vaadin/client/widgets/Escalator.java View File

@@ -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 href=
* "http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsOverlay.html"
@@ -339,6 +341,11 @@ public class Escalator extends Widget
/*-{
return this.targetTouches[0].pageY;
}-*/;

public native String getPointerType()
/*-{
return this.pointerType;
}-*/;
}

private final Escalator escalator;
@@ -456,6 +463,15 @@ public class Escalator extends Widget
}

int pagePosition(CustomTouchEvent event) {
// Use native event's screen x and y for IE11 and Edge
// since there is no touches for these browsers (#18737)
if (isCurrentBrowserIE11OrEdge()) {
return vertical
? event.getNativeEvent().getClientY()
+ Window.getScrollTop()
: event.getNativeEvent().getClientX()
+ Window.getScrollLeft();
}
JsArray<Touch> 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();
}
}

+ 175
- 49
client/src/main/java/com/vaadin/client/widgets/Grid.java View File

@@ -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<T> extends ResizeComposite implements HasSelectionHandlers<T>,

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<T> extends ResizeComposite implements HasSelectionHandlers<T>,
&& 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<?, T> 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<?, T> 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<?, T> 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<?, T> 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<T> extends ResizeComposite implements HasSelectionHandlers<T>,
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);

+ 17
- 12
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java View File

@@ -389,7 +389,7 @@ public class GridConnector extends AbstractHasComponentsConnector
} else {
Collection<Column<?, JsonObject>> errorColumns;
if (errorColumnsIds != null) {
errorColumns = new ArrayList<Grid.Column<?, JsonObject>>();
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<JsonObject> event) {
if (!columnsUpdatedFromState) {
List<Column<?, JsonObject>> columns = getWidget().getColumns();
final List<String> newColumnOrder = new ArrayList<String>();
final List<String> newColumnOrder = new ArrayList<>();
for (Column<?, JsonObject> 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<String, ComponentConnector> idToDetailsMap = new HashMap<String, ComponentConnector>();
private final Map<String, Integer> idToRowIndex = new HashMap<String, Integer>();
private final Map<String, ComponentConnector> idToDetailsMap = new HashMap<>();
private final Map<String, Integer> idToRowIndex = new HashMap<>();

@Override
public Widget getDetails(int rowIndex) {
@@ -544,7 +544,7 @@ public class GridConnector extends AbstractHasComponentsConnector
}

public void updateConnectorHierarchy(List<ServerConnector> children) {
Set<String> connectorIds = new HashSet<String>();
Set<String> 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<String> removedDetails = new HashSet<String>();
Set<String> removedDetails = new HashSet<>();
for (Entry<String, ComponentConnector> 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<String, CustomGridColumn> columnIdToColumn = new HashMap<String, CustomGridColumn>();
private Map<String, CustomGridColumn> columnIdToColumn = new HashMap<>();

private List<String> columnOrder = new ArrayList<String>();
private List<String> 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<Column<?, JsonObject>, String> columnToErrorMessage = new HashMap<Column<?, JsonObject>, String>();
private final Map<Column<?, JsonObject>, 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<String> columnsInState = new HashSet<String>();
Set<String> 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> sortOrder = new ArrayList<SortOrder>();
List<SortOrder> 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<String> errors = new ArrayList<String>();
List<String> errors = new ArrayList<>();

for (Grid.Column<?, JsonObject> c : getWidget().getColumns()) {
if (!(c instanceof CustomGridColumn)) {

+ 7
- 1
compatibility-client/src/main/java/com/vaadin/v7/client/ui/VTextField.java View File

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

+ 175
- 49
compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java View File

@@ -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<T> extends ResizeComposite implements HasSelectionHandlers<T>,

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<T> extends ResizeComposite implements HasSelectionHandlers<T>,
&& 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<?, T> 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<?, T> 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<?, T> 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<?, T> 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<T> extends ResizeComposite implements HasSelectionHandlers<T>,
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) {

+ 31
- 14
compatibility-server/src/main/java/com/vaadin/v7/data/fieldgroup/FieldGroup.java View File

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

+ 76
- 4
compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java View File

@@ -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<Field<?>> fields = new ArrayList<>(getFields());
Item itemDataSource = getItemDataSource();

if (itemDataSource == null) {
unbindFields(fields);
} else {
bindFields(fields, itemDataSource);
}
}

private void unbindFields(List<Field<?>> fields) {
for (Field<?> field : fields) {
clearField(field);
unbind(field);
field.setParent(null);
}
}

private void bindFields(List<Field<?>> 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<Object, Field<?>> 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);
}

/**

+ 334
- 0
compatibility-server/src/test/java/com/vaadin/v7/tests/server/component/grid/GridEditorMissingPropertyTest.java View File

@@ -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<Entry> folderItem = new BeanItem<>(folder);
final BeanItem<Entry> 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<Object, String, BeanItem> {

private final List<BeanItem<Entry>> items;
private final List<String> pids;

public TestContainer(List<BeanItem<Entry>> items, List<String> pids) {
this.items = items;
this.pids = pids;
}

@Override
protected List<Object> getAllItemIds() {
List<Object> ids = new ArrayList<>();
for (BeanItem<Entry> item : items) {
ids.add(item.getBean());
}
return ids;
}

@Override
protected BeanItem<Entry> getUnfilteredItem(Object itemId) {
for (BeanItem<Entry> 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();
}
}
}

+ 36
- 0
compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/ColumnResizeMode.java View File

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

}

+ 7
- 2
compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/GridState.java View File

@@ -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<GridColumnState> columns = new ArrayList<GridColumnState>();
public List<GridColumnState> columns = new ArrayList<>();

/**
* Column order in grid.
*/
public List<String> columnOrder = new ArrayList<String>();
public List<String> columnOrder = new ArrayList<>();

public GridStaticSectionState header = new GridStaticSectionState();


+ 2
- 0
compatibility-themes/src/main/themes/VAADIN/themes/base/escalator/escalator.scss View File

@@ -75,6 +75,8 @@
}

.#{$primaryStyleName}-body {
-ms-touch-action: none;
touch-action: none;
z-index: 0;
top: 0;


+ 16
- 0
compatibility-themes/src/main/themes/VAADIN/themes/base/grid/grid.scss View File

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


+ 23
- 2
server/src/main/java/com/vaadin/ui/Grid.java View File

@@ -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<T> extends AbstractListing<T>
if (column != null && column.isResizable()) {
column.getState().width = pixels;
fireColumnResizeEvent(column, true);
markAsDirty();
}
}
}
@@ -3465,6 +3466,27 @@ public class Grid<T> extends AbstractListing<T>
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<T> extends AbstractListing<T>
getDataCommunicator().setInMemorySorting(null);
return;
}

sortOrder.addAll(order);
sort(userOriginated);
}

+ 2
- 2
server/src/main/java/com/vaadin/ui/GridLayout.java View File

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

+ 24
- 0
server/src/test/java/com/vaadin/tests/server/component/gridlayout/GridLayoutTest.java View File

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

+ 36
- 0
shared/src/main/java/com/vaadin/shared/ui/grid/ColumnResizeMode.java View File

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

}

+ 5
- 0
shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java View File

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


+ 2
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_escalator.scss View File

@@ -75,6 +75,8 @@
}

.#{$primaryStyleName}-body {
-ms-touch-action: none;
touch-action: none;
z-index: 0;
top: 0;


+ 16
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_grid.scss View File

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


+ 57
- 0
uitest/src/main/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResize.java View File

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

}

+ 10
- 0
uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java View File

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

+ 125
- 0
uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java View File

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

}

}

+ 129
- 0
uitest/src/main/java/com/vaadin/v7/tests/components/grid/GridMissingProperty.java View File

@@ -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<Entry> folderItem = new BeanItem<>(folder);

final File file = new File("File name", "10kB");
final BeanItem<Entry> 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<Object, String, BeanItem> {

private final List<BeanItem<Entry>> items;
private final List<String> pids;

public TestContainer(List<BeanItem<Entry>> items, List<String> pids) {
this.items = items;
this.pids = pids;
}

@Override
protected List<Object> getAllItemIds() {
List<Object> ids = new ArrayList<>();
for (BeanItem<Entry> item : items) {
ids.add(item.getBean());
}
return ids;
}

@Override
protected BeanItem<Entry> getUnfilteredItem(Object itemId) {
for (BeanItem<Entry> 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;
}
}
}

+ 10
- 1
uitest/src/main/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridBasicFeatures.java View File

@@ -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> {
grid.getColumns().get(0).setMaximumWidth(30);
}
}, null);
createBooleanAction("Simple resize mode", "Columns", false,
new Command<Grid, Boolean>() {
@Override
public void execute(Grid g, Boolean value, Object data) {
g.setColumnResizeMode(value ? ColumnResizeMode.SIMPLE
: ColumnResizeMode.ANIMATED);
}
});
}

private static String getColumnProperty(int c) {

+ 136
- 0
uitest/src/main/java/com/vaadin/v7/tests/components/textfield/TextChangeEvents.java View File

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

}

+ 68
- 0
uitest/src/test/java/com/vaadin/tests/components/grid/HorizontalScrollAfterResizeTest.java View File

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

+ 82
- 0
uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java View File

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

}

}

+ 50
- 0
uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java View File

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

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

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

+ 81
- 0
uitest/src/test/java/com/vaadin/v7/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java View File

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

}

}

+ 58
- 0
uitest/src/test/java/com/vaadin/v7/tests/components/textfield/TextChangeEventsTest.java View File

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

}
}

Loading…
Cancel
Save