aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtur Signell <artur@vaadin.com>2015-01-13 22:47:47 +0200
committerArtur Signell <artur@vaadin.com>2015-01-13 22:47:47 +0200
commita264cdf59106360c250af73d93a25d7c7a3b1542 (patch)
tree9479177a1b36a432c4e90b994e3eb0139f4bec58
parentdd116c6495de1caab73fe350acae876bd9380e96 (diff)
parent8a544b5a6e78337b24a5e56bcde1a21ff6087fae (diff)
downloadvaadin-framework-a264cdf59106360c250af73d93a25d7c7a3b1542.tar.gz
vaadin-framework-a264cdf59106360c250af73d93a25d7c7a3b1542.zip
Merge remote-tracking branch 'origin/grid' into 7.4
-rw-r--r--WebContent/VAADIN/themes/reindeer/progressindicator/img/base-static.gifbin0 -> 1123 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/progressindicator/progressindicator.scss8
-rw-r--r--WebContent/VAADIN/themes/runo/progressindicator/img/base-static.gifbin0 -> 1123 bytes
-rw-r--r--WebContent/VAADIN/themes/runo/progressindicator/progressindicator.scss8
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ServerRpcVisitor.java6
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java24
-rw-r--r--client/src/com/vaadin/client/JavaScriptConnectorHelper.java13
-rw-r--r--client/src/com/vaadin/client/VLoadingIndicator.java12
-rw-r--r--client/src/com/vaadin/client/connectors/GridConnector.java135
-rw-r--r--client/src/com/vaadin/client/connectors/JavaScriptRendererConnector.java278
-rw-r--r--client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java37
-rw-r--r--client/src/com/vaadin/client/data/AbstractRemoteDataSource.java28
-rw-r--r--client/src/com/vaadin/client/metadata/TypeDataStore.java6
-rw-r--r--client/src/com/vaadin/client/renderers/ProgressBarRenderer.java4
-rw-r--r--client/src/com/vaadin/client/widget/grid/RendererCellReference.java2
-rw-r--r--client/src/com/vaadin/client/widgets/Escalator.java7
-rw-r--r--server/src/com/vaadin/data/RpcDataProviderExtension.java99
-rw-r--r--server/src/com/vaadin/server/AbstractJavaScriptExtension.java4
-rw-r--r--server/src/com/vaadin/ui/AbstractJavaScriptComponent.java4
-rw-r--r--server/src/com/vaadin/ui/Grid.java50
-rw-r--r--server/src/com/vaadin/ui/renderer/AbstractJavaScriptRenderer.java157
-rw-r--r--server/src/com/vaadin/ui/themes/Reindeer.java20
-rw-r--r--server/src/com/vaadin/ui/themes/Runo.java12
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/grid/GridEditorTest.java69
-rw-r--r--shared/src/com/vaadin/shared/annotations/NoLoadingIndicator.java35
-rw-r--r--shared/src/com/vaadin/shared/data/DataRequestRpc.java2
-rw-r--r--shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorServerRpc.java2
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java2
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java12
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderers.java75
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java46
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/MyBeanJSRenderer.java34
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java22
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientStructureTest.java37
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/LoadingIndicatorTest.java85
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/myBeanJsRenderer.js16
-rw-r--r--uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticReindeer.java32
-rw-r--r--uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticReindeerTest.java28
-rw-r--r--uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticRuno.java32
-rw-r--r--uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticRunoTest.java28
41 files changed, 1291 insertions, 181 deletions
diff --git a/WebContent/VAADIN/themes/reindeer/progressindicator/img/base-static.gif b/WebContent/VAADIN/themes/reindeer/progressindicator/img/base-static.gif
new file mode 100644
index 0000000000..474b684196
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/progressindicator/img/base-static.gif
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/progressindicator/progressindicator.scss b/WebContent/VAADIN/themes/reindeer/progressindicator/progressindicator.scss
index 52e4239752..2417202828 100644
--- a/WebContent/VAADIN/themes/reindeer/progressindicator/progressindicator.scss
+++ b/WebContent/VAADIN/themes/reindeer/progressindicator/progressindicator.scss
@@ -11,4 +11,10 @@
background: #f7f9f9 url(img/progress.png);
}
-} \ No newline at end of file
+// Static style
+
+.#{$primaryStyleName}-static .#{$primaryStyleName}-wrapper {
+ background: #dfe2e4 url(img/base-static.gif) repeat-x;
+}
+
+}
diff --git a/WebContent/VAADIN/themes/runo/progressindicator/img/base-static.gif b/WebContent/VAADIN/themes/runo/progressindicator/img/base-static.gif
new file mode 100644
index 0000000000..474b684196
--- /dev/null
+++ b/WebContent/VAADIN/themes/runo/progressindicator/img/base-static.gif
Binary files differ
diff --git a/WebContent/VAADIN/themes/runo/progressindicator/progressindicator.scss b/WebContent/VAADIN/themes/runo/progressindicator/progressindicator.scss
index 9664a473b2..432123cf1f 100644
--- a/WebContent/VAADIN/themes/runo/progressindicator/progressindicator.scss
+++ b/WebContent/VAADIN/themes/runo/progressindicator/progressindicator.scss
@@ -20,4 +20,10 @@
background: #dfe2e4;
}
-} \ No newline at end of file
+// Static style
+
+.#{$primaryStyleName}-static .#{$primaryStyleName}-wrapper {
+ background: #dfe2e4 url(img/base-static.gif) repeat-x;
+}
+
+}
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ServerRpcVisitor.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ServerRpcVisitor.java
index a1852d5b32..86ece28041 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ServerRpcVisitor.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ServerRpcVisitor.java
@@ -24,6 +24,7 @@ import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;
import com.vaadin.client.metadata.TypeDataStore.MethodAttribute;
+import com.vaadin.shared.annotations.NoLoadingIndicator;
import com.vaadin.shared.annotations.Delayed;
public class ServerRpcVisitor extends TypeVisitor {
@@ -51,6 +52,11 @@ public class ServerRpcVisitor extends TypeVisitor {
}
}
+ if (method.getAnnotation(NoLoadingIndicator.class) != null) {
+ bundle.setMethodAttribute(type, method,
+ MethodAttribute.NO_LOADING_INDICATOR);
+ }
+
bundle.setNeedsParamTypes(type, method);
JType[] parameterTypes = method.getParameterTypes();
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index aa00516feb..6abaf28eda 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -81,6 +81,7 @@ import com.vaadin.client.metadata.NoDataException;
import com.vaadin.client.metadata.Property;
import com.vaadin.client.metadata.Type;
import com.vaadin.client.metadata.TypeData;
+import com.vaadin.client.metadata.TypeDataStore;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.AbstractConnector;
import com.vaadin.client.ui.FontIcon;
@@ -1275,7 +1276,6 @@ public class ApplicationConnection implements HasHandlers {
}
hasActiveRequest = true;
requestStartTime = new Date();
- loadingIndicator.trigger();
eventBus.fireEvent(new RequestStartingEvent(this));
}
@@ -1300,7 +1300,8 @@ public class ApplicationConnection implements HasHandlers {
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
- if (!hasActiveRequest()) {
+ if (!isApplicationRunning()
+ || !(hasActiveRequest() || deferredSendPending)) {
getLoadingIndicator().hide();
// If on Liferay and session expiration management is in
@@ -2720,8 +2721,8 @@ public class ApplicationConnection implements HasHandlers {
*
*/
public void sendPendingVariableChanges() {
- if (!deferedSendPending) {
- deferedSendPending = true;
+ if (!deferredSendPending) {
+ deferredSendPending = true;
Scheduler.get().scheduleFinally(sendPendingCommand);
}
}
@@ -2729,11 +2730,11 @@ public class ApplicationConnection implements HasHandlers {
private final ScheduledCommand sendPendingCommand = new ScheduledCommand() {
@Override
public void execute() {
- deferedSendPending = false;
+ deferredSendPending = false;
doSendPendingVariableChanges();
}
};
- private boolean deferedSendPending = false;
+ private boolean deferredSendPending = false;
private void doSendPendingVariableChanges() {
if (isApplicationRunning()) {
@@ -2768,7 +2769,7 @@ public class ApplicationConnection implements HasHandlers {
*/
private void buildAndSendVariableBurst(
LinkedHashMap<String, MethodInvocation> pendingInvocations) {
-
+ boolean showLoadingIndicator = false;
JsonArray reqJson = Json.createArray();
if (!pendingInvocations.isEmpty()) {
if (ApplicationConfiguration.isDebugMode()) {
@@ -2791,10 +2792,16 @@ public class ApplicationConnection implements HasHandlers {
Method method = type.getMethod(invocation
.getMethodName());
parameterTypes = method.getParameterTypes();
+
+ showLoadingIndicator |= !TypeDataStore
+ .isNoLoadingIndicator(method);
} catch (NoDataException e) {
throw new RuntimeException("No type data for "
+ invocation.toString(), e);
}
+ } else {
+ // Always show loading indicator for legacy requests
+ showLoadingIndicator = true;
}
for (int i = 0; i < invocation.getParameters().length; ++i) {
@@ -2826,6 +2833,9 @@ public class ApplicationConnection implements HasHandlers {
getConfiguration().setWidgetsetVersionSent();
}
+ if (showLoadingIndicator) {
+ getLoadingIndicator().trigger();
+ }
makeUidlRequest(reqJson, extraParams);
}
diff --git a/client/src/com/vaadin/client/JavaScriptConnectorHelper.java b/client/src/com/vaadin/client/JavaScriptConnectorHelper.java
index 11511f9c36..3a9a6198d3 100644
--- a/client/src/com/vaadin/client/JavaScriptConnectorHelper.java
+++ b/client/src/com/vaadin/client/JavaScriptConnectorHelper.java
@@ -50,7 +50,7 @@ public class JavaScriptConnectorHelper {
private JavaScriptObject connectorWrapper;
private int tag;
- private boolean inited = false;
+ private String initFunctionName;
public JavaScriptConnectorHelper(ServerConnector connector) {
this.connector = connector;
@@ -96,9 +96,8 @@ public class JavaScriptConnectorHelper {
}
// Init after setting up callbacks & rpc
- if (!inited) {
+ if (initFunctionName == null) {
initJavaScript();
- inited = true;
}
invokeIfPresent(wrapper, "onStateChange");
@@ -120,7 +119,7 @@ public class JavaScriptConnectorHelper {
return object;
}
- private boolean initJavaScript() {
+ protected boolean initJavaScript() {
ApplicationConfiguration conf = connector.getConnection()
.getConfiguration();
ArrayList<String> attemptedNames = new ArrayList<String>();
@@ -132,6 +131,7 @@ public class JavaScriptConnectorHelper {
if (tryInitJs(initFunctionName, getConnectorWrapper())) {
VConsole.log("JavaScript connector initialized using "
+ initFunctionName);
+ this.initFunctionName = initFunctionName;
return true;
} else {
VConsole.log("No JavaScript function " + initFunctionName
@@ -160,7 +160,7 @@ public class JavaScriptConnectorHelper {
}
}-*/;
- private JavaScriptObject getConnectorWrapper() {
+ public JavaScriptObject getConnectorWrapper() {
if (connectorWrapper == null) {
connectorWrapper = createConnectorWrapper(this,
connector.getConnection(), nativeState, rpcMap,
@@ -465,4 +465,7 @@ public class JavaScriptConnectorHelper {
}
}-*/;
+ public String getInitFunctionName() {
+ return initFunctionName;
+ }
}
diff --git a/client/src/com/vaadin/client/VLoadingIndicator.java b/client/src/com/vaadin/client/VLoadingIndicator.java
index e873005d3a..7c7edeb04f 100644
--- a/client/src/com/vaadin/client/VLoadingIndicator.java
+++ b/client/src/com/vaadin/client/VLoadingIndicator.java
@@ -154,6 +154,18 @@ public class VLoadingIndicator {
}
/**
+ * Triggers displaying of this loading indicator unless it's already visible
+ * or scheduled to be shown after a delay.
+ *
+ * @since 7.4
+ */
+ public void ensureTriggered() {
+ if (!isVisible() && !firstTimer.isRunning()) {
+ trigger();
+ }
+ }
+
+ /**
* Shows the loading indicator in its standard state and triggers timers for
* transitioning into the "second" and "third" states.
*/
diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java
index 450df31b36..a2e63fc397 100644
--- a/client/src/com/vaadin/client/connectors/GridConnector.java
+++ b/client/src/com/vaadin/client/connectors/GridConnector.java
@@ -160,12 +160,13 @@ public class GridConnector extends AbstractHasComponentsConnector implements
public Object getValue(final JsonObject obj) {
final JsonObject rowData = obj.getObject(GridState.JSONKEY_DATA);
- assert rowData.hasKey(id) : "Could not find data for column with id "
- + id;
+ if (rowData.hasKey(id)) {
+ final JsonValue columnValue = rowData.get(id);
- final JsonValue columnValue = rowData.get(id);
+ return rendererConnector.decode(columnValue);
+ }
- return rendererConnector.decode(columnValue);
+ return null;
}
/*
@@ -202,19 +203,8 @@ public class GridConnector extends AbstractHasComponentsConnector implements
@Override
public void bind(final int rowIndex) {
- /*
- * Because most shared state handling is deferred, we must
- * defer this too to ensure the editorConnector references
- * in shared state are up to date before opening the editor.
- * Yes, this is a hack on top of a hack.
- */
- Scheduler.get().scheduleDeferred(new ScheduledCommand() {
- @Override
- public void execute() {
- serverInitiated = true;
- GridConnector.this.getWidget().editRow(rowIndex);
- }
- });
+ serverInitiated = true;
+ GridConnector.this.getWidget().editRow(rowIndex);
}
@Override
@@ -225,15 +215,8 @@ public class GridConnector extends AbstractHasComponentsConnector implements
@Override
public void confirmBind() {
- /*
- * See comment in bind()
- */
- Scheduler.get().scheduleDeferred(new ScheduledCommand() {
- @Override
- public void execute() {
- endRequest();
- }
- });
+ endRequest();
+
}
@Override
@@ -382,17 +365,33 @@ public class GridConnector extends AbstractHasComponentsConnector implements
registerRpc(GridClientRpc.class, new GridClientRpc() {
@Override
public void scrollToStart() {
- getWidget().scrollToStart();
+ Scheduler.get().scheduleFinally(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ getWidget().scrollToStart();
+ }
+ });
}
@Override
public void scrollToEnd() {
- getWidget().scrollToEnd();
+ Scheduler.get().scheduleFinally(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ getWidget().scrollToEnd();
+ }
+ });
}
@Override
- public void scrollToRow(int row, ScrollDestination destination) {
- getWidget().scrollToRow(row, destination);
+ public void scrollToRow(final int row,
+ final ScrollDestination destination) {
+ Scheduler.get().scheduleFinally(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ getWidget().scrollToRow(row, destination);
+ }
+ });
}
});
@@ -447,62 +446,42 @@ public class GridConnector extends AbstractHasComponentsConnector implements
updateSelectionFromState();
}
- /*
- * The operations in here have been made deferred.
- *
- * The row data needed to react to column changes comes in the RPC
- * calls. Since state is always updated before RPCs are called, we need
- * to be sure that RPC is called before Grid reacts to state changes.
- *
- * Note that there are still some methods annotated with @OnStateChange
- * that aren't deferred. That's okay, though.
- */
-
- Scheduler.get().scheduleDeferred(new ScheduledCommand() {
- @Override
- public void execute() {
- // Column updates
- if (stateChangeEvent.hasPropertyChanged("columns")) {
-
- // Remove old columns
- purgeRemovedColumns();
-
- // Add new columns
- for (GridColumnState state : getState().columns) {
- if (!columnIdToColumn.containsKey(state.id)) {
- addColumnFromStateChangeEvent(state);
- }
- updateColumnFromState(columnIdToColumn.get(state.id),
- state);
- }
- }
+ // Column updates
+ if (stateChangeEvent.hasPropertyChanged("columns")) {
- if (stateChangeEvent.hasPropertyChanged("columnOrder")) {
- if (orderNeedsUpdate(getState().columnOrder)) {
- updateColumnOrderFromState(getState().columnOrder);
- }
- }
+ // Remove old columns
+ purgeRemovedColumns();
- if (stateChangeEvent.hasPropertyChanged("header")) {
- updateHeaderFromState(getState().header);
+ // Add new columns
+ for (GridColumnState state : getState().columns) {
+ if (!columnIdToColumn.containsKey(state.id)) {
+ addColumnFromStateChangeEvent(state);
}
+ updateColumnFromState(columnIdToColumn.get(state.id), state);
+ }
+ }
- if (stateChangeEvent.hasPropertyChanged("footer")) {
- updateFooterFromState(getState().footer);
- }
+ if (stateChangeEvent.hasPropertyChanged("columnOrder")) {
+ if (orderNeedsUpdate(getState().columnOrder)) {
+ updateColumnOrderFromState(getState().columnOrder);
+ }
+ }
- if (stateChangeEvent.hasPropertyChanged("editorEnabled")) {
- getWidget().setEditorEnabled(getState().editorEnabled);
- }
+ if (stateChangeEvent.hasPropertyChanged("header")) {
+ updateHeaderFromState(getState().header);
+ }
- if (stateChangeEvent.hasPropertyChanged("frozenColumnCount")) {
- getWidget().setFrozenColumnCount(
- getState().frozenColumnCount);
- }
+ if (stateChangeEvent.hasPropertyChanged("footer")) {
+ updateFooterFromState(getState().footer);
+ }
- }
- });
+ if (stateChangeEvent.hasPropertyChanged("editorEnabled")) {
+ getWidget().setEditorEnabled(getState().editorEnabled);
+ }
+ if (stateChangeEvent.hasPropertyChanged("frozenColumnCount")) {
+ getWidget().setFrozenColumnCount(getState().frozenColumnCount);
+ }
}
private void updateColumnOrderFromState(List<String> stateColumnOrder) {
diff --git a/client/src/com/vaadin/client/connectors/JavaScriptRendererConnector.java b/client/src/com/vaadin/client/connectors/JavaScriptRendererConnector.java
new file mode 100644
index 0000000000..a7036342f0
--- /dev/null
+++ b/client/src/com/vaadin/client/connectors/JavaScriptRendererConnector.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2000-2014 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.client.connectors;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.dom.client.NativeEvent;
+import com.vaadin.client.BrowserInfo;
+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.ui.renderer.AbstractJavaScriptRenderer;
+
+import elemental.json.JsonObject;
+import elemental.json.JsonValue;
+
+/**
+ * Connector for server-side renderer implemented using JavaScript.
+ *
+ * @since 7.4
+ * @author Vaadin Ltd
+ */
+@Connect(AbstractJavaScriptRenderer.class)
+public class JavaScriptRendererConnector extends
+ AbstractRendererConnector<JsonValue> implements
+ HasJavaScriptConnectorHelper {
+ private final JavaScriptConnectorHelper helper = new JavaScriptConnectorHelper(
+ this);
+
+ private final JavaScriptObject cellReferenceWrapper = createCellReferenceWrapper(BrowserInfo
+ .get().isIE8());
+
+ @Override
+ protected void init() {
+ super.init();
+ helper.init();
+
+ addGetRowKey(helper.getConnectorWrapper());
+ }
+
+ private static native JavaScriptObject createCellReferenceWrapper(
+ boolean isIE8)
+ /*-{
+ var reference = {};
+ if (isIE8) {
+ // IE8 only supports defineProperty for DOM objects
+ reference = $doc.createElement('div');
+ }
+
+ var setProperty = function(name, getter, setter) {
+ var descriptor = {
+ get: getter
+ }
+ if (setter) {
+ descriptor.set = setter;
+ }
+ Object.defineProperty(reference, name, descriptor);
+ };
+
+ setProperty("element", function() {
+ return reference.target.@CellReference::getElement()();
+ }, null);
+
+ setProperty("rowIndex", function() {
+ return reference.target.@CellReference::getRowIndex()();
+ }, null);
+
+ setProperty("columnIndex", function() {
+ return reference.target.@CellReference::getColumnIndex()();
+ }, null);
+
+ setProperty("colSpan", function() {
+ return reference.target.@RendererCellReference::getColSpan()();
+ }, function(colSpan) {
+ reference.target.@RendererCellReference::setColSpan(*)(colSpan);
+ });
+
+ return reference;
+ }-*/;
+
+ @Override
+ public JavaScriptExtensionState getState() {
+ return (JavaScriptExtensionState) super.getState();
+ }
+
+ private native void addGetRowKey(JavaScriptObject wrapper)
+ /*-{
+ var self = this;
+ wrapper.getRowKey = $entry(function(rowIndex) {
+ return @JavaScriptRendererConnector::findRowKey(*)(self, rowIndex);
+ });
+ }-*/;
+
+ private static String findRowKey(JavaScriptRendererConnector connector,
+ int rowIndex) {
+ GridConnector gc = (GridConnector) connector.getParent();
+ JsonObject row = gc.getWidget().getDataSource().getRow(rowIndex);
+ return connector.getRowKey(row);
+ }
+
+ private boolean hasFunction(String name) {
+ return hasFunction(helper.getConnectorWrapper(), name);
+ }
+
+ private static native boolean hasFunction(JavaScriptObject wrapper,
+ String name)
+ /*-{
+ return typeof wrapper[name] === 'function';
+ }-*/;
+
+ @Override
+ protected Renderer<JsonValue> createRenderer() {
+ if (!hasFunction("render")) {
+ throw new RuntimeException("JavaScriptRenderer "
+ + helper.getInitFunctionName()
+ + " must have a function named 'render'");
+ }
+
+ final boolean hasInit = hasFunction("init");
+ final boolean hasDestroy = hasFunction("destroy");
+ final boolean hasOnActivate = hasFunction("onActivate");
+ final boolean hasGetConsumedEvents = hasFunction("getConsumedEvents");
+ final boolean hasOnBrowserEvent = hasFunction("onBrowserEvent");
+
+ return new ComplexRenderer<JsonValue>() {
+ @Override
+ public void render(RendererCellReference cell, JsonValue data) {
+ render(helper.getConnectorWrapper(), getJsCell(cell),
+ Util.json2jso(data));
+ }
+
+ private JavaScriptObject getJsCell(CellReference<?> cell) {
+ updateCellReference(cellReferenceWrapper, cell);
+ return cellReferenceWrapper;
+ }
+
+ public native void render(JavaScriptObject wrapper,
+ JavaScriptObject cell, JavaScriptObject data)
+ /*-{
+ wrapper.render(cell, data);
+ }-*/;
+
+ @Override
+ public void init(RendererCellReference cell) {
+ if (hasInit) {
+ init(helper.getConnectorWrapper(), getJsCell(cell));
+ }
+ }
+
+ private native void init(JavaScriptObject wrapper,
+ JavaScriptObject cell)
+ /*-{
+ wrapper.init(cell);
+ }-*/;
+
+ private native void updateCellReference(
+ JavaScriptObject cellWrapper, CellReference<?> target)
+ /*-{
+ cellWrapper.target = target;
+ }-*/;
+
+ @Override
+ public void destroy(RendererCellReference cell) {
+ if (hasDestroy) {
+ destory(helper.getConnectorWrapper(), getJsCell(cell));
+ } else {
+ super.destroy(cell);
+ }
+ }
+
+ private native void destory(JavaScriptObject wrapper,
+ JavaScriptObject cell)
+ /*-{
+ wrapper.destory(cell);
+ }-*/;
+
+ @Override
+ public boolean onActivate(CellReference<?> cell) {
+ if (hasOnActivate) {
+ return onActivate(helper.getConnectorWrapper(),
+ getJsCell(cell));
+ } else {
+ return super.onActivate(cell);
+ }
+ }
+
+ private native boolean onActivate(JavaScriptObject wrapper,
+ JavaScriptObject cell)
+ /*-{
+ return !!wrapper.onActivate(cell);
+ }-*/;
+
+ @Override
+ public Collection<String> getConsumedEvents() {
+ if (hasGetConsumedEvents) {
+ JsArrayString events = getConsumedEvents(helper
+ .getConnectorWrapper());
+
+ ArrayList<String> list = new ArrayList<String>(
+ events.length());
+ for (int i = 0; i < events.length(); i++) {
+ list.add(events.get(i));
+ }
+ return list;
+ } else {
+ return super.getConsumedEvents();
+ }
+ }
+
+ private native JsArrayString getConsumedEvents(
+ JavaScriptObject wrapper)
+ /*-{
+ var rawEvents = wrapper.getConsumedEvents();
+ var events = [];
+ for(var i = 0; i < rawEvents.length; i++) {
+ events[i] = ""+rawEvents[i];
+ }
+ return events;
+ }-*/;
+
+ @Override
+ public boolean onBrowserEvent(CellReference<?> cell,
+ NativeEvent event) {
+ if (hasOnBrowserEvent) {
+ return onBrowserEvent(helper.getConnectorWrapper(),
+ getJsCell(cell), event);
+ } else {
+ return super.onBrowserEvent(cell, event);
+ }
+ }
+
+ private native boolean onBrowserEvent(JavaScriptObject wrapper,
+ JavaScriptObject cell, NativeEvent event)
+ /*-{
+ return !!wrapper.onBrowserEvent(cell, event);
+ }-*/;
+ };
+ }
+
+ @Override
+ public JsonValue decode(JsonValue value) {
+ // Let the js logic decode the raw json that the server sent
+ return value;
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+ helper.onUnregister();
+ }
+
+ @Override
+ public JavaScriptConnectorHelper getJavascriptConnectorHelper() {
+ return helper;
+ }
+}
diff --git a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java
index c46db08553..74c8dfb02f 100644
--- a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java
+++ b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java
@@ -104,6 +104,43 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector {
rpcProxy.requestRows(firstRowIndex, numberOfRows,
cached.getStart(), cached.length());
+
+ /*
+ * Show the progress indicator if there is a pending data request
+ * and some of the visible rows are being requested. The RPC in
+ * itself will not trigger the indicator since it might just fetch
+ * some rows in the background to fill the cache.
+ *
+ * The indicator will be hidden by the framework when the response
+ * is received (unless another request is already on its way at that
+ * point).
+ */
+ if (getRequestedAvailability().intersects(
+ Range.withLength(firstRowIndex, numberOfRows))) {
+ getConnection().getLoadingIndicator().ensureTriggered();
+ }
+ }
+
+ @Override
+ public void ensureAvailability(int firstRowIndex, int numberOfRows) {
+ super.ensureAvailability(firstRowIndex, numberOfRows);
+
+ /*
+ * We trigger the indicator already at this point since the actual
+ * RPC will not be sent right away when waiting for the response to
+ * a previous request.
+ *
+ * Only triggering here would not be enough since the check that
+ * sets isWaitingForData is deferred. We don't want to trigger the
+ * loading indicator here if we don't know that there is actually a
+ * request going on since some other bug might then cause the
+ * loading indicator to not be hidden.
+ */
+ if (isWaitingForData()
+ && !Range.withLength(firstRowIndex, numberOfRows)
+ .isSubsetOf(getCachedRange())) {
+ getConnection().getLoadingIndicator().ensureTriggered();
+ }
}
@Override
diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
index ffd1d4d170..0ad1631e19 100644
--- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
+++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
@@ -262,10 +262,19 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
ensureCoverageCheck();
}
+ /**
+ * Gets the row index range that was requested by the previous call to
+ * {@link #ensureAvailability(int, int)}.
+ *
+ * @return the requested availability range
+ */
+ public Range getRequestedAvailability() {
+ return requestedAvailability;
+ }
+
private void checkCacheCoverage() {
- if (currentRequestCallback != null) {
- // Anyone clearing currentRequestCallback should run this method
- // again
+ if (isWaitingForData()) {
+ // Anyone clearing the waiting status should run this method again
return;
}
@@ -301,6 +310,17 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
Profiler.leave("AbstractRemoteDataSource.checkCacheCoverage");
}
+ /**
+ * Checks whether this data source is currently waiting for more rows to
+ * become available.
+ *
+ * @return <code>true</code> if waiting for data; otherwise
+ * <code>false</code>
+ */
+ public boolean isWaitingForData() {
+ return currentRequestCallback != null;
+ }
+
private void discardStaleCacheEntries() {
Range[] cacheParition = cached.partitionWith(getMaxCacheRange());
dropFromCache(cacheParition[0]);
@@ -378,7 +398,7 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
Range received = Range.withLength(firstRowIndex, rowData.size());
- if (currentRequestCallback != null) {
+ if (isWaitingForData()) {
cacheStrategy.onDataArrive(Duration.currentTimeMillis()
- currentRequestCallback.requestStart, received.length());
diff --git a/client/src/com/vaadin/client/metadata/TypeDataStore.java b/client/src/com/vaadin/client/metadata/TypeDataStore.java
index e3db0ccded..46f26f1b25 100644
--- a/client/src/com/vaadin/client/metadata/TypeDataStore.java
+++ b/client/src/com/vaadin/client/metadata/TypeDataStore.java
@@ -29,7 +29,7 @@ import com.vaadin.shared.annotations.NoLayout;
public class TypeDataStore {
public static enum MethodAttribute {
- DELAYED, LAST_ONLY, NO_LAYOUT;
+ DELAYED, LAST_ONLY, NO_LAYOUT, NO_LOADING_INDICATOR;
}
private static final String CONSTRUCTOR_NAME = "!new";
@@ -219,6 +219,10 @@ public class TypeDataStore {
return hasMethodAttribute(method, MethodAttribute.DELAYED);
}
+ public static boolean isNoLoadingIndicator(Method method) {
+ return hasMethodAttribute(method, MethodAttribute.NO_LOADING_INDICATOR);
+ }
+
private static boolean hasMethodAttribute(Method method,
MethodAttribute attribute) {
FastStringSet attributes = get().methodAttributes.get(method
diff --git a/client/src/com/vaadin/client/renderers/ProgressBarRenderer.java b/client/src/com/vaadin/client/renderers/ProgressBarRenderer.java
index 8e09641cfc..5b2c70d274 100644
--- a/client/src/com/vaadin/client/renderers/ProgressBarRenderer.java
+++ b/client/src/com/vaadin/client/renderers/ProgressBarRenderer.java
@@ -29,7 +29,9 @@ public class ProgressBarRenderer extends WidgetRenderer<Double, VProgressBar> {
@Override
public VProgressBar createWidget() {
- return GWT.create(VProgressBar.class);
+ VProgressBar progressBar = GWT.create(VProgressBar.class);
+ progressBar.addStyleDependentName("static");
+ return progressBar;
}
@Override
diff --git a/client/src/com/vaadin/client/widget/grid/RendererCellReference.java b/client/src/com/vaadin/client/widget/grid/RendererCellReference.java
index 07ca462293..533eafded6 100644
--- a/client/src/com/vaadin/client/widget/grid/RendererCellReference.java
+++ b/client/src/com/vaadin/client/widget/grid/RendererCellReference.java
@@ -83,7 +83,7 @@ public class RendererCellReference extends CellReference<Object> {
*
* @return the number of columns that the cell should span
*/
- public int getColspan() {
+ public int getColSpan() {
return cell.getColSpan();
}
}
diff --git a/client/src/com/vaadin/client/widgets/Escalator.java b/client/src/com/vaadin/client/widgets/Escalator.java
index deaa9005c3..a4e3846196 100644
--- a/client/src/com/vaadin/client/widgets/Escalator.java
+++ b/client/src/com/vaadin/client/widgets/Escalator.java
@@ -64,7 +64,6 @@ import com.vaadin.client.widget.escalator.PositionFunction.AbsolutePosition;
import com.vaadin.client.widget.escalator.PositionFunction.Translate3DPosition;
import com.vaadin.client.widget.escalator.PositionFunction.TranslatePosition;
import com.vaadin.client.widget.escalator.PositionFunction.WebkitTranslate3DPosition;
-import com.vaadin.client.widget.escalator.Row;
import com.vaadin.client.widget.escalator.RowContainer;
import com.vaadin.client.widget.escalator.RowVisibilityChangeEvent;
import com.vaadin.client.widget.escalator.RowVisibilityChangeHandler;
@@ -2184,6 +2183,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
bodyElem.getStyle().setMarginTop(heightOfSection, Unit.PX);
verticalScrollbar.getElement().getStyle()
.setTop(heightOfSection, Unit.PX);
+ headerDeco.getStyle().setHeight(heightOfSection, Unit.PX);
}
@Override
@@ -2225,6 +2225,8 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
vscrollHeight -= horizontalScrollbar.getScrollbarThickness();
}
+ footerDeco.getStyle().setHeight(footer.heightOfSection, Unit.PX);
+
verticalScrollbar.setOffsetSize(vscrollHeight);
}
}
@@ -4730,9 +4732,6 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
body.recalculateSectionHeight();
footer.recalculateSectionHeight();
- headerDeco.getStyle().setHeight(header.heightOfSection, Unit.PX);
- footerDeco.getStyle().setHeight(footer.heightOfSection, Unit.PX);
-
scroller.recalculateScrollbarsForVirtualViewport();
body.verifyEscalatorCount();
Profiler.leave("Escalator.recalculateElementSizes");
diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java
index 10857f8d6a..2e10ccfef1 100644
--- a/server/src/com/vaadin/data/RpcDataProviderExtension.java
+++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java
@@ -404,9 +404,9 @@ public class RpcDataProviderExtension extends AbstractExtension {
itemId);
valueChangeListeners.put(itemId, listener);
- for (final Object propertyId : item.getItemPropertyIds()) {
- final Property<?> property = item
- .getItemProperty(propertyId);
+ for (final Column column : getGrid().getColumns()) {
+ final Property<?> property = item.getItemProperty(column
+ .getPropertyId());
if (property instanceof ValueChangeNotifier) {
((ValueChangeNotifier) property)
.addValueChangeListener(listener);
@@ -423,9 +423,9 @@ public class RpcDataProviderExtension extends AbstractExtension {
.remove(itemId);
if (listener != null) {
- for (final Object propertyId : item.getItemPropertyIds()) {
+ for (final Column column : getGrid().getColumns()) {
final Property<?> property = item
- .getItemProperty(propertyId);
+ .getItemProperty(column.getPropertyId());
if (property instanceof ValueChangeNotifier) {
((ValueChangeNotifier) property)
.removeValueChangeListener(listener);
@@ -436,30 +436,46 @@ public class RpcDataProviderExtension extends AbstractExtension {
}
/**
- * Manages removed properties in active rows.
+ * Manages removed columns in active rows.
+ * <p>
+ * This method does <em>not</em> send data again to the client.
*
- * @param removedPropertyIds
- * the property ids that have been removed from the container
+ * @param removedColumns
+ * the columns that have been removed from the grid
*/
- public void propertiesRemoved(
- @SuppressWarnings("unused") Collection<Object> removedPropertyIds) {
- /*
- * no-op, for now.
- *
- * The Container should be responsible for cleaning out any
- * ValueChangeListeners from removed Properties. Components will
- * benefit from this, however.
- */
+ public void columnsRemoved(Collection<Column> removedColumns) {
+ if (removedColumns.isEmpty()) {
+ return;
+ }
+
+ for (int i = activeRange.getStart(); i < activeRange.getEnd(); i++) {
+ final Object itemId = container.getIdByIndex(i);
+ final Item item = container.getItem(itemId);
+ final GridValueChangeListener listener = valueChangeListeners
+ .get(itemId);
+ assert (listener != null) : "a listener should've been pre-made by addValueChangeListeners";
+
+ for (final Column column : removedColumns) {
+ final Property<?> property = item.getItemProperty(column
+ .getPropertyId());
+ if (property instanceof ValueChangeNotifier) {
+ ((ValueChangeNotifier) property)
+ .removeValueChangeListener(listener);
+ }
+ }
+ }
}
/**
- * Manages added properties in active rows.
+ * Manages added columns in active rows.
+ * <p>
+ * This method sends the data for the changed rows to client side.
*
- * @param addedPropertyIds
- * the property ids that have been added to the container
+ * @param addedColumns
+ * the columns that have been added to the grid
*/
- public void propertiesAdded(Collection<Object> addedPropertyIds) {
- if (addedPropertyIds.isEmpty()) {
+ public void columnsAdded(Collection<Column> addedColumns) {
+ if (addedColumns.isEmpty()) {
return;
}
@@ -470,9 +486,9 @@ public class RpcDataProviderExtension extends AbstractExtension {
.get(itemId);
assert (listener != null) : "a listener should've been pre-made by addValueChangeListeners";
- for (final Object propertyId : addedPropertyIds) {
- final Property<?> property = item
- .getItemProperty(propertyId);
+ for (final Column column : addedColumns) {
+ final Property<?> property = item.getItemProperty(column
+ .getPropertyId());
if (property instanceof ValueChangeNotifier) {
((ValueChangeNotifier) property)
.addValueChangeListener(listener);
@@ -924,37 +940,24 @@ public class RpcDataProviderExtension extends AbstractExtension {
}
/**
- * Informs this data provider that some of the properties have been removed
- * from the container.
- * <p>
- * Please note that we could add our own
- * {@link com.vaadin.data.Container.PropertySetChangeListener
- * PropertySetChangeListener} to the container, but then we'd need to
- * implement the same bookeeping for finding what's added and removed that
- * Grid already does in its own listener.
+ * Informs this data provider that given columns have been removed from
+ * grid.
*
* @param removedColumns
- * a list of property ids for the removed columns
+ * a list of removed columns
*/
- public void propertiesRemoved(List<Object> removedColumns) {
- activeRowHandler.propertiesRemoved(removedColumns);
+ public void columnsRemoved(List<Column> removedColumns) {
+ activeRowHandler.columnsRemoved(removedColumns);
}
/**
- * Informs this data provider that some of the properties have been added to
- * the container.
- * <p>
- * Please note that we could add our own
- * {@link com.vaadin.data.Container.PropertySetChangeListener
- * PropertySetChangeListener} to the container, but then we'd need to
- * implement the same bookeeping for finding what's added and removed that
- * Grid already does in its own listener.
+ * Informs this data provider that given columns have been added to grid.
*
- * @param addedPropertyIds
- * a list of property ids for the added columns
+ * @param addedColumns
+ * a list of added columns
*/
- public void propertiesAdded(HashSet<Object> addedPropertyIds) {
- activeRowHandler.propertiesAdded(addedPropertyIds);
+ public void columnsAdded(List<Column> addedColumns) {
+ activeRowHandler.columnsAdded(addedColumns);
}
public DataProviderKeyMapper getKeyMapper() {
diff --git a/server/src/com/vaadin/server/AbstractJavaScriptExtension.java b/server/src/com/vaadin/server/AbstractJavaScriptExtension.java
index e182319c85..e9cf2c5e33 100644
--- a/server/src/com/vaadin/server/AbstractJavaScriptExtension.java
+++ b/server/src/com/vaadin/server/AbstractJavaScriptExtension.java
@@ -106,8 +106,8 @@ import com.vaadin.ui.JavaScriptFunction;
* <li>Java Dates are represented by JavaScript numbers containing the timestamp
* </li>
* <li>List, Set and all arrays in Java are represented by JavaScript arrays.</li>
- * <li>Map<String, ?> in Java is represented by JavaScript object with fields
- * corresponding to the map keys.</li>
+ * <li>Map&lt;String, ?&gt; in Java is represented by JavaScript object with
+ * fields corresponding to the map keys.</li>
* <li>Any other Java Map is represented by a JavaScript array containing two
* arrays, the first contains the keys and the second contains the values in the
* same order.</li>
diff --git a/server/src/com/vaadin/ui/AbstractJavaScriptComponent.java b/server/src/com/vaadin/ui/AbstractJavaScriptComponent.java
index f3cbf47b62..84023555bb 100644
--- a/server/src/com/vaadin/ui/AbstractJavaScriptComponent.java
+++ b/server/src/com/vaadin/ui/AbstractJavaScriptComponent.java
@@ -119,8 +119,8 @@ import com.vaadin.shared.ui.JavaScriptComponentState;
* <li>Java Dates are represented by JavaScript numbers containing the timestamp
* </li>
* <li>List, Set and all arrays in Java are represented by JavaScript arrays.</li>
- * <li>Map<String, ?> in Java is represented by JavaScript object with fields
- * corresponding to the map keys.</li>
+ * <li>Map&lt;String, ?&gt; in Java is represented by JavaScript object with
+ * fields corresponding to the map keys.</li>
* <li>Any other Java Map is represented by a JavaScript array containing two
* arrays, the first contains the keys and the second contains the values in the
* same order.</li>
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index 316f7682de..0843fb6ec1 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -2447,28 +2447,30 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
Collection<?> properties = new HashSet<Object>(event.getContainer()
.getContainerPropertyIds());
- // Cleanup columns that are no longer in grid
- List<Object> removedColumns = new LinkedList<Object>();
- for (Object columnId : columns.keySet()) {
- if (!properties.contains(columnId)) {
- removedColumns.add(columnId);
+ // Find columns that need to be removed.
+ List<Column> removedColumns = new LinkedList<Column>();
+ for (Object propertyId : columns.keySet()) {
+ if (!properties.contains(propertyId)) {
+ removedColumns.add(getColumn(propertyId));
}
}
- for (Object columnId : removedColumns) {
- removeColumn(columnId);
- columnKeys.remove(columnId);
+
+ // Actually remove columns.
+ for (Column column : removedColumns) {
+ Object propertyId = column.getPropertyId();
+ internalRemoveColumn(propertyId);
+ columnKeys.remove(propertyId);
}
- datasourceExtension.propertiesRemoved(removedColumns);
+ datasourceExtension.columnsRemoved(removedColumns);
// Add new columns
- HashSet<Object> addedPropertyIds = new HashSet<Object>();
+ List<Column> addedColumns = new LinkedList<Column>();
for (Object propertyId : properties) {
if (!columns.containsKey(propertyId)) {
- appendColumn(propertyId);
- addedPropertyIds.add(propertyId);
+ addedColumns.add(appendColumn(propertyId));
}
}
- datasourceExtension.propertiesAdded(addedPropertyIds);
+ datasourceExtension.columnsAdded(addedColumns);
if (getFrozenColumnCount() > columns.size()) {
setFrozenColumnCount(columns.size());
@@ -2950,7 +2952,14 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
} else {
addColumnProperty(propertyId, String.class, "");
}
- return getColumn(propertyId);
+
+ // Inform the data provider of this new column.
+ Column column = getColumn(propertyId);
+ List<Column> addedColumns = new ArrayList<Column>();
+ addedColumns.add(column);
+ datasourceExtension.columnsAdded(addedColumns);
+
+ return column;
}
/**
@@ -3012,10 +3021,12 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* Removes all columns from this Grid.
*/
public void removeAllColumns() {
+ List<Column> removed = new ArrayList<Column>(columns.values());
Set<Object> properties = new HashSet<Object>(columns.keySet());
for (Object propertyId : properties) {
removeColumn(propertyId);
}
+ datasourceExtension.columnsRemoved(removed);
}
/**
@@ -3093,6 +3104,13 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* The property id of column to be removed
*/
public void removeColumn(Object propertyId) {
+ List<Column> removed = new ArrayList<Column>();
+ removed.add(getColumn(propertyId));
+ internalRemoveColumn(propertyId);
+ datasourceExtension.columnsRemoved(removed);
+ }
+
+ private void internalRemoveColumn(Object propertyId) {
setEditorField(propertyId, null);
header.removeColumn(propertyId);
footer.removeColumn(propertyId);
@@ -4439,7 +4457,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
/**
- * Cancels the currently active edit if any.
+ * Cancels the currently active edit if any. Hides the editor and discards
+ * possible unsaved changes in the editor fields.
*/
public void cancelEditor() {
if (isEditorActive()) {
@@ -4451,6 +4470,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
protected void doCancelEditor() {
editedItemId = null;
+ editorFieldGroup.discard();
}
void resetEditor() {
diff --git a/server/src/com/vaadin/ui/renderer/AbstractJavaScriptRenderer.java b/server/src/com/vaadin/ui/renderer/AbstractJavaScriptRenderer.java
new file mode 100644
index 0000000000..8fabded536
--- /dev/null
+++ b/server/src/com/vaadin/ui/renderer/AbstractJavaScriptRenderer.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2000-2014 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.ui.renderer;
+
+import com.vaadin.server.AbstractJavaScriptExtension;
+import com.vaadin.server.JavaScriptCallbackHelper;
+import com.vaadin.shared.JavaScriptExtensionState;
+import com.vaadin.shared.communication.ServerRpc;
+import com.vaadin.ui.Grid.AbstractRenderer;
+import com.vaadin.ui.JavaScriptFunction;
+
+/**
+ * Base class for Renderers with all client-side logic implemented using
+ * JavaScript.
+ * <p>
+ * When a new JavaScript renderer is initialized in the browser, the framework
+ * will look for a globally defined JavaScript function that will initialize the
+ * renderer. The name of the initialization function is formed by replacing .
+ * with _ in the name of the server-side class. If no such function is defined,
+ * each super class is used in turn until a match is found. The framework will
+ * thus first attempt with <code>com_example_MyRenderer</code> for the
+ * server-side
+ * <code>com.example.MyRenderer extends AbstractJavaScriptRenderer</code> class.
+ * If MyRenderer instead extends <code>com.example.SuperRenderer</code> , then
+ * <code>com_example_SuperRenderer</code> will also be attempted if
+ * <code>com_example_MyRenderer</code> has not been defined.
+ * <p>
+ *
+ * In addition to the general JavaScript extension functionality explained in
+ * {@link AbstractJavaScriptExtension}, this class also provides some
+ * functionality specific for renderers.
+ * <p>
+ * The initialization function will be called with <code>this</code> pointing to
+ * a connector wrapper object providing integration to Vaadin with the following
+ * functions:
+ * <ul>
+ * <li><code>getRowKey(rowIndex)</code> - Gets a unique identifier for the row
+ * at the given index. This identifier can be used on the server to retrieve the
+ * corresponding ItemId using {@link #getItemId(String)}.</li>
+ * </ul>
+ * The connector wrapper also supports these special functions that can be
+ * implemented by the connector:
+ * <ul>
+ * <li><code>render(cell, data)</code> - Callback for rendering the given data
+ * into the given cell. The structure of cell and data are described in separate
+ * sections below. The renderer is required to implement this function.
+ * Corresponds to
+ * {@link com.vaadin.client.renderers.Renderer#render(com.vaadin.client.widget.grid.RendererCellReference, Object)}
+ * .</li>
+ * <li><code>init(cell)</code> - Prepares a cell for rendering. Corresponds to
+ * {@link com.vaadin.client.renderers.ComplexRenderer#init(com.vaadin.client.widget.grid.RendererCellReference)}
+ * .</li>
+ * <li><code>destory(cell)</code> - Allows the renderer to release resources
+ * allocate for a cell that will no longer be used. Corresponds to
+ * {@link com.vaadin.client.renderers.ComplexRenderer#destroy(com.vaadin.client.widget.grid.RendererCellReference)}
+ * .</li>
+ * <li><code>onActivate(cell)</code> - Called when the cell is activated by the
+ * user e.g. by double clicking on the cell or pressing enter with the cell
+ * focused. Corresponds to
+ * {@link com.vaadin.client.renderers.ComplexRenderer#onActivate(com.vaadin.client.widget.grid.CellReference)}
+ * .</li>
+ * <li><code>getConsumedEvents()</code> - Returns a JavaScript array of event
+ * names that should cause onBrowserEvent to be invoked whenever an event is
+ * fired for a cell managed by this renderer. Corresponds to
+ * {@link com.vaadin.client.renderers.ComplexRenderer#getConsumedEvents()}.</li>
+ * <li><code>onBrowserEvent(cell, event)</code> - Called by Grid when an event
+ * of a type returned by getConsumedEvents is fired for a cell managed by this
+ * renderer. Corresponds to
+ * {@link com.vaadin.client.renderers.ComplexRenderer#onBrowserEvent(com.vaadin.client.widget.grid.CellReference, com.google.gwt.dom.client.NativeEvent)}
+ * .</li>
+ * </ul>
+ *
+ * <p>
+ * The cell object passed to functions defined by the renderer has these
+ * properties:
+ * <ul>
+ * <li><code>element</code> - The DOM element corresponding to this cell.
+ * Readonly.</li>
+ * <li><code>rowIndex</code> - The current index of the row of this cell.
+ * Readonly.</li>
+ * <li><code>columnIndex</code> - The current index of the column of this cell.
+ * Readonly.</li>
+ * <li><code>colSpan</code> - The number of columns spanned by this cell. Only
+ * supported in the object passed to the <code>render</code> function - other
+ * functions should not use the property. Readable and writable.
+ * </ul>
+ *
+ * @author Vaadin Ltd
+ * @since 7.4
+ */
+public abstract class AbstractJavaScriptRenderer<T> extends AbstractRenderer<T> {
+ private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper(
+ this);
+
+ protected AbstractJavaScriptRenderer(Class<T> presentationType) {
+ super(presentationType);
+ }
+
+ @Override
+ protected <R extends ServerRpc> void registerRpc(R implementation,
+ Class<R> rpcInterfaceType) {
+ super.registerRpc(implementation, rpcInterfaceType);
+ callbackHelper.registerRpc(rpcInterfaceType);
+ }
+
+ /**
+ * Register a {@link JavaScriptFunction} that can be called from the
+ * JavaScript using the provided name. A JavaScript function with the
+ * provided name will be added to the connector wrapper object (initially
+ * available as <code>this</code>). Calling that JavaScript function will
+ * cause the call method in the registered {@link JavaScriptFunction} to be
+ * invoked with the same arguments.
+ *
+ * @param functionName
+ * the name that should be used for client-side callback
+ * @param function
+ * the {@link JavaScriptFunction} object that will be invoked
+ * when the JavaScript function is called
+ */
+ protected void addFunction(String functionName, JavaScriptFunction function) {
+ callbackHelper.registerCallback(functionName, function);
+ }
+
+ /**
+ * Invoke a named function that the connector JavaScript has added to the
+ * JavaScript connector wrapper object. The arguments should only contain
+ * data types that can be represented in JavaScript including primitives,
+ * their boxed types, arrays, String, List, Set, Map, Connector and
+ * JavaBeans.
+ *
+ * @param name
+ * the name of the function
+ * @param arguments
+ * function arguments
+ */
+ protected void callFunction(String name, Object... arguments) {
+ callbackHelper.invokeCallback(name, arguments);
+ }
+
+ @Override
+ protected JavaScriptExtensionState getState() {
+ return (JavaScriptExtensionState) super.getState();
+ }
+}
diff --git a/server/src/com/vaadin/ui/themes/Reindeer.java b/server/src/com/vaadin/ui/themes/Reindeer.java
index 6eeebd8a03..e0ab792a15 100644
--- a/server/src/com/vaadin/ui/themes/Reindeer.java
+++ b/server/src/com/vaadin/ui/themes/Reindeer.java
@@ -15,14 +15,6 @@
*/
package com.vaadin.ui.themes;
-import com.vaadin.ui.CssLayout;
-import com.vaadin.ui.FormLayout;
-import com.vaadin.ui.GridLayout;
-import com.vaadin.ui.HorizontalLayout;
-import com.vaadin.ui.HorizontalSplitPanel;
-import com.vaadin.ui.VerticalLayout;
-import com.vaadin.ui.VerticalSplitPanel;
-
public class Reindeer extends BaseTheme {
public static final String THEME_NAME = "reindeer";
@@ -90,6 +82,18 @@ public class Reindeer extends BaseTheme {
/***************************************************************************
*
+ * ProgressBar Styles
+ *
+ **************************************************************************/
+
+ /**
+ * Displays the progress bar with a static background, instead of an
+ * animated one.
+ */
+ public static final String PROGRESSBAR_STATIC = "static";
+
+ /***************************************************************************
+ *
* SplitPanel styles
*
**************************************************************************/
diff --git a/server/src/com/vaadin/ui/themes/Runo.java b/server/src/com/vaadin/ui/themes/Runo.java
index 11f1bae682..6f8d5f37d9 100644
--- a/server/src/com/vaadin/ui/themes/Runo.java
+++ b/server/src/com/vaadin/ui/themes/Runo.java
@@ -59,6 +59,18 @@ public class Runo extends BaseTheme {
/***************************************************************************
*
+ * ProgressBar Styles
+ *
+ **************************************************************************/
+
+ /**
+ * Displays the progress bar with a static background, instead of an
+ * animated one.
+ */
+ public static final String PROGRESSBAR_STATIC = "static";
+
+ /***************************************************************************
+ *
* TabSheet styles
*
**************************************************************************/
diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridEditorTest.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridEditorTest.java
index c3817efc3f..3e52314fbc 100644
--- a/server/tests/src/com/vaadin/tests/server/component/grid/GridEditorTest.java
+++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridEditorTest.java
@@ -24,11 +24,14 @@ import static org.junit.Assert.assertTrue;
import org.easymock.EasyMock;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.vaadin.data.Item;
+import com.vaadin.data.Property;
import com.vaadin.data.fieldgroup.FieldGroup;
+import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.server.MockVaadinSession;
import com.vaadin.server.VaadinService;
@@ -41,6 +44,8 @@ public class GridEditorTest {
private static final Object PROPERTY_NAME = "name";
private static final Object PROPERTY_AGE = "age";
+ private static final String DEFAULT_NAME = "Some Valid Name";
+ private static final Integer DEFAULT_AGE = 25;
private static final Object ITEM_ID = new Object();
private Grid grid;
@@ -57,8 +62,8 @@ public class GridEditorTest {
Integer.valueOf(-1));
Item item = container.addItem(ITEM_ID);
- item.getItemProperty(PROPERTY_NAME).setValue("Some Valid Name");
- item.getItemProperty(PROPERTY_AGE).setValue(Integer.valueOf(25));
+ item.getItemProperty(PROPERTY_NAME).setValue(DEFAULT_NAME);
+ item.getItemProperty(PROPERTY_AGE).setValue(DEFAULT_AGE);
grid = new Grid(container);
@@ -125,6 +130,57 @@ public class GridEditorTest {
public void editItem() throws Exception {
startEdit();
assertEquals(ITEM_ID, grid.getEditedItemId());
+ assertEquals(getEditedItem(), grid.getEditorFieldGroup()
+ .getItemDataSource());
+
+ assertEquals(DEFAULT_NAME, grid.getEditorField(PROPERTY_NAME)
+ .getValue());
+ assertEquals(String.valueOf(DEFAULT_AGE),
+ grid.getEditorField(PROPERTY_AGE).getValue());
+ }
+
+ @Test
+ public void saveEditor() throws Exception {
+ startEdit();
+ TextField field = (TextField) grid.getEditorField(PROPERTY_NAME);
+
+ field.setValue("New Name");
+ assertEquals(DEFAULT_NAME, field.getPropertyDataSource().getValue());
+
+ grid.saveEditor();
+ assertTrue(grid.isEditorActive());
+ assertFalse(field.isModified());
+ assertEquals("New Name", field.getValue());
+ assertEquals("New Name", getEditedProperty(PROPERTY_NAME).getValue());
+ }
+
+ @Test
+ public void saveEditorCommitFail() throws Exception {
+ startEdit();
+
+ ((TextField) grid.getEditorField(PROPERTY_AGE)).setValue("Invalid");
+ try {
+ // Manual fail instead of @Test(expected=...) to check it is
+ // saveEditor that fails and not setValue
+ grid.saveEditor();
+ Assert.fail("CommitException expected when saving an invalid field value");
+ } catch (CommitException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void cancelEditor() throws Exception {
+ startEdit();
+ TextField field = (TextField) grid.getEditorField(PROPERTY_NAME);
+ field.setValue("New Name");
+
+ grid.cancelEditor();
+ assertFalse(grid.isEditorActive());
+ assertNull(grid.getEditedItemId());
+ assertFalse(field.isModified());
+ assertEquals(DEFAULT_NAME, field.getValue());
+ assertEquals(DEFAULT_NAME, field.getPropertyDataSource().getValue());
}
@Test(expected = IllegalArgumentException.class)
@@ -206,4 +262,13 @@ public class GridEditorTest {
grid.setEditorEnabled(true);
grid.editItem(ITEM_ID);
}
+
+ private Item getEditedItem() {
+ assertNotNull(grid.getEditedItemId());
+ return grid.getContainerDataSource().getItem(grid.getEditedItemId());
+ }
+
+ private Property<?> getEditedProperty(Object propertyId) {
+ return getEditedItem().getItemProperty(PROPERTY_NAME);
+ }
}
diff --git a/shared/src/com/vaadin/shared/annotations/NoLoadingIndicator.java b/shared/src/com/vaadin/shared/annotations/NoLoadingIndicator.java
new file mode 100644
index 0000000000..2e519b69e8
--- /dev/null
+++ b/shared/src/com/vaadin/shared/annotations/NoLoadingIndicator.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used to mark server RPC methods for which it isn't necessary to
+ * show the loading indicator. The framework will show a loading indicator when
+ * sending requests for RPC methods that are not marked with this annotation.
+ * The loading indicator is hidden once a response is received.
+ *
+ * @since 7.4
+ * @author Vaadin Ltd
+ */
+@Target(ElementType.METHOD)
+@Documented
+public @interface NoLoadingIndicator {
+ // Just an empty marker annotation
+}
diff --git a/shared/src/com/vaadin/shared/data/DataRequestRpc.java b/shared/src/com/vaadin/shared/data/DataRequestRpc.java
index 773a82fa9a..0d9b919a4e 100644
--- a/shared/src/com/vaadin/shared/data/DataRequestRpc.java
+++ b/shared/src/com/vaadin/shared/data/DataRequestRpc.java
@@ -16,6 +16,7 @@
package com.vaadin.shared.data;
+import com.vaadin.shared.annotations.NoLoadingIndicator;
import com.vaadin.shared.annotations.Delayed;
import com.vaadin.shared.communication.ServerRpc;
@@ -39,6 +40,7 @@ public interface DataRequestRpc extends ServerRpc {
* @param cacheSize
* the number of cached rows
*/
+ @NoLoadingIndicator
public void requestRows(int firstRowIndex, int numberOfRows,
int firstCachedRowIndex, int cacheSize);
diff --git a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorServerRpc.java b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorServerRpc.java
index dd437094c7..f541395cef 100644
--- a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorServerRpc.java
+++ b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorServerRpc.java
@@ -15,8 +15,10 @@
*/
package com.vaadin.shared.ui.progressindicator;
+import com.vaadin.shared.annotations.NoLoadingIndicator;
import com.vaadin.shared.communication.ServerRpc;
public interface ProgressIndicatorServerRpc extends ServerRpc {
+ @NoLoadingIndicator
public void poll();
}
diff --git a/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java b/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java
index 8227415e58..887ea760b3 100644
--- a/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java
+++ b/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java
@@ -15,6 +15,7 @@
*/
package com.vaadin.shared.ui.ui;
+import com.vaadin.shared.annotations.NoLoadingIndicator;
import com.vaadin.shared.annotations.Delayed;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.ui.ClickRpc;
@@ -27,6 +28,7 @@ public interface UIServerRpc extends ClickRpc, ServerRpc {
@Delayed(lastOnly = true)
public void scroll(int scrollTop, int scrollLeft);
+ @NoLoadingIndicator
@Delayed(lastOnly = true)
/*
* @Delayed just to get lastOnly semantics, sendPendingVariableChanges()
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java
index e9987db1a8..2ab0282102 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java
@@ -44,6 +44,7 @@ public class GridSingleColumn extends AbstractTestUI {
column.setHeaderCaption("Header");
addComponent(grid);
+ grid.scrollTo(grid.getContainerDataSource().getIdByIndex(50));
}
@Override
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java
index 05f6b4b9f7..42eb2197bf 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java
@@ -20,6 +20,7 @@ import org.junit.Test;
import com.vaadin.testbench.elements.GridElement;
import com.vaadin.testbench.elements.GridElement.GridCellElement;
+import com.vaadin.testbench.elements.NotificationElement;
import com.vaadin.tests.annotations.TestCategory;
import com.vaadin.tests.tb3.MultiBrowserTest;
@@ -27,11 +28,20 @@ import com.vaadin.tests.tb3.MultiBrowserTest;
public class GridSingleColumnTest extends MultiBrowserTest {
@Test
- public void headerIsVisible() {
+ public void testHeaderIsVisible() {
openTestURL();
GridCellElement cell = $(GridElement.class).first().getHeaderCell(0, 0);
Assert.assertTrue("No header available", cell.getText()
.equalsIgnoreCase("header"));
}
+
+ @Test
+ public void testScrollDidNotThrow() {
+ setDebug(true);
+ openTestURL();
+
+ Assert.assertFalse("Exception when scrolling on init",
+ isElementPresent(NotificationElement.class));
+ }
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderers.java b/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderers.java
new file mode 100644
index 0000000000..4bfa244c22
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderers.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.grid;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Grid;
+
+public class JavaScriptRenderers extends AbstractTestUI {
+
+ public static class MyBean {
+ private int integer;
+ private String string;
+
+ public MyBean(int integer, String string) {
+ super();
+ this.integer = integer;
+ this.string = string;
+ }
+
+ public int getInteger() {
+ return integer;
+ }
+
+ public void setInteger(int integer) {
+ this.integer = integer;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public void setString(String string) {
+ this.string = string;
+ }
+ }
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ IndexedContainer container = new IndexedContainer();
+ container.addContainerProperty("id", Integer.class, Integer.valueOf(0));
+ container.addContainerProperty("bean", MyBean.class, null);
+
+ for (int i = 0; i < 1000; i++) {
+ Integer itemId = Integer.valueOf(i);
+ Item item = container.addItem(itemId);
+ item.getItemProperty("id").setValue(itemId);
+ item.getItemProperty("bean").setValue(
+ new MyBean(i + 1, Integer.toString(i - 1)));
+ }
+
+ Grid grid = new Grid(container);
+
+ grid.getColumn("bean").setRenderer(new MyBeanJSRenderer());
+ grid.getColumn("bean").setWidth(250);
+
+ addComponent(grid);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java b/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java
new file mode 100644
index 0000000000..a3bb736086
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.grid;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.elements.GridElement.GridCellElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class JavaScriptRenderersTest extends MultiBrowserTest {
+
+ @Test
+ public void testJavaScriptRenderer() {
+ setDebug(true);
+ openTestURL();
+
+ GridElement grid = $(GridElement.class).first();
+ GridCellElement cell_1_2 = grid.getCell(1, 2);
+
+ // Verify render functionality
+ Assert.assertEquals("Bean(2, 0)", cell_1_2.getText());
+
+ // Verify init functionality
+ Assert.assertEquals("2", cell_1_2.getAttribute("column"));
+
+ // Verify onbrowserevent
+ cell_1_2.click();
+ Assert.assertTrue(cell_1_2.getText().startsWith(
+ "Clicked 1 with key 1 at"));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/MyBeanJSRenderer.java b/uitest/src/com/vaadin/tests/components/grid/MyBeanJSRenderer.java
new file mode 100644
index 0000000000..ccb94f5d2d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/MyBeanJSRenderer.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.grid;
+
+import com.vaadin.annotations.JavaScript;
+import com.vaadin.tests.components.grid.JavaScriptRenderers.MyBean;
+import com.vaadin.ui.renderer.AbstractJavaScriptRenderer;
+
+/**
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@JavaScript("myBeanJsRenderer.js")
+public class MyBeanJSRenderer extends AbstractJavaScriptRenderer<MyBean> {
+
+ public MyBeanJSRenderer() {
+ super(MyBean.class);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
index 20b6a3c418..5912f2b5a5 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
@@ -77,6 +77,8 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
public static final int COLUMNS = 12;
public static final int ROWS = 1000;
+ private int containerDelay = 0;
+
private IndexedContainer ds;
private Grid grid;
private SelectionListener selectionListener = new SelectionListener() {
@@ -101,6 +103,13 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
public List<Object> getItemIds(int startIndex, int numberOfIds) {
log("Requested items " + startIndex + " - "
+ (startIndex + numberOfIds));
+ if (containerDelay > 0) {
+ try {
+ Thread.sleep(containerDelay);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
return super.getItemIds(startIndex, numberOfIds);
}
};
@@ -437,6 +446,19 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
c.setFrozenColumnCount(value.intValue());
}
});
+
+ LinkedHashMap<String, Integer> containerDelayValues = new LinkedHashMap<String, Integer>();
+ for (int delay : new int[] { 0, 500, 2000, 10000 }) {
+ containerDelayValues.put(String.valueOf(delay),
+ Integer.valueOf(delay));
+ }
+ createSelectAction("Container delay", "State", containerDelayValues,
+ "0", new Command<Grid, Integer>() {
+ @Override
+ public void execute(Grid grid, Integer delay, Object data) {
+ containerDelay = delay.intValue();
+ }
+ });
}
protected void createHeaderActions() {
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientStructureTest.java
new file mode 100644
index 0000000000..74cf368da9
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientStructureTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.grid.basicfeatures.client;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest;
+
+@SuppressWarnings("all")
+public class GridClientStructureTest extends GridBasicClientFeaturesTest {
+ @Test
+ public void haederDecoSizeShouldBeRecalculated() {
+ // it's easier to notice with valo
+ openTestURL("theme=valo");
+
+ WebElement topDeco = getGridElement().findElement(
+ By.className("v-grid-header-deco"));
+ assertGreater(
+ "The header deco in Valo hasn't been recalculated after initial rendering",
+ topDeco.getSize().getHeight(), 20);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/LoadingIndicatorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/LoadingIndicatorTest.java
new file mode 100644
index 0000000000..1f16efdd39
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/LoadingIndicatorTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.grid.basicfeatures.server;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+public class LoadingIndicatorTest extends GridBasicFeaturesTest {
+ @Test
+ public void testLoadingIndicator() throws InterruptedException {
+ setDebug(true);
+ openTestURL();
+
+ selectMenuPath("Component", "State", "Container delay", "2000");
+
+ GridElement gridElement = $(GridElement.class).first();
+
+ Assert.assertFalse(
+ "Loading indicator should not be visible before disabling waitForVaadin",
+ isLoadingIndicatorVisible());
+
+ testBench().disableWaitForVaadin();
+
+ // Scroll to a completely new location
+ gridElement.getCell(200, 1);
+
+ // Wait for loading indicator delay
+ Thread.sleep(500);
+
+ Assert.assertTrue(
+ "Loading indicator should be visible when fetching rows that are visible",
+ isLoadingIndicatorVisible());
+
+ waitUntilNot(ExpectedConditions.visibilityOfElementLocated(By
+ .className("v-loading-indicator")));
+
+ // Scroll so much that more data gets fetched, but not so much that
+ // missing rows are shown
+ gridElement.getCell(230, 1);
+
+ // Wait for potentially triggered loading indicator to become visible
+ Thread.sleep(500);
+
+ Assert.assertFalse(
+ "Loading indicator should not be visible when fetching rows that are not visible",
+ isLoadingIndicatorVisible());
+
+ // Finally verify that there was actually a request going on
+ Thread.sleep(2000);
+
+ String firstLogRow = getLogRow(0);
+ Assert.assertTrue("Last log message was not the fourth message: "
+ + firstLogRow, firstLogRow.startsWith("4. Requested items"));
+ }
+
+ private boolean isLoadingIndicatorVisible() {
+ WebElement loadingIndicator = findElement(By
+ .className("v-loading-indicator"));
+ if (loadingIndicator == null) {
+ return false;
+ } else {
+ return loadingIndicator.isDisplayed();
+ }
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/myBeanJsRenderer.js b/uitest/src/com/vaadin/tests/components/grid/myBeanJsRenderer.js
new file mode 100644
index 0000000000..5e7bde5ec7
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/myBeanJsRenderer.js
@@ -0,0 +1,16 @@
+window.com_vaadin_tests_components_grid_MyBeanJSRenderer = function() {
+ this.init = function(cell) {
+ cell.element.setAttribute("column", cell.columnIndex);
+ }
+
+ this.render = function(cell, data) {
+ cell.element.innerHTML = 'Bean(' + data.integer + ', ' + data.string + ')'
+ }
+
+ this.getConsumedEvents = function() { return ["click"] };
+
+ this.onBrowserEvent = function(cell, event) {
+ cell.element.innerHTML = "Clicked " + cell.rowIndex + " with key " + this.getRowKey(cell.rowIndex) +" at " + event.clientX;
+ return true;
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticReindeer.java b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticReindeer.java
new file mode 100644
index 0000000000..6cf7fb0ded
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticReindeer.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.progressindicator;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ProgressBar;
+import com.vaadin.ui.themes.Reindeer;
+
+@Theme(Reindeer.THEME_NAME)
+public class ProgressBarStaticReindeer extends AbstractTestUI {
+ @Override
+ protected void setup(VaadinRequest request) {
+ ProgressBar progressBar = new ProgressBar();
+ progressBar.addStyleName(Reindeer.PROGRESSBAR_STATIC);
+ addComponent(progressBar);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticReindeerTest.java b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticReindeerTest.java
new file mode 100644
index 0000000000..f1056a640d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticReindeerTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.progressindicator;
+
+import org.junit.Test;
+
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class ProgressBarStaticReindeerTest extends MultiBrowserTest {
+ @Test
+ public void compareScreenshot() throws Exception {
+ openTestURL();
+ compareScreen("screen");
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticRuno.java b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticRuno.java
new file mode 100644
index 0000000000..4e1ff7c886
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticRuno.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.progressindicator;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ProgressBar;
+import com.vaadin.ui.themes.Runo;
+
+@Theme(Runo.THEME_NAME)
+public class ProgressBarStaticRuno extends AbstractTestUI {
+ @Override
+ protected void setup(VaadinRequest request) {
+ ProgressBar progressBar = new ProgressBar();
+ progressBar.addStyleName(Runo.PROGRESSBAR_STATIC);
+ addComponent(progressBar);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticRunoTest.java b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticRunoTest.java
new file mode 100644
index 0000000000..751e048694
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarStaticRunoTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.progressindicator;
+
+import org.junit.Test;
+
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class ProgressBarStaticRunoTest extends MultiBrowserTest {
+ @Test
+ public void compareScreenshot() throws Exception {
+ openTestURL();
+ compareScreen("screen");
+ }
+}