summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebContent/release-notes.html348
-rw-r--r--all/build.xml2
-rw-r--r--client/src/com/vaadin/client/ui/FocusableScrollPanel.java8
-rw-r--r--client/src/com/vaadin/client/ui/TouchScrollDelegate.java68
-rw-r--r--client/src/com/vaadin/client/ui/VScrollTable.java16
-rw-r--r--server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java2
-rw-r--r--server/src/com/vaadin/server/WebBrowser.java10
-rw-r--r--server/src/com/vaadin/ui/Table.java102
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.html178
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java181
-rw-r--r--uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.html179
-rw-r--r--uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java84
12 files changed, 1026 insertions, 152 deletions
diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html
index eaa8404580..d5c1109068 100644
--- a/WebContent/release-notes.html
+++ b/WebContent/release-notes.html
@@ -117,103 +117,257 @@
The @version@ includes many major and minor enhancements and changes. Below is a
list of the most notable changes:
</p>
-
+
<ul>
- <li>GWT is now built into Vaadin Framework
+ <li>UI replaces Application as the main entry point
<ul>
- <li>New SuperDevMode allows debugging client-side Java code in the browser without any plugins</li>
+ <li>Heartbeat to reliably detect closed UI</li>
+ <li>Supports multiple browser tabs by default</li>
+ <li>Browser and request details available in UI init</li>
+ <li>Direct access to request and session in UI init</li>
+ <li>Access detected browser details in UI init</li>
+ <li>Default UI class chosen based on a servlet parameter</li>
+ <li>Custom UIProvider allows providing different UIs based on request parameters</li>
+ <li>UI is by default reinitialized when the page is reloaded</li>
</ul>
</li>
- <li>Applications are now written by extending the <b>UI</b> class instead of the <b>Application</b> class
- <ul>
- <li>The UI class needs to be specified in the <tt>web.xml</tt> with the <tt>ui</tt> parameter</li>
- <li>A <b>Page</b> object accessible from UI with <tt>getPage()</tt> contains API related to the browser window</li>
- <li>The <tt>executeJavaScript()</tt> method is removed and replaced with a <b>JavaScript</b> object accessible from the <b>Page</b> with <tt>getJavaScript()</tt></li>
- <li>Reloading page spawns a new instance unless <tt>@PreserveOnRefresh</tt> specified for the UI</li>
- <li>UIs use heartbeat to detect closing</li>
- <li>Embedding of Vaadin applications (now UIs) in HTML pages has changed
- <ul>
- <li>Embedded UIs can have different themes and widget sets</li>
- </ul>
- </li>
- </ul>
- </li>
- <li>The <b>Application</b> class is removed altogether
- <ul>
- <li><b>ApplicationServlet</b> is replaced with <b>VaadinServlet</b> and <b>VaadinService</b></li>
- <li>User session is now associated with a <b>VaadinSession</b></li>
- <li><b>ApplicationResource</b> is replaced with <b>ConnectorResource</b></li>
- </ul>
- </li>
- <li>The current <b>UI</b>, <b>Page</b>, <b>VaadinServlet</b>, <b>VaadinService</b>, and <b>VaadinSession</b> can be accessed globally with a static <tt>getCurrent()</tt> method. The instance is a ThreadLocal object for the currently processed request.</li>
- <li>The <b>Window</b> now only has the meaning of a floating sub-window inside browser window</li>
- <li>The <b>Panel</b> and <b>Window</b>no longer extend <b>ComponentContainer</b>,
- but <b>SingleComponentContainer</b>, which has no <tt>addComponent()</tt> method
- <ul>
- <li>The <b>UI</b>, <b>Panel</b>, and <b>Window</b> do not have have default
- content (used to be a <b>VerticalLayout</b>), but you must set the content
- component explicitly with the <tt>setContent()</tt> method or in the
- constructor</li>
-
- <li>If the content is a layout, you need to add other components to the layout
- component with <tt>addComponent()</tt> instead of the container</li>
- </ul>
- </li>
- <li>Popup windows can no longer be opened directly from code, but by using a <b>BrowserWindowOpener</b> extension which can be attached to any component</li>
- <li>Navigation API for view navigation
- <ul>
- <li>View navigation with bookmarking/linking with URI fragments and browser history support</li>
- <li>Access control for views, view change confirmation</li>
- </ul>
- </li>
- <li>Component and UI extensions are now possible</li>
- <li>Complete overhaul of the client-server communication architecture
- <ul>
- <li>All add-on components that have widgets need to be ported to Vaadin 7</li>
- <li>Integration of a GWT widget is done in a connector class</li>
- <li>Component-to-widget mapping now defined on the client-side, in the connector</li>
- <li>No more Paintable or VariableOwner</li>
- <li>Server-side components communicate their state to client-side widgets with a shared state object which is automatically synchronized</li>
- <li>Both client-side and server-side can make RPC calls to the other side
- <ul>
- <li>Communicated in the next request/response</li>
- <li>No return values</li>
- <li>Typically for communicating events</li>
- </ul>
- </li>
- <li>Support for JavaScript components - no GWT integration code or widgets required</li>
- <li>Handle JavaScript callbacks on the server-side</li>
- <li>UIDL is deprecated</li>
- <li>Compatibility layer for Vaadin 6 included for easy migration</li>
- </ul>
- </li>
- <li><b>Form</b> is deprecated and form data binding is replaced with the new <b>FieldGroup</b>
- <ul>
- <li>Conversion between property and field type now handled with <b>Converter</b>s</li>
- </ul>
- </li>
- <li>The <b>LoginForm</b> component is now deprecated because of unreliable support in browsers</li>
- <li>Themeing is now done with <a href="http://sass-lang.com/">Sass</a>
- <ul>
- <li>Sass themes in SCSS notation are compiled on-the-fly when loading the theme (in debug/development mode), or manually with the theme compiler (in production mode)</li>
- <li>Pure CSS themes are supported and largely compatible with Vaadin 6, but should include <tt>legacy-styles.css</tt>
- <li>SASS themes need to (and CSS themes can) be compiled to a single CSS stylesheet with the <tt>vaadin-theme-compiler</tt></li>
- <li>Sass compiler can also be used in client-side projects.</li>
- <li>Multiple themes can be used in a page</li>
- </ul>
- </li>
- <li>All <tt>addListener()</tt> methods have changed to listener-specific methods, such as <tt>addClickListener()</tt>, <tt>addValueChangeListener()</tt>, etc.</li>
- <li><b>UriFragmentListener</b> changed to <b>UriFragmentChangedListener</b></li>
- <li><b>UriHandler</b> and <b>ParameterHandler</b> replaced with <b>RequestHandler</b></li>
- <li>Resource loading (JS/CSS) by the framework</li>
- <li>Packaging has changed, now in a ZIP package (see <a href="package">Package Contents</a> above)
- </li>
- <li>Add-ons can modify the startup page</li>
- <li>You can get the computed style of a component from the browser</li>
- <li>Support for border, padding, and margin in core layout components</li>
- <li>The <b>ColorPicker</b> component is now included in the Vaadin core framework</li>
- </ul>
-
+ <li>Redesigned layouts
+ <ul>
+ <li>Minimal or no layout calculations to maximize layout speed</li>
+ <li>Full control of layouts with CSS including borders and margins</li>
+ <li>Redesigned lighter DOM for vertical, horizontal and css layout</li>
+ <li>Client-side ComputedStyle API available</li>
+ </ul>
+ </li>
+ <li>Split to seven jars to allow deploying only what you need</li>
+ <li>Adding multiple components with varargs in addComponents and appropriate constructors</li>
+ <li>Support for mixing multiple themes on the same page</li>
+
+ <li>RPC for communication between the server and the browser
+ <ul>
+ <li>Static typing allows compile time checking</li>
+ <li>Supports Java's primitive and boxed types, String, enums, arrays, List, Set, Map and Java beans</li>
+ <li>Supports references to external or self served resources and references to other components</li>
+ <li>Call from browser to server can be delayed to piggyback on the next XHR, optionally folding similar calls to only send the last value</li>
+ <li>Calls to disabled or invisible components are ignored for security reasons</li>
+ </ul>
+ </li>
+ <li>Server-client shared state
+ <ul>
+ <li>Java objects can be shared between client and server for easy component development</li>
+ <li>State is automatically mirrored from server to client</li>
+ <li>Support both public fields and bean properties</li>
+ <li>Supports the same types as with RPC</li>
+ <li>Only parts of the state that are modified are sent over the wire</li>
+ <li>Allow calculating state on the fly just before state is sent to client</li>
+ <li>Client-side can listen to shared state changes to simplify connectors</li>
+ <li>State class can be annotated to automatically delegate state changes to corresponding properties in widgets</li>
+ </ul>
+ </li>
+ <li>Google Web Toolkit included
+ <ul>
+ <li>A full copy of GWT is included in Vaadin Framework</li>
+ <li>Vaadin team maintains a branch of GWT to include bug fixes and new features independent of official GWT release schedules</li>
+ <li>All functionality of GWT is included to enable writing of client side UI:s, stateless applications, offline functionality and custom widgets</li>
+ <li>Included Elemental library gives direct access to all cutting edge browser features</li>
+ <li>Both browser plug-in based dev mode debugging as well as super dev mode are supported</li>
+ </ul>
+ </li>
+ <li>No more need to call requestRepaint() in components</li>
+ <li>High level view navigation
+ <ul>
+ <li>Support for URI fragment based view management</li>
+ <li>Support for registering both pre-initialized view instances as well as view classes</li>
+ <li>Programmatic navigation with navigateTo()</li>
+ <li>Supports saving bookmarks to views</li>
+ <li>Supports parameterized views</li>
+ <li>Views can block navigation</li>
+ </ul>
+ </li>
+ <li>Connectors
+ <ul>
+ <li>Connectors provide a flexible communication channel between client and server</li>
+ <li>Separating communication code from widgets promotes reusability</li>
+ <li>An explicit Connector hierarchy is maintained</li>
+ <li>Mapping between server-side and client-side defined in client-side code to avoid server-side classpath issues</li>
+ </ul>
+ </li>
+ <li>JavaScript Connectors
+ <ul>
+ <li>Implement connector logic using JavaScript instead of Java for easier integration with JavaScript libraries</li>
+ <li>Wrap around any existing JavaScript based widget to adapt it for use in Vaadin</li>
+ <li>No widgetset compilation needed</li>
+ <li>Support for shared state and RPC as well as JSON-based communication based on simple JavaScript functions</li>
+ </ul>
+ </li>
+ <li>ColorPicker component
+ <ul>
+ <li>Easy to use interface with clickable color gradients</li>
+ <li>RGB, HSV and swatches color modes</li>
+ <li>Color history</li>
+ <li>Color preview</li>
+ <li>CSS color code representation and handling</li>
+ </ul>
+ </li>
+ <li>Add listeners without method overloads
+ <ul>
+ <li>Write addClickListener() instead of generic addListener()</li>
+ <li>Supports code completion in IDE:s better</li>
+ <li>Enables using Java 8 Lambda</li>
+ </ul>
+ </li>
+ <li>Renewed Vaadin Maven Plugin including features from GWT Maven Plugin
+ <ul>
+ <li>New Maven architype eases creation of Vaadin 7 applications</li>
+ </ul>
+ </li>
+ <li>Renewed Eclipse Plugin adding Apache Ivy based dependency management</li>
+ <li>Page bootstrapping renewed
+ <ul>
+ <li>Simpler inclusion of Vaadin UIs to custom web pages</li>
+ <li>Add-ons and applications can dynamically modify bootstrap page HTML</li>
+ </ul>
+ </li>
+ <li>VaadinSession
+ <ul>
+ <li>Full control over session lifecycle</li>
+ <li>Abstract away from servlets and portlets</li>
+ </ul>
+ </li>
+ <li>VaadinService
+ <ul>
+ <li>Easily access deployment information and HTTP requests</li>
+ <li>Abstract away from servlets and portlets</li>
+ </ul>
+ </li>
+ <li>Component extension API
+ <ul>
+ <li>Allow adding functionality and customizations to any component</li>
+ <li>Modify DOM and hook event listeners</li>
+ </ul>
+ </li>
+ <li>JavaScript callbacks
+ <ul>
+ <li>Declare client-side JavaScript API from server</li>
+ <li>Eases integration with parts of the page not controlled with Vaadin</li>
+ </ul>
+ </li>
+ <li>Relative paths used for all requests
+ <ul>
+ <li>More flexible deployment</li>
+ <li>Adds support for Apache ProxyPass and other similar proxies</li>
+ </ul>
+ </li>
+ <li>HTML5
+ <ul>
+ <li>Vaadin 7 uses HTML5 doctype</li>
+ <li>Use any parts of HTML5 in your application</li>
+ </ul>
+ </li>
+ <li>Page
+ <ul>
+ <li>Abstraction for one browser window</li>
+ <li>Run JavaScript</li>
+ <li>Listen to page resizes</li>
+ <li>Control navigation</li>
+ </ul>
+ </li>
+ <li>Loading custom JavaScript
+ <ul>
+ <li>Annotate server-side classes with @JavaScript to request loading of JavaScript files</li>
+ <li>Automated control of loading order and ensuring that files are loaded only once</li>
+ </ul>
+ </li>
+ <li>API cleanup
+ <ul>
+ <li>API deprecated in Vaadin 6 or before removed</li>
+ <li>Use enums instead of integer constants</li>
+ </ul>
+ </li>
+ <li>Embedded split up to different components for different purposes
+ <ul>
+ <li>Image for showing images</li>
+ <li>BrowserFrame for embedding web pages with iframes</li>
+ <li>Flash for embedding Flash content</li>
+ <li>Embedded now only intended for embedding using &lt;object&gt;
+ </ul>
+ </li>
+ <li>Support for Firefox 17 extended support release in addition to latest stable Firefox release</li>
+ <li>Sass Compiler
+ <ul>
+ <li>Allows modularization of themes for better reuse and easier maintenance</li>
+ <li>Support the most important features of SCSS</li>
+ <li>Pure Java implementation without Ruby dependency</li>
+ <li>Supports all of CSS</li>
+ <li>On the fly conversion of SCSS to CSS during development</li>
+ <li>Built in themes are now based on Sass</li>
+ <li>Can be used in client-side projects as well</li>
+ </ul>
+ </li>
+ <li>@StyleSheet for automatic injection of css files</li>
+ <li>ConnectorResource replaces ApplicationResource to reduce memory consumption</li>
+ <li>Hierarchical error handling</li>
+ <li>Open popups and start downloads in a way not stopped by popup blockers</li>
+ <li>ThreadLocal access to VaadinService, VaadinRequest, VaadinResponse, VaadinSession and the current UI instance</li>
+ <li>Component id replaces debug ids to allow wider use possibilities for identifying corresponding widget elements in DOM</li>
+ <li>Range retrieval for indexed containers to enable optimize performance</li>
+ <li>Native support for percent sizes to let the browser do the percent to pixel calculation speeds up rendering</li>
+ <li>Custom class loader
+ <ul>
+ <li>Allow specifying custom class loaders to better support Java EE, CDI and Spring</li>
+ <li>Supports both servlets and portlets</li>
+ </ul>
+ </li>
+ <li>Updated data model
+ <ul>
+ <li>Property getValue() uses generics to return the expected type</li>
+ <li>Two phase commit support for commit/rollback</li>
+ <li>BeanItem supports nested properties to allow flattening complex datatypes</li>
+ </ul>
+ </li>
+ <li>Bean Validation - Annotate beans with JSR-303 standard annotations to automatically create validators for the fields</li>
+ <li>Field group
+ <ul>
+ <li>Allow data binding of multiple fields together to item data source</li>
+ <li>Supports buffering</li>
+ <li>Supports two phase commit</li>
+ <li>Annotation based and field name based property mapping</li>
+ </ul>
+ </li>
+ <li>Explicit data model converters
+ <ul>
+ <li>All fields support explicit conversion from presentation format to data source format</li>
+ <li>Conversions are bidirectional</li>
+ <li>Allow defining a default converter for a specific type and override for specific fields</li>
+ <li>Converters can be set per Table column to customize column formatting</li>
+ </ul>
+ </li>
+ <li>Built-in default converters
+ <ul>
+ <li>automated conversions beween String, Boolean, Long, Date, Double, Float, Integer and Number</li>
+ <li>Built in converters support internationalization</li>
+ </ul>
+ </li>
+ <li>Custom field component for building new fields as composition of existing components</li>
+ <li>Simplified validation API
+ <ul>
+ <li>No need to implement isValid() in validators any more</li>
+ </ul>
+ </li>
+ <li>Unsupported browser detection with customizable information page</li>
+ <li>Vaadin 6 compatibility layer to ease migration from Vaadin 6</li>
+ <li>Explicit layouts for Window and Panel</li>
+ <ul>
+ <li>Window and Panel components now require setting layout explicitly</li>
+ <li>Distinction between Window or Panel and it's layout</li>
+ </ul>
+ </li>
+ <li>Layout manager
+ <ul>
+ <li>Allows building custom layout calculations for widgets when browser based layouts are not powerful enough</li>
+ <li>Optimizes number of reflows by batching layout calculations from multiple widgets together</li>
+ </ul>
+ </li>
</ul>
<p>
@@ -1317,8 +1471,7 @@
<h2 id="supportedversions">Supported Technologies</h2>
<p>
- Vaadin 7 is compatible with <b>Java 6</b> and with most operating systems
- supporting the Java 6 or newer. Vaadin 7 is especially supported on the following
+ Vaadin 7 is compatible with <b>Java 6</b>. Vaadin 7 is especially supported on the following
<b>operating systems</b>:
</p>
@@ -1364,7 +1517,8 @@
</p>
<ul>
- <li>Mozilla Firefox 17 or newer</li>
+ <li>Mozilla Firefox 18</li>
+ <li>Mozilla Firefox 17 ESR</li>
<li>Internet Explorer 8-10</li>
<li>Safari 6</li>
<li>Opera 12</li>
@@ -1396,7 +1550,7 @@
<li><a href="http://vaadin.com">vaadin.com - The developer
portal containing everything you need to know about Vaadin</a>
</li>
- <li><a href="http://demo.vaadin.com">demo.vaadin.com - A
+ <li><a href="http://vaadin.com/demo">vaadin.com/demo - A
collection of demos for Vaadin</a></li>
<li><a href="http://vaadin.com/learn">vaadin.com/learn -
Getting started with Vaadin</a></li>
diff --git a/all/build.xml b/all/build.xml
index d5a484a902..ef8ac71c4d 100644
--- a/all/build.xml
+++ b/all/build.xml
@@ -39,7 +39,7 @@
<antcontrib:foreach list="${modules.to.publish.to.maven}" target="unzip.to.javadoctemp" param="module" />
<property name="javadoc.dir" location="${result.dir}/javadoc" />
- <property name="title" value="Vaadin" />
+ <property name="title" value="Vaadin ${vaadin.version} API" />
<javadoc maxmemory="1024m" destdir="${javadoc.dir}" author="true" version="true" use="true" windowtitle="${title}" encoding="utf-8">
<packageset dir="${javadoc.temp.dir}">
<!-- TODO Javadoc throws ClassCastException if this is included (#9660)-->
diff --git a/client/src/com/vaadin/client/ui/FocusableScrollPanel.java b/client/src/com/vaadin/client/ui/FocusableScrollPanel.java
index a1d2ad6ccc..01d39392af 100644
--- a/client/src/com/vaadin/client/ui/FocusableScrollPanel.java
+++ b/client/src/com/vaadin/client/ui/FocusableScrollPanel.java
@@ -192,4 +192,12 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements
});
}
+ public Element getFocusElement() {
+ if (useFakeFocusElement()) {
+ return focusElement.cast();
+ } else {
+ return getElement();
+ }
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/TouchScrollDelegate.java b/client/src/com/vaadin/client/ui/TouchScrollDelegate.java
index 45bd2616f3..9d7e435339 100644
--- a/client/src/com/vaadin/client/ui/TouchScrollDelegate.java
+++ b/client/src/com/vaadin/client/ui/TouchScrollDelegate.java
@@ -21,6 +21,7 @@ import java.util.HashSet;
import com.google.gwt.animation.client.Animation;
import com.google.gwt.core.client.Duration;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
@@ -111,20 +112,51 @@ public class TouchScrollDelegate implements NativePreviewHandler {
private static final String SCROLLABLE_CLASSNAME = "v-scrollable";
- private final TouchScrollDelegate delegate;
+ private TouchScrollDelegate delegate;
private final boolean requiresDelegate = BrowserInfo.get()
.requiresTouchScrollDelegate();
+ private Widget widget;
+
/**
- * Constructs a scroll handler for the given widget.
+ * Constructs a scroll handler. You must call
+ * {@link #init(Widget, Element...)} before using the scroll handler.
+ */
+ public TouchScrollHandler() {
+
+ }
+
+ /**
+ * Attaches the scroll handler to the widget. This method must be called
+ * before calling any other methods in this class.
*
* @param widget
* The widget that contains scrollable elements
* @param scrollables
* The elements of the widget that should be scrollable.
+ *
+ * @deprecated Use {@link GWT#create(Class)} and
+ * {@link #init(Widget, Element...)} instead of this
+ * constructor to enable overriding.
*/
+ @Deprecated
public TouchScrollHandler(Widget widget, Element... scrollables) {
- if (requiresDelegate) {
+ this();
+ init(widget, scrollables);
+ }
+
+ /**
+ * Attaches the scroll handler to the widget. This method must be called
+ * once before calling any other method in this class.
+ *
+ * @param widget
+ * The widget that contains scrollable elements
+ * @param scrollables
+ * The elements of the widget that should be scrollable.
+ */
+ public void init(Widget widget, Element... scrollables) {
+ this.widget = widget;
+ if (requiresDelegate()) {
delegate = new TouchScrollDelegate();
widget.addDomHandler(this, TouchStartEvent.getType());
} else {
@@ -150,7 +182,7 @@ public class TouchScrollDelegate implements NativePreviewHandler {
*/
public void addElement(Element scrollable) {
scrollable.addClassName(SCROLLABLE_CLASSNAME);
- if (requiresDelegate) {
+ if (requiresDelegate()) {
delegate.scrollableElements.add(scrollable);
}
}
@@ -162,7 +194,7 @@ public class TouchScrollDelegate implements NativePreviewHandler {
*/
public void removeElement(Element scrollable) {
scrollable.removeClassName(SCROLLABLE_CLASSNAME);
- if (requiresDelegate) {
+ if (requiresDelegate()) {
delegate.scrollableElements.remove(scrollable);
}
}
@@ -175,7 +207,7 @@ public class TouchScrollDelegate implements NativePreviewHandler {
* The elements that should be scrollable
*/
public void setElements(Element... scrollables) {
- if (requiresDelegate) {
+ if (requiresDelegate()) {
for (Element e : delegate.scrollableElements) {
e.removeClassName(SCROLLABLE_CLASSNAME);
}
@@ -185,6 +217,26 @@ public class TouchScrollDelegate implements NativePreviewHandler {
addElement(e);
}
}
+
+ /**
+ * Checks if a delegate for scrolling is required or if the native
+ * scrolling of the device should be used. By default, relies on
+ * {@link BrowserInfo#requiresTouchScrollDelegate()}, override to change
+ * the behavior.
+ *
+ * @return true if a Javascript delegate should be used for scrolling,
+ * false to use the native scrolling of the device
+ */
+ protected boolean requiresDelegate() {
+ return requiresDelegate;
+ }
+
+ /**
+ * @return The widget this {@link TouchScrollHandler} is connected to.
+ */
+ protected Widget getWidget() {
+ return widget;
+ }
}
/**
@@ -199,7 +251,9 @@ public class TouchScrollDelegate implements NativePreviewHandler {
*/
public static TouchScrollHandler enableTouchScrolling(Widget widget,
Element... scrollables) {
- return new TouchScrollHandler(widget, scrollables);
+ TouchScrollHandler handler = GWT.create(TouchScrollHandler.class);
+ handler.init(widget, scrollables);
+ return handler;
}
public TouchScrollDelegate(Element... elements) {
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index 9ac9532ae4..b9244a1e91 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -6924,11 +6924,19 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
navKeyDown = false;
if (BrowserInfo.get().isIE()) {
- // IE sometimes moves focus to a clicked table cell...
+ /*
+ * IE sometimes moves focus to a clicked table cell... (#7965)
+ * ...and sometimes it sends blur events even though the focus
+ * handler is still active. (#10464)
+ */
Element focusedElement = Util.getIEFocusedElement();
- if (Util.getConnectorForElement(client, getParent(), focusedElement) == this) {
- // ..in that case, steal the focus back to the focus handler
- // but not if focus is in a child component instead (#7965)
+ if (Util.getConnectorForElement(client, getParent(), focusedElement) == this
+ && focusedElement != null
+ && focusedElement != scrollBodyPanel.getFocusElement()) {
+ /*
+ * Steal focus back to the focus handler if it was moved to some
+ * other part of the table. Avoid stealing focus in other cases.
+ */
focus();
return;
}
diff --git a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
index f7f3e73a7f..2ad48aff8c 100644
--- a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
+++ b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
@@ -1116,7 +1116,7 @@ public class SQLContainer implements Container, Container.Filterable,
delegate.setOrderBy(sorters);
} catch (UnsupportedOperationException e) {
getLogger().log(Level.FINE,
- "The query delegate doesn't support filtering", e);
+ "The query delegate doesn't support sorting", e);
}
int newSize = delegate.getCount();
sizeUpdated = new Date();
diff --git a/server/src/com/vaadin/server/WebBrowser.java b/server/src/com/vaadin/server/WebBrowser.java
index ca0e4cd6ce..4122f053ae 100644
--- a/server/src/com/vaadin/server/WebBrowser.java
+++ b/server/src/com/vaadin/server/WebBrowser.java
@@ -293,19 +293,19 @@ public class WebBrowser implements Serializable {
}
/**
- * Gets the difference in minutes between the browser's GMT TimeZone and
+ * Returns the offset in milliseconds between the browser's GMT TimeZone and
* DST.
*
- * @return the amount of minutes that the TimeZone shifts when DST is in
- * effect
+ * @return the number of milliseconds that the TimeZone shifts when DST is
+ * in effect
*/
public int getDSTSavings() {
return dstSavings;
}
/**
- * Determines whether daylight savings time (DST) is currently in effect in
- * the region of the browser or not.
+ * Returns whether daylight saving time (DST) is currently in effect in the
+ * region of the browser or not.
*
* @return true if the browser resides at a location that currently is in
* DST
diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java
index e73c6d7188..10752140db 100644
--- a/server/src/com/vaadin/ui/Table.java
+++ b/server/src/com/vaadin/ui/Table.java
@@ -557,6 +557,8 @@ public class Table extends AbstractSelect implements Action.Container,
*/
private boolean keyMapperReset;
+ private List<Throwable> exceptionsDuringCachePopulation = new ArrayList<Throwable>();
+
/* Table constructors */
/**
@@ -1646,6 +1648,55 @@ public class Table extends AbstractSelect implements Action.Container,
setRowCacheInvalidated(true);
markAsDirty();
+ maybeThrowCacheUpdateExceptions();
+
+ }
+
+ private void maybeThrowCacheUpdateExceptions() {
+ if (!exceptionsDuringCachePopulation.isEmpty()) {
+ Throwable[] causes = new Throwable[exceptionsDuringCachePopulation
+ .size()];
+ exceptionsDuringCachePopulation.toArray(causes);
+
+ exceptionsDuringCachePopulation.clear();
+ throw new CacheUpdateException(this,
+ "Error during Table cache update", causes);
+ }
+
+ }
+
+ /**
+ * Exception thrown when one or more exceptions occurred during updating of
+ * the Table cache.
+ * <p>
+ * Contains all exceptions which occurred during the cache update.
+ * </p>
+ *
+ */
+ public static class CacheUpdateException extends RuntimeException {
+ private Throwable[] causes;
+ private Table table;
+
+ public CacheUpdateException(Table table, String message,
+ Throwable[] causes) {
+ super(message);
+ this.table = table;
+ this.causes = causes;
+ }
+
+ /**
+ * Returns the cause(s) for this exception
+ *
+ * @return the exception(s) which caused this exception
+ */
+ public Throwable[] getCauses() {
+ return causes;
+ }
+
+ public Table getTable() {
+ return table;
+ }
+
}
/**
@@ -2036,9 +2087,19 @@ public class Table extends AbstractSelect implements Action.Container,
cells[CELL_HEADER][i] = String.valueOf(i + firstIndex + 1);
break;
default:
- cells[CELL_HEADER][i] = getItemCaption(id);
+ try {
+ cells[CELL_HEADER][i] = getItemCaption(id);
+ } catch (Exception e) {
+ exceptionsDuringCachePopulation.add(e);
+ cells[CELL_HEADER][i] = "";
+ }
+ }
+ try {
+ cells[CELL_ICON][i] = getItemIcon(id);
+ } catch (Exception e) {
+ exceptionsDuringCachePopulation.add(e);
+ cells[CELL_ICON][i] = null;
}
- cells[CELL_ICON][i] = getItemIcon(id);
}
GeneratedRow generatedRow = rowGenerator != null ? rowGenerator
@@ -2056,7 +2117,12 @@ public class Table extends AbstractSelect implements Action.Container,
boolean isGenerated = isGeneratedRow || isGeneratedColumn;
if (!isGenerated) {
- p = getContainerProperty(id, colids[j]);
+ try {
+ p = getContainerProperty(id, colids[j]);
+ } catch (Exception e) {
+ exceptionsDuringCachePopulation.add(e);
+ value = null;
+ }
}
if (isGeneratedRow) {
@@ -2089,7 +2155,12 @@ public class Table extends AbstractSelect implements Action.Container,
if (isGeneratedColumn) {
ColumnGenerator cg = columnGenerators
.get(colids[j]);
- value = cg.generateCell(this, id, colids[j]);
+ try {
+ value = cg.generateCell(this, id, colids[j]);
+ } catch (Exception e) {
+ exceptionsDuringCachePopulation.add(e);
+ value = null;
+ }
if (value != null && !(value instanceof Component)
&& !(value instanceof String)) {
// Avoid errors if a generator returns
@@ -2098,10 +2169,20 @@ public class Table extends AbstractSelect implements Action.Container,
value = value.toString();
}
} else if (iscomponent[j]) {
- value = p.getValue();
+ try {
+ value = p.getValue();
+ } catch (Exception e) {
+ exceptionsDuringCachePopulation.add(e);
+ value = null;
+ }
listenProperty(p, oldListenedProperties);
} else if (p != null) {
- value = getPropertyValue(id, colids[j], p);
+ try {
+ value = getPropertyValue(id, colids[j], p);
+ } catch (Exception e) {
+ exceptionsDuringCachePopulation.add(e);
+ value = null;
+ }
/*
* If returned value is Component (via fieldfactory
* or overridden getPropertyValue) we expect it to
@@ -2114,7 +2195,12 @@ public class Table extends AbstractSelect implements Action.Container,
listenProperty(p, oldListenedProperties);
}
} else {
- value = getPropertyValue(id, colids[j], null);
+ try {
+ value = getPropertyValue(id, colids[j], null);
+ } catch (Exception e) {
+ exceptionsDuringCachePopulation.add(e);
+ value = null;
+ }
}
}
}
@@ -3049,6 +3135,7 @@ public class Table extends AbstractSelect implements Action.Container,
indexInRowbuffer, itemId);
}
target.endTag("urows");
+ maybeThrowCacheUpdateExceptions();
}
private void paintPartialRowAdditions(PaintTarget target,
@@ -3096,6 +3183,7 @@ public class Table extends AbstractSelect implements Action.Container,
target.addAttribute("firstprowix", firstIx);
target.addAttribute("numprows", count);
target.endTag("prows");
+ maybeThrowCacheUpdateExceptions();
}
/**
diff --git a/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.html b/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.html
new file mode 100644
index 0000000000..c2481e6be6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.html
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:9999/" />
+<title>TableWithBrokenGeneratorAndContainer</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">TableWithBrokenGeneratorAndContainer</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.table.TableWithBrokenGeneratorAndContainer?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>item1/prop1</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
+ <td>item2/prop1</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>item3/prop1</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[4]/domChild[0]</td>
+ <td>Generated item1/Gen</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[4]/domChild[0]</td>
+ <td>Generated item2/Gen</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[4]/domChild[0]</td>
+ <td>Generated item3/Gen</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VCheckBox[0]/domChild[0]</td>
+ <td>12,6</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--error indicator should be present-->
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<!--error notification should not be present-->
+<tr>
+ <td>assertElementNotPresent</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::Root/VNotification[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
+ <td>item2/prop1</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>item3/prop1</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[4]/domChild[0]</td>
+ <td>Generated item1/Gen</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[4]/domChild[0]</td>
+ <td>Generated item2/Gen</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[4]/domChild[0]</td>
+ <td>Generated item3/Gen</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VCheckBox[0]/domChild[0]</td>
+ <td>9,6</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<!--error indicator should be present-->
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<!--error notification should not be present-->
+<tr>
+ <td>assertElementNotPresent</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::Root/VNotification[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
+ <td>item2/prop1</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>item3/prop1</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[4]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[4]/domChild[0]</td>
+ <td>Generated item2/Gen</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[4]/domChild[0]</td>
+ <td>Generated item3/Gen</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VCheckBox[0]/domChild[0]</td>
+ <td>9,8</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<!--error notification-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::Root/VNotification[0]/HTML[0]/domChild[0]</td>
+ <td>Problem updating table. Please try again later</td>
+</tr>
+<!--table should be empty-->
+<tr>
+ <td>assertElementNotPresent</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java b/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java
new file mode 100644
index 0000000000..9c5ce9dc0c
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2000-2013 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.table;
+
+import java.lang.reflect.InvocationTargetException;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.event.ListenerMethod.MethodException;
+import com.vaadin.server.ErrorEvent;
+import com.vaadin.server.ErrorHandler;
+import com.vaadin.server.ServerRpcManager.RpcInvocationException;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.CacheUpdateException;
+import com.vaadin.ui.Table.ColumnGenerator;
+
+public class TableWithBrokenGeneratorAndContainer extends TestBase {
+
+ private CheckBox brokenContainer = new CheckBox("Broken container");
+ private CheckBox brokenGenerator = new CheckBox("Broken generator");
+ private CheckBox clearTableOnError = new CheckBox("Clear Table on Error");
+
+ /**
+ * Container which throws an exception on every fifth call to
+ * {@link #getContainerProperty(Object, Object)}.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0
+ *
+ */
+ public class BrokenContainer extends IndexedContainer {
+ private int counter = 0;
+
+ public BrokenContainer() {
+ super();
+ }
+
+ @Override
+ public Property getContainerProperty(Object itemId, Object propertyId) {
+ if (counter++ % 5 == 0
+ && Boolean.TRUE.equals(brokenContainer.getValue())) {
+ throw new RuntimeException(getClass().getSimpleName()
+ + " cannot fetch the property for " + itemId + "/"
+ + propertyId + " right now");
+ }
+ return super.getContainerProperty(itemId, propertyId);
+ }
+ }
+
+ public class BrokenColumnGenerator implements ColumnGenerator {
+ private int brokenInterval;
+ private int counter = 0;
+
+ public BrokenColumnGenerator(int brokenInterval) {
+ this.brokenInterval = brokenInterval;
+ }
+
+ public Object generateCell(Table source, Object itemId, Object columnId) {
+ if (counter++ % brokenInterval == 0
+ && Boolean.TRUE.equals(brokenGenerator.getValue())) {
+ throw new IllegalArgumentException("Broken generator for "
+ + itemId + "/" + columnId);
+ } else {
+ return "Generated " + itemId + "/" + columnId;
+ }
+ }
+
+ }
+
+ @Override
+ protected void setup() {
+ brokenContainer.setImmediate(true);
+ brokenGenerator.setImmediate(true);
+ clearTableOnError.setImmediate(true);
+ clearTableOnError.addValueChangeListener(new ValueChangeListener() {
+
+ public void valueChange(ValueChangeEvent event) {
+ Boolean value = clearTableOnError.getValue();
+ setErrorHandler(value != null ? value : false);
+ }
+ });
+ final Table table = new Table("Semi-broken table");
+ table.setContainerDataSource(createBrokenContainer(10, 4));
+ table.addGeneratedColumn("Gen", new BrokenColumnGenerator(4));
+ table.setPageLength(20);
+
+ Button refreshTableCache = new Button("Refresh table cache",
+ new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ table.markAsDirty();
+ table.refreshRowCache();
+ }
+ });
+ addComponent(refreshTableCache);
+ addComponent(brokenContainer);
+ addComponent(brokenGenerator);
+ addComponent(clearTableOnError);
+ addComponent(table);
+ }
+
+ protected void setErrorHandler(boolean enabled) {
+ if (enabled) {
+ VaadinSession.getCurrent().setErrorHandler(new ErrorHandler() {
+
+ @Override
+ public void error(ErrorEvent event) {
+ Throwable t = event.getThrowable();
+ if (t instanceof RpcInvocationException) {
+ t = t.getCause();
+ if (t instanceof InvocationTargetException) {
+ t = t.getCause();
+ if (t instanceof MethodException) {
+ t = t.getCause();
+ if (t instanceof CacheUpdateException) {
+ Table table = ((CacheUpdateException) t)
+ .getTable();
+ table.removeAllItems();
+ Notification
+ .show("Problem updating table. Please try again later",
+ Notification.Type.ERROR_MESSAGE);
+ }
+ }
+ }
+ }
+ }
+ });
+ } else {
+ VaadinSession.getCurrent().setErrorHandler(this);
+ }
+ }
+
+ private BrokenContainer createBrokenContainer(int rows, int cols) {
+ BrokenContainer container = new BrokenContainer();
+ for (int j = 1; j <= cols; j++) {
+ container.addContainerProperty("prop" + j, String.class, null);
+ }
+ for (int i = 1; i <= rows; i++) {
+ Item item = container.addItem("item" + i);
+ for (int j = 1; j <= cols; j++) {
+ item.getItemProperty("prop" + j).setValue(
+ "item" + i + "/prop" + j);
+ }
+ }
+ return container;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 10312;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "A Table should not show 'Internal Error' just because a column generator or container throws an exception during filling of the cache";
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.html b/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.html
new file mode 100644
index 0000000000..3aecf8bf97
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.html
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>ValueAfterClearingContainer</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">ValueAfterClearingContainer</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.table.ValueAfterClearingContainer?restartApplication</td>
+ <td></td>
+</tr>
+<!-- add items and select one of them -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SaddItemsButton/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_Stable/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>40,13</td>
+</tr>
+<!-- verify selection -->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>1. Value changed to 2</td>
+</tr>
+<!-- remove items from table -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SremoveItemsFromTableButton/domChild[0]</td>
+ <td></td>
+</tr>
+<!-- verify that removal cleared the selection -->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>2. Value changed to null</td>
+</tr>
+<!-- replace the items and select one of them -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SaddItemsButton/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_Stable/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>40,13</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>3. Value changed to 2</td>
+</tr>
+<!-- remove items from container -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SremoveItemsFromContainerButton/domChild[0]</td>
+ <td></td>
+</tr>
+<!-- verify that removal failed to clear the value -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SshowValueButton/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>4. Table selection: 2</td>
+</tr>
+<!-- replace the items -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SaddItemsButton/domChild[0]</td>
+ <td></td>
+</tr>
+<!-- verify that selection still exists -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SshowValueButton/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>5. Table selection: 2</td>
+</tr>
+<!-- remove items from container and sanitize the table -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SremoveItemsFromContainerAndSanitizeButton/domChild[0]</td>
+ <td></td>
+</tr>
+<!-- verify that sanitizing cleared the value -->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>6. Value changed to null</td>
+</tr>
+<!-- replace the items and select one of them -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SaddItemsButton/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_Stable/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>40,13</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>7. Value changed to 2</td>
+</tr>
+<!-- remove selected item from the table -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SremoveSelectedFromTableButton/domChild[0]</td>
+ <td></td>
+</tr>
+<!-- verify that removal cleared the selection -->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>8. Value changed to null</td>
+</tr>
+<!-- select new item and remove it from the container -->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_Stable/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>40,13</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>9. Value changed to 3</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SremoveSelectedFromContainer/domChild[0]</td>
+ <td></td>
+</tr>
+<!-- verify that removal failed to clear the value -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SshowValueButton/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>10. Table selection: 3</td>
+</tr>
+<!-- verify the item has been removed -->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_Stable/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>40,13</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableValueAfterClearingContainer::PID_SLog_row_0</td>
+ <td>11. Value changed to 4</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java b/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java
index 93e7cafa99..f378c146ea 100644
--- a/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java
+++ b/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java
@@ -19,6 +19,8 @@ public class ValueAfterClearingContainer extends TestBase {
@Override
protected void setup() {
+ log.setId("log");
+ table.setId("table");
table.setSelectable(true);
table.addContainerProperty(PROPERTY_ID, Integer.class, null);
table.setImmediate(true);
@@ -33,6 +35,7 @@ public class ValueAfterClearingContainer extends TestBase {
addComponent(table);
final CheckBox multiselect = new CheckBox("Multiselect");
multiselect.setImmediate(true);
+ multiselect.setId("multiselect");
multiselect.addValueChangeListener(new ValueChangeListener() {
public void valueChange(ValueChangeEvent event) {
@@ -41,48 +44,64 @@ public class ValueAfterClearingContainer extends TestBase {
}
});
addComponent(multiselect);
- addComponent(new Button("Add table items", new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- if (!table.getItemIds().isEmpty()) {
- Notification.show("Only possible when the table is empty");
- return;
- } else {
- for (int i = 0; i < 5; i++) {
- table.addItem(new Object[] { Integer.valueOf(i) },
- Integer.valueOf(i));
+ Button addItemsButton = new Button("Add table items",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (!table.getItemIds().isEmpty()) {
+ Notification
+ .show("Only possible when the table is empty");
+ return;
+ } else {
+ for (int i = 0; i < 5; i++) {
+ table.addItem(
+ new Object[] { Integer.valueOf(i) },
+ Integer.valueOf(i));
+ }
+ }
}
- }
- }
- }));
+ });
+ addItemsButton.setId("addItemsButton");
+ addComponent(addItemsButton);
- addComponent(new Button("Show value", new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- log.log("Table selection: " + table.getValue());
- }
- }));
-
- addComponent(new Button("Remove items from table",
+ Button showValueButton = new Button("Show value",
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
+ log.log("Table selection: " + table.getValue());
+ }
+ });
+ showValueButton.setId("showValueButton");
+ addComponent(showValueButton);
+
+ Button removeItemsFromTableButton = new Button(
+ "Remove items from table", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
table.removeAllItems();
}
- }));
+ });
+ removeItemsFromTableButton.setId("removeItemsFromTableButton");
+ addComponent(removeItemsFromTableButton);
- addComponent(new Button("Remove items from container",
- new Button.ClickListener() {
+ Button removeItemsFromContainerButton = new Button(
+ "Remove items from container", new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
table.getContainerDataSource().removeAllItems();
}
- }));
- addComponent(new Button("Remove items from container and sanitize",
+ });
+ removeItemsFromContainerButton.setId("removeItemsFromContainerButton");
+ addComponent(removeItemsFromContainerButton);
+ Button removeItemsFromContainerAndSanitizeButton = new Button(
+ "Remove items from container and sanitize",
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
table.getContainerDataSource().removeAllItems();
table.sanitizeSelection();
}
- }));
- addComponent(new Button("Remove selected item from table",
- new Button.ClickListener() {
+ });
+ removeItemsFromContainerAndSanitizeButton
+ .setId("removeItemsFromContainerAndSanitizeButton");
+ addComponent(removeItemsFromContainerAndSanitizeButton);
+ Button removeSelectedFromTableButton = new Button(
+ "Remove selected item from table", new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
Object selection = table.getValue();
if (selection == null) {
@@ -92,8 +111,11 @@ public class ValueAfterClearingContainer extends TestBase {
table.removeItem(selection);
}
}
- }));
- addComponent(new Button("Remove selected item from container",
+ });
+ removeSelectedFromTableButton.setId("removeSelectedFromTableButton");
+ addComponent(removeSelectedFromTableButton);
+ Button removeSelectedFromContainer = new Button(
+ "Remove selected item from container",
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
Object selection = table.getValue();
@@ -105,7 +127,9 @@ public class ValueAfterClearingContainer extends TestBase {
.removeItem(selection);
}
}
- }));
+ });
+ removeSelectedFromContainer.setId("removeSelectedFromContainer");
+ addComponent(removeSelectedFromContainer);
}
@Override