* 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
@@ -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()); | |||
} | |||
} | |||
@@ -72,4 +72,5 @@ public class VTextField extends TextBoxBase | |||
public void onFocus(FocusEvent event) { | |||
addStyleDependentName(CLASSNAME_FOCUS); | |||
} | |||
} |
@@ -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. | |||
* |
@@ -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; | |||
} | |||
} | |||
} | |||
@@ -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 |
@@ -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(); | |||
} | |||
} |
@@ -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); |
@@ -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)) { |
@@ -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; | |||
} | |||
} |
@@ -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) { |
@@ -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. | |||
*/ |
@@ -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); | |||
} | |||
/** |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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 | |||
} |
@@ -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(); | |||
@@ -75,6 +75,8 @@ | |||
} | |||
.#{$primaryStyleName}-body { | |||
-ms-touch-action: none; | |||
touch-action: none; | |||
z-index: 0; | |||
top: 0; | |||
@@ -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 | |||
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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; |
@@ -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 | |||
} |
@@ -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(); | |||
@@ -75,6 +75,8 @@ | |||
} | |||
.#{$primaryStyleName}-body { | |||
-ms-touch-action: none; | |||
touch-action: none; | |||
z-index: 0; | |||
top: 0; | |||
@@ -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 | |||
@@ -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 | |||
} | |||
} |
@@ -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) { |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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) { |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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")); | |||
} | |||
} |
@@ -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")); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |