* 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
import com.vaadin.client.widget.grid.sort.SortOrder; | import com.vaadin.client.widget.grid.sort.SortOrder; | ||||
import com.vaadin.client.widgets.Grid; | import com.vaadin.client.widgets.Grid; | ||||
import com.vaadin.client.widgets.Grid.Column; | 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.FooterRow; | ||||
import com.vaadin.client.widgets.Grid.HeaderCell; | |||||
import com.vaadin.client.widgets.Grid.HeaderRow; | import com.vaadin.client.widgets.Grid.HeaderRow; | ||||
import com.vaadin.shared.MouseEventDetails; | import com.vaadin.shared.MouseEventDetails; | ||||
import com.vaadin.shared.data.sort.SortDirection; | import com.vaadin.shared.data.sort.SortDirection; | ||||
.map(this::getColumn).toArray(size -> new Column[size])); | .map(this::getColumn).toArray(size -> new Column[size])); | ||||
} | } | ||||
@OnStateChange("columnResizeMode") | |||||
void updateColumnResizeMode() { | |||||
getWidget().setColumnResizeMode(getState().columnResizeMode); | |||||
} | |||||
/** | /** | ||||
* Updates the grid header section on state change. | * Updates the grid header section on state change. | ||||
*/ | */ | ||||
} | } | ||||
} | } | ||||
private void updateStaticRow(RowState rowState, Grid.StaticSection.StaticRow row) { | |||||
private void updateStaticRow(RowState rowState, | |||||
Grid.StaticSection.StaticRow row) { | |||||
rowState.cells.forEach((columnId, cellState) -> { | rowState.cells.forEach((columnId, cellState) -> { | ||||
updateStaticCellFromState(row.getCell(getColumn(columnId)), | updateStaticCellFromState(row.getCell(getColumn(columnId)), | ||||
cellState); | 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(); | 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. | // Set state to be the same as first in group. | ||||
updateStaticCellFromState(row.join(columns), cellGroupEntry.getKey()); | |||||
updateStaticCellFromState(row.join(columns), | |||||
cellGroupEntry.getKey()); | |||||
} | } | ||||
} | } | ||||
public void onFocus(FocusEvent event) { | public void onFocus(FocusEvent event) { | ||||
addStyleDependentName(CLASSNAME_FOCUS); | addStyleDependentName(CLASSNAME_FOCUS); | ||||
} | } | ||||
} | } |
public class DragHandle { | public class DragHandle { | ||||
/** | /** | ||||
* Callback interface for the DragHandle event life cycle | |||||
* Callback interface for the DragHandle event life cycle. | |||||
*/ | */ | ||||
public interface DragHandleCallback { | public interface DragHandleCallback { | ||||
/** | /** | ||||
* Called when dragging starts | |||||
* Called when dragging starts. | |||||
*/ | */ | ||||
public void onStart(); | |||||
void onStart(); | |||||
/** | /** | ||||
* Called when the drag handle has moved. | * Called when the drag handle has moved. | ||||
* @param deltaY | * @param deltaY | ||||
* change in Y direction since start | * 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 | * 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(); | |||||
} | } | ||||
private DragHandleCallback userCallback; | 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. | * Creates a new DragHandle. | ||||
* | * | ||||
@Override | @Override | ||||
public void onDrop() { | public void onDrop() { | ||||
removeDraggingStyle(); | removeDraggingStyle(); | ||||
userCallback.onComplete(); | |||||
if (userCallback != null) { | |||||
userCallback.onComplete(); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public void onDragUpdate(Event e) { | 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 | @Override | ||||
public boolean onDragStart(Event e) { | public boolean onDragStart(Event e) { | ||||
addDraggingStyle(); | 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; | return true; | ||||
} | } | ||||
@Override | @Override | ||||
public void onDragCancel() { | public void onDragCancel() { | ||||
removeDraggingStyle(); | removeDraggingStyle(); | ||||
userCallback.onCancel(); | |||||
if (userCallback != null) { | |||||
userCallback.onCancel(); | |||||
} | |||||
} | } | ||||
private void addDraggingStyle() { | private void addDraggingStyle() { | ||||
}); | }); | ||||
} | } | ||||
/** | |||||
* 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. | * Returns the current parent element for this drag handle. May be null. | ||||
* | * |
// Chrome >= v21 and Opera >= v? | // Chrome >= v21 and Opera >= v? | ||||
if (this.dataTransfer.items) { | if (this.dataTransfer.items) { | ||||
var item = this.dataTransfer.items[fileIndex]; | 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; | |||||
} | |||||
} | } | ||||
} | } | ||||
boolean offsetSizeBecomesGreaterThanScrollSize = showsScrollHandle() | boolean offsetSizeBecomesGreaterThanScrollSize = showsScrollHandle() | ||||
&& newOffsetSizeIsGreaterThanScrollSize; | && newOffsetSizeIsGreaterThanScrollSize; | ||||
if (offsetSizeBecomesGreaterThanScrollSize && getScrollPos() != 0) { | if (offsetSizeBecomesGreaterThanScrollSize && getScrollPos() != 0) { | ||||
if (offsetSizeTemporaryScrollHandler != null) { | |||||
offsetSizeTemporaryScrollHandler.removeHandler(); | |||||
} | |||||
// must be a field because Java insists. | // must be a field because Java insists. | ||||
offsetSizeTemporaryScrollHandler = addScrollHandler( | offsetSizeTemporaryScrollHandler = addScrollHandler( | ||||
new ScrollHandler() { | new ScrollHandler() { | ||||
*/ | */ | ||||
boolean delayedSizeSet = !BrowserInfo.get().isFirefox(); | boolean delayedSizeSet = !BrowserInfo.get().isFirefox(); | ||||
if (delayedSizeSet) { | if (delayedSizeSet) { | ||||
if (scrollSizeTemporaryScrollHandler != null) { | |||||
scrollSizeTemporaryScrollHandler.removeHandler(); | |||||
} | |||||
scrollSizeTemporaryScrollHandler = addScrollHandler( | scrollSizeTemporaryScrollHandler = addScrollHandler( | ||||
new ScrollHandler() { | new ScrollHandler() { | ||||
@Override | @Override |
static class JsniUtil { | static class JsniUtil { | ||||
public static class TouchHandlerBundle { | public static class TouchHandlerBundle { | ||||
public static final String POINTER_EVENT_TYPE_TOUCH = "touch"; | |||||
/** | /** | ||||
* A <a href= | * A <a href= | ||||
* "http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsOverlay.html" | * "http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsOverlay.html" | ||||
/*-{ | /*-{ | ||||
return this.targetTouches[0].pageY; | return this.targetTouches[0].pageY; | ||||
}-*/; | }-*/; | ||||
public native String getPointerType() | |||||
/*-{ | |||||
return this.pointerType; | |||||
}-*/; | |||||
} | } | ||||
private final Escalator escalator; | private final Escalator escalator; | ||||
} | } | ||||
int pagePosition(CustomTouchEvent event) { | 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(); | JsArray<Touch> a = event.getNativeEvent().getTouches(); | ||||
return vertical ? a.get(0).getPageY() : a.get(0).getPageX(); | return vertical ? a.get(0).getPageY() : a.get(0).getPageX(); | ||||
} | } | ||||
}; | }; | ||||
public void touchStart(final CustomTouchEvent event) { | public void touchStart(final CustomTouchEvent event) { | ||||
if (event.getNativeEvent().getTouches().length() == 1) { | |||||
if (allowTouch(event)) { | |||||
if (yMov == null) { | if (yMov == null) { | ||||
yMov = new Movement(true); | yMov = new Movement(true); | ||||
xMov = new Movement(false); | xMov = new Movement(false); | ||||
} | } | ||||
} | } | ||||
// 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) { | private double easingInOutCos(double val, double max) { | ||||
return 0.5 - 0.5 * Math.cos(Math.PI * Math.signum(val) | return 0.5 - 0.5 * Math.cos(Math.PI * Math.signum(val) | ||||
* Math.min(Math.abs(val), max) / max); | * Math.min(Math.abs(val), max) / max); | ||||
public native void detachScrollListener(Element element) | 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 | * GWT didn't provide enough details in events, or triggering the event | ||||
* handlers with GWT bindings was unsuccessful. Maybe, with more time | * handlers with GWT bindings was unsuccessful. Maybe, with more time | ||||
* and skill, it could be done with better success. JavaScript overlay | * and skill, it could be done with better success. JavaScript overlay | ||||
element.removeEventListener("touchcancel", this.@com.vaadin.client.widgets.JsniWorkaround::touchEndFunction); | 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, | public void scrollToColumn(final int columnIndex, | ||||
final ScrollDestination destination, final int padding) { | final ScrollDestination destination, final int padding) { | ||||
assert columnIndex >= columnConfiguration.frozenColumns : "Can't scroll to a frozen column"; | assert columnIndex >= columnConfiguration.frozenColumns : "Can't scroll to a frozen column"; | ||||
scroller.attachScrollListener(verticalScrollbar.getElement()); | scroller.attachScrollListener(verticalScrollbar.getElement()); | ||||
scroller.attachScrollListener(horizontalScrollbar.getElement()); | scroller.attachScrollListener(horizontalScrollbar.getElement()); | ||||
scroller.attachMousewheelListener(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 | @Override | ||||
scroller.detachScrollListener(verticalScrollbar.getElement()); | scroller.detachScrollListener(verticalScrollbar.getElement()); | ||||
scroller.detachScrollListener(horizontalScrollbar.getElement()); | scroller.detachScrollListener(horizontalScrollbar.getElement()); | ||||
scroller.detachMousewheelListener(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 | * We can call paintRemoveRows here, because static ranges are simple to | ||||
double getMinCellWidth(int colIndex) { | double getMinCellWidth(int colIndex) { | ||||
return columnConfiguration.getMinCellWidth(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(); | |||||
} | |||||
} | } |
import com.google.gwt.core.shared.GWT; | import com.google.gwt.core.shared.GWT; | ||||
import com.google.gwt.dom.client.BrowserEvents; | import com.google.gwt.dom.client.BrowserEvents; | ||||
import com.google.gwt.dom.client.DivElement; | 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.Element; | ||||
import com.google.gwt.dom.client.EventTarget; | import com.google.gwt.dom.client.EventTarget; | ||||
import com.google.gwt.dom.client.NativeEvent; | import com.google.gwt.dom.client.NativeEvent; | ||||
import com.vaadin.shared.Range; | import com.vaadin.shared.Range; | ||||
import com.vaadin.shared.Registration; | import com.vaadin.shared.Registration; | ||||
import com.vaadin.shared.data.sort.SortDirection; | 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; | ||||
import com.vaadin.shared.ui.grid.GridConstants.Section; | import com.vaadin.shared.ui.grid.GridConstants.Section; | ||||
import com.vaadin.shared.ui.grid.GridStaticCellType; | import com.vaadin.shared.ui.grid.GridStaticCellType; | ||||
private AutoScroller autoScroller = new AutoScroller(this); | private AutoScroller autoScroller = new AutoScroller(this); | ||||
private ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; | |||||
private DragAndDropHandler.DragAndDropCallback headerCellDndCallback = new DragAndDropCallback() { | private DragAndDropHandler.DragAndDropCallback headerCellDndCallback = new DragAndDropCallback() { | ||||
private final AutoScrollerCallback autoScrollerCallback = new AutoScrollerCallback() { | private final AutoScrollerCallback autoScrollerCallback = new AutoScrollerCallback() { | ||||
&& staticRow instanceof HeaderRow | && staticRow instanceof HeaderRow | ||||
&& ((HeaderRow) staticRow).isDefault()) { | && ((HeaderRow) staticRow).isDefault()) { | ||||
final DivElement resizeElement = Document.get() | |||||
.createDivElement(); | |||||
resizeElement.addClassName(getStylePrimaryName() | |||||
+ "-column-resize-simple-indicator"); | |||||
final int column = cell.getColumn(); | 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); | cellFocusHandler.updateFocusedCellStyle(cell, container); | ||||
fireEvent(new GridEnabledEvent(enabled)); | 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 | @Override | ||||
public void setStylePrimaryName(String style) { | public void setStylePrimaryName(String style) { | ||||
super.setStylePrimaryName(style); | super.setStylePrimaryName(style); |
} else { | } else { | ||||
Collection<Column<?, JsonObject>> errorColumns; | Collection<Column<?, JsonObject>> errorColumns; | ||||
if (errorColumnsIds != null) { | if (errorColumnsIds != null) { | ||||
errorColumns = new ArrayList<Grid.Column<?, JsonObject>>(); | |||||
errorColumns = new ArrayList<>(); | |||||
for (String colId : errorColumnsIds) { | for (String colId : errorColumnsIds) { | ||||
errorColumns.add(columnIdToColumn.get(colId)); | errorColumns.add(columnIdToColumn.get(colId)); | ||||
} | } | ||||
public void onColumnReorder(ColumnReorderEvent<JsonObject> event) { | public void onColumnReorder(ColumnReorderEvent<JsonObject> event) { | ||||
if (!columnsUpdatedFromState) { | if (!columnsUpdatedFromState) { | ||||
List<Column<?, JsonObject>> columns = getWidget().getColumns(); | List<Column<?, JsonObject>> columns = getWidget().getColumns(); | ||||
final List<String> newColumnOrder = new ArrayList<String>(); | |||||
final List<String> newColumnOrder = new ArrayList<>(); | |||||
for (Column<?, JsonObject> column : columns) { | for (Column<?, JsonObject> column : columns) { | ||||
if (column instanceof CustomGridColumn) { | if (column instanceof CustomGridColumn) { | ||||
newColumnOrder.add(((CustomGridColumn) column).id); | newColumnOrder.add(((CustomGridColumn) column).id); | ||||
private class CustomDetailsGenerator | private class CustomDetailsGenerator | ||||
implements HeightAwareDetailsGenerator { | 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 | @Override | ||||
public Widget getDetails(int rowIndex) { | public Widget getDetails(int rowIndex) { | ||||
} | } | ||||
public void updateConnectorHierarchy(List<ServerConnector> children) { | public void updateConnectorHierarchy(List<ServerConnector> children) { | ||||
Set<String> connectorIds = new HashSet<String>(); | |||||
Set<String> connectorIds = new HashSet<>(); | |||||
for (ServerConnector child : children) { | for (ServerConnector child : children) { | ||||
if (child instanceof ComponentConnector) { | if (child instanceof ComponentConnector) { | ||||
connectorIds.add(child.getConnectorId()); | connectorIds.add(child.getConnectorId()); | ||||
} | } | ||||
} | } | ||||
Set<String> removedDetails = new HashSet<String>(); | |||||
Set<String> removedDetails = new HashSet<>(); | |||||
for (Entry<String, ComponentConnector> entry : idToDetailsMap | for (Entry<String, ComponentConnector> entry : idToDetailsMap | ||||
.entrySet()) { | .entrySet()) { | ||||
ComponentConnector connector = entry.getValue(); | ComponentConnector connector = entry.getValue(); | ||||
/** | /** | ||||
* Maps a generated column id to a grid column instance | * 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 | * {@link #columnsUpdatedFromState} is set to true when | ||||
private RpcDataSource dataSource; | private RpcDataSource dataSource; | ||||
/* Used to track Grid editor columns with validation errors */ | /* 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(); | private ItemClickHandler itemClickHandler = new ItemClickHandler(); | ||||
} | } | ||||
} | } | ||||
// Column resize mode | |||||
if (stateChangeEvent.hasPropertyChanged("columnResizeMode")) { | |||||
getWidget().setColumnResizeMode(getState().columnResizeMode); | |||||
} | |||||
// Header and footer | // Header and footer | ||||
if (stateChangeEvent.hasPropertyChanged("header")) { | if (stateChangeEvent.hasPropertyChanged("header")) { | ||||
updateHeaderFromState(getState().header); | updateHeaderFromState(getState().header); | ||||
private void purgeRemovedColumns() { | private void purgeRemovedColumns() { | ||||
// Get columns still registered in the state | // Get columns still registered in the state | ||||
Set<String> columnsInState = new HashSet<String>(); | |||||
Set<String> columnsInState = new HashSet<>(); | |||||
for (GridColumnState columnState : getState().columns) { | for (GridColumnState columnState : getState().columns) { | ||||
columnsInState.add(columnState.id); | columnsInState.add(columnState.id); | ||||
} | } | ||||
} | } | ||||
private void onSortStateChange() { | private void onSortStateChange() { | ||||
List<SortOrder> sortOrder = new ArrayList<SortOrder>(); | |||||
List<SortOrder> sortOrder = new ArrayList<>(); | |||||
String[] sortColumns = getState().sortColumns; | String[] sortColumns = getState().sortColumns; | ||||
SortDirection[] sortDirs = getState().sortDirs; | SortDirection[] sortDirs = getState().sortDirs; | ||||
* @return displayed error string | * @return displayed error string | ||||
*/ | */ | ||||
private String getColumnErrors() { | private String getColumnErrors() { | ||||
List<String> errors = new ArrayList<String>(); | |||||
List<String> errors = new ArrayList<>(); | |||||
for (Grid.Column<?, JsonObject> c : getWidget().getColumns()) { | for (Grid.Column<?, JsonObject> c : getWidget().getColumns()) { | ||||
if (!(c instanceof CustomGridColumn)) { | if (!(c instanceof CustomGridColumn)) { |
import com.google.gwt.user.client.ui.TextBoxBase; | import com.google.gwt.user.client.ui.TextBoxBase; | ||||
import com.vaadin.client.ApplicationConnection; | import com.vaadin.client.ApplicationConnection; | ||||
import com.vaadin.client.BrowserInfo; | import com.vaadin.client.BrowserInfo; | ||||
import com.vaadin.client.DeferredWorker; | |||||
import com.vaadin.client.WidgetUtil; | import com.vaadin.client.WidgetUtil; | ||||
import com.vaadin.client.ui.Field; | import com.vaadin.client.ui.Field; | ||||
import com.vaadin.shared.EventId; | import com.vaadin.shared.EventId; | ||||
*/ | */ | ||||
@Deprecated | @Deprecated | ||||
public class VTextField extends TextBoxBase implements Field, ChangeHandler, | public class VTextField extends TextBoxBase implements Field, ChangeHandler, | ||||
FocusHandler, BlurHandler, KeyDownHandler { | |||||
FocusHandler, BlurHandler, KeyDownHandler, DeferredWorker { | |||||
/** | /** | ||||
* The input node CSS classname. | * The input node CSS classname. | ||||
} | } | ||||
possibleInputError = false; | possibleInputError = false; | ||||
} | } | ||||
@Override | |||||
public boolean isWorkPending() { | |||||
return scheduled; | |||||
} | |||||
} | } |
import com.google.gwt.core.shared.GWT; | import com.google.gwt.core.shared.GWT; | ||||
import com.google.gwt.dom.client.BrowserEvents; | import com.google.gwt.dom.client.BrowserEvents; | ||||
import com.google.gwt.dom.client.DivElement; | 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.Element; | ||||
import com.google.gwt.dom.client.EventTarget; | import com.google.gwt.dom.client.EventTarget; | ||||
import com.google.gwt.dom.client.NativeEvent; | import com.google.gwt.dom.client.NativeEvent; | ||||
import com.vaadin.v7.client.widgets.Grid.Editor.State; | 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.StaticCell; | ||||
import com.vaadin.v7.client.widgets.Grid.StaticSection.StaticRow; | 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; | ||||
import com.vaadin.v7.shared.ui.grid.GridConstants.Section; | import com.vaadin.v7.shared.ui.grid.GridConstants.Section; | ||||
import com.vaadin.v7.shared.ui.grid.GridStaticCellType; | import com.vaadin.v7.shared.ui.grid.GridStaticCellType; | ||||
private AutoScroller autoScroller = new AutoScroller(this); | private AutoScroller autoScroller = new AutoScroller(this); | ||||
private ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; | |||||
private DragAndDropHandler.DragAndDropCallback headerCellDndCallback = new DragAndDropCallback() { | private DragAndDropHandler.DragAndDropCallback headerCellDndCallback = new DragAndDropCallback() { | ||||
private final AutoScrollerCallback autoScrollerCallback = new AutoScrollerCallback() { | private final AutoScrollerCallback autoScrollerCallback = new AutoScrollerCallback() { | ||||
&& staticRow instanceof HeaderRow | && staticRow instanceof HeaderRow | ||||
&& ((HeaderRow) staticRow).isDefault()) { | && ((HeaderRow) staticRow).isDefault()) { | ||||
final DivElement resizeElement = Document.get() | |||||
.createDivElement(); | |||||
resizeElement.addClassName(getStylePrimaryName() | |||||
+ "-column-resize-simple-indicator"); | |||||
final int column = cell.getColumn(); | 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); | cellFocusHandler.updateFocusedCellStyle(cell, container); | ||||
return enabled; | 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 | @Override | ||||
public void setEnabled(boolean enabled) { | public void setEnabled(boolean enabled) { | ||||
if (enabled == this.enabled) { | if (enabled == this.enabled) { |
public void setItemDataSource(Item itemDataSource) { | public void setItemDataSource(Item itemDataSource) { | ||||
this.itemDataSource = itemDataSource; | this.itemDataSource = itemDataSource; | ||||
bindFields(); | |||||
} | |||||
/** | |||||
* Binds all fields to the properties in the item in use. | |||||
*/ | |||||
protected void bindFields() { | |||||
for (Field<?> f : fieldToPropertyId.keySet()) { | for (Field<?> f : fieldToPropertyId.keySet()) { | ||||
bind(f, fieldToPropertyId.get(f)); | bind(f, fieldToPropertyId.get(f)); | ||||
} | } | ||||
fieldToPropertyId.put(field, propertyId); | fieldToPropertyId.put(field, propertyId); | ||||
propertyIdToField.put(propertyId, field); | propertyIdToField.put(propertyId, field); | ||||
if (itemDataSource == null) { | 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 | // Will be bound when data source is set | ||||
return; | return; | ||||
configureField(field); | 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. | * Wrap property to transactional property. | ||||
*/ | */ |
import com.vaadin.v7.event.SelectionEvent.SelectionNotifier; | import com.vaadin.v7.event.SelectionEvent.SelectionNotifier; | ||||
import com.vaadin.v7.server.communication.data.DataGenerator; | import com.vaadin.v7.server.communication.data.DataGenerator; | ||||
import com.vaadin.v7.server.communication.data.RpcDataProviderExtension; | 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.EditorClientRpc; | ||||
import com.vaadin.v7.shared.ui.grid.EditorServerRpc; | import com.vaadin.v7.shared.ui.grid.EditorServerRpc; | ||||
import com.vaadin.v7.shared.ui.grid.GridClientRpc; | import com.vaadin.v7.shared.ui.grid.GridClientRpc; | ||||
} | } | ||||
return field; | 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)); | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
/** | /** | ||||
Renderer<?> renderer = column.getRenderer(); | Renderer<?> renderer = column.getRenderer(); | ||||
Item item = cell.getItem(); | 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 | data.put(columnKeys.key(cell.getPropertyId()), AbstractRenderer | ||||
.encodeValue(modelValue, renderer, converter, getLocale())); | .encodeValue(modelValue, renderer, converter, getLocale())); | ||||
private boolean editorSaving = false; | private boolean editorSaving = false; | ||||
private FieldGroup editorFieldGroup = new CustomFieldGroup(); | 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 CellStyleGenerator cellStyleGenerator; | ||||
private RowStyleGenerator rowStyleGenerator; | private RowStyleGenerator rowStyleGenerator; | ||||
return (GridState) super.getState(markAsDirty); | 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 | * Creates a new column based on a property id and appends it as the last | ||||
* column. | * column. | ||||
Field<?> editor = editorFieldGroup.getField(propertyId); | 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 { | try { | ||||
if (editor == null) { | if (editor == null) { | ||||
editor = editorFieldGroup.buildAndBind(propertyId); | editor = editorFieldGroup.buildAndBind(propertyId); | ||||
editorFieldGroup.setItemDataSource(item); | editorFieldGroup.setItemDataSource(item); | ||||
for (Column column : getColumns()) { | for (Column column : getColumns()) { | ||||
column.getState().editorConnector = getEditorField( | |||||
column.getPropertyId()); | |||||
column.getState().editorConnector = item | |||||
.getItemProperty(column.getPropertyId()) == null ? null | |||||
: getEditorField(column.getPropertyId()); | |||||
} | } | ||||
editorActive = true; | editorActive = true; | ||||
field.setParent(this); | field.setParent(this); | ||||
editorFieldGroup.bind(field, propertyId); | editorFieldGroup.bind(field, propertyId); | ||||
} | } | ||||
// Store field for this property for future reference | |||||
editorFields.put(propertyId, field); | |||||
} | } | ||||
/** | /** |
/* | |||||
* 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(); | |||||
} | |||||
} | |||||
} |
/* | |||||
* 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 | |||||
} |
primaryStyleName = "v-grid"; | primaryStyleName = "v-grid"; | ||||
} | } | ||||
/** | |||||
* Column resize mode in grid. | |||||
*/ | |||||
public ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; | |||||
/** | /** | ||||
* Columns in grid. | * Columns in grid. | ||||
*/ | */ | ||||
public List<GridColumnState> columns = new ArrayList<GridColumnState>(); | |||||
public List<GridColumnState> columns = new ArrayList<>(); | |||||
/** | /** | ||||
* Column order in grid. | * Column order in grid. | ||||
*/ | */ | ||||
public List<String> columnOrder = new ArrayList<String>(); | |||||
public List<String> columnOrder = new ArrayList<>(); | |||||
public GridStaticSectionState header = new GridStaticSectionState(); | public GridStaticSectionState header = new GridStaticSectionState(); | ||||
} | } | ||||
.#{$primaryStyleName}-body { | .#{$primaryStyleName}-body { | ||||
-ms-touch-action: none; | |||||
touch-action: none; | |||||
z-index: 0; | z-index: 0; | ||||
top: 0; | top: 0; | ||||
-ms-user-select: none; | -ms-user-select: none; | ||||
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 | // Footer | ||||
import com.vaadin.shared.data.DataCommunicatorConstants; | import com.vaadin.shared.data.DataCommunicatorConstants; | ||||
import com.vaadin.shared.data.sort.SortDirection; | import com.vaadin.shared.data.sort.SortDirection; | ||||
import com.vaadin.shared.ui.grid.AbstractGridExtensionState; | 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.ColumnState; | ||||
import com.vaadin.shared.ui.grid.DetailsManagerState; | import com.vaadin.shared.ui.grid.DetailsManagerState; | ||||
import com.vaadin.shared.ui.grid.GridConstants; | import com.vaadin.shared.ui.grid.GridConstants; | ||||
import com.vaadin.shared.ui.grid.SectionState; | import com.vaadin.shared.ui.grid.SectionState; | ||||
import com.vaadin.shared.util.SharedUtil; | import com.vaadin.shared.util.SharedUtil; | ||||
import com.vaadin.ui.Grid.FooterRow; | 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.AbstractSelectionModel; | ||||
import com.vaadin.ui.components.grid.EditorComponentGenerator; | import com.vaadin.ui.components.grid.EditorComponentGenerator; | ||||
import com.vaadin.ui.components.grid.EditorImpl; | import com.vaadin.ui.components.grid.EditorImpl; | ||||
if (column != null && column.isResizable()) { | if (column != null && column.isResizable()) { | ||||
column.getState().width = pixels; | column.getState().width = pixels; | ||||
fireColumnResizeEvent(column, true); | fireColumnResizeEvent(column, true); | ||||
markAsDirty(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
return (GridState) super.getState(markAsDirty); | 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 | * Creates a new Editor instance. Can be overridden to create a custom | ||||
* Editor. If the Editor is a {@link AbstractGridExtension}, it will be | * Editor. If the Editor is a {@link AbstractGridExtension}, it will be | ||||
getDataCommunicator().setInMemorySorting(null); | getDataCommunicator().setInMemorySorting(null); | ||||
return; | return; | ||||
} | } | ||||
sortOrder.addAll(order); | sortOrder.addAll(order); | ||||
sort(userOriginated); | sort(userOriginated); | ||||
} | } |
// Forget expands for removed columns | // Forget expands for removed columns | ||||
if (columns < getColumns()) { | if (columns < getColumns()) { | ||||
for (int i = columns - 1; i < getColumns(); i++) { | |||||
for (int i = columns; i < getColumns(); i++) { | |||||
columnExpandRatio.remove(i); | columnExpandRatio.remove(i); | ||||
getState().explicitColRatios.remove(i); | getState().explicitColRatios.remove(i); | ||||
} | } | ||||
} | } | ||||
// Forget expands for removed rows | // Forget expands for removed rows | ||||
if (rows < getRows()) { | if (rows < getRows()) { | ||||
for (int i = rows - 1; i < getRows(); i++) { | |||||
for (int i = rows; i < getRows(); i++) { | |||||
rowExpandRatio.remove(i); | rowExpandRatio.remove(i); | ||||
getState().explicitRowRatios.remove(i); | getState().explicitRowRatios.remove(i); | ||||
} | } |
assertOrder(grid, new int[] { 0, 1, 2, 3 }); | 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) { | private void assertContentPositions(GridLayout grid) { | ||||
assertEquals(grid.getComponentCount(), children.length); | assertEquals(grid.getComponentCount(), children.length); | ||||
int c = 0; | int c = 0; |
/* | |||||
* 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 | |||||
} |
primaryStyleName = "v-grid"; | primaryStyleName = "v-grid"; | ||||
} | } | ||||
/** | |||||
* Column resize mode in grid. | |||||
*/ | |||||
public ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; | |||||
/** The state of the header section. */ | /** The state of the header section. */ | ||||
public SectionState header = new SectionState(); | public SectionState header = new SectionState(); | ||||
} | } | ||||
.#{$primaryStyleName}-body { | .#{$primaryStyleName}-body { | ||||
-ms-touch-action: none; | |||||
touch-action: none; | |||||
z-index: 0; | z-index: 0; | ||||
top: 0; | top: 0; | ||||
-ms-user-select: none; | -ms-user-select: none; | ||||
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 | // Footer | ||||
/* | |||||
* 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 | |||||
} | |||||
} |
import com.vaadin.server.VaadinRequest; | import com.vaadin.server.VaadinRequest; | ||||
import com.vaadin.shared.Registration; | import com.vaadin.shared.Registration; | ||||
import com.vaadin.shared.data.sort.SortDirection; | import com.vaadin.shared.data.sort.SortDirection; | ||||
import com.vaadin.shared.ui.grid.ColumnResizeMode; | |||||
import com.vaadin.shared.ui.grid.HeightMode; | import com.vaadin.shared.ui.grid.HeightMode; | ||||
import com.vaadin.tests.components.AbstractTestUIWithLog; | import com.vaadin.tests.components.AbstractTestUIWithLog; | ||||
import com.vaadin.ui.Button; | import com.vaadin.ui.Button; | ||||
.getSelectionModel()) | .getSelectionModel()) | ||||
.addSingleSelectionListener(this::onSingleSelect); | .addSingleSelectionListener(this::onSingleSelect); | ||||
grid.addColumnResizeListener( | |||||
event -> log("ColumnResizeEvent: isUserOriginated? " | |||||
+ event.isUserOriginated())); | |||||
layout.addComponent(createMenu()); | layout.addComponent(createMenu()); | ||||
layout.addComponent(grid); | layout.addComponent(grid); | ||||
addComponent(layout); | addComponent(layout); | ||||
item -> grid.sort(col, SortDirection.DESCENDING)); | item -> grid.sort(col, SortDirection.DESCENDING)); | ||||
} | } | ||||
columnsMenu.addItem("Clear sort", item -> grid.clearSortOrder()); | 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) { | private void createSizeMenu(MenuItem sizeMenu) { |
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; | |||||
} | |||||
} | |||||
} |
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; | |||||
} | |||||
} | |||||
} |
import com.vaadin.v7.data.fieldgroup.FieldGroup.CommitException; | import com.vaadin.v7.data.fieldgroup.FieldGroup.CommitException; | ||||
import com.vaadin.v7.data.util.IndexedContainer; | import com.vaadin.v7.data.util.IndexedContainer; | ||||
import com.vaadin.v7.event.ItemClickEvent; | import com.vaadin.v7.event.ItemClickEvent; | ||||
import com.vaadin.v7.event.SelectionEvent; | |||||
import com.vaadin.v7.event.ItemClickEvent.ItemClickListener; | import com.vaadin.v7.event.ItemClickEvent.ItemClickListener; | ||||
import com.vaadin.v7.event.SelectionEvent; | |||||
import com.vaadin.v7.event.SelectionEvent.SelectionListener; | 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.GridStaticCellType; | ||||
import com.vaadin.v7.shared.ui.grid.HeightMode; | import com.vaadin.v7.shared.ui.grid.HeightMode; | ||||
import com.vaadin.v7.ui.Field; | import com.vaadin.v7.ui.Field; | ||||
grid.getColumns().get(0).setMaximumWidth(30); | grid.getColumns().get(0).setMaximumWidth(30); | ||||
} | } | ||||
}, null); | }, 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) { | private static String getColumnProperty(int c) { |
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; | |||||
} | |||||
} | |||||
} |
/* | |||||
* 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; | |||||
} | |||||
} |
/* | |||||
* 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")); | |||||
} | |||||
} |
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")); | |||||
} | |||||
} |
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()); | |||||
} | |||||
} |
/* | |||||
* 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"); | |||||
} | |||||
} |
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)); | |||||
} | |||||
} |