diff options
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 <object> + </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 |