Browse Source

Duplicate client-side of the Vaadin 7 Grid

Change-Id: I069df183806937c2d97eb3e9c8a073ef53ab5c24
tags/8.0.0.alpha1
Teemu Suo-Anttila 7 years ago
parent
commit
d409100157
100 changed files with 9265 additions and 78 deletions
  1. 19
    2
      client-compiler/src/main/java/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
  2. 18
    8
      client-compiler/src/main/java/com/vaadin/server/widgetsetutils/metadata/RendererVisitor.java
  3. 2
    3
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/AbstractGridRendererConnector.java
  4. 128
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/AbstractRendererConnector.java
  5. 2
    2
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/AbstractSelectionModelConnector.java
  6. 2
    2
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/ButtonRendererConnector.java
  7. 3
    3
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/ClickableRendererConnector.java
  8. 28
    28
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java
  9. 2
    2
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/ImageRendererConnector.java
  10. 4
    4
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/JavaScriptRendererConnector.java
  11. 12
    12
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/MultiSelectionModelConnector.java
  12. 2
    2
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/NoSelectionModelConnector.java
  13. 1
    1
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/ProgressBarRendererConnector.java
  14. 5
    5
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/SingleSelectionModelConnector.java
  15. 1
    1
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/TextRendererConnector.java
  16. 2
    2
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/UnsafeHtmlRendererConnector.java
  17. 44
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ButtonRenderer.java
  18. 234
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ClickableRenderer.java
  19. 157
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ComplexRenderer.java
  20. 108
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/DateRenderer.java
  21. 41
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/HtmlRenderer.java
  22. 49
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ImageRenderer.java
  23. 71
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/NumberRenderer.java
  24. 47
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ProgressBarRenderer.java
  25. 54
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/Renderer.java
  26. 32
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/TextRenderer.java
  27. 112
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/renderers/WidgetRenderer.java
  28. 1
    1
      compatibility-client/src/main/java/com/vaadin/v7/client/ui/JsniMousewheelHandler.java
  29. 85
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/Cell.java
  30. 198
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/ColumnConfiguration.java
  31. 157
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/EscalatorUpdater.java
  32. 201
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/FlyweightCell.java
  33. 298
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/FlyweightRow.java
  34. 118
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/PositionFunction.java
  35. 49
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/Row.java
  36. 282
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/RowContainer.java
  37. 99
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/RowVisibilityChangeEvent.java
  38. 38
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/RowVisibilityChangeHandler.java
  39. 869
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/ScrollbarBundle.java
  40. 47
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/Spacer.java
  41. 64
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/SpacerUpdater.java
  42. 48
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/events/RowHeightChangedEvent.java
  43. 36
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/events/RowHeightChangedHandler.java
  44. 647
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/AutoScroller.java
  45. 151
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/CellReference.java
  46. 40
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/CellStyleGenerator.java
  47. 55
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/DataAvailableEvent.java
  48. 37
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/DataAvailableHandler.java
  49. 332
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/DefaultEditorEventHandler.java
  50. 46
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/DetailsGenerator.java
  51. 174
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/EditorHandler.java
  52. 128
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/EventCellReference.java
  53. 45
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/HeightAwareDetailsGenerator.java
  54. 93
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/RendererCellReference.java
  55. 104
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/RowReference.java
  56. 40
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/RowStyleGenerator.java
  57. 465
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/datasources/ListDataSource.java
  58. 176
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/datasources/ListSorter.java
  59. 44
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/AbstractGridKeyEventHandler.java
  60. 39
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/AbstractGridMouseEventHandler.java
  61. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyClickHandler.java
  62. 29
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyDoubleClickHandler.java
  63. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyKeyDownHandler.java
  64. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyKeyPressHandler.java
  65. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyKeyUpHandler.java
  66. 51
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnReorderEvent.java
  67. 40
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnReorderHandler.java
  68. 67
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnResizeEvent.java
  69. 40
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnResizeHandler.java
  70. 93
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnVisibilityChangeEvent.java
  71. 41
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnVisibilityChangeHandler.java
  72. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterClickHandler.java
  73. 29
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterDoubleClickHandler.java
  74. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterKeyDownHandler.java
  75. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterKeyPressHandler.java
  76. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterKeyUpHandler.java
  77. 52
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridClickEvent.java
  78. 55
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridDoubleClickEvent.java
  79. 46
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridEnabledEvent.java
  80. 37
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridEnabledHandler.java
  81. 123
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridKeyDownEvent.java
  82. 76
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridKeyPressEvent.java
  83. 123
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridKeyUpEvent.java
  84. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderClickHandler.java
  85. 29
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderDoubleClickHandler.java
  86. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderKeyDownHandler.java
  87. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderKeyPressHandler.java
  88. 28
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderKeyUpHandler.java
  89. 40
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ScrollEvent.java
  90. 35
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ScrollHandler.java
  91. 59
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/SelectAllEvent.java
  92. 37
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/SelectAllHandler.java
  93. 66
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/AbstractRowHandleSelectionModel.java
  94. 77
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/ClickSelectHandler.java
  95. 42
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/HasSelectionHandlers.java
  96. 781
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/MultiSelectionRenderer.java
  97. 178
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/SelectionEvent.java
  98. 39
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/SelectionHandler.java
  99. 258
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/SelectionModel.java
  100. 0
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/SelectionModelMulti.java

+ 19
- 2
client-compiler/src/main/java/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java View File

@@ -57,6 +57,8 @@ import elemental.json.JsonValue;
public class ConnectorBundle {
private static final String FAIL_IF_NOT_SERIALIZABLE = "vFailIfNotSerializable";

static final String OLD_RENDERER_CONNECTOR_NAME = "com.vaadin.v7.client.connectors.AbstractRendererConnector";

public static final Comparator<JClassType> jClassComparator = new Comparator<JClassType>() {
@Override
public int compare(JClassType o1, JClassType o2) {
@@ -475,8 +477,7 @@ public class ConnectorBundle {
}

public static boolean isConnectedRendererConnector(JClassType type) {
return isConnected(type)
&& isType(type, AbstractRendererConnector.class);
return isConnected(type) && isRendererType(type);
}

private static boolean isInterfaceType(JClassType type, Class<?> class1) {
@@ -492,6 +493,22 @@ public class ConnectorBundle {
}
}

private static boolean isRendererType(JClassType type) {
TypeOracle oracle = type.getOracle();
boolean isNew = false, isOld = false;
try {
isNew = oracle.getType(AbstractRendererConnector.class.getName())
.isAssignableFrom(type);
} catch (NotFoundException e) {
}
try {
isOld = oracle.getType(OLD_RENDERER_CONNECTOR_NAME)
.isAssignableFrom(type);
} catch (NotFoundException e) {
}
return isNew || isOld;
}

public void setNeedsInvoker(JClassType type, JMethod method) {
if (!isNeedsInvoker(type, method)) {
addMapping(needsInvoker, type, method);

+ 18
- 8
client-compiler/src/main/java/com/vaadin/server/widgetsetutils/metadata/RendererVisitor.java View File

@@ -61,13 +61,15 @@ public class RendererVisitor extends TypeVisitor {
.findInheritedMethod(type, "createRenderer").getEnclosingType();

// Needs GWT constructor if createRenderer is not overridden
if (createRendererClass.getQualifiedSourceName()
.equals(AbstractRendererConnector.class.getCanonicalName())) {
String connectorSrcName = createRendererClass.getQualifiedSourceName();

if (isAbstractRendererConnector(connectorSrcName)) {
// createRenderer not overridden
JMethod getRenderer = ConnectorBundle.findInheritedMethod(type,
"getRenderer");
if (getRenderer.getEnclosingType().getQualifiedSourceName().equals(
AbstractRendererConnector.class.getCanonicalName())) {
String rendererSrcName = getRenderer.getEnclosingType()
.getQualifiedSourceName();
if (isAbstractRendererConnector(rendererSrcName)) {
// getRenderer not overridden
logger.log(Type.ERROR, type.getQualifiedSourceName()
+ " must override either createRenderer or getRenderer");
@@ -108,8 +110,9 @@ public class RendererVisitor extends TypeVisitor {
throw new NotFoundException();
}

return !decodeMethod.getEnclosingType().getQualifiedSourceName()
.equals(AbstractRendererConnector.class.getName());
String decodeSrcName = decodeMethod.getEnclosingType()
.getQualifiedSourceName();
return !isAbstractRendererConnector(decodeSrcName);
} catch (NotFoundException e) {
logger.log(Type.ERROR,
"Can't find decode method for renderer " + type, e);
@@ -121,8 +124,8 @@ public class RendererVisitor extends TypeVisitor {
throws UnableToCompleteException {
JClassType originalType = type;
while (type != null) {
if (type.getQualifiedBinaryName()
.equals(AbstractRendererConnector.class.getName())) {
String typeBinName = type.getQualifiedBinaryName();
if (isAbstractRendererConnector(typeBinName)) {
JParameterizedType parameterized = type.isParameterized();
if (parameterized == null) {
logger.log(Type.ERROR, type.getQualifiedSourceName()
@@ -138,4 +141,11 @@ public class RendererVisitor extends TypeVisitor {
+ originalType.getQualifiedSourceName() + " does not extend "
+ AbstractRendererConnector.class.getName());
}

private static boolean isAbstractRendererConnector(String connectorSrcName) {
return connectorSrcName
.equals(AbstractRendererConnector.class.getName())
|| connectorSrcName
.equals(ConnectorBundle.OLD_RENDERER_CONNECTOR_NAME);
}
}

+ 2
- 3
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/AbstractGridRendererConnector.java View File

@@ -16,9 +16,8 @@
package com.vaadin.v7.client.connectors;

import com.vaadin.client.ServerConnector;
import com.vaadin.client.connectors.AbstractRendererConnector;
import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.widgets.Grid.Column;
import com.vaadin.v7.client.renderers.Renderer;
import com.vaadin.v7.client.widgets.Grid.Column;

import elemental.json.JsonObject;


+ 128
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/AbstractRendererConnector.java View File

@@ -0,0 +1,128 @@
/*
* 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.client.connectors;

import com.vaadin.client.ServerConnector;
import com.vaadin.client.communication.JsonDecoder;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.metadata.NoDataException;
import com.vaadin.client.metadata.Type;
import com.vaadin.client.metadata.TypeData;
import com.vaadin.client.metadata.TypeDataStore;
import com.vaadin.v7.client.renderers.Renderer;

import elemental.json.JsonValue;

/**
* An abstract base class for renderer connectors.
*
* @param <T>
* the presentation type of the renderer
*/
public abstract class AbstractRendererConnector<T>
extends AbstractExtensionConnector {

private Renderer<T> renderer = null;

private final Type presentationType = TypeDataStore
.getPresentationType(this.getClass());

protected AbstractRendererConnector() {
if (presentationType == null) {
throw new IllegalStateException("No presentation type found for "
+ getClass().getSimpleName()
+ ". This may be caused by some unspecified problem in widgetset compilation.");
}
}

/**
* Returns the renderer associated with this renderer connector.
* <p>
* A subclass of AbstractRendererConnector should override this method as
* shown below. The framework uses
* {@link com.google.gwt.core.client.GWT#create(Class) GWT.create(Class)} to
* create a renderer based on the return type of the overridden method, but
* only if {@link #createRenderer()} is not overridden as well:
*
* <pre>
* public MyRenderer getRenderer() {
* return (MyRenderer) super.getRenderer();
* }
* </pre>
*
* @return the renderer bound to this connector
*/
public Renderer<T> getRenderer() {
if (renderer == null) {
renderer = createRenderer();
}
return renderer;
}

/**
* Creates a new Renderer instance associated with this renderer connector.
* <p>
* You should typically not override this method since the framework by
* default generates an implementation that uses
* {@link com.google.gwt.core.client.GWT#create(Class)} to create a renderer
* of the same type as returned by the most specific override of
* {@link #getRenderer()}. If you do override the method, you can't call
* <code>super.createRenderer()</code> since the metadata needed for that
* implementation is not generated if there's an override of the method.
*
* @return a new renderer to be used with this connector
*/
protected Renderer<T> createRenderer() {
// TODO generate type data
Type type = TypeData.getType(getClass());
try {
Type rendererType = type.getMethod("getRenderer").getReturnType();
@SuppressWarnings("unchecked")
Renderer<T> instance = (Renderer<T>) rendererType.createInstance();
return instance;
} catch (NoDataException e) {
throw new IllegalStateException(
"Default implementation of createRenderer() does not work for "
+ getClass().getSimpleName()
+ ". This might be caused by explicitely using "
+ "super.createRenderer() or some unspecified "
+ "problem with the widgetset compilation.",
e);
}
}

/**
* Decodes the given JSON value into a value of type T so it can be passed
* to the {@link #getRenderer() renderer}.
*
* @param value
* the value to decode
* @return the decoded value of {@code value}
*/
public T decode(JsonValue value) {
@SuppressWarnings("unchecked")
T decodedValue = (T) JsonDecoder.decodeValue(presentationType, value,
null, getConnection());
return decodedValue;
}

@Override
@Deprecated
protected void extend(ServerConnector target) {
// NOOP
}

}

+ 2
- 2
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/AbstractSelectionModelConnector.java View File

@@ -19,9 +19,9 @@ import java.util.Collection;

import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widgets.Grid;
import com.vaadin.shared.ui.grid.GridState;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel;
import com.vaadin.v7.client.widgets.Grid;

import elemental.json.JsonObject;


+ 2
- 2
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/ButtonRendererConnector.java View File

@@ -16,9 +16,9 @@
package com.vaadin.v7.client.connectors;

import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.renderers.ButtonRenderer;
import com.vaadin.client.renderers.ClickableRenderer.RendererClickHandler;
import com.vaadin.shared.ui.Connect;
import com.vaadin.v7.client.renderers.ButtonRenderer;
import com.vaadin.v7.client.renderers.ClickableRenderer.RendererClickHandler;

import elemental.json.JsonObject;


+ 3
- 3
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/ClickableRendererConnector.java View File

@@ -17,10 +17,10 @@ package com.vaadin.v7.client.connectors;

import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.renderers.ClickableRenderer;
import com.vaadin.client.renderers.ClickableRenderer.RendererClickEvent;
import com.vaadin.client.renderers.ClickableRenderer.RendererClickHandler;
import com.vaadin.shared.ui.grid.renderers.RendererClickRpc;
import com.vaadin.v7.client.renderers.ClickableRenderer;
import com.vaadin.v7.client.renderers.ClickableRenderer.RendererClickEvent;
import com.vaadin.v7.client.renderers.ClickableRenderer.RendererClickHandler;

import elemental.json.JsonObject;


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

@@ -50,34 +50,6 @@ import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.AbstractHasComponentsConnector;
import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.SimpleManagedLayout;
import com.vaadin.client.widget.escalator.events.RowHeightChangedEvent;
import com.vaadin.client.widget.escalator.events.RowHeightChangedHandler;
import com.vaadin.client.widget.grid.CellReference;
import com.vaadin.client.widget.grid.CellStyleGenerator;
import com.vaadin.client.widget.grid.EditorHandler;
import com.vaadin.client.widget.grid.EventCellReference;
import com.vaadin.client.widget.grid.HeightAwareDetailsGenerator;
import com.vaadin.client.widget.grid.RowReference;
import com.vaadin.client.widget.grid.RowStyleGenerator;
import com.vaadin.client.widget.grid.events.BodyClickHandler;
import com.vaadin.client.widget.grid.events.BodyDoubleClickHandler;
import com.vaadin.client.widget.grid.events.ColumnReorderEvent;
import com.vaadin.client.widget.grid.events.ColumnReorderHandler;
import com.vaadin.client.widget.grid.events.ColumnResizeEvent;
import com.vaadin.client.widget.grid.events.ColumnResizeHandler;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeEvent;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler;
import com.vaadin.client.widget.grid.events.GridClickEvent;
import com.vaadin.client.widget.grid.events.GridDoubleClickEvent;
import com.vaadin.client.widget.grid.sort.SortEvent;
import com.vaadin.client.widget.grid.sort.SortHandler;
import com.vaadin.client.widget.grid.sort.SortOrder;
import com.vaadin.client.widgets.Grid;
import com.vaadin.client.widgets.Grid.Column;
import com.vaadin.client.widgets.Grid.FooterCell;
import com.vaadin.client.widgets.Grid.FooterRow;
import com.vaadin.client.widgets.Grid.HeaderCell;
import com.vaadin.client.widgets.Grid.HeaderRow;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.shared.ui.Connect;
@@ -95,6 +67,34 @@ import com.vaadin.shared.ui.grid.GridStaticSectionState.RowState;
import com.vaadin.shared.ui.grid.ScrollDestination;
import com.vaadin.v7.client.connectors.RpcDataSourceConnector.DetailsListener;
import com.vaadin.v7.client.connectors.RpcDataSourceConnector.RpcDataSource;
import com.vaadin.v7.client.widget.escalator.events.RowHeightChangedEvent;
import com.vaadin.v7.client.widget.escalator.events.RowHeightChangedHandler;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.CellStyleGenerator;
import com.vaadin.v7.client.widget.grid.EditorHandler;
import com.vaadin.v7.client.widget.grid.EventCellReference;
import com.vaadin.v7.client.widget.grid.HeightAwareDetailsGenerator;
import com.vaadin.v7.client.widget.grid.RowReference;
import com.vaadin.v7.client.widget.grid.RowStyleGenerator;
import com.vaadin.v7.client.widget.grid.events.BodyClickHandler;
import com.vaadin.v7.client.widget.grid.events.BodyDoubleClickHandler;
import com.vaadin.v7.client.widget.grid.events.ColumnReorderEvent;
import com.vaadin.v7.client.widget.grid.events.ColumnReorderHandler;
import com.vaadin.v7.client.widget.grid.events.ColumnResizeEvent;
import com.vaadin.v7.client.widget.grid.events.ColumnResizeHandler;
import com.vaadin.v7.client.widget.grid.events.ColumnVisibilityChangeEvent;
import com.vaadin.v7.client.widget.grid.events.ColumnVisibilityChangeHandler;
import com.vaadin.v7.client.widget.grid.events.GridClickEvent;
import com.vaadin.v7.client.widget.grid.events.GridDoubleClickEvent;
import com.vaadin.v7.client.widget.grid.sort.SortEvent;
import com.vaadin.v7.client.widget.grid.sort.SortHandler;
import com.vaadin.v7.client.widget.grid.sort.SortOrder;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.client.widgets.Grid.Column;
import com.vaadin.v7.client.widgets.Grid.FooterCell;
import com.vaadin.v7.client.widgets.Grid.FooterRow;
import com.vaadin.v7.client.widgets.Grid.HeaderCell;
import com.vaadin.v7.client.widgets.Grid.HeaderRow;

import elemental.json.JsonObject;
import elemental.json.JsonValue;

+ 2
- 2
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/ImageRendererConnector.java View File

@@ -18,10 +18,10 @@ package com.vaadin.v7.client.connectors;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.communication.JsonDecoder;
import com.vaadin.client.metadata.TypeDataStore;
import com.vaadin.client.renderers.ClickableRenderer.RendererClickHandler;
import com.vaadin.client.renderers.ImageRenderer;
import com.vaadin.shared.communication.URLReference;
import com.vaadin.shared.ui.Connect;
import com.vaadin.v7.client.renderers.ImageRenderer;
import com.vaadin.v7.client.renderers.ClickableRenderer.RendererClickHandler;

import elemental.json.JsonObject;
import elemental.json.JsonValue;

+ 4
- 4
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/JavaScriptRendererConnector.java View File

@@ -24,12 +24,12 @@ import com.google.gwt.dom.client.NativeEvent;
import com.vaadin.client.JavaScriptConnectorHelper;
import com.vaadin.client.Util;
import com.vaadin.client.communication.HasJavaScriptConnectorHelper;
import com.vaadin.client.renderers.ComplexRenderer;
import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.widget.grid.CellReference;
import com.vaadin.client.widget.grid.RendererCellReference;
import com.vaadin.shared.JavaScriptExtensionState;
import com.vaadin.shared.ui.Connect;
import com.vaadin.v7.client.renderers.ComplexRenderer;
import com.vaadin.v7.client.renderers.Renderer;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.RendererCellReference;
import com.vaadin.v7.ui.renderers.AbstractJavaScriptRenderer;

import elemental.json.JsonObject;

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

@@ -29,23 +29,23 @@ import com.vaadin.client.ServerConnector;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.renderers.ComplexRenderer;
import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.widget.grid.DataAvailableEvent;
import com.vaadin.client.widget.grid.DataAvailableHandler;
import com.vaadin.client.widget.grid.events.SelectAllEvent;
import com.vaadin.client.widget.grid.events.SelectAllHandler;
import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widget.grid.selection.SelectionModel.Multi;
import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
import com.vaadin.client.widgets.Grid;
import com.vaadin.client.widgets.Grid.HeaderCell;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.GridState;
import com.vaadin.shared.ui.grid.Range;
import com.vaadin.shared.ui.grid.selection.MultiSelectionModelServerRpc;
import com.vaadin.shared.ui.grid.selection.MultiSelectionModelState;
import com.vaadin.v7.client.renderers.ComplexRenderer;
import com.vaadin.v7.client.renderers.Renderer;
import com.vaadin.v7.client.widget.grid.DataAvailableEvent;
import com.vaadin.v7.client.widget.grid.DataAvailableHandler;
import com.vaadin.v7.client.widget.grid.events.SelectAllEvent;
import com.vaadin.v7.client.widget.grid.events.SelectAllHandler;
import com.vaadin.v7.client.widget.grid.selection.MultiSelectionRenderer;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel;
import com.vaadin.v7.client.widget.grid.selection.SpaceSelectHandler;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel.Multi;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.client.widgets.Grid.HeaderCell;
import com.vaadin.v7.ui.Grid.MultiSelectionModel;

import elemental.json.JsonObject;

+ 2
- 2
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/NoSelectionModelConnector.java View File

@@ -16,9 +16,9 @@
package com.vaadin.v7.client.connectors;

import com.vaadin.client.ServerConnector;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widget.grid.selection.SelectionModelNone;
import com.vaadin.shared.ui.Connect;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel;
import com.vaadin.v7.client.widget.grid.selection.SelectionModelNone;
import com.vaadin.v7.ui.Grid.NoSelectionModel;

import elemental.json.JsonObject;

+ 1
- 1
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/ProgressBarRendererConnector.java View File

@@ -15,8 +15,8 @@
*/
package com.vaadin.v7.client.connectors;

import com.vaadin.client.renderers.ProgressBarRenderer;
import com.vaadin.shared.ui.Connect;
import com.vaadin.v7.client.renderers.ProgressBarRenderer;

/**
* A connector for {@link ProgressBarRenderer}.

+ 5
- 5
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/SingleSelectionModelConnector.java View File

@@ -18,15 +18,15 @@ package com.vaadin.v7.client.connectors;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.widget.grid.selection.ClickSelectHandler;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widget.grid.selection.SelectionModel.Single;
import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.GridState;
import com.vaadin.shared.ui.grid.selection.SingleSelectionModelServerRpc;
import com.vaadin.shared.ui.grid.selection.SingleSelectionModelState;
import com.vaadin.v7.client.renderers.Renderer;
import com.vaadin.v7.client.widget.grid.selection.ClickSelectHandler;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel;
import com.vaadin.v7.client.widget.grid.selection.SpaceSelectHandler;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel.Single;
import com.vaadin.v7.ui.Grid.SingleSelectionModel;

import elemental.json.JsonObject;

+ 1
- 1
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/TextRendererConnector.java View File

@@ -15,8 +15,8 @@
*/
package com.vaadin.v7.client.connectors;

import com.vaadin.client.renderers.TextRenderer;
import com.vaadin.shared.ui.Connect;
import com.vaadin.v7.client.renderers.TextRenderer;

/**
* A connector for {@link TextRenderer}.

+ 2
- 2
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/UnsafeHtmlRendererConnector.java View File

@@ -15,9 +15,9 @@
*/
package com.vaadin.v7.client.connectors;

import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.widget.grid.RendererCellReference;
import com.vaadin.shared.ui.Connect;
import com.vaadin.v7.client.renderers.Renderer;
import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* A connector for {@link UnsafeHtmlRenderer}

+ 44
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ButtonRenderer.java View File

@@ -0,0 +1,44 @@
/*
* 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.client.renderers;

import com.google.gwt.core.shared.GWT;
import com.google.gwt.user.client.ui.Button;
import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* A Renderer that displays buttons with textual captions. The values of the
* corresponding column are used as the captions. Click handlers can be added to
* the renderer, invoked when any of the rendered buttons is clicked.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class ButtonRenderer extends ClickableRenderer<String, Button> {

@Override
public Button createWidget() {
Button b = GWT.create(Button.class);
b.addClickHandler(this);
b.setStylePrimaryName("v-nativebutton");
return b;
}

@Override
public void render(RendererCellReference cell, String text, Button button) {
button.setText(text);
}
}

+ 234
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ClickableRenderer.java View File

@@ -0,0 +1,234 @@
/*
* 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.client.renderers;

import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.MouseEvent;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.WidgetUtil;
import com.vaadin.shared.ui.grid.GridConstants.Section;
import com.vaadin.v7.client.widget.escalator.Cell;
import com.vaadin.v7.client.widget.escalator.RowContainer;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.EventCellReference;
import com.vaadin.v7.client.widgets.Escalator;
import com.vaadin.v7.client.widgets.Grid;

/**
* An abstract superclass for renderers that render clickable widgets. Click
* handlers can be added to a renderer to listen to click events emitted by all
* widgets rendered by the renderer.
*
* @param <T>
* the presentation (column) type
* @param <W>
* the widget type
*
* @since 7.4
* @author Vaadin Ltd
*/
public abstract class ClickableRenderer<T, W extends Widget>
extends WidgetRenderer<T, W> implements ClickHandler {

/**
* A handler for {@link RendererClickEvent renderer click events}.
*
* @param <R>
* the row type of the containing Grid
*
* @see {@link ButtonRenderer#addClickHandler(RendererClickHandler)}
*/
public interface RendererClickHandler<R> extends EventHandler {

/**
* Called when a rendered button is clicked.
*
* @param event
* the event representing the click
*/
void onClick(RendererClickEvent<R> event);
}

/**
* An event fired when a widget rendered by a ClickableWidgetRenderer
* subclass is clicked.
*
* @param <R>
* the row type of the containing Grid
*/
@SuppressWarnings("rawtypes")
public static class RendererClickEvent<R>
extends MouseEvent<RendererClickHandler> {

@SuppressWarnings("unchecked")
static final Type<RendererClickHandler> TYPE = new Type<RendererClickHandler>(
BrowserEvents.CLICK, new RendererClickEvent());

private CellReference<R> cell;

private R row;

private RendererClickEvent() {
}

/**
* Returns the cell of the clicked button.
*
* @return the cell
*/
public CellReference<R> getCell() {
return cell;
}

/**
* Returns the data object corresponding to the row of the clicked
* button.
*
* @return the row data object
*/
public R getRow() {
return row;
}

@Override
public Type<RendererClickHandler> getAssociatedType() {
return TYPE;
}

@Override
@SuppressWarnings("unchecked")
protected void dispatch(RendererClickHandler handler) {

EventTarget target = getNativeEvent().getEventTarget();

if (!Element.is(target)) {
return;
}

Element e = Element.as(target);
Grid<R> grid = (Grid<R>) findClosestParentGrid(e);

cell = findCell(grid, e);
row = cell.getRow();

handler.onClick(this);
}

/**
* Returns the cell the given element belongs to.
*
* @param grid
* the grid instance that is queried
* @param e
* a cell element or the descendant of one
* @return the cell or null if the element is not a grid cell or a
* descendant of one
*/
private static <T> CellReference<T> findCell(Grid<T> grid, Element e) {
RowContainer container = getEscalator(grid).findRowContainer(e);
if (container == null) {
return null;
}
Cell cell = container.getCell(e);
EventCellReference<T> cellReference = new EventCellReference<T>(
grid);
// FIXME: Section is currently always body. Might be useful for the
// future to have an actual check.
cellReference.set(cell, Section.BODY);
return cellReference;
}

private native static Escalator getEscalator(Grid<?> grid)
/*-{
return grid.@com.vaadin.v7.client.widgets.Grid::escalator;
}-*/;

/**
* Returns the Grid instance containing the given element, if any.
* <p>
* <strong>Note:</strong> This method may not work reliably if the grid
* in question is wrapped in a {@link Composite} <em>unless</em> the
* element is inside another widget that is a child of the wrapped grid;
* please refer to the note in
* {@link WidgetUtil#findWidget(Element, Class) Util.findWidget} for
* details.
*
* @param e
* the element whose parent grid to find
* @return the parent grid or null if none found.
*/
private static Grid<?> findClosestParentGrid(Element e) {
Widget w = WidgetUtil.findWidget(e, null);

while (w != null && !(w instanceof Grid)) {
w = w.getParent();
}
return (Grid<?>) w;
}
}

private HandlerManager handlerManager;

/**
* {@inheritDoc}
* <p>
* <em>Implementation note:</em> It is the implementing method's
* responsibility to add {@code this} as a click handler of the returned
* widget, or a widget nested therein, in order to make click events
* propagate properly to handlers registered via
* {@link #addClickHandler(RendererClickHandler) addClickHandler}.
*/
@Override
public abstract W createWidget();

/**
* Adds a click handler to this button renderer. The handler is invoked
* every time one of the widgets rendered by this renderer is clicked.
* <p>
* Note that the row type of the click handler must match the row type of
* the containing Grid.
*
* @param handler
* the click handler to be added
*/
public HandlerRegistration addClickHandler(
RendererClickHandler<?> handler) {
if (handlerManager == null) {
handlerManager = new HandlerManager(this);
}
return handlerManager.addHandler(RendererClickEvent.TYPE, handler);
}

@Override
public void onClick(ClickEvent event) {
/*
* The handler manager is lazily instantiated so it's null iff
* addClickHandler is never called.
*/
if (handlerManager != null) {
DomEvent.fireNativeEvent(event.getNativeEvent(), handlerManager);
}
}
}

+ 157
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ComplexRenderer.java View File

@@ -0,0 +1,157 @@
/*
* 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.client.renderers;

import java.util.Collection;
import java.util.Collections;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.Style.Visibility;
import com.vaadin.v7.client.widget.escalator.Cell;
import com.vaadin.v7.client.widget.escalator.FlyweightCell;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* Base class for renderers that needs initialization and destruction logic
* (override {@link #init(FlyweightCell)} and {@link #destroy(FlyweightCell) }
* and event handling (see {@link #onBrowserEvent(Cell, NativeEvent)},
* {@link #getConsumedEvents()} and {@link #onActivate()}.
*
* <p>
* Also provides a helper method for hiding the cell contents by overriding
* {@link #setContentVisible(FlyweightCell, boolean)}
*
* @since 7.4.0
* @author Vaadin Ltd
*/
public abstract class ComplexRenderer<T> implements Renderer<T> {

/**
* Called at initialization stage. Perform any initialization here e.g.
* attach handlers, attach widgets etc.
*
* @param cell
* The cell. Note that the cell is not to be stored outside of
* the method as the cell instance will change. See
* {@link FlyweightCell}
*/
public abstract void init(RendererCellReference cell);

/**
* Called after the cell is deemed to be destroyed and no longer used by the
* Grid. Called after the cell element is detached from the DOM.
* <p>
* The row object in the cell reference will be <code>null</code> since the
* row might no longer be present in the data source.
*
* @param cell
* The cell. Note that the cell is not to be stored outside of
* the method as the cell instance will change. See
* {@link FlyweightCell}
*/
public void destroy(RendererCellReference cell) {
// Implement if needed
}

/**
* Returns the events that the renderer should consume. These are also the
* events that the Grid will pass to
* {@link #onBrowserEvent(Cell, NativeEvent)} when they occur.
*
* @return a list of consumed events
*
* @see com.google.gwt.dom.client.BrowserEvents
*/
public Collection<String> getConsumedEvents() {
return Collections.emptyList();
}

/**
* Called whenever a registered event is triggered in the column the
* renderer renders.
* <p>
* The events that triggers this needs to be returned by the
* {@link #getConsumedEvents()} method.
* <p>
* Returns boolean telling if the event has been completely handled and
* should not cause any other actions.
*
* @param cell
* Object containing information about the cell the event was
* triggered on.
*
* @param event
* The original DOM event
* @return true if event should not be handled by grid
*/
public boolean onBrowserEvent(CellReference<?> cell, NativeEvent event) {
return false;
}

/**
* Used by Grid to toggle whether to show actual data or just an empty
* placeholder while data is loading. This method is invoked whenever a cell
* changes between data being available and data missing.
* <p>
* Default implementation hides content by setting visibility: hidden to all
* elements inside the cell. Text nodes are left as is - renderers that add
* such to the root element need to implement explicit support hiding them.
*
* @param cell
* The cell
* @param hasData
* Has the cell content been loaded from the data source
*
*/
public void setContentVisible(RendererCellReference cell, boolean hasData) {
Element cellElement = cell.getElement();
for (int n = 0; n < cellElement.getChildCount(); n++) {
Node node = cellElement.getChild(n);
if (Element.is(node)) {
Element e = Element.as(node);
if (hasData) {
e.getStyle().clearVisibility();
} else {
e.getStyle().setVisibility(Visibility.HIDDEN);
}
}
}
}

/**
* Called when the cell is activated by pressing <code>enter</code>, double
* clicking or performing a double tap on the cell.
*
* @param cell
* the activated cell
* @return <code>true</code> if event was handled and should not be
* interpreted as a generic gesture by Grid.
*/
public boolean onActivate(CellReference<?> cell) {
return false;
}

/**
* Called when the renderer is deemed to be destroyed and no longer used by
* the Grid.
*/
public void destroy() {
// Implement if needed
}
}

+ 108
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/DateRenderer.java View File

@@ -0,0 +1,108 @@
/*
* 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.client.renderers;

import java.util.Date;

import com.google.gwt.i18n.client.TimeZone;
import com.google.gwt.i18n.shared.DateTimeFormat;
import com.google.gwt.i18n.shared.DateTimeFormat.PredefinedFormat;
import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* A renderer for rendering dates into cells
*
* @since 7.4
* @author Vaadin Ltd
*/
public class DateRenderer implements Renderer<Date> {

private DateTimeFormat format;

// Calendar is unavailable for GWT
@SuppressWarnings("deprecation")
private TimeZone timeZone = TimeZone
.createTimeZone(new Date().getTimezoneOffset());

public DateRenderer() {
this(PredefinedFormat.DATE_TIME_SHORT);
}

public DateRenderer(PredefinedFormat format) {
this(DateTimeFormat.getFormat(format));
}

public DateRenderer(DateTimeFormat format) {
setFormat(format);
}

@Override
public void render(RendererCellReference cell, Date date) {
String dateStr = format.format(date, timeZone);
cell.getElement().setInnerText(dateStr);
}

/**
* Gets the format of how the date is formatted.
*
* @return the format
* @see <a href=
* "http://www.gwtproject.org/javadoc/latest/com/google/gwt/i18n/shared/DateTimeFormat.html">GWT
* documentation on DateTimeFormat</a>
*/
public DateTimeFormat getFormat() {
return format;
}

/**
* Sets the format used for formatting the dates.
*
* @param format
* the format to set
* @see <a href=
* "http://www.gwtproject.org/javadoc/latest/com/google/gwt/i18n/shared/DateTimeFormat.html">GWT
* documentation on DateTimeFormat</a>
*/
public void setFormat(DateTimeFormat format) {
if (format == null) {
throw new IllegalArgumentException("Format should not be null");
}
this.format = format;
}

/**
* Returns the time zone of the date.
*
* @return the time zone
*/
public TimeZone getTimeZone() {
return timeZone;
}

/**
* Sets the time zone of the the date. By default uses the time zone of the
* browser.
*
* @param timeZone
* the timeZone to set
*/
public void setTimeZone(TimeZone timeZone) {
if (timeZone == null) {
throw new IllegalArgumentException("Timezone should not be null");
}
this.timeZone = timeZone;
}
}

+ 41
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/HtmlRenderer.java View File

@@ -0,0 +1,41 @@
/*
* 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.client.renderers;

import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* Renders a string as HTML into a cell.
* <p>
* The html string is rendered as is without any escaping. It is up to the
* developer to ensure that the html string honors the {@link SafeHtml}
* contract. For more information see
* {@link SafeHtmlUtils#fromSafeConstant(String)}.
*
* @since 7.4
* @author Vaadin Ltd
* @see SafeHtmlUtils#fromSafeConstant(String)
*/
public class HtmlRenderer implements Renderer<String> {

@Override
public void render(RendererCellReference cell, String htmlString) {
cell.getElement()
.setInnerSafeHtml(SafeHtmlUtils.fromSafeConstant(htmlString));
}
}

+ 49
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ImageRenderer.java View File

@@ -0,0 +1,49 @@
/*
* 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.client.renderers;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Image;
import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* A renderer that renders an image into a cell. Click handlers can be added to
* the renderer, invoked every time any of the images rendered by that rendered
* is clicked.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class ImageRenderer extends ClickableRenderer<String, Image> {

public static final String TRANSPARENT_GIF_1PX = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=";

@Override
public Image createWidget() {
Image image = GWT.create(Image.class);
image.addClickHandler(this);
return image;
}

@Override
public void render(RendererCellReference cell, String url, Image image) {
if (url == null) {
image.setUrl(TRANSPARENT_GIF_1PX);
} else {
image.setUrl(url);
}
}
}

+ 71
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/NumberRenderer.java View File

@@ -0,0 +1,71 @@
/*
* 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.client.renderers;

import com.google.gwt.i18n.client.NumberFormat;
import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* Renders a number into a cell using a specific {@link NumberFormat}. By
* default uses the default number format returned by
* {@link NumberFormat#getDecimalFormat()}.
*
* @since 7.4
* @author Vaadin Ltd
* @param <T>
* The number type to render.
*/
public class NumberRenderer implements Renderer<Number> {

private NumberFormat format;

public NumberRenderer() {
this(NumberFormat.getDecimalFormat());
}

public NumberRenderer(NumberFormat format) {
setFormat(format);
}

/**
* Gets the number format that the number should be formatted in.
*
* @return the number format used to render the number
*/
public NumberFormat getFormat() {
return format;
}

/**
* Sets the number format to use for formatting the number.
*
* @param format
* the format to use
* @throws IllegalArgumentException
* when the format is null
*/
public void setFormat(NumberFormat format) throws IllegalArgumentException {
if (format == null) {
throw new IllegalArgumentException("Format cannot be null");
}
this.format = format;
}

@Override
public void render(RendererCellReference cell, Number number) {
cell.getElement().setInnerText(format.format(number));
}
}

+ 47
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/ProgressBarRenderer.java View File

@@ -0,0 +1,47 @@
/*
* 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.client.renderers;

import com.google.gwt.core.shared.GWT;
import com.vaadin.client.ui.VProgressBar;
import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* A Renderer that represents a double value as a graphical progress bar.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class ProgressBarRenderer extends WidgetRenderer<Double, VProgressBar> {

@Override
public VProgressBar createWidget() {
VProgressBar progressBar = GWT.create(VProgressBar.class);
progressBar.addStyleDependentName("static");
return progressBar;
}

@Override
public void render(RendererCellReference cell, Double data,
VProgressBar progressBar) {
if (data == null) {
progressBar.setEnabled(false);
} else {
progressBar.setEnabled(true);
progressBar.setState(data.floatValue());
}
}
}

+ 54
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/Renderer.java View File

@@ -0,0 +1,54 @@
/*
* 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.client.renderers;

import com.vaadin.v7.client.widget.escalator.Cell;
import com.vaadin.v7.client.widget.grid.RendererCellReference;
import com.vaadin.v7.client.widgets.Grid;

/**
* Renderer for rending a value &lt;T&gt; into cell.
* <p>
* You can add a renderer to any column by overring the
* {@link GridColumn#getRenderer()} method and returning your own renderer. You
* can retrieve the cell element using {@link Cell#getElement()}.
*
* @param <T>
* The column type
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface Renderer<T> {

/**
* Called whenever the {@link Grid} updates a cell.
* <p>
* For optimal performance, work done in this method should be kept to a
* minimum since it will be called continuously while the user is scrolling.
* It is recommended to set up the cell's DOM structure in
* {@link ComplexRenderer#init(RendererCellReference)} and only make
* incremental updates based on cell data in this method.
*
* @param cell
* The cell. Note that the cell is a flyweight and should not be
* stored outside of the method as it will change.
*
* @param data
* The column data object
*/
void render(RendererCellReference cell, T data);
}

+ 32
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/TextRenderer.java View File

@@ -0,0 +1,32 @@
/*
* 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.client.renderers;

import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* Renderer that renders text into a cell.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class TextRenderer implements Renderer<String> {

@Override
public void render(RendererCellReference cell, String text) {
cell.getElement().setInnerText(text);
}
}

+ 112
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/renderers/WidgetRenderer.java View File

@@ -0,0 +1,112 @@
/*
* 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.client.renderers;

import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.WidgetUtil;
import com.vaadin.v7.client.widget.grid.RendererCellReference;

/**
* A renderer for rendering widgets into cells.
*
* @since 7.4
* @author Vaadin Ltd
* @param <T>
* the row data type
* @param <W>
* the Widget type
*/
public abstract class WidgetRenderer<T, W extends Widget>
extends ComplexRenderer<T> {

@Override
public void init(RendererCellReference cell) {
// Implement if needed
}

/**
* Creates a widget to attach to a cell. The widgets will be attached to the
* cell after the cell element has been attached to DOM.
*
* @return widget to attach to a cell. All returned instances should be new
* widget instances without a parent.
*/
public abstract W createWidget();

@Override
public void render(RendererCellReference cell, T data) {
W w = getWidget(cell.getElement());
assert w != null : "Widget not found in cell (" + cell.getColumn() + ","
+ cell.getRow() + ")";
render(cell, data, w);
}

/**
* Renders a cell with a widget. This provides a way to update any
* information in the widget that is cell specific. Do not detach the Widget
* here, it will be done automatically by the Grid when the widget is no
* longer needed.
* <p>
* For optimal performance, work done in this method should be kept to a
* minimum since it will be called continuously while the user is scrolling.
* The renderer can use {@link Widget#setLayoutData(Object)} to store cell
* data that might be needed in e.g. event listeners.
*
* @param cell
* The cell to render. Note that the cell is a flyweight and
* should not be stored and used outside of this method as its
* contents will change.
* @param data
* the data of the cell
* @param widget
* the widget embedded in the cell
*/
public abstract void render(RendererCellReference cell, T data, W widget);

/**
* Returns the widget contained inside the given cell element. Cannot be
* called for cells that do not contain a widget.
*
* @param e
* the element inside which to find a widget
* @return the widget inside the element
*/
protected W getWidget(TableCellElement e) {
W w = getWidget(e, null);
assert w != null : "Widget not found inside cell";
return w;
}

/**
* Returns the widget contained inside the given cell element, or null if it
* is not an instance of the given class. Cannot be called for cells that do
* not contain a widget.
*
* @param e
* the element inside to find a widget
* @param klass
* the type of the widget to find
* @return the widget inside the element, or null if its type does not match
*/
protected static <W extends Widget> W getWidget(TableCellElement e,
Class<W> klass) {
W w = WidgetUtil.findWidget(e.getFirstChildElement(), klass);
assert w == null || w.getElement() == e
.getFirstChildElement() : "Widget not found inside cell";
return w;
}
}

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

@@ -19,7 +19,7 @@ import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.widgets.Escalator;
import com.vaadin.v7.client.widgets.Escalator;

/**
* A mousewheel handling class to get around the limits of

+ 85
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/Cell.java View File

@@ -0,0 +1,85 @@
/*
* 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.client.widget.escalator;

import com.google.gwt.dom.client.TableCellElement;

/**
* Describes a cell
* <p>
* It's a representation of the element in a grid cell, and its row and column
* indices.
* <p>
* Unlike the {@link FlyweightRow}, an instance of {@link Cell} can be stored in
* a field.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class Cell {

private final int row;

private final int column;

private final TableCellElement element;

/**
* Constructs a new {@link Cell}.
*
* @param row
* The index of the row
* @param column
* The index of the column
* @param element
* The cell element
*/
public Cell(int row, int column, TableCellElement element) {
super();
this.row = row;
this.column = column;
this.element = element;
}

/**
* Returns the index of the row the cell resides in.
*
* @return the row index
*
*/
public int getRow() {
return row;
}

/**
* Returns the index of the column the cell resides in.
*
* @return the column index
*/
public int getColumn() {
return column;
}

/**
* Returns the element of the cell.
*
* @return the cell element
*/
public TableCellElement getElement() {
return element;
}

}

+ 198
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/ColumnConfiguration.java View File

@@ -0,0 +1,198 @@
/*
* 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.client.widget.escalator;

import java.util.Map;

import com.vaadin.v7.client.widgets.Escalator;

/**
* A representation of the columns in an instance of {@link Escalator}.
*
* @since 7.4
* @author Vaadin Ltd
* @see Escalator#getColumnConfiguration()
*/
public interface ColumnConfiguration {

/**
* Removes columns at certain indices.
* <p>
* If any of the removed columns were frozen, the number of frozen columns
* will be reduced by the number of the removed columns that were frozen.
* <p>
* <em>Note:</em> This method simply removes the given columns, and does not
* do much of anything else. Especially if you have column spans, you
* probably need to run {@link #refreshColumns(int, int)} or
* {@link RowContainer#refreshRows(int, int)}
*
* @param index
* the index of the first column to be removed
* @param numberOfColumns
* the number of rows to remove, starting from {@code index}
* @throws IndexOutOfBoundsException
* if the entire range of removed columns is not currently
* present in the escalator
* @throws IllegalArgumentException
* if <code>numberOfColumns</code> is less than 1.
*/
public void removeColumns(int index, int numberOfColumns)
throws IndexOutOfBoundsException, IllegalArgumentException;

/**
* Adds columns at a certain index.
* <p>
* The new columns will be inserted between the column at the index, and the
* column before (an index of 0 means that the columns are inserted at the
* beginning). Therefore, the columns at the index and afterwards will be
* moved to the right.
* <p>
* The contents of the inserted columns will be queried from the respective
* cell renderers in the header, body and footer.
* <p>
* If there are frozen columns and the first added column is to the left of
* the last frozen column, the number of frozen columns will be increased by
* the number of inserted columns.
* <p>
* <em>Note:</em> Only the contents of the inserted columns will be
* rendered. If inserting new columns affects the contents of existing
* columns (e.g. you have column spans),
* {@link RowContainer#refreshRows(int, int)} or
* {@link #refreshColumns(int, int)} needs to be called as appropriate.
*
* @param index
* the index of the column before which new columns are inserted,
* or {@link #getColumnCount()} to add new columns at the end
* @param numberOfColumns
* the number of columns to insert after the <code>index</code>
* @throws IndexOutOfBoundsException
* if <code>index</code> is not an integer in the range
* <code>[0..{@link #getColumnCount()}]</code>
* @throws IllegalArgumentException
* if {@code numberOfColumns} is less than 1.
*/
public void insertColumns(int index, int numberOfColumns)
throws IndexOutOfBoundsException, IllegalArgumentException;

/**
* Returns the number of columns in the escalator.
*
* @return the number of columns in the escalator
*/
public int getColumnCount();

/**
* Sets the number of leftmost columns that are not affected by horizontal
* scrolling.
*
* @param count
* the number of columns to freeze
*
* @throws IllegalArgumentException
* if the column count is &lt; 0 or &gt; the number of columns
*
*/
public void setFrozenColumnCount(int count) throws IllegalArgumentException;

/**
* Get the number of leftmost columns that are not affected by horizontal
* scrolling.
*
* @return the number of frozen columns
*/
public int getFrozenColumnCount();

/**
* Sets (or unsets) an explicit width for a column.
*
* @param index
* the index of the column for which to set a width
* @param px
* the number of pixels the indicated column should be, or a
* negative number to let the escalator decide
* @throws IllegalArgumentException
* if <code>index</code> is not a valid column index
*/
public void setColumnWidth(int index, double px)
throws IllegalArgumentException;

/**
* Returns the user-defined width of a column.
*
* @param index
* the index of the column for which to retrieve the width
* @return the column's width in pixels, or a negative number if the width
* is implicitly decided by the escalator
* @throws IllegalArgumentException
* if <code>index</code> is not a valid column index
*/
public double getColumnWidth(int index) throws IllegalArgumentException;

/**
* Sets widths for a set of columns.
*
* @param indexWidthMap
* a map from column index to its respective width to be set. If
* the given width for a column index is negative, the column is
* resized-to-fit.
* @throws IllegalArgumentException
* if {@code indexWidthMap} is {@code null}
* @throws IllegalArgumentException
* if any column index in {@code indexWidthMap} is invalid
* @throws NullPointerException
* If any value in the map is <code>null</code>
*/
public void setColumnWidths(Map<Integer, Double> indexWidthMap)
throws IllegalArgumentException;

/**
* Returns the actual width of a column.
*
* @param index
* the index of the column for which to retrieve the width
* @return the column's actual width in pixels
* @throws IllegalArgumentException
* if <code>index</code> is not a valid column index
*/
public double getColumnWidthActual(int index)
throws IllegalArgumentException;

/**
* Refreshes a range of rows in the current row containers in each Escalator
* section.
* <p>
* The data for the refreshed columns is queried from the current cell
* renderer.
*
* @param index
* the index of the first row that will be updated
* @param numberOfRows
* the number of rows to update, starting from the index
* @throws IndexOutOfBoundsException
* if any integer number in the range
* <code>[index..(index+numberOfColumns)]</code> is not an
* existing column index.
* @throws IllegalArgumentException
* if {@code numberOfColumns} is less than 1.
* @see RowContainer#setEscalatorUpdater(EscalatorUpdater)
* @see Escalator#getHeader()
* @see Escalator#getBody()
* @see Escalator#getFooter()
*/
public void refreshColumns(int index, int numberOfColumns)
throws IndexOutOfBoundsException, IllegalArgumentException;
}

+ 157
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/EscalatorUpdater.java View File

@@ -0,0 +1,157 @@
/*
* 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.client.widget.escalator;

import com.vaadin.v7.client.widgets.Escalator;

/**
* An interface that allows client code to define how a certain row in Escalator
* will be displayed. The contents of an escalator's header, body and footer are
* rendered by their respective updaters.
* <p>
* The updater is responsible for internally handling all remote communication,
* should the displayed data need to be fetched remotely.
* <p>
* This has a similar function to {@link Grid Grid's} {@link Renderer Renderers}
* , although they operate on different abstraction levels.
*
* @since 7.4
* @author Vaadin Ltd
* @see RowContainer#setEscalatorUpdater(EscalatorUpdater)
* @see Escalator#getHeader()
* @see Escalator#getBody()
* @see Escalator#getFooter()
* @see Renderer
*/
public interface EscalatorUpdater {

/**
* An {@link EscalatorUpdater} that doesn't render anything.
*/
public static final EscalatorUpdater NULL = new EscalatorUpdater() {
@Override
public void update(final Row row,
final Iterable<FlyweightCell> cellsToUpdate) {
// NOOP
}

@Override
public void preAttach(final Row row,
final Iterable<FlyweightCell> cellsToAttach) {
// NOOP

}

@Override
public void postAttach(final Row row,
final Iterable<FlyweightCell> attachedCells) {
// NOOP
}

@Override
public void preDetach(final Row row,
final Iterable<FlyweightCell> cellsToDetach) {
// NOOP
}

@Override
public void postDetach(final Row row,
final Iterable<FlyweightCell> detachedCells) {
// NOOP
}
};

/**
* Renders a row contained in a row container.
* <p>
* <em>Note:</em> If rendering of cells is deferred (e.g. because
* asynchronous data retrieval), this method is responsible for explicitly
* displaying some placeholder data (empty content is valid). Because the
* cells (and rows) in an escalator are recycled, failing to reset a cell's
* presentation will lead to wrong data being displayed in the escalator.
* <p>
* For performance reasons, the escalator will never autonomously clear any
* data in a cell.
*
* @param row
* Information about the row that is being updated.
* <em>Note:</em> You should not store nor reuse this reference.
* @param cellsToUpdate
* A collection of cells that need to be updated. <em>Note:</em>
* You should neither store nor reuse the reference to the
* iterable, nor to the individual cells.
*/
public void update(Row row, Iterable<FlyweightCell> cellsToUpdate);

/**
* Called before attaching new cells to the escalator.
*
* @param row
* Information about the row to which the cells will be added.
* <em>Note:</em> You should not store nor reuse this reference.
* @param cellsToAttach
* A collection of cells that are about to be attached.
* <em>Note:</em> You should neither store nor reuse the
* reference to the iterable, nor to the individual cells.
*
*/
public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach);

/**
* Called after attaching new cells to the escalator.
*
* @param row
* Information about the row to which the cells were added.
* <em>Note:</em> You should not store nor reuse this reference.
* @param attachedCells
* A collection of cells that were attached. <em>Note:</em> You
* should neither store nor reuse the reference to the iterable,
* nor to the individual cells.
*
*/
public void postAttach(Row row, Iterable<FlyweightCell> attachedCells);

/**
* Called before detaching cells from the escalator.
*
* @param row
* Information about the row from which the cells will be
* removed. <em>Note:</em> You should not store nor reuse this
* reference.
* @param cellsToAttach
* A collection of cells that are about to be detached.
* <em>Note:</em> You should neither store nor reuse the
* reference to the iterable, nor to the individual cells.
*
*/
public void preDetach(Row row, Iterable<FlyweightCell> cellsToDetach);

/**
* Called after detaching cells from the escalator.
*
* @param row
* Information about the row from which the cells were removed.
* <em>Note:</em> You should not store nor reuse this reference.
* @param attachedCells
* A collection of cells that were detached. <em>Note:</em> You
* should neither store nor reuse the reference to the iterable,
* nor to the individual cells.
*
*/
public void postDetach(Row row, Iterable<FlyweightCell> detachedCells);

}

+ 201
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/FlyweightCell.java View File

@@ -0,0 +1,201 @@
/*
* 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.client.widget.escalator;

import java.util.List;

import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.TableCellElement;
import com.vaadin.v7.client.widget.escalator.FlyweightRow.CellIterator;
import com.vaadin.v7.client.widgets.Escalator;

/**
* A {@link FlyweightCell} represents a cell in the {@link Grid} or
* {@link Escalator} at a certain point in time.
*
* <p>
* Since the {@link FlyweightCell} follows the <code>Flyweight</code>-pattern
* any instance of this object is subject to change without the user knowing it
* and so should not be stored anywhere outside of the method providing these
* instances.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class FlyweightCell {
public static final String COLSPAN_ATTR = "colSpan";

private final int column;
private final FlyweightRow row;

private TableCellElement element = null;
private CellIterator currentIterator = null;

public FlyweightCell(final FlyweightRow row, final int column) {
this.row = row;
this.column = column;
}

/**
* Returns the row index of the cell
*/
public int getRow() {
assertSetup();
return row.getRow();
}

/**
* Returns the column index of the cell
*/
public int getColumn() {
assertSetup();
return column;
}

/**
* Returns the element of the cell. Can be either a <code>TD</code> element
* or a <code>TH</code> element.
*/
public TableCellElement getElement() {
assertSetup();
return element;
}

/**
* Return the colspan attribute of the element of the cell.
*/
public int getColSpan() {
assertSetup();
return element.getPropertyInt(COLSPAN_ATTR);
}

/**
* Sets the DOM element for this FlyweightCell, either a <code>TD</code> or
* a <code>TH</code>. It is the caller's responsibility to actually insert
* the given element to the document when needed.
*
* @param element
* the element corresponding to this cell, cannot be null
*/
public void setElement(TableCellElement element) {
assert element != null;
assertSetup();
this.element = element;
}

void setup(final CellIterator iterator) {
currentIterator = iterator;

if (iterator.areCellsAttached()) {
final TableCellElement e = row.getElement().getCells()
.getItem(column);

assert e != null : "Cell " + column + " for logical row "
+ row.getRow() + " doesn't exist in the DOM!";

e.setPropertyInt(COLSPAN_ATTR, 1);
if (row.getColumnWidth(column) >= 0) {
e.getStyle().setWidth(row.getColumnWidth(column), Unit.PX);
}
e.getStyle().clearDisplay();
setElement(e);
}
}

/**
* Tear down the state of the Cell.
* <p>
* This is an internal check method, to prevent retrieving uninitialized
* data by calling {@link #getRow()}, {@link #getColumn()} or
* {@link #getElement()} at an improper time.
* <p>
* This should only be used with asserts ("
* <code>assert flyweightCell.teardown()</code> ") so that the code is never
* run when asserts aren't enabled.
*
* @return always <code>true</code>
* @see FlyweightRow#teardown()
*/
boolean teardown() {
currentIterator = null;
element = null;
return true;
}

/**
* Asserts that the flyweight cell has properly been set up before trying to
* access any of its data.
*/
private void assertSetup() {
assert currentIterator != null : "FlyweightCell was not properly "
+ "initialized. This is either a bug in Grid/Escalator "
+ "or a Cell reference has been stored and reused "
+ "inappropriately.";
}

public void setColSpan(final int numberOfCells) {
if (numberOfCells < 1) {
throw new IllegalArgumentException(
"Number of cells should be more than 0");
}

/*-
* This will default to 1 if unset, as per DOM specifications:
* http://www.w3.org/TR/html5/tabular-data.html#attributes-common-to-td-and-th-elements
*/
final int prevColSpan = getElement().getPropertyInt(COLSPAN_ATTR);
if (numberOfCells == 1 && prevColSpan == 1) {
return;
}

getElement().setPropertyInt(COLSPAN_ATTR, numberOfCells);
adjustCellWidthForSpan(numberOfCells);
hideOrRevealAdjacentCellElements(numberOfCells, prevColSpan);
currentIterator.setSkipNext(numberOfCells - 1);
}

private void adjustCellWidthForSpan(final int numberOfCells) {
final int cellsToTheRight = currentIterator
.rawPeekNext(numberOfCells - 1).size();

final double selfWidth = row.getColumnWidth(column);
double widthsOfColumnsToTheRight = 0;
for (int i = 0; i < cellsToTheRight; i++) {
widthsOfColumnsToTheRight += row.getColumnWidth(column + i + 1);
}
getElement().getStyle().setWidth(selfWidth + widthsOfColumnsToTheRight,
Unit.PX);
}

private void hideOrRevealAdjacentCellElements(final int numberOfCells,
final int prevColSpan) {
final int affectedCellsNumber = Math.max(prevColSpan, numberOfCells);
final List<FlyweightCell> affectedCells = currentIterator
.rawPeekNext(affectedCellsNumber - 1);
if (prevColSpan < numberOfCells) {
for (int i = 0; i < affectedCells.size(); i++) {
affectedCells.get(prevColSpan + i - 1).getElement().getStyle()
.setDisplay(Display.NONE);
}
} else if (prevColSpan > numberOfCells) {
for (int i = 0; i < affectedCells.size(); i++) {
affectedCells.get(numberOfCells + i - 1).getElement().getStyle()
.clearDisplay();
}
}
}
}

+ 298
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/FlyweightRow.java View File

@@ -0,0 +1,298 @@
/*
* 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.client.widget.escalator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.dom.client.TableRowElement;
import com.vaadin.v7.client.widgets.Escalator;

/**
* An internal implementation of the {@link Row} interface.
* <p>
* There is only one instance per Escalator. This is designed to be re-used when
* rendering rows.
*
* @since 7.4
* @author Vaadin Ltd
* @see Escalator.AbstractRowContainer#refreshRow(Node, int)
*/
public class FlyweightRow implements Row {

static class CellIterator implements Iterator<FlyweightCell> {
/** A defensive copy of the cells in the current row. */
private final ArrayList<FlyweightCell> cells;
private final boolean cellsAttached;
private int cursor = 0;
private int skipNext = 0;

/**
* Creates a new iterator of attached flyweight cells. A cell is
* attached if it has a corresponding {@link FlyweightCell#getElement()
* DOM element} attached to the row element.
*
* @param cells
* the collection of cells to iterate
*/
public static CellIterator attached(
final Collection<FlyweightCell> cells) {
return new CellIterator(cells, true);
}

/**
* Creates a new iterator of unattached flyweight cells. A cell is
* unattached if it does not have a corresponding
* {@link FlyweightCell#getElement() DOM element} attached to the row
* element.
*
* @param cells
* the collection of cells to iterate
*/
public static CellIterator unattached(
final Collection<FlyweightCell> cells) {
return new CellIterator(cells, false);
}

private CellIterator(final Collection<FlyweightCell> cells,
final boolean attached) {
this.cells = new ArrayList<FlyweightCell>(cells);
cellsAttached = attached;
}

@Override
public boolean hasNext() {
return cursor + skipNext < cells.size();
}

@Override
public FlyweightCell next() {
// if we needed to skip some cells since the last invocation.
for (int i = 0; i < skipNext; i++) {
cells.remove(cursor);
}
skipNext = 0;

final FlyweightCell cell = cells.get(cursor++);
cell.setup(this);
return cell;
}

@Override
public void remove() {
throw new UnsupportedOperationException(
"Cannot remove cells via iterator");
}

/**
* Sets the number of cells to skip when {@link #next()} is called the
* next time. Cell hiding is also handled eagerly in this method.
*
* @param colspan
* the number of cells to skip on next invocation of
* {@link #next()}
*/
public void setSkipNext(final int colspan) {
assert colspan > 0 : "Number of cells didn't make sense: "
+ colspan;
skipNext = colspan;
}

/**
* Gets the next <code>n</code> cells in the iterator, ignoring any
* possibly spanned cells.
*
* @param n
* the number of next cells to retrieve
* @return A list of next <code>n</code> cells, or less if there aren't
* enough cells to retrieve
*/
public List<FlyweightCell> rawPeekNext(final int n) {
final int from = Math.min(cursor, cells.size());
final int to = Math.min(cursor + n, cells.size());
List<FlyweightCell> nextCells = cells.subList(from, to);
for (FlyweightCell cell : nextCells) {
cell.setup(this);
}
return nextCells;
}

public boolean areCellsAttached() {
return cellsAttached;
}
}

private static final int BLANK = Integer.MIN_VALUE;

private int row;
private TableRowElement element;
private double[] columnWidths = null;
private final List<FlyweightCell> cells = new ArrayList<FlyweightCell>();

public void setup(final TableRowElement e, final int row,
double[] columnWidths) {
element = e;
this.row = row;
this.columnWidths = columnWidths;
}

/**
* Tear down the state of the Row.
* <p>
* This is an internal check method, to prevent retrieving uninitialized
* data by calling {@link #getRow()}, {@link #getElement()} or
* {@link #getCells()} at an improper time.
* <p>
* This should only be used with asserts ("
* <code>assert flyweightRow.teardown()</code> ") so that the code is never
* run when asserts aren't enabled.
*
* @return always <code>true</code>
*/
public boolean teardown() {
element = null;
row = BLANK;
columnWidths = null;
for (final FlyweightCell cell : cells) {
assert cell.teardown();
}
return true;
}

@Override
public int getRow() {
assertSetup();
return row;
}

@Override
public TableRowElement getElement() {
assertSetup();
return element;
}

public void addCells(final int index, final int numberOfColumns) {
for (int i = 0; i < numberOfColumns; i++) {
final int col = index + i;
cells.add(col, new FlyweightCell(this, col));
}
updateRestOfCells(index + numberOfColumns);
}

public void removeCells(final int index, final int numberOfColumns) {
cells.subList(index, index + numberOfColumns).clear();
updateRestOfCells(index);
}

private void updateRestOfCells(final int startPos) {
// update the column number for the cells to the right
for (int col = startPos; col < cells.size(); col++) {
cells.set(col, new FlyweightCell(this, col));
}
}

/**
* Returns flyweight cells for the client code to render. The cells get
* their associated {@link FlyweightCell#getElement() elements} from the row
* element.
* <p>
* Precondition: each cell has a corresponding element in the row
*
* @return an iterable of flyweight cells
*
* @see #setup(Element, int, int[])
* @see #teardown()
*/
public Iterable<FlyweightCell> getCells() {
return getCells(0, cells.size());
}

/**
* Returns a subrange of flyweight cells for the client code to render. The
* cells get their associated {@link FlyweightCell#getElement() elements}
* from the row element.
* <p>
* Precondition: each cell has a corresponding element in the row
*
* @param offset
* the index of the first cell to return
* @param numberOfCells
* the number of cells to return
* @return an iterable of flyweight cells
*/
public Iterable<FlyweightCell> getCells(final int offset,
final int numberOfCells) {
assertSetup();
assert offset >= 0 && offset + numberOfCells <= cells
.size() : "Invalid range of cells";
return new Iterable<FlyweightCell>() {
@Override
public Iterator<FlyweightCell> iterator() {
return CellIterator.attached(
cells.subList(offset, offset + numberOfCells));
}
};
}

/**
* Returns a subrange of unattached flyweight cells. Unattached cells do not
* have {@link FlyweightCell#getElement() elements} associated. Note that
* FlyweightRow does not keep track of whether cells in actuality have
* corresponding DOM elements or not; it is the caller's responsibility to
* invoke this method with correct parameters.
* <p>
* Precondition: the range [offset, offset + numberOfCells) must be valid
*
* @param offset
* the index of the first cell to return
* @param numberOfCells
* the number of cells to return
* @return an iterable of flyweight cells
*/
public Iterable<FlyweightCell> getUnattachedCells(final int offset,
final int numberOfCells) {
assertSetup();
assert offset >= 0 && offset + numberOfCells <= cells
.size() : "Invalid range of cells";
return new Iterable<FlyweightCell>() {
@Override
public Iterator<FlyweightCell> iterator() {
return CellIterator.unattached(
cells.subList(offset, offset + numberOfCells));
}
};
}

/**
* Asserts that the flyweight row has properly been set up before trying to
* access any of its data.
*/
private void assertSetup() {
assert element != null && row != BLANK
&& columnWidths != null : "Flyweight row was not "
+ "properly initialized. Make sure the setup-method is "
+ "called before retrieving data. This is either a bug "
+ "in Escalator, or the instance of the flyweight row "
+ "has been stored and accessed.";
}

double getColumnWidth(int column) {
assertSetup();
return columnWidths[column];
}
}

+ 118
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/PositionFunction.java View File

@@ -0,0 +1,118 @@
/*
* 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.client.widget.escalator;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;

/**
* A functional interface that can be used for positioning elements in the DOM.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface PositionFunction {
/**
* A position function using "transform: translate3d(x,y,z)" to position
* elements in the DOM.
*/
public static class Translate3DPosition implements PositionFunction {
@Override
public void set(Element e, double x, double y) {
e.getStyle().setProperty("transform",
"translate3d(" + x + "px, " + y + "px, 0)");
}

@Override
public void reset(Element e) {
e.getStyle().clearProperty("transform");
}
}

/**
* A position function using "transform: translate(x,y)" to position
* elements in the DOM.
*/
public static class TranslatePosition implements PositionFunction {
@Override
public void set(Element e, double x, double y) {
e.getStyle().setProperty("transform",
"translate(" + x + "px," + y + "px)");
}

@Override
public void reset(Element e) {
e.getStyle().clearProperty("transform");
}
}

/**
* A position function using "-webkit-transform: translate3d(x,y,z)" to
* position elements in the DOM.
*/
public static class WebkitTranslate3DPosition implements PositionFunction {
@Override
public void set(Element e, double x, double y) {
e.getStyle().setProperty("webkitTransform",
"translate3d(" + x + "px," + y + "px,0)");
}

@Override
public void reset(Element e) {
e.getStyle().clearProperty("webkitTransform");
}
}

/**
* A position function using "left: x" and "top: y" to position elements in
* the DOM.
*/
public static class AbsolutePosition implements PositionFunction {
@Override
public void set(Element e, double x, double y) {
e.getStyle().setLeft(x, Unit.PX);
e.getStyle().setTop(y, Unit.PX);
}

@Override
public void reset(Element e) {
e.getStyle().clearLeft();
e.getStyle().clearTop();
}
}

/**
* Position an element in an (x,y) coordinate system in the DOM.
*
* @param e
* the element to position. Never <code>null</code>.
* @param x
* the x coordinate, in pixels
* @param y
* the y coordinate, in pixels
*/
void set(Element e, double x, double y);

/**
* Resets any previously applied positioning, clearing the used style
* attributes.
*
* @param e
* the element for which to reset the positioning
*/
void reset(Element e);
}

+ 49
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/Row.java View File

@@ -0,0 +1,49 @@
/*
* 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.client.widget.escalator;

import com.google.gwt.dom.client.TableRowElement;
import com.vaadin.v7.client.widgets.Escalator;

/**
* A representation of a row in an {@link Escalator}.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface Row {
/**
* Gets the row index.
*
* @return the row index
*/
public int getRow();

/**
* Gets the root element for this row.
* <p>
* The {@link EscalatorUpdater} may update the class names of the element
* and add inline styles, but may not modify the contained DOM structure.
* <p>
* If you wish to modify the cells within this row element, access them via
* the <code>List&lt;{@link Cell}&gt;</code> objects passed in to
* {@code EscalatorUpdater.updateCells(Row, List)}
*
* @return the root element of the row
*/
public TableRowElement getElement();
}

+ 282
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/RowContainer.java View File

@@ -0,0 +1,282 @@
/*
* 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.client.widget.escalator;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;
import com.vaadin.v7.client.widgets.Escalator;

/**
* A representation of the rows in each of the sections (header, body and
* footer) in an {@link com.vaadin.v7.client.widgets.Escalator}.
*
* @since 7.4
* @author Vaadin Ltd
* @see com.vaadin.v7.client.widgets.Escalator#getHeader()
* @see com.vaadin.v7.client.widgets.Escalator#getBody()
* @see com.vaadin.v7.client.widgets.Escalator#getFooter()
* @see SpacerContainer
*/
public interface RowContainer {

/**
* The row container for the body section in an
* {@link com.vaadin.v7.client.widgets.Escalator}.
* <p>
* The body section can contain both rows and spacers.
*
* @since 7.5.0
* @author Vaadin Ltd
* @see com.vaadin.v7.client.widgets.Escalator#getBody()
*/
public interface BodyRowContainer extends RowContainer {

/**
* Marks a spacer and its height.
* <p>
* If a spacer is already registered with the given row index, that
* spacer will be updated with the given height.
* <p>
* <em>Note:</em> The row index for a spacer will change if rows are
* inserted or removed above the current position. Spacers will also be
* removed alongside their associated rows
*
* @param rowIndex
* the row index for the spacer to modify. The affected
* spacer is underneath the given index. Use -1 to insert a
* spacer before the first row
* @param height
* the pixel height of the spacer. If {@code height} is
* negative, the affected spacer (if exists) will be removed
* @throws IllegalArgumentException
* if {@code rowIndex} is not a valid row index
* @see #insertRows(int, int)
* @see #removeRows(int, int)
*/
void setSpacer(int rowIndex, double height)
throws IllegalArgumentException;

/**
* Sets a new spacer updater.
* <p>
* Spacers that are currently visible will be updated, i.e.
* {@link SpacerUpdater#destroy(Spacer) destroyed} with the previous
* one, and {@link SpacerUpdater#init(Spacer) initialized} with the new
* one.
*
* @param spacerUpdater
* the new spacer updater
* @throws IllegalArgumentException
* if {@code spacerUpdater} is {@code null}
*/
void setSpacerUpdater(SpacerUpdater spacerUpdater)
throws IllegalArgumentException;

/**
* Gets the spacer updater currently in use.
* <p>
* {@link SpacerUpdater#NULL} is the default.
*
* @return the spacer updater currently in use. Never <code>null</code>
*/
SpacerUpdater getSpacerUpdater();

/**
* {@inheritDoc}
* <p>
* Any spacers underneath {@code index} will be offset and "pushed"
* down. This also modifies the row index they are associated with.
*/
@Override
public void insertRows(int index, int numberOfRows)
throws IndexOutOfBoundsException, IllegalArgumentException;

/**
* {@inheritDoc}
* <p>
* Any spacers underneath {@code index} will be offset and "pulled" up.
* This also modifies the row index they are associated with. Any
* spacers in the removed range will also be closed and removed.
*/
@Override
public void removeRows(int index, int numberOfRows)
throws IndexOutOfBoundsException, IllegalArgumentException;
}

/**
* An arbitrary pixel height of a row, before any autodetection for the row
* height has been made.
*/
public static final double INITIAL_DEFAULT_ROW_HEIGHT = 20;

/**
* Returns the current {@link EscalatorUpdater} used to render cells.
*
* @return the current escalator updater
*/
public EscalatorUpdater getEscalatorUpdater();

/**
* Sets the {@link EscalatorUpdater} to use when displaying data in the
* escalator.
*
* @param escalatorUpdater
* the escalator updater to use to render cells. May not be
* <code>null</code>
* @throws IllegalArgumentException
* if {@code cellRenderer} is <code>null</code>
* @see EscalatorUpdater#NULL
*/
public void setEscalatorUpdater(EscalatorUpdater escalatorUpdater)
throws IllegalArgumentException;

/**
* Removes rows at a certain index in the current row container.
*
* @param index
* the index of the first row to be removed
* @param numberOfRows
* the number of rows to remove, starting from the index
* @throws IndexOutOfBoundsException
* if any integer number in the range
* <code>[index..(index+numberOfRows)]</code> is not an existing
* row index
* @throws IllegalArgumentException
* if {@code numberOfRows} is less than 1.
*/
public void removeRows(int index, int numberOfRows)
throws IndexOutOfBoundsException, IllegalArgumentException;

/**
* Adds rows at a certain index in this row container.
* <p>
* The new rows will be inserted between the row at the index, and the row
* before (an index of 0 means that the rows are inserted at the beginning).
* Therefore, the rows currently at the index and afterwards will be moved
* downwards.
* <p>
* The contents of the inserted rows will subsequently be queried from the
* escalator updater.
* <p>
* <em>Note:</em> Only the contents of the inserted rows will be rendered.
* If inserting new rows affects the contents of existing rows,
* {@link #refreshRows(int, int)} needs to be called for those rows
* separately.
*
* @param index
* the index of the row before which new rows are inserted, or
* {@link #getRowCount()} to add rows at the end
* @param numberOfRows
* the number of rows to insert after the <code>index</code>
* @see #setEscalatorUpdater(EscalatorUpdater)
* @throws IndexOutOfBoundsException
* if <code>index</code> is not an integer in the range
* <code>[0..{@link #getRowCount()}]</code>
* @throws IllegalArgumentException
* if {@code numberOfRows} is less than 1.
*/
public void insertRows(int index, int numberOfRows)
throws IndexOutOfBoundsException, IllegalArgumentException;

/**
* Refreshes a range of rows in the current row container.
* <p>
* The data for the refreshed rows is queried from the current cell
* renderer.
*
* @param index
* the index of the first row that will be updated
* @param numberOfRows
* the number of rows to update, starting from the index
* @see #setEscalatorUpdater(EscalatorUpdater)
* @throws IndexOutOfBoundsException
* if any integer number in the range
* <code>[index..(index+numberOfColumns)]</code> is not an
* existing column index.
* @throws IllegalArgumentException
* if {@code numberOfRows} is less than 1.
*/
public void refreshRows(int index, int numberOfRows)
throws IndexOutOfBoundsException, IllegalArgumentException;

/**
* Gets the number of rows in the current row container.
*
* @return the number of rows in the current row container
*/
public int getRowCount();

/**
* The default height of the rows in this RowContainer.
*
* @param px
* the default height in pixels of the rows in this RowContainer
* @throws IllegalArgumentException
* if <code>px &lt; 1</code>
* @see #getDefaultRowHeight()
*/
public void setDefaultRowHeight(double px) throws IllegalArgumentException;

/**
* Returns the default height of the rows in this RowContainer.
* <p>
* This value will be equal to {@link #INITIAL_DEFAULT_ROW_HEIGHT} if the
* {@link Escalator} has not yet had a chance to autodetect the row height,
* or no explicit value has yet given via {@link #setDefaultRowHeight(int)}
*
* @return the default height of the rows in this RowContainer, in pixels
* @see #setDefaultRowHeight(int)
*/
public double getDefaultRowHeight();

/**
* Returns the cell object which contains information about the cell the
* element is in.
*
* @param element
* The element to get the cell for. If element is not present in
* row container then <code>null</code> is returned.
*
* @return the cell of the element, or <code>null</code> if element is not
* present in the {@link RowContainer}.
*/
public Cell getCell(Element element);

/**
* Gets the row element with given logical index. For lazy loaded containers
* such as Escalators BodyRowContainer visibility should be checked before
* calling this function. See {@link Escalator#getVisibleRowRange()}.
*
* @param index
* the logical index of the element to retrieve
* @return the element at position {@code index}
* @throws IndexOutOfBoundsException
* if {@code index} is not valid within container
* @throws IllegalStateException
* if {@code index} is currently not available in the DOM
*/
public TableRowElement getRowElement(int index)
throws IndexOutOfBoundsException, IllegalStateException;

/**
* Returns the root element of RowContainer
*
* @return RowContainer root element
*/
public TableSectionElement getElement();
}

+ 99
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/RowVisibilityChangeEvent.java View File

@@ -0,0 +1,99 @@
/*
* 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.client.widget.escalator;

import com.google.gwt.event.shared.GwtEvent;
import com.vaadin.shared.ui.grid.Range;

/**
* Event fired when the range of visible rows changes e.g. because of scrolling.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class RowVisibilityChangeEvent
extends GwtEvent<RowVisibilityChangeHandler> {
/**
* The type of this event.
*/
public static final Type<RowVisibilityChangeHandler> TYPE = new Type<RowVisibilityChangeHandler>();

private final Range visibleRows;

/**
* Creates a new row visibility change event
*
* @param firstVisibleRow
* the index of the first visible row
* @param visibleRowCount
* the number of visible rows
*/
public RowVisibilityChangeEvent(int firstVisibleRow, int visibleRowCount) {
visibleRows = Range.withLength(firstVisibleRow, visibleRowCount);
}

/**
* Gets the index of the first row that is at least partially visible.
*
* @return the index of the first visible row
*/
public int getFirstVisibleRow() {
return visibleRows.getStart();
}

/**
* Gets the number of at least partially visible rows.
*
* @return the number of visible rows
*/
public int getVisibleRowCount() {
return visibleRows.length();
}

/**
* Gets the range of visible rows.
*
* @since 7.6
* @return the visible rows
*/
public Range getVisibleRowRange() {
return visibleRows;
}

/*
* (non-Javadoc)
*
* @see com.google.gwt.event.shared.GwtEvent#getAssociatedType()
*/
@Override
public Type<RowVisibilityChangeHandler> getAssociatedType() {
return TYPE;
}

/*
* (non-Javadoc)
*
* @see
* com.google.gwt.event.shared.GwtEvent#dispatch(com.google.gwt.event.shared
* .EventHandler)
*/
@Override
protected void dispatch(RowVisibilityChangeHandler handler) {
handler.onRowVisibilityChange(this);
}

}

+ 38
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/RowVisibilityChangeHandler.java View File

@@ -0,0 +1,38 @@
/*
* 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.client.widget.escalator;

import com.google.gwt.event.shared.EventHandler;

/**
* Event handler that gets notified when the range of visible rows changes e.g.
* because of scrolling.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface RowVisibilityChangeHandler extends EventHandler {

/**
* Called when the range of visible rows changes e.g. because of scrolling.
*
* @param event
* the row visibility change event describing the change
*/
void onRowVisibilityChange(RowVisibilityChangeEvent event);

}

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

@@ -0,0 +1,869 @@
/*
* 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.client.widget.escalator;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Timer;
import com.vaadin.client.DeferredWorker;
import com.vaadin.client.WidgetUtil;
import com.vaadin.v7.client.widget.grid.events.ScrollEvent;
import com.vaadin.v7.client.widget.grid.events.ScrollHandler;

/**
* An element-like bundle representing a configurable and visual scrollbar in
* one axis.
*
* @since 7.4
* @author Vaadin Ltd
* @see VerticalScrollbarBundle
* @see HorizontalScrollbarBundle
*/
public abstract class ScrollbarBundle implements DeferredWorker {

private class ScrollEventFirer {
private final ScheduledCommand fireEventCommand = new ScheduledCommand() {
@Override
public void execute() {

/*
* Some kind of native-scroll-event related asynchronous problem
* occurs here (at least on desktops) where the internal
* bookkeeping isn't up to date with the real scroll position.
* The weird thing is, that happens only once, and if you drag
* scrollbar fast enough. After it has failed once, it never
* fails again.
*
* Theory: the user drags the scrollbar, and this command is
* executed before the browser has a chance to fire a scroll
* event (which normally would correct this situation). This
* would explain why slow scrolling doesn't trigger the problem,
* while fast scrolling does.
*
* To make absolutely sure that we have the latest scroll
* position, let's update the internal value.
*
* This might lead to a slight performance hit (on my computer
* it was never more than 3ms on either of Chrome 38 or Firefox
* 31). It also _slightly_ counteracts the purpose of the
* internal bookkeeping. But since getScrollPos is called 3
* times (on one direction) per scroll loop, it's still better
* to have take this small penalty than removing it altogether.
*/
updateScrollPosFromDom();

getHandlerManager().fireEvent(new ScrollEvent());
isBeingFired = false;
}
};

private boolean isBeingFired;

public void scheduleEvent() {
if (!isBeingFired) {
/*
* We'll gather all the scroll events, and only fire once, once
* everything has calmed down.
*/
Scheduler.get().scheduleDeferred(fireEventCommand);
isBeingFired = true;
}
}
}

/**
* The orientation of the scrollbar.
*/
public enum Direction {
VERTICAL, HORIZONTAL;
}

private class TemporaryResizer {
private static final int TEMPORARY_RESIZE_DELAY = 1000;

private final Timer timer = new Timer() {
@Override
public void run() {
internalSetScrollbarThickness(1);
root.getStyle().setVisibility(Visibility.HIDDEN);
}
};

public void show() {
internalSetScrollbarThickness(OSX_INVISIBLE_SCROLLBAR_FAKE_SIZE_PX);
root.getStyle().setVisibility(Visibility.VISIBLE);
timer.schedule(TEMPORARY_RESIZE_DELAY);
}
}

/**
* A means to listen to when the scrollbar handle in a
* {@link ScrollbarBundle} either appears or is removed.
*/
public interface VisibilityHandler extends EventHandler {
/**
* This method is called whenever the scrollbar handle's visibility is
* changed in a {@link ScrollbarBundle}.
*
* @param event
* the {@link VisibilityChangeEvent}
*/
void visibilityChanged(VisibilityChangeEvent event);
}

public static class VisibilityChangeEvent
extends GwtEvent<VisibilityHandler> {
public static final Type<VisibilityHandler> TYPE = new Type<ScrollbarBundle.VisibilityHandler>() {
@Override
public String toString() {
return "VisibilityChangeEvent";
}
};

private final boolean isScrollerVisible;

private VisibilityChangeEvent(boolean isScrollerVisible) {
this.isScrollerVisible = isScrollerVisible;
}

/**
* Checks whether the scroll handle is currently visible or not
*
* @return <code>true</code> if the scroll handle is currently visible.
* <code>false</code> if not.
*/
public boolean isScrollerVisible() {
return isScrollerVisible;
}

@Override
public Type<VisibilityHandler> getAssociatedType() {
return TYPE;
}

@Override
protected void dispatch(VisibilityHandler handler) {
handler.visibilityChanged(this);
}
}

/**
* The pixel size for OSX's invisible scrollbars.
* <p>
* Touch devices don't show a scrollbar at all, so the scrollbar size is
* irrelevant in their case. There doesn't seem to be any other popular
* platforms that has scrollbars similar to OSX. Thus, this behavior is
* tailored for OSX only, until additional platforms start behaving this
* way.
*/
private static final int OSX_INVISIBLE_SCROLLBAR_FAKE_SIZE_PX = 13;

/**
* A representation of a single vertical scrollbar.
*
* @see VerticalScrollbarBundle#getElement()
*/
public final static class VerticalScrollbarBundle extends ScrollbarBundle {

@Override
public void setStylePrimaryName(String primaryStyleName) {
super.setStylePrimaryName(primaryStyleName);
root.addClassName(primaryStyleName + "-scroller-vertical");
}

@Override
protected void internalSetScrollPos(int px) {
root.setScrollTop(px);
}

@Override
protected int internalGetScrollPos() {
return root.getScrollTop();
}

@Override
protected void internalSetScrollSize(double px) {
scrollSizeElement.getStyle().setHeight(px, Unit.PX);
}

@Override
protected String internalGetScrollSize() {
return scrollSizeElement.getStyle().getHeight();
}

@Override
protected void internalSetOffsetSize(double px) {
root.getStyle().setHeight(px, Unit.PX);
}

@Override
public String internalGetOffsetSize() {
return root.getStyle().getHeight();
}

@Override
protected void internalSetScrollbarThickness(double px) {
root.getStyle().setPaddingRight(px, Unit.PX);
root.getStyle().setWidth(0, Unit.PX);
scrollSizeElement.getStyle().setWidth(px, Unit.PX);
}

@Override
protected String internalGetScrollbarThickness() {
return scrollSizeElement.getStyle().getWidth();
}

@Override
protected void internalForceScrollbar(boolean enable) {
if (enable) {
root.getStyle().setOverflowY(Overflow.SCROLL);
} else {
root.getStyle().clearOverflowY();
}
}

@Override
public Direction getDirection() {
return Direction.VERTICAL;
}
}

/**
* A representation of a single horizontal scrollbar.
*
* @see HorizontalScrollbarBundle#getElement()
*/
public final static class HorizontalScrollbarBundle
extends ScrollbarBundle {

@Override
public void setStylePrimaryName(String primaryStyleName) {
super.setStylePrimaryName(primaryStyleName);
root.addClassName(primaryStyleName + "-scroller-horizontal");
}

@Override
protected void internalSetScrollPos(int px) {
root.setScrollLeft(px);
}

@Override
protected int internalGetScrollPos() {
return root.getScrollLeft();
}

@Override
protected void internalSetScrollSize(double px) {
scrollSizeElement.getStyle().setWidth(px, Unit.PX);
}

@Override
protected String internalGetScrollSize() {
return scrollSizeElement.getStyle().getWidth();
}

@Override
protected void internalSetOffsetSize(double px) {
root.getStyle().setWidth(px, Unit.PX);
}

@Override
public String internalGetOffsetSize() {
return root.getStyle().getWidth();
}

@Override
protected void internalSetScrollbarThickness(double px) {
root.getStyle().setPaddingBottom(px, Unit.PX);
root.getStyle().setHeight(0, Unit.PX);
scrollSizeElement.getStyle().setHeight(px, Unit.PX);
}

@Override
protected String internalGetScrollbarThickness() {
return scrollSizeElement.getStyle().getHeight();
}

@Override
protected void internalForceScrollbar(boolean enable) {
if (enable) {
root.getStyle().setOverflowX(Overflow.SCROLL);
} else {
root.getStyle().clearOverflowX();
}
}

@Override
public Direction getDirection() {
return Direction.HORIZONTAL;
}
}

protected final Element root = DOM.createDiv();
protected final Element scrollSizeElement = DOM.createDiv();
protected boolean isInvisibleScrollbar = false;

private double scrollPos = 0;
private double maxScrollPos = 0;

private boolean scrollHandleIsVisible = false;

private boolean isLocked = false;

/** @deprecated access via {@link #getHandlerManager()} instead. */
@Deprecated
private HandlerManager handlerManager;

private TemporaryResizer invisibleScrollbarTemporaryResizer = new TemporaryResizer();

private final ScrollEventFirer scrollEventFirer = new ScrollEventFirer();

private HandlerRegistration scrollSizeTemporaryScrollHandler;
private HandlerRegistration offsetSizeTemporaryScrollHandler;

private ScrollbarBundle() {
root.appendChild(scrollSizeElement);
root.getStyle().setDisplay(Display.NONE);
root.setTabIndex(-1);
}

protected abstract String internalGetScrollSize();

/**
* Sets the primary style name
*
* @param primaryStyleName
* The primary style name to use
*/
public void setStylePrimaryName(String primaryStyleName) {
root.setClassName(primaryStyleName + "-scroller");
}

/**
* Gets the root element of this scrollbar-composition.
*
* @return the root element
*/
public final Element getElement() {
return root;
}

/**
* Modifies the scroll position of this scrollbar by a number of pixels.
* <p>
* <em>Note:</em> Even though {@code double} values are used, they are
* currently only used as integers as large {@code int} (or small but fast
* {@code long}). This means, all values are truncated to zero decimal
* places.
*
* @param delta
* the delta in pixels to change the scroll position by
*/
public final void setScrollPosByDelta(double delta) {
if (delta != 0) {
setScrollPos(getScrollPos() + delta);
}
}

/**
* Modifies {@link #root root's} dimensions in the axis the scrollbar is
* representing.
*
* @param px
* the new size of {@link #root} in the dimension this scrollbar
* is representing
*/
protected abstract void internalSetOffsetSize(double px);

/**
* Sets the length of the scrollbar.
*
* @param px
* the length of the scrollbar in pixels
*/
public final void setOffsetSize(final double px) {

/*
* This needs to be made step-by-step because IE8 flat-out refuses to
* fire a scroll event when the scroll size becomes smaller than the
* offset size. All other browser need to suffer alongside.
*/

boolean newOffsetSizeIsGreaterThanScrollSize = px > getScrollSize();
boolean offsetSizeBecomesGreaterThanScrollSize = showsScrollHandle()
&& newOffsetSizeIsGreaterThanScrollSize;
if (offsetSizeBecomesGreaterThanScrollSize && getScrollPos() != 0) {
// must be a field because Java insists.
offsetSizeTemporaryScrollHandler = addScrollHandler(
new ScrollHandler() {
@Override
public void onScroll(ScrollEvent event) {
setOffsetSizeNow(px);
}
});
setScrollPos(0);
} else {
setOffsetSizeNow(px);
}
}

private void setOffsetSizeNow(double px) {
internalSetOffsetSize(Math.max(0, px));
recalculateMaxScrollPos();
forceScrollbar(showsScrollHandle());
fireVisibilityChangeIfNeeded();
if (offsetSizeTemporaryScrollHandler != null) {
offsetSizeTemporaryScrollHandler.removeHandler();
offsetSizeTemporaryScrollHandler = null;
}
}

/**
* Force the scrollbar to be visible with CSS. In practice, this means to
* set either <code>overflow-x</code> or <code>overflow-y</code> to "
* <code>scroll</code>" in the scrollbar's direction.
* <p>
* This is an IE8 workaround, since it doesn't always show scrollbars with
* <code>overflow: auto</code> enabled.
*/
protected void forceScrollbar(boolean enable) {
if (enable) {
root.getStyle().clearDisplay();
} else {
root.getStyle().setDisplay(Display.NONE);
}
internalForceScrollbar(enable);
}

protected abstract void internalForceScrollbar(boolean enable);

/**
* Gets the length of the scrollbar
*
* @return the length of the scrollbar in pixels
*/
public double getOffsetSize() {
return parseCssDimensionToPixels(internalGetOffsetSize());
}

public abstract String internalGetOffsetSize();

/**
* Sets the scroll position of the scrollbar in the axis the scrollbar is
* representing.
* <p>
* <em>Note:</em> Even though {@code double} values are used, they are
* currently only used as integers as large {@code int} (or small but fast
* {@code long}). This means, all values are truncated to zero decimal
* places.
*
* @param px
* the new scroll position in pixels
*/
public final void setScrollPos(double px) {
if (isLocked()) {
return;
}

double oldScrollPos = scrollPos;
scrollPos = Math.max(0, Math.min(maxScrollPos, truncate(px)));

if (!WidgetUtil.pixelValuesEqual(oldScrollPos, scrollPos)) {
if (isInvisibleScrollbar) {
invisibleScrollbarTemporaryResizer.show();
}

/*
* This is where the value needs to be converted into an integer no
* matter how we flip it, since GWT expects an integer value.
* There's no point making a JSNI method that accepts doubles as the
* scroll position, since the browsers themselves don't support such
* large numbers (as of today, 25.3.2014). This double-ranged is
* only facilitating future virtual scrollbars.
*/
internalSetScrollPos(toInt32(scrollPos));
}
}

/**
* Should be called whenever this bundle is attached to the DOM (typically,
* from the onLoad of the containing widget). Used to ensure the DOM scroll
* position is maintained when detaching and reattaching the bundle.
*
* @since 7.4.1
*/
public void onLoad() {
internalSetScrollPos(toInt32(scrollPos));
}

/**
* Truncates a double such that no decimal places are retained.
* <p>
* E.g. {@code trunc(2.3d) == 2.0d} and {@code trunc(-2.3d) == -2.0d}.
*
* @param num
* the double value to be truncated
* @return the {@code num} value without any decimal digits
*/
private static double truncate(double num) {
if (num > 0) {
return Math.floor(num);
} else {
return Math.ceil(num);
}
}

/**
* Modifies the element's scroll position (scrollTop or scrollLeft).
* <p>
* <em>Note:</em> The parameter here is a type of integer (instead of a
* double) by design. The browsers internally convert all double values into
* an integer value. To make this fact explicit, this API has chosen to
* force integers already at this level.
*
* @param px
* integer pixel value to scroll to
*/
protected abstract void internalSetScrollPos(int px);

/**
* Gets the scroll position of the scrollbar in the axis the scrollbar is
* representing.
*
* @return the new scroll position in pixels
*/
public final double getScrollPos() {
assert internalGetScrollPos() == toInt32(
scrollPos) : "calculated scroll position (" + scrollPos
+ ") did not match the DOM element scroll position ("
+ internalGetScrollPos() + ")";
return scrollPos;
}

/**
* Retrieves the element's scroll position (scrollTop or scrollLeft).
* <p>
* <em>Note:</em> The parameter here is a type of integer (instead of a
* double) by design. The browsers internally convert all double values into
* an integer value. To make this fact explicit, this API has chosen to
* force integers already at this level.
*
* @return integer pixel value of the scroll position
*/
protected abstract int internalGetScrollPos();

/**
* Modifies {@link #scrollSizeElement scrollSizeElement's} dimensions in
* such a way that the scrollbar is able to scroll a certain number of
* pixels in the axis it is representing.
*
* @param px
* the new size of {@link #scrollSizeElement} in the dimension
* this scrollbar is representing
*/
protected abstract void internalSetScrollSize(double px);

/**
* Sets the amount of pixels the scrollbar needs to be able to scroll
* through.
*
* @param px
* the number of pixels the scrollbar should be able to scroll
* through
*/
public final void setScrollSize(final double px) {

/*
* This needs to be made step-by-step because IE8 flat-out refuses to
* fire a scroll event when the scroll size becomes smaller than the
* offset size. All other browser need to suffer alongside.
*/

boolean newScrollSizeIsSmallerThanOffsetSize = px <= getOffsetSize();
boolean scrollSizeBecomesSmallerThanOffsetSize = showsScrollHandle()
&& newScrollSizeIsSmallerThanOffsetSize;
if (scrollSizeBecomesSmallerThanOffsetSize && getScrollPos() != 0) {
// must be a field because Java insists.
scrollSizeTemporaryScrollHandler = addScrollHandler(
new ScrollHandler() {
@Override
public void onScroll(ScrollEvent event) {
setScrollSizeNow(px);
}
});
setScrollPos(0);
} else {
setScrollSizeNow(px);
}
}

private void setScrollSizeNow(double px) {
internalSetScrollSize(Math.max(0, px));
recalculateMaxScrollPos();
forceScrollbar(showsScrollHandle());
fireVisibilityChangeIfNeeded();
if (scrollSizeTemporaryScrollHandler != null) {
scrollSizeTemporaryScrollHandler.removeHandler();
scrollSizeTemporaryScrollHandler = null;
}
}

/**
* Gets the amount of pixels the scrollbar needs to be able to scroll
* through.
*
* @return the number of pixels the scrollbar should be able to scroll
* through
*/
public double getScrollSize() {
return parseCssDimensionToPixels(internalGetScrollSize());
}

/**
* Modifies {@link #scrollSizeElement scrollSizeElement's} dimensions in the
* opposite axis to what the scrollbar is representing.
*
* @param px
* the dimension that {@link #scrollSizeElement} should take in
* the opposite axis to what the scrollbar is representing
*/
protected abstract void internalSetScrollbarThickness(double px);

/**
* Sets the scrollbar's thickness.
* <p>
* If the thickness is set to 0, the scrollbar will be treated as an
* "invisible" scrollbar. This means, the DOM structure will be given a
* non-zero size, but {@link #getScrollbarThickness()} will still return the
* value 0.
*
* @param px
* the scrollbar's thickness in pixels
*/
public final void setScrollbarThickness(double px) {
isInvisibleScrollbar = (px == 0);

if (isInvisibleScrollbar) {
Event.sinkEvents(root, Event.ONSCROLL);
Event.setEventListener(root, new EventListener() {
@Override
public void onBrowserEvent(Event event) {
invisibleScrollbarTemporaryResizer.show();
}
});
root.getStyle().setVisibility(Visibility.HIDDEN);
} else {
Event.sinkEvents(root, 0);
Event.setEventListener(root, null);
root.getStyle().clearVisibility();
}

internalSetScrollbarThickness(Math.max(1d, px));
}

/**
* Gets the scrollbar's thickness as defined in the DOM.
*
* @return the scrollbar's thickness as defined in the DOM, in pixels
*/
protected abstract String internalGetScrollbarThickness();

/**
* Gets the scrollbar's thickness.
* <p>
* This value will differ from the value in the DOM, if the thickness was
* set to 0 with {@link #setScrollbarThickness(double)}, as the scrollbar is
* then treated as "invisible."
*
* @return the scrollbar's thickness in pixels
*/
public final double getScrollbarThickness() {
if (!isInvisibleScrollbar) {
return parseCssDimensionToPixels(internalGetScrollbarThickness());
} else {
return 0;
}
}

/**
* Checks whether the scrollbar's handle is visible.
* <p>
* In other words, this method checks whether the contents is larger than
* can visually fit in the element.
*
* @return <code>true</code> iff the scrollbar's handle is visible
*/
public boolean showsScrollHandle() {
return getScrollSize() - getOffsetSize() > WidgetUtil.PIXEL_EPSILON;
}

public void recalculateMaxScrollPos() {
double scrollSize = getScrollSize();
double offsetSize = getOffsetSize();
maxScrollPos = Math.max(0, scrollSize - offsetSize);

// make sure that the correct max scroll position is maintained.
setScrollPos(scrollPos);
}

/**
* This is a method that JSNI can call to synchronize the object state from
* the DOM.
*/
private final void updateScrollPosFromDom() {

/*
* TODO: this method probably shouldn't be called from Escalator's JSNI,
* but probably could be handled internally by this listening to its own
* element. Would clean up the code quite a bit. Needs further
* investigation.
*/

int newScrollPos = internalGetScrollPos();
if (!isLocked()) {
scrollPos = newScrollPos;
scrollEventFirer.scheduleEvent();
} else if (scrollPos != newScrollPos) {
// we need to actually undo the setting of the scroll.
internalSetScrollPos(toInt32(scrollPos));
}
}

protected HandlerManager getHandlerManager() {
if (handlerManager == null) {
handlerManager = new HandlerManager(this);
}
return handlerManager;
}

/**
* Adds handler for the scrollbar handle visibility.
*
* @param handler
* the {@link VisibilityHandler} to add
* @return {@link HandlerRegistration} used to remove the handler
*/
public HandlerRegistration addVisibilityHandler(
final VisibilityHandler handler) {
return getHandlerManager().addHandler(VisibilityChangeEvent.TYPE,
handler);
}

private void fireVisibilityChangeIfNeeded() {
final boolean oldHandleIsVisible = scrollHandleIsVisible;
scrollHandleIsVisible = showsScrollHandle();
if (oldHandleIsVisible != scrollHandleIsVisible) {
final VisibilityChangeEvent event = new VisibilityChangeEvent(
scrollHandleIsVisible);
getHandlerManager().fireEvent(event);
}
}

/**
* Converts a double into an integer by JavaScript's terms.
* <p>
* Implementation copied from {@link Element#toInt32(double)}.
*
* @param val
* the double value to convert into an integer
* @return the double value converted to an integer
*/
private static native int toInt32(double val)
/*-{
return Math.round(val) | 0;
}-*/;

/**
* Locks or unlocks the scrollbar bundle.
* <p>
* A locked scrollbar bundle will refuse to scroll, both programmatically
* and via user-triggered events.
*
* @param isLocked
* <code>true</code> to lock, <code>false</code> to unlock
*/
public void setLocked(boolean isLocked) {
this.isLocked = isLocked;
}

/**
* Checks whether the scrollbar bundle is locked or not.
*
* @return <code>true</code> iff the scrollbar bundle is locked
*/
public boolean isLocked() {
return isLocked;
}

/**
* Returns the scroll direction of this scrollbar bundle.
*
* @return the scroll direction of this scrollbar bundle
*/
public abstract Direction getDirection();

/**
* Adds a scroll handler to the scrollbar bundle.
*
* @param handler
* the handler to add
* @return the registration object for the handler registration
*/
public HandlerRegistration addScrollHandler(final ScrollHandler handler) {
return getHandlerManager().addHandler(ScrollEvent.TYPE, handler);
}

private static double parseCssDimensionToPixels(String size) {

/*
* Sizes of elements are calculated from CSS rather than
* element.getOffset*() because those values are 0 whenever display:
* none. Because we know that all elements have populated
* CSS-dimensions, it's better to do it that way.
*
* Another solution would be to make the elements visible while
* measuring and then re-hide them, but that would cause unnecessary
* reflows that would probably kill the performance dead.
*/

if (size.isEmpty()) {
return 0;
} else {
assert size.endsWith("px") : "Can't parse CSS dimension \"" + size
+ "\"";
return Double.parseDouble(size.substring(0, size.length() - 2));
}
}

@Override
public boolean isWorkPending() {
return scrollSizeTemporaryScrollHandler != null
|| offsetSizeTemporaryScrollHandler != null;
}
}

+ 47
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/Spacer.java View File

@@ -0,0 +1,47 @@
/*
* 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.client.widget.escalator;

import com.google.gwt.dom.client.Element;

/**
* A representation of a spacer element in a
* {@link com.vaadin.v7.client.widget.escalator.RowContainer.BodyRowContainer}.
*
* @since 7.5.0
* @author Vaadin Ltd
*/
public interface Spacer {

/**
* Gets the root element for the spacer content.
*
* @return the root element for the spacer content
*/
Element getElement();

/**
* Gets the decorative element for this spacer.
*/
Element getDecoElement();

/**
* Gets the row index.
*
* @return the row index.
*/
int getRow();
}

+ 64
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/SpacerUpdater.java View File

@@ -0,0 +1,64 @@
/*
* 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.client.widget.escalator;

import com.vaadin.v7.client.widget.escalator.RowContainer.BodyRowContainer;

/**
* An interface that handles the display of content for spacers.
* <p>
* The updater is responsible for making sure all elements are properly
* constructed and cleaned up.
*
* @since 7.5.0
* @author Vaadin Ltd
* @see Spacer
* @see BodyRowContainer
*/
public interface SpacerUpdater {

/** A spacer updater that does nothing. */
public static final SpacerUpdater NULL = new SpacerUpdater() {
@Override
public void init(Spacer spacer) {
// NOOP
}

@Override
public void destroy(Spacer spacer) {
// NOOP
}
};

/**
* Called whenever a spacer should be initialized with content.
*
* @param spacer
* the spacer reference that should be initialized
*/
void init(Spacer spacer);

/**
* Called whenever a spacer should be cleaned.
* <p>
* The structure to clean up is the same that has been constructed by
* {@link #init(Spacer)}.
*
* @param spacer
* the spacer reference that should be destroyed
*/
void destroy(Spacer spacer);
}

+ 48
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/events/RowHeightChangedEvent.java View File

@@ -0,0 +1,48 @@
/*
* 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.client.widget.escalator.events;

import com.google.gwt.event.shared.GwtEvent;

/**
* Event fired when the row height changed in the Escalator's header, body or
* footer.
*
* @since 7.7
* @author Vaadin Ltd
*/
public class RowHeightChangedEvent extends GwtEvent<RowHeightChangedHandler> {

/**
* Handler type.
*/
public final static Type<RowHeightChangedHandler> TYPE = new Type<RowHeightChangedHandler>();

public static final Type<RowHeightChangedHandler> getType() {
return TYPE;
}

@Override
public Type<RowHeightChangedHandler> getAssociatedType() {
return TYPE;
}

@Override
protected void dispatch(RowHeightChangedHandler handler) {
handler.onRowHeightChanged(this);
}

}

+ 36
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/events/RowHeightChangedHandler.java View File

@@ -0,0 +1,36 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.client.widget.escalator.events;

import com.google.gwt.event.shared.EventHandler;

/**
* Event handler for a row height changed event.
*
* @since 7.7
* @author Vaadin Ltd
*/
public interface RowHeightChangedHandler extends EventHandler {

/**
* A row height changed event, fired by Escalator when the header, body or
* footer row height has changed.
*
* @param event
* Row height changed event
*/
public void onRowHeightChanged(RowHeightChangedEvent event);
}

+ 647
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/AutoScroller.java View File

@@ -0,0 +1,647 @@
/*
* 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.client.widget.grid;

import com.google.gwt.animation.client.AnimationScheduler;
import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback;
import com.google.gwt.animation.client.AnimationScheduler.AnimationHandle;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.TableElement;
import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.vaadin.client.WidgetUtil;
import com.vaadin.v7.client.widgets.Grid;

/**
* A class for handling automatic scrolling vertically / horizontally in the
* Grid when the cursor is close enough the edge of the body of the grid,
* depending on the scroll direction chosen.
*
* @since 7.5.0
* @author Vaadin Ltd
*/
public class AutoScroller {

/**
* Callback that notifies when the cursor is on top of a new row or column
* because of the automatic scrolling.
*/
public interface AutoScrollerCallback {

/**
* Triggered when doing automatic scrolling.
* <p>
* Because the auto scroller currently only supports scrolling in one
* axis, this method is used for both vertical and horizontal scrolling.
*
* @param scrollDiff
* the amount of pixels that have been auto scrolled since
* last call
*/
void onAutoScroll(int scrollDiff);

/**
* Triggered when the grid scroll has reached the minimum scroll
* position. Depending on the scroll axis, either scrollLeft or
* scrollTop is 0.
*/
void onAutoScrollReachedMin();

/**
* Triggered when the grid scroll has reached the max scroll position.
* Depending on the scroll axis, either scrollLeft or scrollTop is at
* its maximum value.
*/
void onAutoScrollReachedMax();
}

public enum ScrollAxis {
VERTICAL, HORIZONTAL
}

/** The maximum number of pixels per second to autoscroll. */
private static final int SCROLL_TOP_SPEED_PX_SEC = 500;

/**
* The minimum area where the grid doesn't scroll while the pointer is
* pressed.
*/
private static final int MIN_NO_AUTOSCROLL_AREA_PX = 50;

/** The size of the autoscroll area, both top/left and bottom/right. */
private int scrollAreaPX = 100;

/**
* This class's main objective is to listen when to stop autoscrolling, and
* make sure everything stops accordingly.
*/
private class TouchEventHandler implements NativePreviewHandler {
@Override
public void onPreviewNativeEvent(final NativePreviewEvent event) {
/*
* Remember: targetElement is always where touchstart started, not
* where the finger is pointing currently.
*/
switch (event.getTypeInt()) {
case Event.ONTOUCHSTART: {
if (event.getNativeEvent().getTouches().length() == 1) {
/*
* Something has dropped a touchend/touchcancel and the
* scroller is most probably running amok. Let's cancel it
* and pretend that everything's going as expected
*
* Because this is a preview, this code is run before start
* event can be passed to the start(...) method.
*/
stop();

/*
* Related TODO: investigate why iOS seems to ignore a
* touchend/touchcancel when frames are dropped, and/or if
* something can be done about that.
*/
}
break;
}

case Event.ONTOUCHMOVE:
event.cancel();
break;

case Event.ONTOUCHEND:
case Event.ONTOUCHCANCEL:
// TODO investigate if this works as desired
stop();
break;
}
}

}

/**
* This class's responsibility is to scroll the table while a pointer is
* kept in a scrolling zone.
* <p>
* <em>Techical note:</em> This class is an AnimationCallback because we
* need a timer: when the finger is kept in place while the grid scrolls, we
* still need to be able to make new selections. So, instead of relying on
* events (which won't be fired, since the pointer isn't necessarily
* moving), we do this check on each frame while the pointer is "active"
* (mouse is pressed, finger is on screen).
*/
private class AutoScrollingFrame implements AnimationCallback {

/**
* If the acceleration gradient area is smaller than this, autoscrolling
* will be disabled (it becomes too quick to accelerate to be usable).
*/
private static final int GRADIENT_MIN_THRESHOLD_PX = 10;

/**
* The speed at which the gradient area recovers, once scrolling in that
* direction has started.
*/
private static final int SCROLL_AREA_REBOUND_PX_PER_SEC = 1;
private static final double SCROLL_AREA_REBOUND_PX_PER_MS = SCROLL_AREA_REBOUND_PX_PER_SEC
/ 1000.0d;

/**
* The lowest y/x-coordinate on the {@link Event#getClientY() client-y}
* or {@link Event#getClientX() client-x} from where we need to start
* scrolling towards the top/left.
*/
private int startBound = -1;

/**
* The highest y/x-coordinate on the {@link Event#getClientY() client-y}
* or {@link Event#getClientX() client-x} from where we need to
* scrolling towards the bottom.
*/
private int endBound = -1;

/**
* The area where the selection acceleration takes place. If &lt;
* {@link #GRADIENT_MIN_THRESHOLD_PX}, autoscrolling is disabled
*/
private final int gradientArea;

/**
* The number of pixels per seconds we currently are scrolling (negative
* is towards the top/left, positive is towards the bottom/right).
*/
private double scrollSpeed = 0;

private double prevTimestamp = 0;

/**
* This field stores fractions of pixels to scroll, to make sure that
* we're able to scroll less than one px per frame.
*/
private double pixelsToScroll = 0.0d;

/** Should this animator be running. */
private boolean running = false;

/** The handle in which this instance is running. */
private AnimationHandle handle;

/**
* The pointer's pageY (VERTICAL) / pageX (HORIZONTAL) coordinate
* depending on scrolling axis.
*/
private int scrollingAxisPageCoordinate;

/** @see #doScrollAreaChecks(int) */
private int finalStartBound;

/** @see #doScrollAreaChecks(int) */
private int finalEndBound;

private boolean scrollAreaShouldRebound = false;

public AutoScrollingFrame(final int startBound, final int endBound,
final int gradientArea) {
finalStartBound = startBound;
finalEndBound = endBound;
this.gradientArea = gradientArea;
}

@Override
public void execute(final double timestamp) {
final double timeDiff = timestamp - prevTimestamp;
prevTimestamp = timestamp;

reboundScrollArea(timeDiff);

pixelsToScroll += scrollSpeed * (timeDiff / 1000.0d);
final int intPixelsToScroll = (int) pixelsToScroll;
pixelsToScroll -= intPixelsToScroll;

if (intPixelsToScroll != 0) {
double scrollPos;
double maxScrollPos;
double newScrollPos;
if (scrollDirection == ScrollAxis.VERTICAL) {
scrollPos = grid.getScrollTop();
maxScrollPos = getMaxScrollTop();
} else {
scrollPos = grid.getScrollLeft();
maxScrollPos = getMaxScrollLeft();
}
if (intPixelsToScroll > 0 && scrollPos < maxScrollPos
|| intPixelsToScroll < 0 && scrollPos > 0) {
newScrollPos = scrollPos + intPixelsToScroll;
if (scrollDirection == ScrollAxis.VERTICAL) {
grid.setScrollTop(newScrollPos);
} else {
grid.setScrollLeft(newScrollPos);
}
callback.onAutoScroll(intPixelsToScroll);
if (newScrollPos <= 0) {
callback.onAutoScrollReachedMin();
} else if (newScrollPos >= maxScrollPos) {
callback.onAutoScrollReachedMax();
}
}
}

reschedule();
}

/**
* If the scroll are has been offset by the pointer starting out there,
* move it back a bit
*/
private void reboundScrollArea(double timeDiff) {
if (!scrollAreaShouldRebound) {
return;
}

int reboundPx = (int) Math
.ceil(SCROLL_AREA_REBOUND_PX_PER_MS * timeDiff);
if (startBound < finalStartBound) {
startBound += reboundPx;
startBound = Math.min(startBound, finalStartBound);
updateScrollSpeed(scrollingAxisPageCoordinate);
} else if (endBound > finalEndBound) {
endBound -= reboundPx;
endBound = Math.max(endBound, finalEndBound);
updateScrollSpeed(scrollingAxisPageCoordinate);
}
}

private void updateScrollSpeed(final int pointerPageCordinate) {

final double ratio;
if (pointerPageCordinate < startBound) {
final double distance = pointerPageCordinate - startBound;
ratio = Math.max(-1, distance / gradientArea);
}

else if (pointerPageCordinate > endBound) {
final double distance = pointerPageCordinate - endBound;
ratio = Math.min(1, distance / gradientArea);
}

else {
ratio = 0;
}

scrollSpeed = ratio * SCROLL_TOP_SPEED_PX_SEC;
}

public void start() {
running = true;
reschedule();
}

public void stop() {
running = false;

if (handle != null) {
handle.cancel();
handle = null;
}
}

private void reschedule() {
if (running && gradientArea >= GRADIENT_MIN_THRESHOLD_PX) {
handle = AnimationScheduler.get().requestAnimationFrame(this,
grid.getElement());
}
}

public void updatePointerCoords(int pageX, int pageY) {
final int pageCordinate;
if (scrollDirection == ScrollAxis.VERTICAL) {
pageCordinate = pageY;
} else {
pageCordinate = pageX;
}
doScrollAreaChecks(pageCordinate);
updateScrollSpeed(pageCordinate);
scrollingAxisPageCoordinate = pageCordinate;
}

/**
* This method checks whether the first pointer event started in an area
* that would start scrolling immediately, and does some actions
* accordingly.
* <p>
* If it is, that scroll area will be offset "beyond" the pointer (above
* if pointer is towards the top/left, otherwise below/right).
*/
private void doScrollAreaChecks(int pageCordinate) {
/*
* The first run makes sure that neither scroll position is
* underneath the finger, but offset to either direction from
* underneath the pointer.
*/
if (startBound == -1) {
startBound = Math.min(finalStartBound, pageCordinate);
endBound = Math.max(finalEndBound, pageCordinate);
}

/*
* Subsequent runs make sure that the scroll area grows (but doesn't
* shrink) with the finger, but no further than the final bound.
*/
else {
int oldTopBound = startBound;
if (startBound < finalStartBound) {
startBound = Math.max(startBound,
Math.min(finalStartBound, pageCordinate));
}

int oldBottomBound = endBound;
if (endBound > finalEndBound) {
endBound = Math.min(endBound,
Math.max(finalEndBound, pageCordinate));
}

final boolean startDidNotMove = oldTopBound == startBound;
final boolean endDidNotMove = oldBottomBound == endBound;
final boolean wasMovement = pageCordinate != scrollingAxisPageCoordinate;
scrollAreaShouldRebound = (startDidNotMove && endDidNotMove
&& wasMovement);
}
}
}

/**
* This handler makes sure that pointer movements are handled.
* <p>
* Essentially, a native preview handler is registered (so that selection
* gestures can happen outside of the selection column). The handler itself
* makes sure that it's detached when the pointer is "lifted".
*/
private final NativePreviewHandler scrollPreviewHandler = new NativePreviewHandler() {
@Override
public void onPreviewNativeEvent(final NativePreviewEvent event) {
if (autoScroller == null) {
stop();
return;
}

final NativeEvent nativeEvent = event.getNativeEvent();
int pageY = 0;
int pageX = 0;
switch (event.getTypeInt()) {
case Event.ONMOUSEMOVE:
case Event.ONTOUCHMOVE:
pageY = WidgetUtil.getTouchOrMouseClientY(nativeEvent);
pageX = WidgetUtil.getTouchOrMouseClientX(nativeEvent);
autoScroller.updatePointerCoords(pageX, pageY);
break;
case Event.ONMOUSEUP:
case Event.ONTOUCHEND:
case Event.ONTOUCHCANCEL:
stop();
break;
}
}
};
/** The registration info for {@link #scrollPreviewHandler} */
private HandlerRegistration handlerRegistration;

/**
* The top/left bound, as calculated from the {@link Event#getClientY()
* client-y} or {@link Event#getClientX() client-x} coordinates.
*/
private double startingBound = -1;

/**
* The bottom/right bound, as calculated from the {@link Event#getClientY()
* client-y} or or {@link Event#getClientX() client-x} coordinates.
*/
private int endingBound = -1;

/** The size of the autoscroll acceleration area. */
private int gradientArea;

private Grid<?> grid;

private HandlerRegistration nativePreviewHandlerRegistration;

private ScrollAxis scrollDirection;

private AutoScrollingFrame autoScroller;

private AutoScrollerCallback callback;

/**
* Creates a new instance for scrolling the given grid.
*
* @param grid
* the grid to auto scroll
*/
public AutoScroller(Grid<?> grid) {
this.grid = grid;
}

/**
* Starts the automatic scrolling detection.
*
* @param startEvent
* the event that starts the automatic scroll
* @param scrollAxis
* the axis along which the scrolling should happen
* @param callback
* the callback for getting info about the automatic scrolling
*/
public void start(final NativeEvent startEvent, ScrollAxis scrollAxis,
AutoScrollerCallback callback) {
scrollDirection = scrollAxis;
this.callback = callback;
injectNativeHandler();
start();
startEvent.preventDefault();
startEvent.stopPropagation();
}

/**
* Stops the automatic scrolling.
*/
public void stop() {
if (handlerRegistration != null) {
handlerRegistration.removeHandler();
handlerRegistration = null;
}

if (autoScroller != null) {
autoScroller.stop();
autoScroller = null;
}

removeNativeHandler();
}

/**
* Set the auto scroll area height or width depending on the scrolling axis.
* This is the amount of pixels from the edge of the grid that the scroll is
* triggered.
* <p>
* Defaults to 100px.
*
* @param px
* the pixel height/width for the auto scroll area depending on
* direction
*/
public void setScrollArea(int px) {
scrollAreaPX = px;
}

/**
* Returns the size of the auto scroll area in pixels.
* <p>
* Defaults to 100px.
*
* @return size in pixels
*/
public int getScrollArea() {
return scrollAreaPX;
}

private void start() {
/*
* bounds are updated whenever the autoscroll cycle starts, to make sure
* that the widget hasn't changed in size, moved around, or whatnot.
*/
updateScrollBounds();

assert handlerRegistration == null : "handlerRegistration was not null";
assert autoScroller == null : "autoScroller was not null";
handlerRegistration = Event
.addNativePreviewHandler(scrollPreviewHandler);
autoScroller = new AutoScrollingFrame((int) Math.ceil(startingBound),
endingBound, gradientArea);
autoScroller.start();
}

private void updateScrollBounds() {
double startBorder = getBodyClientStart();
final int endBorder = getBodyClientEnd();
startBorder += getFrozenColumnsWidth();

startingBound = startBorder + scrollAreaPX;
endingBound = endBorder - scrollAreaPX;
gradientArea = scrollAreaPX;

// modify bounds if they're too tightly packed
if (endingBound - startingBound < MIN_NO_AUTOSCROLL_AREA_PX) {
double adjustment = MIN_NO_AUTOSCROLL_AREA_PX
- (endingBound - startingBound);
startingBound -= adjustment / 2;
endingBound += adjustment / 2;
gradientArea -= adjustment / 2;
}
}

private void injectNativeHandler() {
removeNativeHandler();
nativePreviewHandlerRegistration = Event
.addNativePreviewHandler(new TouchEventHandler());
}

private void removeNativeHandler() {
if (nativePreviewHandlerRegistration != null) {
nativePreviewHandlerRegistration.removeHandler();
nativePreviewHandlerRegistration = null;
}
}

private TableElement getTableElement() {
final Element root = grid.getElement();
final Element tablewrapper = Element.as(root.getChild(2));
if (tablewrapper != null) {
return TableElement.as(tablewrapper.getFirstChildElement());
} else {
return null;
}
}

private TableSectionElement getTheadElement() {
TableElement table = getTableElement();
if (table != null) {
return table.getTHead();
} else {
return null;
}
}

private TableSectionElement getTfootElement() {
TableElement table = getTableElement();
if (table != null) {
return table.getTFoot();
} else {
return null;
}
}

private int getBodyClientEnd() {
if (scrollDirection == ScrollAxis.VERTICAL) {
return getTfootElement().getAbsoluteTop() - 1;
} else {
return getTableElement().getAbsoluteRight();
}

}

private int getBodyClientStart() {
if (scrollDirection == ScrollAxis.VERTICAL) {
return getTheadElement().getAbsoluteBottom() + 1;
} else {
return getTableElement().getAbsoluteLeft();
}
}

public double getFrozenColumnsWidth() {
double value = 0;

for (int i = 0; i < getRealFrozenColumnCount(); i++) {
value += grid.getColumn(i).getWidthActual();
}

return value;
}

private int getRealFrozenColumnCount() {
if (grid.getFrozenColumnCount() < 0) {
return 0;
} else if (grid.getSelectionModel()
.getSelectionColumnRenderer() != null) {
// includes the selection column
return grid.getFrozenColumnCount() + 1;
} else {
return grid.getFrozenColumnCount();
}
}

private double getMaxScrollLeft() {
return grid.getScrollWidth()
- (getTableElement().getParentElement().getOffsetWidth()
- getFrozenColumnsWidth());
}

private double getMaxScrollTop() {
return grid.getScrollHeight() - getTfootElement().getOffsetHeight()
- getTheadElement().getOffsetHeight();
}
}

+ 151
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/CellReference.java View File

@@ -0,0 +1,151 @@
/*
* 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.client.widget.grid;

import com.google.gwt.dom.client.TableCellElement;
import com.vaadin.v7.client.widgets.Grid;

/**
* A data class which contains information which identifies a cell in a
* {@link Grid}.
* <p>
* Since this class follows the <code>Flyweight</code>-pattern any instance of
* this object is subject to change without the user knowing it and so should
* not be stored anywhere outside of the method providing these instances.
*
* @author Vaadin Ltd
* @param <T>
* the type of the row object containing this cell
* @since 7.4
*/
public class CellReference<T> {

private int columnIndexDOM;
private int columnIndex;
private Grid.Column<?, T> column;
private final RowReference<T> rowReference;

public CellReference(RowReference<T> rowReference) {
this.rowReference = rowReference;
}

/**
* Sets the identifying information for this cell.
* <p>
* The difference between {@link #columnIndexDOM} and {@link #columnIndex}
* comes from hidden columns.
*
* @param columnIndexDOM
* the index of the column in the DOM
* @param columnIndex
* the index of the column
* @param column
* the column object
*/
public void set(int columnIndexDOM, int columnIndex,
Grid.Column<?, T> column) {
this.columnIndexDOM = columnIndexDOM;
this.columnIndex = columnIndex;
this.column = column;
}

/**
* Gets the grid that contains the referenced cell.
*
* @return the grid that contains referenced cell
*/
public Grid<T> getGrid() {
return rowReference.getGrid();
}

/**
* Gets the row index of the row.
*
* @return the index of the row
*/
public int getRowIndex() {
return rowReference.getRowIndex();
}

/**
* Gets the row data object.
*
* @return the row object
*/
public T getRow() {
return rowReference.getRow();
}

/**
* Gets the index of the column.
* <p>
* <em>NOTE:</em> The index includes hidden columns in the count, unlike
* {@link #getColumnIndexDOM()}.
*
* @return the index of the column
*/
public int getColumnIndex() {
return columnIndex;
}

/**
* Gets the index of the cell in the DOM. The difference to
* {@link #getColumnIndex()} is caused by hidden columns.
*
* @since 7.5.0
* @return the index of the column in the DOM
*/
public int getColumnIndexDOM() {
return columnIndexDOM;
}

/**
* Gets the column objects.
*
* @return the column object
*/
public Grid.Column<?, T> getColumn() {
return column;
}

/**
* Gets the value of the cell.
*
* @return the value of the cell
*/
public Object getValue() {
return getColumn().getValue(getRow());
}

/**
* Get the element of the cell.
*
* @return the element of the cell
*/
public TableCellElement getElement() {
return rowReference.getElement().getCells().getItem(columnIndexDOM);
}

/**
* Gets the RowReference for this CellReference.
*
* @return the row reference
*/
protected RowReference<T> getRowReference() {
return rowReference;
}

}

+ 40
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/CellStyleGenerator.java View File

@@ -0,0 +1,40 @@
/*
* 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.client.widget.grid;

import com.vaadin.v7.client.widgets.Grid;

/**
* Callback interface for generating custom style names for cells
*
* @author Vaadin Ltd
* @param <T>
* the row type of the target grid
* @see Grid#setCellStyleGenerator(CellStyleGenerator)
* @since 7.4
*/
public interface CellStyleGenerator<T> {

/**
* Called by Grid to generate a style name for a column element.
*
* @param cellReference
* The cell to generate a style for
* @return the style name to add to this cell, or {@code null} to not set
* any style
*/
public abstract String getStyle(CellReference<T> cellReference);
}

+ 55
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/DataAvailableEvent.java View File

@@ -0,0 +1,55 @@
/*
* 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.client.widget.grid;

import com.google.gwt.event.shared.GwtEvent;
import com.vaadin.shared.ui.grid.Range;

/**
* Event object describing a change of row availability in DataSource of a Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class DataAvailableEvent extends GwtEvent<DataAvailableHandler> {

private Range rowsAvailable;
public static final Type<DataAvailableHandler> TYPE = new Type<DataAvailableHandler>();

public DataAvailableEvent(Range rowsAvailable) {
this.rowsAvailable = rowsAvailable;
}

/**
* Returns the range of available rows in {@link DataSource} for this event.
*
* @return range of available rows
*/
public Range getAvailableRows() {
return rowsAvailable;
}

@Override
public Type<DataAvailableHandler> getAssociatedType() {
return TYPE;
}

@Override
protected void dispatch(DataAvailableHandler handler) {
handler.onDataAvailable(this);
}

}

+ 37
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/DataAvailableHandler.java View File

@@ -0,0 +1,37 @@
/*
* 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.client.widget.grid;

import com.google.gwt.event.shared.EventHandler;

/**
* Handler for {@link DataAvailableEvent}s.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface DataAvailableHandler extends EventHandler {

/**
* Called when DataSource has data available. Supplied with row range.
*
* @param availableRows
* Range of rows available in the DataSource
* @return true if the command was successfully completed, false to call
* again the next time new data is available
*/
public void onDataAvailable(DataAvailableEvent event);
}

+ 332
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/DefaultEditorEventHandler.java View File

@@ -0,0 +1,332 @@
/*
* 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.client.widget.grid;

import com.google.gwt.core.client.Duration;
import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.ui.FocusUtil;
import com.vaadin.v7.client.widgets.Grid.Editor;
import com.vaadin.v7.client.widgets.Grid.EditorDomEvent;

/**
* The default handler for Grid editor events. Offers several overridable
* protected methods for easier customization.
*
* @since 7.6
* @author Vaadin Ltd
*/
public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> {

public static final int KEYCODE_OPEN = KeyCodes.KEY_ENTER;
public static final int KEYCODE_MOVE_VERTICAL = KeyCodes.KEY_ENTER;
public static final int KEYCODE_CLOSE = KeyCodes.KEY_ESCAPE;
public static final int KEYCODE_MOVE_HORIZONTAL = KeyCodes.KEY_TAB;
public static final int KEYCODE_BUFFERED_SAVE = KeyCodes.KEY_ENTER;

private double lastTouchEventTime = 0;
private int lastTouchEventX = -1;
private int lastTouchEventY = -1;
private int lastTouchEventRow = -1;

/**
* Returns whether the given event is a touch event that should open the
* editor.
*
* @param event
* the received event
* @return whether the event is a touch open event
*/
protected boolean isTouchOpenEvent(EditorDomEvent<T> event) {
final Event e = event.getDomEvent();
final int type = e.getTypeInt();

final double now = Duration.currentTimeMillis();
final int currentX = WidgetUtil.getTouchOrMouseClientX(e);
final int currentY = WidgetUtil.getTouchOrMouseClientY(e);

final boolean validTouchOpenEvent = type == Event.ONTOUCHEND
&& now - lastTouchEventTime < 500
&& lastTouchEventRow == event.getCell().getRowIndex()
&& Math.abs(lastTouchEventX - currentX) < 20
&& Math.abs(lastTouchEventY - currentY) < 20;

if (type == Event.ONTOUCHSTART) {
lastTouchEventX = currentX;
lastTouchEventY = currentY;
}

if (type == Event.ONTOUCHEND) {
lastTouchEventTime = now;
lastTouchEventRow = event.getCell().getRowIndex();
}

return validTouchOpenEvent;
}

/**
* Returns whether the given event should open the editor. The default
* implementation returns true if and only if the event is a doubleclick or
* if it is a keydown event and the keycode is {@link #KEYCODE_OPEN}.
*
* @param event
* the received event
* @return true if the event is an open event, false otherwise
*/
protected boolean isOpenEvent(EditorDomEvent<T> event) {
final Event e = event.getDomEvent();
return e.getTypeInt() == Event.ONDBLCLICK
|| (e.getTypeInt() == Event.ONKEYDOWN
&& e.getKeyCode() == KEYCODE_OPEN)
|| isTouchOpenEvent(event);
}

/**
* Opens the editor on the appropriate row if the received event is an open
* event. The default implementation uses
* {@link #isOpenEvent(EditorDomEvent) isOpenEvent}.
*
* @param event
* the received event
* @return true if this method handled the event and nothing else should be
* done, false otherwise
*/
protected boolean handleOpenEvent(EditorDomEvent<T> event) {
if (isOpenEvent(event)) {
final EventCellReference<T> cell = event.getCell();

editRow(event, cell.getRowIndex(), cell.getColumnIndexDOM());

event.getDomEvent().preventDefault();

return true;
}
return false;
}

/**
* Moves the editor to another row or another column if the received event
* is a move event. The default implementation moves the editor to the
* clicked row if the event is a click; otherwise, if the event is a keydown
* and the keycode is {@link #KEYCODE_MOVE_VERTICAL}, moves the editor one
* row up or down if the shift key is pressed or not, respectively. Keydown
* event with keycode {@link #KEYCODE_MOVE_HORIZONTAL} moves the editor left
* or right if shift key is pressed or not, respectively.
*
* @param event
* the received event
* @return true if this method handled the event and nothing else should be
* done, false otherwise
*/
protected boolean handleMoveEvent(EditorDomEvent<T> event) {
Event e = event.getDomEvent();
final EventCellReference<T> cell = event.getCell();

// TODO: Move on touch events
if (e.getTypeInt() == Event.ONCLICK) {

editRow(event, cell.getRowIndex(), cell.getColumnIndexDOM());

return true;
}

else if (e.getTypeInt() == Event.ONKEYDOWN) {

int rowDelta = 0;
int colDelta = 0;

if (e.getKeyCode() == KEYCODE_MOVE_VERTICAL) {
rowDelta = (e.getShiftKey() ? -1 : +1);
} else if (e.getKeyCode() == KEYCODE_MOVE_HORIZONTAL) {
colDelta = (e.getShiftKey() ? -1 : +1);
// Prevent tab out of Grid Editor
event.getDomEvent().preventDefault();
}

final boolean changed = rowDelta != 0 || colDelta != 0;

if (changed) {

int columnCount = event.getGrid().getVisibleColumns().size();

int colIndex = event.getFocusedColumnIndex() + colDelta;
int rowIndex = event.getRowIndex();

// Handle row change with horizontal move when column goes out
// of range.
if (rowDelta == 0) {
if (colIndex >= columnCount
&& rowIndex < event.getGrid().getDataSource().size()
- 1) {
rowDelta = 1;
colIndex = 0;
} else if (colIndex < 0 && rowIndex > 0) {
rowDelta = -1;
colIndex = columnCount - 1;
}
}

editRow(event, rowIndex + rowDelta, colIndex);
}

return changed;
}

return false;
}

/**
* Moves the editor to another column if the received event is a move event.
* By default the editor is moved on a keydown event with keycode
* {@link #KEYCODE_MOVE_HORIZONTAL}. This moves the editor left or right if
* shift key is pressed or not, respectively.
*
* @param event
* the received event
* @return true if this method handled the event and nothing else should be
* done, false otherwise
*/
protected boolean handleBufferedMoveEvent(EditorDomEvent<T> event) {
Event e = event.getDomEvent();

if (e.getType().equals(BrowserEvents.CLICK)
&& event.getRowIndex() == event.getCell().getRowIndex()) {

editRow(event, event.getRowIndex(),
event.getCell().getColumnIndexDOM());

return true;

} else if (e.getType().equals(BrowserEvents.KEYDOWN)
&& e.getKeyCode() == KEYCODE_MOVE_HORIZONTAL) {

// Prevent tab out of Grid Editor
event.getDomEvent().preventDefault();

editRow(event, event.getRowIndex(), event.getFocusedColumnIndex()
+ (e.getShiftKey() ? -1 : +1));

return true;
} else if (e.getType().equals(BrowserEvents.KEYDOWN)
&& e.getKeyCode() == KEYCODE_BUFFERED_SAVE) {
triggerValueChangeEvent(event);

// Save and close.
event.getGrid().getEditor().save();
return true;
}

return false;
}

/**
* Returns whether the given event should close the editor. The default
* implementation returns true if and only if the event is a keydown event
* and the keycode is {@link #KEYCODE_CLOSE}.
*
* @param event
* the received event
* @return true if the event is a close event, false otherwise
*/
protected boolean isCloseEvent(EditorDomEvent<T> event) {
final Event e = event.getDomEvent();
return e.getTypeInt() == Event.ONKEYDOWN
&& e.getKeyCode() == KEYCODE_CLOSE;
}

/**
* Closes the editor if the received event is a close event. The default
* implementation uses {@link #isCloseEvent(EditorDomEvent) isCloseEvent}.
*
* @param event
* the received event
* @return true if this method handled the event and nothing else should be
* done, false otherwise
*/
protected boolean handleCloseEvent(EditorDomEvent<T> event) {
if (isCloseEvent(event)) {
event.getEditor().cancel();
FocusUtil.setFocus(event.getGrid(), true);
return true;
}
return false;
}

protected void editRow(EditorDomEvent<T> event, int rowIndex,
int colIndex) {
int rowCount = event.getGrid().getDataSource().size();
// Limit rowIndex between 0 and rowCount - 1
rowIndex = Math.max(0, Math.min(rowCount - 1, rowIndex));

int colCount = event.getGrid().getVisibleColumns().size();
// Limit colIndex between 0 and colCount - 1
colIndex = Math.max(0, Math.min(colCount - 1, colIndex));

if (rowIndex != event.getRowIndex()) {
triggerValueChangeEvent(event);
}

event.getEditor().editRow(rowIndex, colIndex);
}

/**
* Triggers a value change event from the editor field if it has focus. This
* is based on the assumption that editor field will fire the value change
* when a blur event occurs.
*
* @param event
* the editor DOM event
*/
private void triggerValueChangeEvent(EditorDomEvent<T> event) {
// Force a blur to cause a value change event
Widget editorWidget = event.getEditorWidget();
if (editorWidget != null) {
Element focusedElement = WidgetUtil.getFocusedElement();
if (editorWidget.getElement().isOrHasChild(focusedElement)) {
focusedElement.blur();
focusedElement.focus();
}
}
}

@Override
public boolean handleEvent(EditorDomEvent<T> event) {
final Editor<T> editor = event.getEditor();
final boolean isBody = event.getCell().isBody();

final boolean handled;
if (event.getGrid().isEditorActive()) {
handled = handleCloseEvent(event)
|| (!editor.isBuffered() && isBody
&& handleMoveEvent(event))
|| (editor.isBuffered() && isBody
&& handleBufferedMoveEvent(event));
} else {
handled = event.getGrid().isEnabled() && isBody
&& handleOpenEvent(event);
}

// Buffered mode should swallow all events, if not already handled.
boolean swallowEvent = event.getGrid().isEditorActive()
&& editor.isBuffered();

return handled || swallowEvent;
}
}

+ 46
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/DetailsGenerator.java View File

@@ -0,0 +1,46 @@
/*
* 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.client.widget.grid;

import com.google.gwt.user.client.ui.Widget;

/**
* A callback interface for generating details for a particular row in Grid.
*
* @since 7.5.0
* @author Vaadin Ltd
*/
public interface DetailsGenerator {

/** A details generator that provides no details */
public static final DetailsGenerator NULL = new DetailsGenerator() {
@Override
public Widget getDetails(int rowIndex) {
return null;
}
};

/**
* This method is called for whenever a new details row needs to be
* generated.
*
* @param rowIndex
* the index of the row for which to generate details
* @return the details for the given row, or <code>null</code> to leave the
* details empty.
*/
Widget getDetails(int rowIndex);
}

+ 174
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/EditorHandler.java View File

@@ -0,0 +1,174 @@
/*
* 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.client.widget.grid;

import java.util.Collection;

import com.google.gwt.user.client.ui.Widget;
import com.vaadin.v7.client.widgets.Grid;

/**
* An interface for binding widgets and data to the grid row editor. Used by the
* editor to support different row types, data sources and custom data binding
* mechanisms.
*
* @param <T>
* the row data type
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface EditorHandler<T> {

/**
* A request class passed as a parameter to the editor handler methods. The
* request is callback-based to facilitate usage with remote or otherwise
* asynchronous data sources.
* <p>
* An implementation must call either {@link #success()} or {@link #fail()},
* according to whether the operation was a success or failed during
* execution, respectively.
*
* @param <T>
* the row data type
*/
public interface EditorRequest<T> {
/**
* Returns the index of the row being requested.
*
* @return the row index
*/
public int getRowIndex();

/**
* Returns the index of the column being focused.
*
* @return the column index
*/
public int getColumnIndex();

/**
* Returns the row data related to the row being requested.
*
* @return the row data
*/
public T getRow();

/**
* Returns the grid instance related to this editor request.
*
* @return the grid instance
*/
public Grid<T> getGrid();

/**
* Returns the editor widget used to edit the values of the given
* column.
*
* @param column
* the column whose widget to get
* @return the widget related to the column
*/
public Widget getWidget(Grid.Column<?, T> column);

/**
* Informs Grid that the editor request was a success.
*/
public void success();

/**
* Informs Grid that an error occurred while trying to process the
* request.
*
* @param errorMessage
* and error message to show to the user, or
* <code>null</code> to not show any message.
* @param errorColumns
* a collection of columns for which an error indicator
* should be shown, or <code>null</code> if no columns should
* be marked as erroneous.
*/
public void failure(String errorMessage,
Collection<Grid.Column<?, T>> errorColumns);

/**
* Checks whether the request is completed or not.
*
* @return <code>true</code> iff the request is completed
*/
public boolean isCompleted();
}

/**
* Binds row data to the editor widgets. Called by the editor when it is
* opened for editing.
* <p>
* The implementation <em>must</em> call either
* {@link EditorRequest#success()} or
* {@link EditorRequest#failure(String, Collection)} to signal a successful
* or a failed (respectively) bind action.
*
* @param request
* the data binding request
*
* @see Grid#editRow(int)
*/
public void bind(EditorRequest<T> request);

/**
* Called by the editor when editing is cancelled. This method may have an
* empty implementation in case no special processing is required.
* <p>
* In contrast to {@link #bind(EditorRequest)} and
* {@link #save(EditorRequest)}, any calls to
* {@link EditorRequest#success()} or
* {@link EditorRequest#failure(String, Collection)} have no effect on the
* outcome of the cancel action. The editor is already closed when this
* method is called.
*
* @param request
* the cancel request
*
* @see Grid#cancelEditor()
*/
public void cancel(EditorRequest<T> request);

/**
* Commits changes in the currently active edit to the data source. Called
* by the editor when changes are saved.
* <p>
* The implementation <em>must</em> call either
* {@link EditorRequest#success()} or {@link EditorRequest#fail()} to signal
* a successful or a failed (respectively) save action.
*
* @param request
* the save request
*
* @see Grid#saveEditor()
*/
public void save(EditorRequest<T> request);

/**
* Returns a widget instance that is used to edit the values in the given
* column. A null return value means the column is not editable.
*
* @param column
* the column whose values should be edited
* @return the editor widget for the column or null if the column is not
* editable
*/
public Widget getWidget(Grid.Column<?, T> column);
}

+ 128
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/EventCellReference.java View File

@@ -0,0 +1,128 @@
/*
* 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.client.widget.grid;

import com.google.gwt.dom.client.TableCellElement;
import com.vaadin.shared.ui.grid.GridConstants.Section;
import com.vaadin.v7.client.widget.escalator.Cell;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.client.widgets.Grid.Column;

/**
* A data class which contains information which identifies a cell being the
* target of an event from {@link Grid}.
* <p>
* Since this class follows the <code>Flyweight</code>-pattern any instance of
* this object is subject to change without the user knowing it and so should
* not be stored anywhere outside of the method providing these instances.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class EventCellReference<T> extends CellReference<T> {

private Section section;
private TableCellElement element;

public EventCellReference(Grid<T> grid) {
super(new RowReference<T>(grid));
}

/**
* Sets the RowReference and CellReference to point to given Cell.
*
* @param targetCell
* cell to point to
*/
public void set(Cell targetCell, Section section) {
Grid<T> grid = getGrid();

int columnIndexDOM = targetCell.getColumn();
Column<?, T> column = null;
if (columnIndexDOM >= 0
&& columnIndexDOM < grid.getVisibleColumns().size()) {
column = grid.getVisibleColumns().get(columnIndexDOM);
}

int row = targetCell.getRow();
// Row objects only make sense for body section of Grid.
T rowObject;
if (section == Section.BODY && row >= 0
&& row < grid.getDataSource().size()) {
rowObject = grid.getDataSource().getRow(row);
} else {
rowObject = null;
}

// At least for now we don't need to have the actual TableRowElement
// available.
getRowReference().set(row, rowObject, null);

int columnIndex = grid.getColumns().indexOf(column);
set(columnIndexDOM, columnIndex, column);

this.element = targetCell.getElement();
this.section = section;
}

@Override
public TableCellElement getElement() {
return element;
}

/**
* Is the cell reference for a cell in the header of the Grid.
*
* @since 7.5
* @return <code>true</true> if referenced cell is in the header,
* <code>false</code> if not
*/
public boolean isHeader() {
return section == Section.HEADER;
}

/**
* Is the cell reference for a cell in the body of the Grid.
*
* @since 7.5
* @return <code>true</true> if referenced cell is in the body,
* <code>false</code> if not
*/
public boolean isBody() {
return section == Section.BODY;
}

/**
* Is the cell reference for a cell in the footer of the Grid.
*
* @since 7.5
* @return <code>true</true> if referenced cell is in the footer,
* <code>false</code> if not
*/
public boolean isFooter() {
return section == Section.FOOTER;
}

/**
* Gets the Grid section where the referenced cell is.
*
* @since 7.5
* @return grid section
*/
public Section getSection() {
return section;
}
}

+ 45
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/HeightAwareDetailsGenerator.java View File

@@ -0,0 +1,45 @@
/*
* 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.client.widget.grid;

/**
* {@link DetailsGenerator} that is aware of content heights.
* <p>
* <b>FOR INTERNAL USE ONLY!</b> This class exists only for the sake of a
* temporary workaround and might be removed or renamed at any time.
* </p>
*
* @since 7.6.1
* @author Vaadin Ltd
*/
@Deprecated
public interface HeightAwareDetailsGenerator extends DetailsGenerator {

/**
* This method is called for whenever a details row's height needs to be
* calculated.
* <p>
* <b>FOR INTERNAL USE ONLY!</b> This method exists only for the sake of a
* temporary workaround and might be removed or renamed at any time.
* </p>
*
* @since 7.6.1
* @param rowIndex
* the index of the row for which to calculate details row height
* @return height of the details row
*/
public double getDetailsHeight(int rowIndex);
}

+ 93
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/RendererCellReference.java View File

@@ -0,0 +1,93 @@
/*
* 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.client.widget.grid;

import com.google.gwt.dom.client.TableCellElement;
import com.vaadin.v7.client.widget.escalator.FlyweightCell;
import com.vaadin.v7.client.widgets.Grid;

/**
* A data class which contains information which identifies a cell being
* rendered in a {@link Grid}.
* <p>
* Since this class follows the <code>Flyweight</code>-pattern any instance of
* this object is subject to change without the user knowing it and so should
* not be stored anywhere outside of the method providing these instances.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class RendererCellReference extends CellReference<Object> {

/**
* Creates a new renderer cell reference bound to a row reference.
*
* @param rowReference
* the row reference to bind to
*/
public RendererCellReference(RowReference<Object> rowReference) {
super(rowReference);
}

private FlyweightCell cell;

/**
* Sets the identifying information for this cell.
*
* @param cell
* the flyweight cell to reference
* @param columnIndex
* the index of the column in the grid, including hidden cells
* @param column
* the column to reference
*/
public void set(FlyweightCell cell, int columnIndex,
Grid.Column<?, ?> column) {
this.cell = cell;
super.set(cell.getColumn(), columnIndex,
(Grid.Column<?, Object>) column);
}

/**
* Returns the element of the cell. Can be either a <code>TD</code> element
* or a <code>TH</code> element.
*
* @return the element of the cell
*/
@Override
public TableCellElement getElement() {
return cell.getElement();
}

/**
* Sets the colspan attribute of the element of this cell.
*
* @param numberOfCells
* the number of columns that the cell should span
*/
public void setColSpan(int numberOfCells) {
cell.setColSpan(numberOfCells);
}

/**
* Gets the colspan attribute of the element of this cell.
*
* @return the number of columns that the cell should span
*/
public int getColSpan() {
return cell.getColSpan();
}
}

+ 104
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/RowReference.java View File

@@ -0,0 +1,104 @@
/*
* 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.client.widget.grid;

import com.google.gwt.dom.client.TableRowElement;
import com.vaadin.v7.client.widgets.Grid;

/**
* A data class which contains information which identifies a row in a
* {@link Grid}.
* <p>
* Since this class follows the <code>Flyweight</code>-pattern any instance of
* this object is subject to change without the user knowing it and so should
* not be stored anywhere outside of the method providing these instances.
*
* @author Vaadin Ltd
* @param <T>
* the row object type
* @since 7.4
*/
public class RowReference<T> {
private final Grid<T> grid;

private int rowIndex;
private T row;

private TableRowElement element;

/**
* Creates a new row reference for the given grid.
*
* @param grid
* the grid that the row belongs to
*/
public RowReference(Grid<T> grid) {
this.grid = grid;
}

/**
* Sets the identifying information for this row.
*
* @param rowIndex
* the index of the row
* @param row
* the row object
* @param elemenet
* the element of the row
*/
public void set(int rowIndex, T row, TableRowElement element) {
this.rowIndex = rowIndex;
this.row = row;
this.element = element;
}

/**
* Gets the grid that contains the referenced row.
*
* @return the grid that contains referenced row
*/
public Grid<T> getGrid() {
return grid;
}

/**
* Gets the row index of the row.
*
* @return the index of the row
*/
public int getRowIndex() {
return rowIndex;
}

/**
* Gets the row data object.
*
* @return the row object
*/
public T getRow() {
return row;
}

/**
* Gets the table row element of the row.
*
* @return the element of the row
*/
public TableRowElement getElement() {
return element;
}

}

+ 40
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/RowStyleGenerator.java View File

@@ -0,0 +1,40 @@
/*
* 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.client.widget.grid;

import java.io.Serializable;

/**
* Callback interface for generating custom style names for data rows
*
* @author Vaadin Ltd
* @param <T>
* the row type of the target grid
* @see Grid#setRowStyleGenerator(RowStyleGenerator)
* @since 7.4
*/
public interface RowStyleGenerator<T> extends Serializable {

/**
* Called by Grid to generate a style name for a row.
*
* @param rowReference
* The row to generate a style for
* @return the style name to add to this row, or {@code null} to not set any
* style
*/
public abstract String getStyle(RowReference<T> rowReference);
}

+ 465
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/datasources/ListDataSource.java View File

@@ -0,0 +1,465 @@
/*
* 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.client.widget.grid.datasources;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;

import com.vaadin.client.data.DataChangeHandler;
import com.vaadin.client.data.DataSource;
import com.vaadin.shared.Registration;
import com.vaadin.shared.util.SharedUtil;
import com.vaadin.v7.client.widget.grid.events.SelectAllEvent;
import com.vaadin.v7.client.widget.grid.events.SelectAllHandler;

/**
* A simple list based on an in-memory data source for simply adding a list of
* row pojos to the grid. Based on a wrapped list instance which supports adding
* and removing of items.
*
* <p>
* Usage:
*
* <pre>
* ListDataSource&lt;Integer&gt; ds = new ListDataSource&lt;Integer&gt;(1, 2, 3, 4);
*
* // Add item to the data source
* ds.asList().add(5);
*
* // Remove item from the data source
* ds.asList().remove(3);
*
* // Add multiple items
* ds.asList().addAll(Arrays.asList(5, 6, 7));
* </pre>
*
* @since 7.4
* @author Vaadin Ltd
*/
public class ListDataSource<T> implements DataSource<T> {

private class RowHandleImpl extends RowHandle<T> {

private final T row;

public RowHandleImpl(T row) {
this.row = row;
}

@Override
public T getRow() {
/*
* We'll cheat here and don't throw an IllegalStateException even if
* this isn't pinned, because we know that the reference never gets
* stale.
*/
return row;
}

@Override
public void pin() {
// NOOP, really
}

@Override
public void unpin() throws IllegalStateException {
/*
* Just to make things easier for everyone, we won't throw the
* exception, even in illegal situations.
*/
}

@Override
protected boolean equalsExplicit(Object obj) {
if (obj instanceof ListDataSource.RowHandleImpl) {
/*
* Java prefers AbstractRemoteDataSource<?>.RowHandleImpl. I
* like the @SuppressWarnings more (keeps the line length in
* check.)
*/
@SuppressWarnings("unchecked")
RowHandleImpl rhi = (RowHandleImpl) obj;
return SharedUtil.equals(row, rhi.row);
} else {
return false;
}
}

@Override
protected int hashCodeExplicit() {
return row.hashCode();
}

@Override
public void updateRow() {
getHandlers()
.forEach(dch -> dch.dataUpdated(ds.indexOf(getRow()), 1));
}
}

/**
* Wraps the datasource list and notifies the change handler of changing to
* the list
*/
private class ListWrapper implements List<T> {

@Override
public int size() {
return ds.size();
}

@Override
public boolean isEmpty() {
return ds.isEmpty();
}

@Override
public boolean contains(Object o) {
return ds.contains(o);
}

@Override
public Iterator<T> iterator() {
return new ListWrapperIterator(ds.iterator());
}

@Override
public Object[] toArray() {
return ds.toArray();
}

@Override
@SuppressWarnings("hiding")
public <T> T[] toArray(T[] a) {
return ds.toArray(a);
}

@Override
public boolean add(T e) {
if (ds.add(e)) {
getHandlers().forEach(dch -> dch.dataAdded(ds.size() - 1, 1));
return true;
}
return false;
}

@Override
public boolean remove(Object o) {
int index = ds.indexOf(o);
if (ds.remove(o)) {
getHandlers().forEach(dch -> dch.dataRemoved(index, 1));
return true;
}
return false;
}

@Override
public boolean containsAll(Collection<?> c) {
return ds.containsAll(c);
}

@Override
public boolean addAll(Collection<? extends T> c) {
int idx = ds.size();
if (ds.addAll(c)) {
getHandlers().forEach(dch -> dch.dataAdded(idx, c.size()));
return true;
}
return false;
}

@Override
public boolean addAll(int index, Collection<? extends T> c) {
if (ds.addAll(index, c)) {
getHandlers().forEach(dch -> dch.dataAdded(index, c.size()));
return true;
}
return false;
}

@Override
public boolean removeAll(Collection<?> c) {
if (ds.removeAll(c)) {
getHandlers().forEach(dch -> dch.dataUpdated(0, ds.size()));
getHandlers().forEach(dch -> dch.dataAvailable(0, ds.size()));
return true;
}
return false;
}

@Override
public boolean retainAll(Collection<?> c) {
if (ds.retainAll(c)) {
getHandlers().forEach(dch -> dch.dataUpdated(0, ds.size()));
getHandlers().forEach(dch -> dch.dataAvailable(0, ds.size()));
return true;
}
return false;
}

@Override
public void clear() {
int size = ds.size();
ds.clear();
getHandlers().forEach(dch -> dch.dataRemoved(0, size));
}

@Override
public T get(int index) {
return ds.get(index);
}

@Override
public T set(int index, T element) {
T prev = ds.set(index, element);
getHandlers().forEach(dch -> dch.dataUpdated(index, 1));
return prev;
}

@Override
public void add(int index, T element) {
ds.add(index, element);
getHandlers().forEach(dch -> dch.dataAdded(index, 1));
}

@Override
public T remove(int index) {
T removed = ds.remove(index);
getHandlers().forEach(dch -> dch.dataRemoved(index, 1));
return removed;
}

@Override
public int indexOf(Object o) {
return ds.indexOf(o);
}

@Override
public int lastIndexOf(Object o) {
return ds.lastIndexOf(o);
}

@Override
public ListIterator<T> listIterator() {
// TODO could be implemented by a custom iterator.
throw new UnsupportedOperationException(
"List iterators not supported at this time.");
}

@Override
public ListIterator<T> listIterator(int index) {
// TODO could be implemented by a custom iterator.
throw new UnsupportedOperationException(
"List iterators not supported at this time.");
}

@Override
public List<T> subList(int fromIndex, int toIndex) {
throw new UnsupportedOperationException("Sub lists not supported.");
}
}

/**
* Iterator returned by {@link ListWrapper}
*/
private class ListWrapperIterator implements Iterator<T> {

private final Iterator<T> iterator;

/**
* Constructs a new iterator
*/
public ListWrapperIterator(Iterator<T> iterator) {
this.iterator = iterator;
}

@Override
public boolean hasNext() {
return iterator.hasNext();
}

@Override
public T next() {
return iterator.next();
}

@Override
public void remove() {
throw new UnsupportedOperationException(
"Iterator.remove() is not supported by this iterator.");
}
}

/**
* Datasource for providing row pojo's
*/
private final List<T> ds;

/**
* Wrapper that wraps the data source
*/
private final ListWrapper wrapper;

/**
* Handler for listening to changes in the underlying list.
*/
private Set<DataChangeHandler> changeHandlers = new LinkedHashSet<>();

/**
* Constructs a new list data source.
* <p>
* Note: Modifications to the original list will not be reflected in the
* data source after the data source has been constructed. To add or remove
* items to the data source after it has been constructed use
* {@link ListDataSource#asList()}.
*
*
* @param datasource
* The list to use for providing the data to the grid
*/
public ListDataSource(List<T> datasource) {
if (datasource == null) {
throw new IllegalArgumentException("datasource cannot be null");
}
ds = new ArrayList<T>(datasource);
wrapper = new ListWrapper();
}

/**
* Constructs a data source with a set of rows. You can dynamically add and
* remove rows from the data source via the list you get from
* {@link ListDataSource#asList()}
*
* @param rows
* The rows to initially add to the data source
*/
public ListDataSource(T... rows) {
if (rows == null) {
ds = new ArrayList<T>();
} else {
ds = new ArrayList<T>(Arrays.asList(rows));
}
wrapper = new ListWrapper();
}

@Override
public void ensureAvailability(int firstRowIndex, int numberOfRows) {
if (firstRowIndex >= ds.size()) {
throw new IllegalStateException(
"Trying to fetch rows outside of array");
}

getHandlers()
.forEach(dch -> dch.dataAvailable(firstRowIndex, numberOfRows));
}

@Override
public T getRow(int rowIndex) {
return ds.get(rowIndex);
}

@Override
public int size() {
return ds.size();
}

@Override
public Registration addDataChangeHandler(
DataChangeHandler dataChangeHandler) {
Objects.requireNonNull(dataChangeHandler,
"DataChangeHandler can't be null");
changeHandlers.add(dataChangeHandler);
return () -> changeHandlers.remove(dataChangeHandler);
}

/**
* Gets the list that backs this datasource. Any changes made to this list
* will be reflected in the datasource.
* <p>
* Note: The list is not the same list as passed into the data source via
* the constructor.
*
* @return Returns a list implementation that wraps the real list that backs
* the data source and provides events for the data source
* listeners.
*/
public List<T> asList() {
return wrapper;
}

@Override
public RowHandle<T> getHandle(T row) throws IllegalStateException {
assert ds.contains(row) : "This data source doesn't contain the row "
+ row;
return new RowHandleImpl(row);
}

/**
* Sort entire container according to a {@link Comparator}.
*
* @param comparator
* a comparator object, which compares two data source entries
* (beans/pojos)
*/
public void sort(Comparator<T> comparator) {
Collections.sort(ds, comparator);
getHandlers().forEach(dch -> dch.dataUpdated(0, ds.size()));
}

/**
* Retrieves the index for given row object.
* <p>
* <em>Note:</em> This method does not verify that the given row object
* exists at all in this DataSource.
*
* @param row
* the row object
* @return index of the row; or <code>-1</code> if row is not available
*/
public int indexOf(T row) {
return ds.indexOf(row);
}

/**
* Returns a {@link SelectAllHandler} for this ListDataSource.
*
* @return select all handler
*/
public SelectAllHandler<T> getSelectAllHandler() {
return new SelectAllHandler<T>() {
@Override
public void onSelectAll(SelectAllEvent<T> event) {
event.getSelectionModel().select(asList());
}
};
}

private Stream<DataChangeHandler> getHandlers() {
Set<DataChangeHandler> copy = new LinkedHashSet<>(changeHandlers);
return copy.stream();
}

}

+ 176
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/datasources/ListSorter.java View File

@@ -0,0 +1,176 @@
/*
* 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.client.widget.grid.datasources;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.event.shared.HandlerRegistration;
import com.vaadin.client.data.DataSource;
import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.v7.client.widget.grid.sort.SortEvent;
import com.vaadin.v7.client.widget.grid.sort.SortHandler;
import com.vaadin.v7.client.widget.grid.sort.SortOrder;
import com.vaadin.v7.client.widgets.Grid;

/**
* Provides sorting facility from Grid for the {@link ListDataSource} in-memory
* data source.
*
* @author Vaadin Ltd
* @param <T>
* Grid row data type
* @since 7.4
*/
public class ListSorter<T> {

private Grid<T> grid;
private Map<Grid.Column<?, T>, Comparator<?>> comparators;
private HandlerRegistration sortHandlerRegistration;

public ListSorter(Grid<T> grid) {

if (grid == null) {
throw new IllegalArgumentException("Grid can not be null");
}

this.grid = grid;
comparators = new HashMap<Grid.Column<?, T>, Comparator<?>>();

sortHandlerRegistration = grid.addSortHandler(new SortHandler<T>() {
@Override
public void sort(SortEvent<T> event) {
ListSorter.this.sort(event.getOrder());
}
});
}

/**
* Detach this Sorter from the Grid. This unregisters the sort event handler
* which was used to apply sorting to the ListDataSource.
*/
public void removeFromGrid() {
sortHandlerRegistration.removeHandler();
}

/**
* Assign or remove a comparator for a column. This comparator method, if
* defined, is always used in favour of 'natural' comparison of objects
* (i.e. the compareTo of objects implementing the Comparable interface,
* which includes all standard data classes like String, Number derivatives
* and Dates). Any existing comparator can be removed by passing in a
* non-null GridColumn and a null Comparator.
*
* @param column
* a grid column. May not be null.
* @param comparator
* comparator method for the values returned by the grid column.
* If null, any existing comparator is removed.
*/
public <C> void setComparator(Grid.Column<C, T> column,
Comparator<C> comparator) {
if (column == null) {
throw new IllegalArgumentException(
"Column reference can not be null");
}
if (comparator == null) {
comparators.remove(column);
} else {
comparators.put(column, comparator);
}
}

/**
* Retrieve the comparator assigned for a specific grid column.
*
* @param column
* a grid column. May not be null.
* @return a comparator, or null if no comparator for the specified grid
* column has been set.
*/
@SuppressWarnings("unchecked")
public <C> Comparator<C> getComparator(Grid.Column<C, T> column) {
if (column == null) {
throw new IllegalArgumentException(
"Column reference can not be null");
}
return (Comparator<C>) comparators.get(column);
}

/**
* Remove all comparator mappings. Useful if the data source has changed but
* this Sorter is being re-used.
*/
public void clearComparators() {
comparators.clear();
}

/**
* Apply sorting to the current ListDataSource.
*
* @param order
* the sort order list provided by the grid sort event
*/
private void sort(final List<SortOrder> order) {
DataSource<T> ds = grid.getDataSource();
if (!(ds instanceof ListDataSource)) {
throw new IllegalStateException(
"Grid " + grid + " data source is not a ListDataSource!");
}

((ListDataSource<T>) ds).sort(new Comparator<T>() {

@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public int compare(T a, T b) {

for (SortOrder o : order) {

Grid.Column column = o.getColumn();
Comparator cmp = ListSorter.this.comparators.get(column);
int result = 0;
Object value_a = column.getValue(a);
Object value_b = column.getValue(b);
if (cmp != null) {
result = cmp.compare(value_a, value_b);
} else {
if (!(value_a instanceof Comparable)) {
throw new IllegalStateException("Column " + column
+ " has no assigned comparator and value "
+ value_a + " isn't naturally comparable");
}
result = ((Comparable) value_a).compareTo(value_b);
}

if (result != 0) {
return o.getDirection() == SortDirection.ASCENDING
? result : -result;
}
}

if (order.size() > 0) {
return order.get(0)
.getDirection() == SortDirection.ASCENDING
? a.hashCode() - b.hashCode()
: b.hashCode() - a.hashCode();
}
return a.hashCode() - b.hashCode();
}
});
}
}

+ 44
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/AbstractGridKeyEventHandler.java View File

@@ -0,0 +1,44 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.EventHandler;
import com.vaadin.v7.client.widgets.Grid.AbstractGridKeyEvent;

/**
* Base interface of all handlers for {@link AbstractGridKeyEvent}s.
*
* @since 7.4
* @author Vaadin Ltd
*/
public abstract interface AbstractGridKeyEventHandler extends EventHandler {

public abstract interface GridKeyDownHandler
extends AbstractGridKeyEventHandler {
public void onKeyDown(GridKeyDownEvent event);
}

public abstract interface GridKeyUpHandler
extends AbstractGridKeyEventHandler {
public void onKeyUp(GridKeyUpEvent event);
}

public abstract interface GridKeyPressHandler
extends AbstractGridKeyEventHandler {
public void onKeyPress(GridKeyPressEvent event);
}

}

+ 39
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/AbstractGridMouseEventHandler.java View File

@@ -0,0 +1,39 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.EventHandler;
import com.vaadin.v7.client.widgets.Grid.AbstractGridMouseEvent;

/**
* Base interface of all handlers for {@link AbstractGridMouseEvent}s.
*
* @since 7.4
* @author Vaadin Ltd
*/
public abstract interface AbstractGridMouseEventHandler extends EventHandler {

public abstract interface GridClickHandler
extends AbstractGridMouseEventHandler {
public void onClick(GridClickEvent event);
}

public abstract interface GridDoubleClickHandler
extends AbstractGridMouseEventHandler {
public void onDoubleClick(GridDoubleClickEvent event);
}

}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyClickHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridMouseEventHandler.GridClickHandler;

/**
* Handler for {@link GridClickEvent}s that happen in the body of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface BodyClickHandler extends GridClickHandler {

}

+ 29
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyDoubleClickHandler.java View File

@@ -0,0 +1,29 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridMouseEventHandler.GridDoubleClickHandler;

/**
* Handler for {@link GridDoubleClickEvent}s that happen in the body of the
* Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface BodyDoubleClickHandler extends GridDoubleClickHandler {

}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyKeyDownHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler;

/**
* Handler for {@link GridKeyDownEvent}s that happen when the focused cell is in
* the body of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface BodyKeyDownHandler extends GridKeyDownHandler {
}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyKeyPressHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler;

/**
* Handler for {@link GridKeyPressEvent}s that happen when the focused cell is
* in the body of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface BodyKeyPressHandler extends GridKeyPressHandler {
}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/BodyKeyUpHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler;

/**
* Handler for {@link GridKeyUpEvent}s that happen when the focused cell is in
* the body of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface BodyKeyUpHandler extends GridKeyUpHandler {
}

+ 51
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnReorderEvent.java View File

@@ -0,0 +1,51 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.GwtEvent;

/**
* An event for notifying that the columns in the Grid have been reordered.
*
* @param <T>
* The row type of the grid. The row type is the POJO type from where
* the data is retrieved into the column cells.
* @since 7.5.0
* @author Vaadin Ltd
*/
public class ColumnReorderEvent<T> extends GwtEvent<ColumnReorderHandler<T>> {

/**
* Handler type.
*/
private final static Type<ColumnReorderHandler<?>> TYPE = new Type<ColumnReorderHandler<?>>();

public static final Type<ColumnReorderHandler<?>> getType() {
return TYPE;
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Type<ColumnReorderHandler<T>> getAssociatedType() {
return (Type) TYPE;
}

@Override
protected void dispatch(ColumnReorderHandler<T> handler) {
handler.onColumnReorder(this);
}

}

+ 40
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnReorderHandler.java View File

@@ -0,0 +1,40 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.EventHandler;

/**
* Handler for a Grid column reorder event, called when the Grid's columns has
* been reordered.
*
* @param <T>
* The row type of the grid. The row type is the POJO type from where
* the data is retrieved into the column cells.
* @since 7.5.0
* @author Vaadin Ltd
*/
public interface ColumnReorderHandler<T> extends EventHandler {

/**
* A column reorder event, fired by Grid when the columns of the Grid have
* been reordered.
*
* @param event
* column reorder event
*/
public void onColumnReorder(ColumnReorderEvent<T> event);
}

+ 67
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnResizeEvent.java View File

@@ -0,0 +1,67 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.GwtEvent;
import com.vaadin.v7.client.widgets.Grid.Column;

/**
* An event for notifying that the columns in the Grid have been resized.
*
* @param <T>
* The row type of the grid. The row type is the POJO type from where
* the data is retrieved into the column cells.
* @since 7.6
* @author Vaadin Ltd
*/
public class ColumnResizeEvent<T> extends GwtEvent<ColumnResizeHandler<T>> {

/**
* Handler type.
*/
private final static Type<ColumnResizeHandler<?>> TYPE = new Type<ColumnResizeHandler<?>>();

private Column<?, T> column;

/**
* @param column
*/
public ColumnResizeEvent(Column<?, T> column) {
this.column = column;
}

public static final Type<ColumnResizeHandler<?>> getType() {
return TYPE;
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Type<ColumnResizeHandler<T>> getAssociatedType() {
return (Type) TYPE;
}

@Override
protected void dispatch(ColumnResizeHandler<T> handler) {
handler.onColumnResize(this);
}

/**
* @return the column
*/
public Column<?, T> getColumn() {
return column;
}
}

+ 40
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnResizeHandler.java View File

@@ -0,0 +1,40 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.EventHandler;

/**
* Handler for a Grid column resize event, called when the Grid's columns has
* been resized.
*
* @param <T>
* The row type of the grid. The row type is the POJO type from where
* the data is retrieved into the column cells.
* @since 7.6
* @author Vaadin Ltd
*/
public interface ColumnResizeHandler<T> extends EventHandler {

/**
* A column resize event, fired by Grid when the columns of the Grid have
* been resized.
*
* @param event
* column resize event
*/
public void onColumnResize(ColumnResizeEvent<T> event);
}

+ 93
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnVisibilityChangeEvent.java View File

@@ -0,0 +1,93 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.GwtEvent;
import com.vaadin.v7.client.widgets.Grid.Column;

/**
* An event for notifying that the columns in the Grid's have changed
* visibility.
*
* @param <T>
* The row type of the grid. The row type is the POJO type from where
* the data is retrieved into the column cells.
* @since 7.5.0
* @author Vaadin Ltd
*/
public class ColumnVisibilityChangeEvent<T>
extends GwtEvent<ColumnVisibilityChangeHandler<T>> {

private final static Type<ColumnVisibilityChangeHandler<?>> TYPE = new Type<ColumnVisibilityChangeHandler<?>>();

public static final Type<ColumnVisibilityChangeHandler<?>> getType() {
return TYPE;
}

private final Column<?, T> column;

private final boolean userOriginated;

private final boolean hidden;

public ColumnVisibilityChangeEvent(Column<?, T> column, boolean hidden,
boolean userOriginated) {
this.column = column;
this.hidden = hidden;
this.userOriginated = userOriginated;
}

/**
* Returns the column where the visibility change occurred.
*
* @return the column where the visibility change occurred.
*/
public Column<?, T> getColumn() {
return column;
}

/**
* Was the column set hidden or visible.
*
* @return <code>true</code> if the column was hidden <code>false</code> if
* it was set visible
*/
public boolean isHidden() {
return hidden;
}

/**
* Is the visibility change triggered by user.
*
* @return <code>true</code> if the change was triggered by user,
* <code>false</code> if not
*/
public boolean isUserOriginated() {
return userOriginated;
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public com.google.gwt.event.shared.GwtEvent.Type<ColumnVisibilityChangeHandler<T>> getAssociatedType() {
return (Type) TYPE;
}

@Override
protected void dispatch(ColumnVisibilityChangeHandler<T> handler) {
handler.onVisibilityChange(this);
}

}

+ 41
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ColumnVisibilityChangeHandler.java View File

@@ -0,0 +1,41 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.EventHandler;

/**
* Handler for a Grid column visibility change event, called when the Grid's
* columns have changed visibility to hidden or visible.
*
* @param<T> The
* row type of the grid. The row type is the POJO type from where
* the data is retrieved into the column cells.
*
* @since 7.5.0
* @author Vaadin Ltd
*/
public interface ColumnVisibilityChangeHandler<T> extends EventHandler {

/**
* A column visibility change event, fired by Grid when a column in the Grid
* has changed visibility.
*
* @param event
* column visibility change event
*/
public void onVisibilityChange(ColumnVisibilityChangeEvent<T> event);
}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterClickHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridMouseEventHandler.GridClickHandler;

/**
* Handler for {@link GridClickEvent}s that happen in the footer of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface FooterClickHandler extends GridClickHandler {

}

+ 29
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterDoubleClickHandler.java View File

@@ -0,0 +1,29 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridMouseEventHandler.GridDoubleClickHandler;

/**
* Handler for {@link GridDoubleClickEvent}s that happen in the footer of the
* Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface FooterDoubleClickHandler extends GridDoubleClickHandler {

}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterKeyDownHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler;

/**
* Handler for {@link GridKeyDownEvent}s that happen when the focused cell is in
* the footer of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface FooterKeyDownHandler extends GridKeyDownHandler {
}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterKeyPressHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler;

/**
* Handler for {@link GridKeyPressEvent}s that happen when the focused cell is
* in the footer of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface FooterKeyPressHandler extends GridKeyPressHandler {
}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/FooterKeyUpHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler;

/**
* Handler for {@link GridKeyUpEvent}s that happen when the focused cell is in
* the footer of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface FooterKeyUpHandler extends GridKeyUpHandler {
}

+ 52
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridClickEvent.java View File

@@ -0,0 +1,52 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.dom.client.BrowserEvents;
import com.vaadin.shared.ui.grid.GridConstants.Section;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.events.AbstractGridMouseEventHandler.GridClickHandler;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.client.widgets.Grid.AbstractGridMouseEvent;

/**
* Represents native mouse click event in Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class GridClickEvent extends AbstractGridMouseEvent<GridClickHandler> {

public GridClickEvent(Grid<?> grid, CellReference<?> targetCell) {
super(grid, targetCell);
}

@Override
protected String getBrowserEventType() {
return BrowserEvents.CLICK;
}

@Override
protected void doDispatch(GridClickHandler handler, Section section) {
if ((section == Section.BODY && handler instanceof BodyClickHandler)
|| (section == Section.HEADER
&& handler instanceof HeaderClickHandler)
|| (section == Section.FOOTER
&& handler instanceof FooterClickHandler)) {
handler.onClick(this);
}
}
}

+ 55
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridDoubleClickEvent.java View File

@@ -0,0 +1,55 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.dom.client.BrowserEvents;
import com.vaadin.shared.ui.grid.GridConstants.Section;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.events.AbstractGridMouseEventHandler.GridDoubleClickHandler;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.client.widgets.Grid.AbstractGridMouseEvent;

/**
* Represents native mouse double click event in Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class GridDoubleClickEvent
extends AbstractGridMouseEvent<GridDoubleClickHandler> {

public GridDoubleClickEvent(Grid<?> grid, CellReference<?> targetCell) {
super(grid, targetCell);
}

@Override
protected String getBrowserEventType() {
return BrowserEvents.DBLCLICK;
}

@Override
protected void doDispatch(GridDoubleClickHandler handler, Section section) {
if ((section == Section.BODY
&& handler instanceof BodyDoubleClickHandler)
|| (section == Section.HEADER
&& handler instanceof HeaderDoubleClickHandler)
|| (section == Section.FOOTER
&& handler instanceof FooterDoubleClickHandler)) {
handler.onDoubleClick(this);
}
}

}

+ 46
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridEnabledEvent.java View File

@@ -0,0 +1,46 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.GwtEvent;

/**
* An enabled/disabled event, fired by the Grid when it is disabled or enabled.
*
* @since 7.7
* @author Vaadin Ltd
*/
public class GridEnabledEvent extends GwtEvent<GridEnabledHandler> {
/**
* The type of this event
*/
public static final Type<GridEnabledHandler> TYPE = new Type<GridEnabledHandler>();
private final boolean enabled;

public GridEnabledEvent(boolean enabled) {
this.enabled = enabled;
}

@Override
public Type<GridEnabledHandler> getAssociatedType() {
return TYPE;
}

@Override
protected void dispatch(final GridEnabledHandler handler) {
handler.onEnabled(enabled);
}
}

+ 37
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridEnabledHandler.java View File

@@ -0,0 +1,37 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.EventHandler;

/**
* Handler for a Grid enabled/disabled event, called when the Grid is enabled or
* disabled.
*
* @since 7.7
* @author Vaadin Ltd
*/
public interface GridEnabledHandler extends EventHandler {

/**
* Called when Grid is enabled or disabled.
*
* @param enabled
* true if status changes from disabled to enabled, otherwise
* false.
*/
public void onEnabled(boolean enabled);
}

+ 123
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridKeyDownEvent.java View File

@@ -0,0 +1,123 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.event.dom.client.KeyCodes;
import com.vaadin.shared.ui.grid.GridConstants.Section;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.client.widgets.Grid.AbstractGridKeyEvent;

/**
* Represents native key down event in Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class GridKeyDownEvent extends AbstractGridKeyEvent<GridKeyDownHandler> {

public GridKeyDownEvent(Grid<?> grid, CellReference<?> targetCell) {
super(grid, targetCell);
}

@Override
protected void doDispatch(GridKeyDownHandler handler, Section section) {
if ((section == Section.BODY && handler instanceof BodyKeyDownHandler)
|| (section == Section.HEADER
&& handler instanceof HeaderKeyDownHandler)
|| (section == Section.FOOTER
&& handler instanceof FooterKeyDownHandler)) {
handler.onKeyDown(this);
}
}

@Override
protected String getBrowserEventType() {
return BrowserEvents.KEYDOWN;
}

/**
* Does the key code represent an arrow key?
*
* @param keyCode
* the key code
* @return if it is an arrow key code
*/
public static boolean isArrow(int keyCode) {
switch (keyCode) {
case KeyCodes.KEY_DOWN:
case KeyCodes.KEY_RIGHT:
case KeyCodes.KEY_UP:
case KeyCodes.KEY_LEFT:
return true;
default:
return false;
}
}

/**
* Gets the native key code. These key codes are enumerated in the
* {@link KeyCodes} class.
*
* @return the key code
*/
public int getNativeKeyCode() {
return getNativeEvent().getKeyCode();
}

/**
* Is this a key down arrow?
*
* @return whether this is a down arrow key event
*/
public boolean isDownArrow() {
return getNativeKeyCode() == KeyCodes.KEY_DOWN;
}

/**
* Is this a left arrow?
*
* @return whether this is a left arrow key event
*/
public boolean isLeftArrow() {
return getNativeKeyCode() == KeyCodes.KEY_LEFT;
}

/**
* Is this a right arrow?
*
* @return whether this is a right arrow key event
*/
public boolean isRightArrow() {
return getNativeKeyCode() == KeyCodes.KEY_RIGHT;
}

/**
* Is this a up arrow?
*
* @return whether this is a right arrow key event
*/
public boolean isUpArrow() {
return getNativeKeyCode() == KeyCodes.KEY_UP;
}

@Override
public String toDebugString() {
return super.toDebugString() + "[" + getNativeKeyCode() + "]";
}
}

+ 76
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridKeyPressEvent.java View File

@@ -0,0 +1,76 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.dom.client.BrowserEvents;
import com.vaadin.shared.ui.grid.GridConstants.Section;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.client.widgets.Grid.AbstractGridKeyEvent;

/**
* Represents native key press event in Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class GridKeyPressEvent
extends AbstractGridKeyEvent<GridKeyPressHandler> {

public GridKeyPressEvent(Grid<?> grid, CellReference<?> targetCell) {
super(grid, targetCell);
}

@Override
protected void doDispatch(GridKeyPressHandler handler, Section section) {
if ((section == Section.BODY && handler instanceof BodyKeyPressHandler)
|| (section == Section.HEADER
&& handler instanceof HeaderKeyPressHandler)
|| (section == Section.FOOTER
&& handler instanceof FooterKeyPressHandler)) {
handler.onKeyPress(this);
}
}

@Override
protected String getBrowserEventType() {
return BrowserEvents.KEYPRESS;
}

/**
* Gets the char code for this event.
*
* @return the char code
*/
public char getCharCode() {
return (char) getUnicodeCharCode();
}

/**
* Gets the Unicode char code (code point) for this event.
*
* @return the Unicode char code
*/
public int getUnicodeCharCode() {
return getNativeEvent().getCharCode();
}

@Override
public String toDebugString() {
return super.toDebugString() + "[" + getCharCode() + "]";
}
}

+ 123
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/GridKeyUpEvent.java View File

@@ -0,0 +1,123 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.event.dom.client.KeyCodes;
import com.vaadin.shared.ui.grid.GridConstants.Section;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.client.widgets.Grid.AbstractGridKeyEvent;

/**
* Represents native key up event in Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class GridKeyUpEvent extends AbstractGridKeyEvent<GridKeyUpHandler> {

public GridKeyUpEvent(Grid<?> grid, CellReference<?> targetCell) {
super(grid, targetCell);
}

@Override
protected void doDispatch(GridKeyUpHandler handler, Section section) {
if ((section == Section.BODY && handler instanceof BodyKeyUpHandler)
|| (section == Section.HEADER
&& handler instanceof HeaderKeyUpHandler)
|| (section == Section.FOOTER
&& handler instanceof FooterKeyUpHandler)) {
handler.onKeyUp(this);
}
}

@Override
protected String getBrowserEventType() {
return BrowserEvents.KEYUP;
}

/**
* Does the key code represent an arrow key?
*
* @param keyCode
* the key code
* @return if it is an arrow key code
*/
public static boolean isArrow(int keyCode) {
switch (keyCode) {
case KeyCodes.KEY_DOWN:
case KeyCodes.KEY_RIGHT:
case KeyCodes.KEY_UP:
case KeyCodes.KEY_LEFT:
return true;
default:
return false;
}
}

/**
* Gets the native key code. These key codes are enumerated in the
* {@link KeyCodes} class.
*
* @return the key code
*/
public int getNativeKeyCode() {
return getNativeEvent().getKeyCode();
}

/**
* Is this a key down arrow?
*
* @return whether this is a down arrow key event
*/
public boolean isDownArrow() {
return getNativeKeyCode() == KeyCodes.KEY_DOWN;
}

/**
* Is this a left arrow?
*
* @return whether this is a left arrow key event
*/
public boolean isLeftArrow() {
return getNativeKeyCode() == KeyCodes.KEY_LEFT;
}

/**
* Is this a right arrow?
*
* @return whether this is a right arrow key event
*/
public boolean isRightArrow() {
return getNativeKeyCode() == KeyCodes.KEY_RIGHT;
}

/**
* Is this a up arrow?
*
* @return whether this is a right arrow key event
*/
public boolean isUpArrow() {
return getNativeKeyCode() == KeyCodes.KEY_UP;
}

@Override
public String toDebugString() {
return super.toDebugString() + "[" + getNativeKeyCode() + "]";
}
}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderClickHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridMouseEventHandler.GridClickHandler;

/**
* Handler for {@link GridClickEvent}s that happen in the header of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface HeaderClickHandler extends GridClickHandler {

}

+ 29
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderDoubleClickHandler.java View File

@@ -0,0 +1,29 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridMouseEventHandler.GridDoubleClickHandler;

/**
* Handler for {@link GridDoubleClickEvent}s that happen in the header of the
* Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface HeaderDoubleClickHandler extends GridDoubleClickHandler {

}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderKeyDownHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler;

/**
* Handler for {@link GridKeyDownEvent}s that happen when the focused cell is in
* the header of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface HeaderKeyDownHandler extends GridKeyDownHandler {
}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderKeyPressHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler;

/**
* Handler for {@link GridKeyPressEvent}s that happen when the focused cell is
* in the header of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface HeaderKeyPressHandler extends GridKeyPressHandler {
}

+ 28
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/HeaderKeyUpHandler.java View File

@@ -0,0 +1,28 @@
/*
* 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.client.widget.grid.events;

import com.vaadin.v7.client.widget.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler;

/**
* Handler for {@link GridKeyUpEvent}s that happen when the focused cell is in
* the header of the Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface HeaderKeyUpHandler extends GridKeyUpHandler {
}

+ 40
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ScrollEvent.java View File

@@ -0,0 +1,40 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.GwtEvent;

/**
* An event that signifies that a scrollbar bundle has been scrolled
*
* @author Vaadin Ltd
* @since 7.4
*/
public class ScrollEvent extends GwtEvent<ScrollHandler> {

/** The type of this event */
public static final Type<ScrollHandler> TYPE = new Type<ScrollHandler>();

@Override
public Type<ScrollHandler> getAssociatedType() {
return TYPE;
}

@Override
protected void dispatch(final ScrollHandler handler) {
handler.onScroll(this);
}
}

+ 35
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/ScrollHandler.java View File

@@ -0,0 +1,35 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.EventHandler;

/**
* A handler that gets called whenever a scrollbar bundle is scrolled
*
* @author Vaadin Ltd
* @since 7.4
*/
public interface ScrollHandler extends EventHandler {
/**
* A callback method that is called once a scrollbar bundle has been
* scrolled.
*
* @param event
* the scroll event
*/
public void onScroll(ScrollEvent event);
}

+ 59
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/SelectAllEvent.java View File

@@ -0,0 +1,59 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.GwtEvent;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel;

/**
* A select all event, fired by the Grid when it needs all rows in data source
* to be selected.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class SelectAllEvent<T> extends GwtEvent<SelectAllHandler<T>> {

/**
* Handler type.
*/
private final static Type<SelectAllHandler<?>> TYPE = new Type<SelectAllHandler<?>>();;

private SelectionModel.Multi<T> selectionModel;

public SelectAllEvent(SelectionModel.Multi<T> selectionModel) {
this.selectionModel = selectionModel;
}

public static final Type<SelectAllHandler<?>> getType() {
return TYPE;
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Type<SelectAllHandler<T>> getAssociatedType() {
return (Type) TYPE;
}

@Override
protected void dispatch(SelectAllHandler<T> handler) {
handler.onSelectAll(this);
}

public SelectionModel.Multi<T> getSelectionModel() {
return selectionModel;
}
}

+ 37
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/events/SelectAllHandler.java View File

@@ -0,0 +1,37 @@
/*
* 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.client.widget.grid.events;

import com.google.gwt.event.shared.EventHandler;

/**
* Handler for a Grid select all event, called when the Grid needs all rows in
* data source to be selected.
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface SelectAllHandler<T> extends EventHandler {

/**
* Called when select all value in SelectionColumn header changes value.
*
* @param event
* select all event telling that all rows should be selected
*/
public void onSelectAll(SelectAllEvent<T> event);

}

+ 66
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/AbstractRowHandleSelectionModel.java View File

@@ -0,0 +1,66 @@
/*
* 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.client.widget.grid.selection;

import com.vaadin.client.data.DataSource.RowHandle;

/**
* An abstract class that adds a consistent API for common methods that's needed
* by Vaadin's server-based selection models to work.
* <p>
* <em>Note:</em> This should be an interface instead of an abstract class, if
* only we could define protected methods in an interface.
*
* @author Vaadin Ltd
* @param <T>
* The grid's row type
* @since 7.4
*/
public abstract class AbstractRowHandleSelectionModel<T>
implements SelectionModel<T> {
/**
* Select a row, based on its
* {@link com.vaadin.client.data.DataSource.RowHandle RowHandle}.
* <p>
* <em>Note:</em> this method may not fire selection change events.
*
* @param handle
* the handle to select by
* @return <code>true</code> iff the selection state was changed by this
* call
* @throws UnsupportedOperationException
* if the selection model does not support either handles or
* selection
*/
protected abstract boolean selectByHandle(RowHandle<T> handle);

/**
* Deselect a row, based on its
* {@link com.vaadin.client.data.DataSource.RowHandle RowHandle}.
* <p>
* <em>Note:</em> this method may not fire selection change events.
*
* @param handle
* the handle to deselect by
* @return <code>true</code> iff the selection state was changed by this
* call
* @throws UnsupportedOperationException
* if the selection model does not support either handles or
* deselection
*/
protected abstract boolean deselectByHandle(RowHandle<T> handle)
throws UnsupportedOperationException;
}

+ 77
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/ClickSelectHandler.java View File

@@ -0,0 +1,77 @@
/*
* 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.client.widget.grid.selection;

import com.google.gwt.event.shared.HandlerRegistration;
import com.vaadin.v7.client.widget.grid.events.BodyClickHandler;
import com.vaadin.v7.client.widget.grid.events.GridClickEvent;
import com.vaadin.v7.client.widgets.Grid;

/**
* Generic class to perform selections when clicking on cells in body of Grid.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class ClickSelectHandler<T> {

private Grid<T> grid;
private HandlerRegistration clickHandler;
private boolean deselectAllowed = true;

private class RowClickHandler implements BodyClickHandler {

@Override
public void onClick(GridClickEvent event) {
T row = (T) event.getTargetCell().getRow();
if (!grid.isSelected(row)) {
grid.select(row);
} else if (deselectAllowed) {
grid.deselect(row);
}
}
}

/**
* Constructor for ClickSelectHandler. This constructor will add all
* necessary handlers for selecting rows by clicking cells.
*
* @param grid
* grid to attach to
*/
public ClickSelectHandler(Grid<T> grid) {
this.grid = grid;
clickHandler = grid.addBodyClickHandler(new RowClickHandler());
}

/**
* Clean up function for removing all now obsolete handlers.
*/
public void removeHandler() {
clickHandler.removeHandler();
}

/**
* Sets whether clicking the currently selected row should deselect the row.
*
* @param deselectAllowed
* <code>true</code> to allow deselecting the selected row;
* otherwise <code>false</code>
*/
public void setDeselectAllowed(boolean deselectAllowed) {
this.deselectAllowed = deselectAllowed;
}
}

+ 42
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/HasSelectionHandlers.java View File

@@ -0,0 +1,42 @@
/*
* 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.client.widget.grid.selection;

import com.google.gwt.event.shared.HandlerRegistration;

/**
* Marker interface for widgets that fires selection events.
*
* @author Vaadin Ltd
* @since 7.4
*/
public interface HasSelectionHandlers<T> {

/**
* Register a selection change handler.
* <p>
* This handler is called whenever a
* {@link com.vaadin.ui.components.grid.selection.SelectionModel
* SelectionModel} detects a change in selection state.
*
* @param handler
* a {@link SelectionHandler}
* @return a handler registration object, which can be used to remove the
* handler.
*/
public HandlerRegistration addSelectionHandler(SelectionHandler<T> handler);

}

+ 781
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/MultiSelectionRenderer.java View File

@@ -0,0 +1,781 @@
/*
* 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.client.widget.grid.selection;

import java.util.Collection;
import java.util.HashSet;

import com.google.gwt.animation.client.AnimationScheduler;
import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback;
import com.google.gwt.animation.client.AnimationScheduler.AnimationHandle;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.TableElement;
import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.google.gwt.user.client.ui.CheckBox;
import com.vaadin.client.WidgetUtil;
import com.vaadin.v7.client.renderers.ClickableRenderer;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.RendererCellReference;
import com.vaadin.v7.client.widget.grid.events.GridEnabledEvent;
import com.vaadin.v7.client.widget.grid.events.GridEnabledHandler;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel.Multi.Batched;
import com.vaadin.v7.client.widgets.Grid;

/**
* Renderer showing multi selection check boxes.
*
* @author Vaadin Ltd
* @param <T>
* the type of the associated grid
* @since 7.4
*/
public class MultiSelectionRenderer<T>
extends ClickableRenderer<Boolean, CheckBox> {

private static final String SELECTION_CHECKBOX_CLASSNAME = "-selection-checkbox";

/** The size of the autoscroll area, both top and bottom. */
private static final int SCROLL_AREA_GRADIENT_PX = 100;

/** The maximum number of pixels per second to autoscroll. */
private static final int SCROLL_TOP_SPEED_PX_SEC = 500;

/**
* The minimum area where the grid doesn't scroll while the pointer is
* pressed.
*/
private static final int MIN_NO_AUTOSCROLL_AREA_PX = 50;

/**
* Handler for MouseDown and TouchStart events for selection checkboxes.
*
* @since 7.5
*/
private final class CheckBoxEventHandler implements MouseDownHandler,
TouchStartHandler, ClickHandler, GridEnabledHandler {
private final CheckBox checkBox;

/**
* @param checkBox
* checkbox widget for this handler
*/
private CheckBoxEventHandler(CheckBox checkBox) {
this.checkBox = checkBox;
}

@Override
public void onMouseDown(MouseDownEvent event) {
if (checkBox.isEnabled()) {
if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) {
startDragSelect(event.getNativeEvent(),
checkBox.getElement());
}
}
}

@Override
public void onTouchStart(TouchStartEvent event) {
if (checkBox.isEnabled()) {
startDragSelect(event.getNativeEvent(), checkBox.getElement());
}
}

@Override
public void onClick(ClickEvent event) {
// Clicking is already handled with MultiSelectionRenderer
event.preventDefault();
event.stopPropagation();
}

@Override
public void onEnabled(boolean enabled) {
checkBox.setEnabled(enabled);
}
}

/**
* This class's main objective is to listen when to stop autoscrolling, and
* make sure everything stops accordingly.
*/
private class TouchEventHandler implements NativePreviewHandler {
@Override
public void onPreviewNativeEvent(final NativePreviewEvent event) {
switch (event.getTypeInt()) {
case Event.ONTOUCHSTART: {
if (event.getNativeEvent().getTouches().length() == 1) {
/*
* Something has dropped a touchend/touchcancel and the
* scroller is most probably running amok. Let's cancel it
* and pretend that everything's going as expected
*
* Because this is a preview, this code is run before the
* event handler in MultiSelectionRenderer.onBrowserEvent.
* Therefore, we can simply kill everything and let that
* method restart things as they should.
*/
autoScrollHandler.stop();

/*
* Related TODO: investigate why iOS seems to ignore a
* touchend/touchcancel when frames are dropped, and/or if
* something can be done about that.
*/
}
break;
}

case Event.ONTOUCHMOVE:
event.cancel();
break;

case Event.ONTOUCHEND:
case Event.ONTOUCHCANCEL:
/*
* Remember: targetElement is always where touchstart started,
* not where the finger is pointing currently.
*/
final Element targetElement = Element
.as(event.getNativeEvent().getEventTarget());
if (isInFirstColumn(targetElement)) {
removeNativeHandler();
event.cancel();
}
break;
}
}

private boolean isInFirstColumn(final Element element) {
if (element == null) {
return false;
}
final Element tbody = getTbodyElement();

if (tbody == null || !tbody.isOrHasChild(element)) {
return false;
}

/*
* The null-parent in the while clause is in the case where element
* is an immediate tr child in the tbody. Should never happen in
* internal code, but hey...
*/
Element cursor = element;
while (cursor.getParentElement() != null
&& cursor.getParentElement().getParentElement() != tbody) {
cursor = cursor.getParentElement();
}

final Element tr = cursor.getParentElement();
return tr.getFirstChildElement().equals(cursor);
}
}

/**
* This class's responsibility is to
* <ul>
* <li>scroll the table while a pointer is kept in a scrolling zone and
* <li>select rows whenever a pointer is "activated" on a selection cell
* </ul>
* <p>
* <em>Techical note:</em> This class is an AnimationCallback because we
* need a timer: when the finger is kept in place while the grid scrolls, we
* still need to be able to make new selections. So, instead of relying on
* events (which won't be fired, since the pointer isn't necessarily
* moving), we do this check on each frame while the pointer is "active"
* (mouse is pressed, finger is on screen).
*/
private class AutoScrollerAndSelector implements AnimationCallback {

/**
* If the acceleration gradient area is smaller than this, autoscrolling
* will be disabled (it becomes too quick to accelerate to be usable).
*/
private static final int GRADIENT_MIN_THRESHOLD_PX = 10;

/**
* The speed at which the gradient area recovers, once scrolling in that
* direction has started.
*/
private static final int SCROLL_AREA_REBOUND_PX_PER_SEC = 1;
private static final double SCROLL_AREA_REBOUND_PX_PER_MS = SCROLL_AREA_REBOUND_PX_PER_SEC
/ 1000.0d;

/**
* The lowest y-coordinate on the {@link Event#getClientY() client} from
* where we need to start scrolling towards the top.
*/
private int topBound = -1;

/**
* The highest y-coordinate on the {@link Event#getClientY() client}
* from where we need to scrolling towards the bottom.
*/
private int bottomBound = -1;

/**
* <code>true</code> if the pointer is selecting, <code>false</code> if
* the pointer is deselecting.
*/
private final boolean selectionPaint;

/**
* The area where the selection acceleration takes place. If &lt;
* {@link #GRADIENT_MIN_THRESHOLD_PX}, autoscrolling is disabled
*/
private final int gradientArea;

/**
* The number of pixels per seconds we currently are scrolling (negative
* is towards the top, positive is towards the bottom).
*/
private double scrollSpeed = 0;

private double prevTimestamp = 0;

/**
* This field stores fractions of pixels to scroll, to make sure that
* we're able to scroll less than one px per frame.
*/
private double pixelsToScroll = 0.0d;

/** Should this animator be running. */
private boolean running = false;

/** The handle in which this instance is running. */
private AnimationHandle handle;

/** The pointer's pageX coordinate of the first click. */
private int initialPageX = -1;

/** The pointer's pageY coordinate. */
private int pageY;

/** The logical index of the row that was most recently modified. */
private int lastModifiedLogicalRow = -1;

/** @see #doScrollAreaChecks(int) */
private int finalTopBound;

/** @see #doScrollAreaChecks(int) */
private int finalBottomBound;

private boolean scrollAreaShouldRebound = false;

private final int bodyAbsoluteTop;
private final int bodyAbsoluteBottom;

public AutoScrollerAndSelector(final int topBound,
final int bottomBound, final int gradientArea,
final boolean selectionPaint) {
finalTopBound = topBound;
finalBottomBound = bottomBound;
this.gradientArea = gradientArea;
this.selectionPaint = selectionPaint;

bodyAbsoluteTop = getBodyClientTop();
bodyAbsoluteBottom = getBodyClientBottom();
}

@Override
public void execute(final double timestamp) {
final double timeDiff = timestamp - prevTimestamp;
prevTimestamp = timestamp;

reboundScrollArea(timeDiff);

pixelsToScroll += scrollSpeed * (timeDiff / 1000.0d);
final int intPixelsToScroll = (int) pixelsToScroll;
pixelsToScroll -= intPixelsToScroll;

if (intPixelsToScroll != 0) {
grid.setScrollTop(grid.getScrollTop() + intPixelsToScroll);
}

int constrainedPageY = Math.max(bodyAbsoluteTop,
Math.min(bodyAbsoluteBottom, pageY));
int logicalRow = getLogicalRowIndex(WidgetUtil
.getElementFromPoint(initialPageX, constrainedPageY));

int incrementOrDecrement = (logicalRow > lastModifiedLogicalRow) ? 1
: -1;

/*
* Both pageY and initialPageX have their initialized (and
* unupdated) values while the cursor hasn't moved since the first
* invocation. This will lead to logicalRow being -1, until the
* pointer has been moved.
*/
while (logicalRow != -1 && lastModifiedLogicalRow != logicalRow) {
lastModifiedLogicalRow += incrementOrDecrement;
setSelected(lastModifiedLogicalRow, selectionPaint);
}

reschedule();
}

/**
* If the scroll are has been offset by the pointer starting out there,
* move it back a bit
*/
private void reboundScrollArea(double timeDiff) {
if (!scrollAreaShouldRebound) {
return;
}

int reboundPx = (int) Math
.ceil(SCROLL_AREA_REBOUND_PX_PER_MS * timeDiff);
if (topBound < finalTopBound) {
topBound += reboundPx;
topBound = Math.min(topBound, finalTopBound);
updateScrollSpeed(pageY);
} else if (bottomBound > finalBottomBound) {
bottomBound -= reboundPx;
bottomBound = Math.max(bottomBound, finalBottomBound);
updateScrollSpeed(pageY);
}
}

private void updateScrollSpeed(final int pointerPageY) {

final double ratio;
if (pointerPageY < topBound) {
final double distance = pointerPageY - topBound;
ratio = Math.max(-1, distance / gradientArea);
}

else if (pointerPageY > bottomBound) {
final double distance = pointerPageY - bottomBound;
ratio = Math.min(1, distance / gradientArea);
}

else {
ratio = 0;
}

scrollSpeed = ratio * SCROLL_TOP_SPEED_PX_SEC;
}

public void start(int logicalRowIndex) {
running = true;
setSelected(logicalRowIndex, selectionPaint);
lastModifiedLogicalRow = logicalRowIndex;
reschedule();
}

public void stop() {
running = false;

if (handle != null) {
handle.cancel();
handle = null;
}
}

private void reschedule() {
if (running && gradientArea >= GRADIENT_MIN_THRESHOLD_PX) {
handle = AnimationScheduler.get().requestAnimationFrame(this,
grid.getElement());
}
}

public void updatePointerCoords(int pageX, int pageY) {
doScrollAreaChecks(pageY);
updateScrollSpeed(pageY);
this.pageY = pageY;

if (initialPageX == -1) {
initialPageX = pageX;
}
}

/**
* This method checks whether the first pointer event started in an area
* that would start scrolling immediately, and does some actions
* accordingly.
* <p>
* If it is, that scroll area will be offset "beyond" the pointer (above
* if pointer is towards the top, otherwise below).
* <p>
* <span style="font-size:smaller">*) This behavior will change in
* future patches (henrik paul 2.7.2014)</span>
*/
private void doScrollAreaChecks(int pageY) {
/*
* The first run makes sure that neither scroll position is
* underneath the finger, but offset to either direction from
* underneath the pointer.
*/
if (topBound == -1) {
topBound = Math.min(finalTopBound, pageY);
bottomBound = Math.max(finalBottomBound, pageY);
}

/*
* Subsequent runs make sure that the scroll area grows (but doesn't
* shrink) with the finger, but no further than the final bound.
*/
else {
int oldTopBound = topBound;
if (topBound < finalTopBound) {
topBound = Math.max(topBound,
Math.min(finalTopBound, pageY));
}

int oldBottomBound = bottomBound;
if (bottomBound > finalBottomBound) {
bottomBound = Math.min(bottomBound,
Math.max(finalBottomBound, pageY));
}

final boolean topDidNotMove = oldTopBound == topBound;
final boolean bottomDidNotMove = oldBottomBound == bottomBound;
final boolean wasVerticalMovement = pageY != this.pageY;
scrollAreaShouldRebound = (topDidNotMove && bottomDidNotMove
&& wasVerticalMovement);
}
}
}

/**
* This class makes sure that pointer movemenets are registered and
* delegated to the autoscroller so that it can:
* <ul>
* <li>modify the speed in which we autoscroll.
* <li>"paint" a new row with the selection.
* </ul>
* Essentially, when a pointer is pressed on the selection column, a native
* preview handler is registered (so that selection gestures can happen
* outside of the selection column). The handler itself makes sure that it's
* detached when the pointer is "lifted".
*/
private class AutoScrollHandler {
private AutoScrollerAndSelector autoScroller;

/** The registration info for {@link #scrollPreviewHandler} */
private HandlerRegistration handlerRegistration;

private final NativePreviewHandler scrollPreviewHandler = new NativePreviewHandler() {
@Override
public void onPreviewNativeEvent(final NativePreviewEvent event) {
if (autoScroller == null) {
stop();
return;
}

final NativeEvent nativeEvent = event.getNativeEvent();
int pageY = 0;
int pageX = 0;
switch (event.getTypeInt()) {
case Event.ONMOUSEMOVE:
case Event.ONTOUCHMOVE:
pageY = WidgetUtil.getTouchOrMouseClientY(nativeEvent);
pageX = WidgetUtil.getTouchOrMouseClientX(nativeEvent);
autoScroller.updatePointerCoords(pageX, pageY);
break;
case Event.ONMOUSEUP:
case Event.ONTOUCHEND:
case Event.ONTOUCHCANCEL:
stop();
break;
}
}
};

/**
* The top bound, as calculated from the {@link Event#getClientY()
* client} coordinates.
*/
private int topBound = -1;

/**
* The bottom bound, as calculated from the {@link Event#getClientY()
* client} coordinates.
*/
private int bottomBound = -1;

/** The size of the autoscroll acceleration area. */
private int gradientArea;

public void start(int logicalRowIndex) {

SelectionModel<T> model = grid.getSelectionModel();
if (model instanceof Batched) {
Batched<?> batchedModel = (Batched<?>) model;
batchedModel.startBatchSelect();
}

/*
* bounds are updated whenever the autoscroll cycle starts, to make
* sure that the widget hasn't changed in size, moved around, or
* whatnot.
*/
updateScrollBounds();

assert handlerRegistration == null : "handlerRegistration was not null";
assert autoScroller == null : "autoScroller was not null";
handlerRegistration = Event
.addNativePreviewHandler(scrollPreviewHandler);

autoScroller = new AutoScrollerAndSelector(topBound, bottomBound,
gradientArea, !isSelected(logicalRowIndex));
autoScroller.start(logicalRowIndex);
}

private void updateScrollBounds() {
final int topBorder = getBodyClientTop();
final int bottomBorder = getBodyClientBottom();

topBound = topBorder + SCROLL_AREA_GRADIENT_PX;
bottomBound = bottomBorder - SCROLL_AREA_GRADIENT_PX;
gradientArea = SCROLL_AREA_GRADIENT_PX;

// modify bounds if they're too tightly packed
if (bottomBound - topBound < MIN_NO_AUTOSCROLL_AREA_PX) {
int adjustment = MIN_NO_AUTOSCROLL_AREA_PX
- (bottomBound - topBound);
topBound -= adjustment / 2;
bottomBound += adjustment / 2;
gradientArea -= adjustment / 2;
}
}

public void stop() {
if (handlerRegistration != null) {
handlerRegistration.removeHandler();
handlerRegistration = null;
}

if (autoScroller != null) {
autoScroller.stop();
autoScroller = null;
}

SelectionModel<T> model = grid.getSelectionModel();
if (model instanceof Batched) {
Batched<?> batchedModel = (Batched<?>) model;
batchedModel.commitBatchSelect();
}

removeNativeHandler();
}
}

private static final String LOGICAL_ROW_PROPERTY_INT = "vEscalatorLogicalRow";

private final Grid<T> grid;
private HandlerRegistration nativePreviewHandlerRegistration;

private final AutoScrollHandler autoScrollHandler = new AutoScrollHandler();

public MultiSelectionRenderer(final Grid<T> grid) {
this.grid = grid;
}

@Override
public void destroy() {
if (nativePreviewHandlerRegistration != null) {
removeNativeHandler();
}
}

@Override
public CheckBox createWidget() {
final CheckBox checkBox = GWT.create(CheckBox.class);
checkBox.setStylePrimaryName(
grid.getStylePrimaryName() + SELECTION_CHECKBOX_CLASSNAME);

CheckBoxEventHandler handler = new CheckBoxEventHandler(checkBox);

// Sink events
checkBox.sinkBitlessEvent(BrowserEvents.MOUSEDOWN);
checkBox.sinkBitlessEvent(BrowserEvents.TOUCHSTART);
checkBox.sinkBitlessEvent(BrowserEvents.CLICK);

// Add handlers
checkBox.addMouseDownHandler(handler);
checkBox.addTouchStartHandler(handler);
checkBox.addClickHandler(handler);
grid.addHandler(handler, GridEnabledEvent.TYPE);

checkBox.setEnabled(grid.isEnabled());

return checkBox;
}

@Override
public void render(final RendererCellReference cell, final Boolean data,
CheckBox checkBox) {
checkBox.setValue(data, false);
checkBox.setEnabled(grid.isEnabled() && !grid.isEditorActive());
checkBox.getElement().setPropertyInt(LOGICAL_ROW_PROPERTY_INT,
cell.getRowIndex());
}

@Override
public Collection<String> getConsumedEvents() {
final HashSet<String> events = new HashSet<String>();

/*
* this column's first interest is only to attach a NativePreventHandler
* that does all the magic. These events are the beginning of that
* cycle.
*/
events.add(BrowserEvents.MOUSEDOWN);
events.add(BrowserEvents.TOUCHSTART);

return events;
}

@Override
public boolean onBrowserEvent(final CellReference<?> cell,
final NativeEvent event) {
if (BrowserEvents.TOUCHSTART.equals(event.getType())
|| (BrowserEvents.MOUSEDOWN.equals(event.getType())
&& event.getButton() == NativeEvent.BUTTON_LEFT)) {
startDragSelect(event, Element.as(event.getEventTarget()));
return true;
} else {
throw new IllegalStateException(
"received unexpected event: " + event.getType());
}
}

private void startDragSelect(NativeEvent event, final Element target) {
injectNativeHandler();
int logicalRowIndex = getLogicalRowIndex(target);
autoScrollHandler.start(logicalRowIndex);
event.preventDefault();
event.stopPropagation();
}

private void injectNativeHandler() {
removeNativeHandler();
nativePreviewHandlerRegistration = Event
.addNativePreviewHandler(new TouchEventHandler());
}

private void removeNativeHandler() {
if (nativePreviewHandlerRegistration != null) {
nativePreviewHandlerRegistration.removeHandler();
nativePreviewHandlerRegistration = null;
}
}

private int getLogicalRowIndex(final Element target) {
if (target == null) {
return -1;
}

/*
* We can't simply go backwards until we find a <tr> first element,
* because of the table-in-table scenario. We need to, unfortunately, go
* up from our known root.
*/
final Element tbody = getTbodyElement();
Element tr = tbody.getFirstChildElement();
while (tr != null) {
if (tr.isOrHasChild(target)) {
final Element td = tr.getFirstChildElement();
assert td != null : "Cell has disappeared";

final Element checkbox = td.getFirstChildElement();
assert checkbox != null : "Checkbox has disappeared";

return checkbox.getPropertyInt(LOGICAL_ROW_PROPERTY_INT);
}
tr = tr.getNextSiblingElement();
}
return -1;
}

private TableElement getTableElement() {
final Element root = grid.getElement();
final Element tablewrapper = Element.as(root.getChild(2));
if (tablewrapper != null) {
return TableElement.as(tablewrapper.getFirstChildElement());
} else {
return null;
}
}

private TableSectionElement getTbodyElement() {
TableElement table = getTableElement();
if (table != null) {
return table.getTBodies().getItem(0);
} else {
return null;
}
}

private TableSectionElement getTheadElement() {
TableElement table = getTableElement();
if (table != null) {
return table.getTHead();
} else {
return null;
}
}

private TableSectionElement getTfootElement() {
TableElement table = getTableElement();
if (table != null) {
return table.getTFoot();
} else {
return null;
}
}

/** Get the "top" of an element in relation to "client" coordinates. */
private int getClientTop(final Element e) {
return e.getAbsoluteTop();
}

private int getBodyClientBottom() {
return getClientTop(getTfootElement()) - 1;
}

private int getBodyClientTop() {
// Off by one pixel miscalculation. possibly border related.
return getClientTop(grid.getElement())
+ getTheadElement().getOffsetHeight() + 1;
}

protected boolean isSelected(final int logicalRow) {
return grid.isSelected(grid.getDataSource().getRow(logicalRow));
}

protected void setSelected(final int logicalRow, final boolean select) {
T row = grid.getDataSource().getRow(logicalRow);
if (select) {
grid.select(row);
} else {
grid.deselect(row);
}
}
}

+ 178
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/SelectionEvent.java View File

@@ -0,0 +1,178 @@
/*
* 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.client.widget.grid.selection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import com.google.gwt.event.shared.GwtEvent;
import com.vaadin.v7.client.widgets.Grid;

/**
* Event object describing a change in Grid row selection state.
*
* @since 7.4
* @author Vaadin Ltd
*/
@SuppressWarnings("rawtypes")
public class SelectionEvent<T> extends GwtEvent<SelectionHandler> {

private static final Type<SelectionHandler> eventType = new Type<SelectionHandler>();

private final Grid<T> grid;
private final List<T> added;
private final List<T> removed;
private final boolean batched;

/**
* Creates an event with a single added or removed row.
*
* @param grid
* grid reference, used for getSource
* @param added
* the added row, or <code>null</code> if a row was not added
* @param removed
* the removed row, or <code>null</code> if a row was not removed
* @param batched
* whether or not this selection change event is triggered during
* a batched selection/deselection action
* @see SelectionModel.Multi.Batched
*/
public SelectionEvent(Grid<T> grid, T added, T removed, boolean batched) {
this.grid = grid;
this.batched = batched;

if (added != null) {
this.added = Collections.singletonList(added);
} else {
this.added = Collections.emptyList();
}

if (removed != null) {
this.removed = Collections.singletonList(removed);
} else {
this.removed = Collections.emptyList();
}
}

/**
* Creates an event where several rows have been added or removed.
*
* @param grid
* Grid reference, used for getSource
* @param added
* a collection of added rows, or <code>null</code> if no rows
* were added
* @param removed
* a collection of removed rows, or <code>null</code> if no rows
* were removed
* @param batched
* whether or not this selection change event is triggered during
* a batched selection/deselection action
* @see SelectionModel.Multi.Batched
*/
public SelectionEvent(Grid<T> grid, Collection<T> added,
Collection<T> removed, boolean batched) {
this.grid = grid;
this.batched = batched;

if (added != null) {
this.added = new ArrayList<T>(added);
} else {
this.added = Collections.emptyList();
}

if (removed != null) {
this.removed = new ArrayList<T>(removed);
} else {
this.removed = Collections.emptyList();
}
}

/**
* Gets a reference to the Grid object that fired this event.
*
* @return a grid reference
*/
@Override
public Grid<T> getSource() {
return grid;
}

/**
* Gets all rows added to the selection since the last
* {@link SelectionEvent} .
*
* @return a collection of added rows. Empty collection if no rows were
* added.
*/
public Collection<T> getAdded() {
return Collections.unmodifiableCollection(added);
}

/**
* Gets all rows removed from the selection since the last
* {@link SelectionEvent}.
*
* @return a collection of removed rows. Empty collection if no rows were
* removed.
*/
public Collection<T> getRemoved() {
return Collections.unmodifiableCollection(removed);
}

/**
* Gets currently selected rows.
*
* @return a non-null collection containing all currently selected rows.
*/
public Collection<T> getSelected() {
return grid.getSelectedRows();
}

/**
* Gets a type identifier for this event.
*
* @return a {@link Type} identifier.
*/
public static Type<SelectionHandler> getType() {
return eventType;
}

@Override
public Type<SelectionHandler> getAssociatedType() {
return eventType;
}

@Override
@SuppressWarnings("unchecked")
protected void dispatch(SelectionHandler handler) {
handler.onSelect(this);
}

/**
* Checks if this selection change event is fired during a batched
* selection/deselection operation.
*
* @return <code>true</code> iff this event is fired during a batched
* selection/deselection operation
*/
public boolean isBatchedSelection() {
return batched;
}
}

+ 39
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/SelectionHandler.java View File

@@ -0,0 +1,39 @@
/*
* 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.client.widget.grid.selection;

import com.google.gwt.event.shared.EventHandler;

/**
* Handler for {@link SelectionEvent}s.
*
* @author Vaadin Ltd
* @param <T>
* The row data type
* @since 7.4
*/
public interface SelectionHandler<T> extends EventHandler {

/**
* Called when a selection model's selection state is changed.
*
* @param event
* a selection event, containing info about rows that have been
* added to or removed from the selection.
*/
public void onSelect(SelectionEvent<T> event);

}

+ 258
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/SelectionModel.java View File

@@ -0,0 +1,258 @@
/*
* 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.client.widget.grid.selection;

import java.util.Collection;

import com.vaadin.v7.client.renderers.Renderer;
import com.vaadin.v7.client.widgets.Grid;

/**
* Common interface for all selection models.
* <p>
* Selection models perform tracking of selected rows in the Grid, as well as
* dispatching events when the selection state changes.
*
* @author Vaadin Ltd
* @param <T>
* Grid's row type
* @since 7.4
*/
public interface SelectionModel<T> {

/**
* Return true if the provided row is considered selected under the
* implementing selection model.
*
* @param row
* row object instance
* @return <code>true</code>, if the row given as argument is considered
* selected.
*/
public boolean isSelected(T row);

/**
* Return the {@link Renderer} responsible for rendering the selection
* column.
*
* @return a renderer instance. If null is returned, a selection column will
* not be drawn.
*/
public Renderer<Boolean> getSelectionColumnRenderer();

/**
* Tells this SelectionModel which Grid it belongs to.
* <p>
* Implementations are free to have this be a no-op. This method is called
* internally by Grid.
*
* @param grid
* a {@link Grid} instance; <code>null</code> when removing from
* Grid
*/
public void setGrid(Grid<T> grid);

/**
* Resets the SelectionModel to the initial state.
* <p>
* This method can be called internally, for example, when the attached
* Grid's data source changes.
*/
public void reset();

/**
* Returns a Collection containing all selected rows.
*
* @return a non-null collection.
*/
public Collection<T> getSelectedRows();

/**
* Selection model that allows a maximum of one row to be selected at any
* one time.
*
* @param <T>
* type parameter corresponding with Grid row type
*/
public interface Single<T> extends SelectionModel<T> {

/**
* Selects a row.
*
* @param row
* a {@link Grid} row object
* @return true, if this row as not previously selected.
*/
public boolean select(T row);

/**
* Deselects a row.
* <p>
* This is a no-op unless {@link row} is the currently selected row.
*
* @param row
* a {@link Grid} row object
* @return true, if the currently selected row was deselected.
*/
public boolean deselect(T row);

/**
* Returns the currently selected row.
*
* @return a {@link Grid} row object or null, if nothing is selected.
*/
public T getSelectedRow();

/**
* Sets whether it's allowed to deselect the selected row through the
* UI. Deselection is allowed by default.
*
* @param deselectAllowed
* <code>true</code> if the selected row can be deselected
* without selecting another row instead; otherwise
* <code>false</code>.
*/
public void setDeselectAllowed(boolean deselectAllowed);

/**
* Sets whether it's allowed to deselect the selected row through the
* UI.
*
* @return <code>true</code> if deselection is allowed; otherwise
* <code>false</code>
*/
public boolean isDeselectAllowed();

}

/**
* Selection model that allows for several rows to be selected at once.
*
* @param <T>
* type parameter corresponding with Grid row type
*/
public interface Multi<T> extends SelectionModel<T> {

/**
* A multi selection model that can send selections and deselections in
* a batch, instead of committing them one-by-one.
*
* @param <T>
* type parameter corresponding with Grid row type
*/
public interface Batched<T> extends Multi<T> {
/**
* Starts a batch selection.
* <p>
* Any commands to any select or deselect method will be batched
* into one, and a final selection event will be fired when
* {@link #commitBatchSelect()} is called.
* <p>
* <em>Note:</em> {@link SelectionEvent SelectionChangeEvents} will
* still be fired for each selection/deselection. You should check
* whether the event is a part of a batch or not with
* {@link SelectionEvent#isBatchedSelection()}.
*/
public void startBatchSelect();

/**
* Commits and ends a batch selection.
* <p>
* Any and all selections and deselections since the last invocation
* of {@link #startBatchSelect()} will be fired at once as one
* collated {@link SelectionEvent}.
*/
public void commitBatchSelect();

/**
* Checks whether or not a batch has been started.
*
* @return <code>true</code> iff a batch has been started
*/
public boolean isBeingBatchSelected();

/**
* Gets all the rows that would become selected in this batch.
*
* @return a collection of the rows that would become selected
*/
public Collection<T> getSelectedRowsBatch();

/**
* Gets all the rows that would become deselected in this batch.
*
* @return a collection of the rows that would become deselected
*/
public Collection<T> getDeselectedRowsBatch();
}

/**
* Selects one or more rows.
*
* @param rows
* {@link Grid} row objects
* @return true, if the set of selected rows was changed.
*/
public boolean select(T... rows);

/**
* Deselects one or more rows.
*
* @param rows
* Grid row objects
* @return true, if the set of selected rows was changed.
*/
public boolean deselect(T... rows);

/**
* De-selects all rows.
*
* @return true, if any row was previously selected.
*/
public boolean deselectAll();

/**
* Select all rows in a {@link Collection}.
*
* @param rows
* a collection of Grid row objects
* @return true, if the set of selected rows was changed.
*/
public boolean select(Collection<T> rows);

/**
* Deselect all rows in a {@link Collection}.
*
* @param rows
* a collection of Grid row objects
* @return true, if the set of selected rows was changed.
*/
public boolean deselect(Collection<T> rows);

}

/**
* Interface for a selection model that does not allow anything to be
* selected.
*
* @param <T>
* type parameter corresponding with Grid row type
*/
public interface None<T> extends SelectionModel<T> {

}

}

+ 0
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/grid/selection/SelectionModelMulti.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save