Browse Source

Merge branch 'master' into feature/elements

feature/elements
Manolo Carrasco 8 years ago
parent
commit
aedc62f24a
100 changed files with 2638 additions and 475 deletions
  1. 5
    46
      .gitignore
  2. 10
    33
      README.md
  3. 3
    1
      all/src/main/templates/release-notes.html
  4. 1
    1
      checkstyle/vaadin-checkstyle.xml
  5. 1
    0
      client-compiled/pom.xml
  6. 1
    1
      client-compiler/pom.xml
  7. 8
    0
      client/src/main/java/com/vaadin/client/BrowserInfo.java
  8. 30
    0
      client/src/main/java/com/vaadin/client/ConnectorHierarchyChangeEvent.java
  9. 51
    2
      client/src/main/java/com/vaadin/client/VTooltip.java
  10. 24
    11
      client/src/main/java/com/vaadin/client/ui/VFilterSelect.java
  11. 15
    17
      client/src/main/java/com/vaadin/client/ui/VGridLayout.java
  12. 51
    13
      client/src/main/java/com/vaadin/client/ui/VListSelect.java
  13. 2
    0
      client/src/main/java/com/vaadin/client/ui/VMenuBar.java
  14. 1
    1
      client/src/main/java/com/vaadin/client/ui/VTextField.java
  15. 20
    7
      client/src/main/java/com/vaadin/client/ui/VWindow.java
  16. 25
    0
      client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java
  17. 4
    13
      client/src/main/java/com/vaadin/client/ui/gridlayout/GridLayoutConnector.java
  18. 46
    0
      client/src/main/java/com/vaadin/client/widget/grid/events/GridEnabledEvent.java
  19. 36
    0
      client/src/main/java/com/vaadin/client/widget/grid/events/GridEnabledHandler.java
  20. 20
    5
      client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java
  21. 39
    1
      client/src/main/java/com/vaadin/client/widgets/Grid.java
  22. 2
    2
      client/src/main/java/com/vaadin/client/widgets/Overlay.java
  23. 29
    0
      client/src/test/java/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java
  24. 1
    1
      documentation/advanced/advanced-dragndrop.asciidoc
  25. 0
    20
      documentation/advanced/advanced-embedding.asciidoc
  26. 1
    1
      documentation/clientside/clientside-debugging.asciidoc
  27. 1
    1
      documentation/gwt/gwt-rpc.asciidoc
  28. 1
    1
      documentation/tutorial.adoc
  29. 3
    3
      pom.xml
  30. 1
    1
      server/pom.xml
  31. 1
    2
      server/src/main/java/com/vaadin/data/util/ContainerHierarchicalWrapper.java
  32. 17
    1
      server/src/main/java/com/vaadin/data/util/ContainerOrderedWrapper.java
  33. 10
    18
      server/src/main/java/com/vaadin/data/util/GeneratedPropertyContainer.java
  34. 3
    6
      server/src/main/java/com/vaadin/data/util/IndexedContainer.java
  35. 22
    4
      server/src/main/java/com/vaadin/event/SelectionEvent.java
  36. 11
    3
      server/src/main/java/com/vaadin/server/BootstrapHandler.java
  37. 1
    1
      server/src/main/java/com/vaadin/server/ClientConnector.java
  38. 2
    3
      server/src/main/java/com/vaadin/server/Constants.java
  39. 14
    0
      server/src/main/java/com/vaadin/server/KeyMapper.java
  40. 28
    6
      server/src/main/java/com/vaadin/server/UIProvider.java
  41. 35
    3
      server/src/main/java/com/vaadin/server/VaadinPortletResponse.java
  42. 12
    7
      server/src/main/java/com/vaadin/server/VaadinService.java
  43. 54
    11
      server/src/main/java/com/vaadin/server/VaadinServlet.java
  44. 21
    9
      server/src/main/java/com/vaadin/server/VaadinServletService.java
  45. 2
    4
      server/src/main/java/com/vaadin/server/communication/ResourceWriter.java
  46. 8
    8
      server/src/main/java/com/vaadin/server/communication/ServerRpcHandler.java
  47. 1
    3
      server/src/main/java/com/vaadin/ui/AbstractComponent.java
  48. 8
    0
      server/src/main/java/com/vaadin/ui/AbstractOrderedLayout.java
  49. 10
    7
      server/src/main/java/com/vaadin/ui/AbstractSelect.java
  50. 27
    55
      server/src/main/java/com/vaadin/ui/GridLayout.java
  51. 3
    0
      server/src/main/java/com/vaadin/ui/Table.java
  52. 2
    2
      server/src/main/java/com/vaadin/ui/declarative/DesignContext.java
  53. 4
    5
      server/src/test/java/com/vaadin/data/util/AbstractContainerTestBase.java
  54. 4
    2
      server/src/test/java/com/vaadin/tests/data/converter/DateToLongConverterTest.java
  55. 3
    1
      server/src/test/java/com/vaadin/tests/data/converter/DefaultConverterFactoryTest.java
  56. 6
    2
      server/src/test/java/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java
  57. 2
    6
      shared/pom.xml
  58. 9
    1
      shared/src/main/java-templates/com/vaadin/shared/Version.java
  59. 8
    2
      shared/src/main/java/com/vaadin/shared/VBrowserDetails.java
  60. 15
    0
      shared/src/main/java/com/vaadin/shared/ui/MarginInfo.java
  61. 2
    0
      shared/src/main/java/com/vaadin/shared/ui/gridlayout/GridLayoutState.java
  62. 4
    0
      themes/src/main/themes/VAADIN/themes/valo/components/_label.scss
  63. 5
    2
      themes/src/main/themes/VAADIN/themes/valo/components/_nativeselect.scss
  64. 4
    0
      themes/src/main/themes/VAADIN/themes/valo/components/_table.scss
  65. 7
    0
      themes/src/main/themes/VAADIN/themes/valo/components/_twincolselect.scss
  66. 5
    13
      uitest/build.xml
  67. 8
    1
      uitest/integration_tests.xml
  68. 28
    86
      uitest/pom.xml
  69. 9
    8
      uitest/src/main/java/com/vaadin/launcher/DevelopmentServerLauncher.java
  70. 51
    0
      uitest/src/main/java/com/vaadin/tests/components/combobox/ComboBoxPopupWhenBodyScrolls.java
  71. 71
    0
      uitest/src/main/java/com/vaadin/tests/components/formlayout/FormLayoutClickListener.java
  72. 32
    0
      uitest/src/main/java/com/vaadin/tests/components/grid/GridDisabledMultiselect.java
  73. 57
    0
      uitest/src/main/java/com/vaadin/tests/components/gridlayout/GridLayoutExpandWithManyRows.java
  74. 140
    0
      uitest/src/main/java/com/vaadin/tests/components/listselect/ListSelectAddRemoveItems.java
  75. 70
    0
      uitest/src/main/java/com/vaadin/tests/components/listselect/ListSelectPushSelectionChanges.java
  76. 63
    0
      uitest/src/main/java/com/vaadin/tests/components/menubar/MenuBarClickOpenedMenu.java
  77. 25
    0
      uitest/src/main/java/com/vaadin/tests/components/nativeselect/NativeSelectNull.java
  78. 84
    0
      uitest/src/main/java/com/vaadin/tests/components/panel/PanelRemoveShortcutListener.java
  79. 42
    0
      uitest/src/main/java/com/vaadin/tests/components/textfield/InputPromptAndCursorPosition.java
  80. 46
    0
      uitest/src/main/java/com/vaadin/tests/components/window/ToolTipInWindow.java
  81. 3
    3
      uitest/src/main/java/com/vaadin/tests/integration/ProxyTest.java
  82. 80
    0
      uitest/src/main/java/com/vaadin/tests/themes/valo/CollapsibleTableColumn.java
  83. 54
    0
      uitest/src/main/java/com/vaadin/tests/themes/valo/DisabledLabel.java
  84. 115
    0
      uitest/src/main/java/com/vaadin/tests/validation/FieldErrorIndication.java
  85. 5
    6
      uitest/src/test/java/com/vaadin/tests/VerifyBrowserVersionTest.java
  86. 6
    0
      uitest/src/test/java/com/vaadin/tests/application/CriticalNotificationsTest.java
  87. 40
    0
      uitest/src/test/java/com/vaadin/tests/components/combobox/ComboBoxPopupWhenBodyScrollsTest.java
  88. 87
    0
      uitest/src/test/java/com/vaadin/tests/components/formlayout/FormLayoutClickListenerTest.java
  89. 81
    0
      uitest/src/test/java/com/vaadin/tests/components/grid/GridDisabledMultiselectTest.java
  90. 40
    0
      uitest/src/test/java/com/vaadin/tests/components/gridlayout/GridLayoutExpandWithManyRowsTest.java
  91. 63
    0
      uitest/src/test/java/com/vaadin/tests/components/listselect/ListSelectAddRemoveItemsTest.java
  92. 70
    0
      uitest/src/test/java/com/vaadin/tests/components/listselect/ListSelectNoDomRebuildTest.java
  93. 135
    0
      uitest/src/test/java/com/vaadin/tests/components/listselect/ListSelectPushSelectionChangesTest.java
  94. 89
    0
      uitest/src/test/java/com/vaadin/tests/components/menubar/MenuBarClickOpenedMenuTest.java
  95. 20
    0
      uitest/src/test/java/com/vaadin/tests/components/nativeselect/NativeSelectNullTest.java
  96. 114
    0
      uitest/src/test/java/com/vaadin/tests/components/panel/PanelRemoveShortcutListenerTest.java
  97. 30
    0
      uitest/src/test/java/com/vaadin/tests/components/textfield/InputPromptAndCursorPositionTest.java
  98. 77
    0
      uitest/src/test/java/com/vaadin/tests/components/window/ToolTipInWindowTest.java
  99. 1
    2
      uitest/src/test/java/com/vaadin/tests/tb3/AbstractTB3Test.java
  100. 0
    0
      uitest/src/test/java/com/vaadin/tests/tb3/ScreenshotTB3Test.java

+ 5
- 46
.gitignore View File

@@ -11,54 +11,10 @@
/.externalToolBuilders
/extras

# /WebContent/VAADIN/themes/base/
/WebContent/VAADIN/themes/base/styles.css
/WebContent/VAADIN/themes/base/legacy-styles.css

# /WebContent/VAADIN/themes/chameleon/
/WebContent/VAADIN/themes/chameleon/styles.css
/WebContent/VAADIN/themes/chameleon/legacy-styles.css

# /WebContent/VAADIN/themes/liferay/
/WebContent/VAADIN/themes/liferay/styles.css
/WebContent/VAADIN/themes/liferay/legacy-styles.css

# /WebContent/VAADIN/themes/reindeer/
/WebContent/VAADIN/themes/reindeer/styles.css
/WebContent/VAADIN/themes/reindeer/legacy-styles.css

# /WebContent/VAADIN/themes/reindeer/button/img/
/WebContent/VAADIN/themes/reindeer/button/img/*-sprites*.png

# /WebContent/VAADIN/themes/reindeer/common/img/
/WebContent/VAADIN/themes/reindeer/common/img/*-sprites*.png

# /WebContent/VAADIN/themes/runo/
/WebContent/VAADIN/themes/runo/styles.css
/WebContent/VAADIN/themes/runo/legacy-styles.css

# /WebContent/VAADIN/themes/runo/common/img/
/WebContent/VAADIN/themes/runo/common/img/ajax-loader-red.gif
/WebContent/VAADIN/themes/runo/common/img/ajax-loader-yellow.gif

# /WebContent/VAADIN/themes/valo/
/WebContent/VAADIN/themes/valo/styles.css
/WebContent/VAADIN/themes/tests-valo*/styles.css
/uitest/src/main/themes/**/styles.css

# Persisted scss cache files
/WebContent/VAADIN/themes/*/styles.scss.cache

# /WebContent/VAADIN/widgetsets/
/WebContent/VAADIN/widgetsets
/WebContent/VAADIN/gwt-unitCache*

WebContent/VAADIN/vaadinPush.js
WebContent/VAADIN/vaadinPush.debug.js
WebContent/VAADIN/vaadinPush.js.gz
WebContent/VAADIN/vaadinPush.debug.js.gz

# /WebContent/WEB-INF/
/WebContent/WEB-INF/classes
/uitest/src/main/themes/**/styles.scss.cache

# /build/
/build/result
@@ -103,3 +59,6 @@ phantomjsdriver.log

*.iml
.idea

*/.checkstyle


+ 10
- 33
README.md View File

@@ -36,8 +36,6 @@ In Eclipse this is done by right clicking on vaadin-themes project it and choosi

Set up extra workspace preferences
--------
TODO check if it's relevant
=====
The following preferences need to be set to keep the project consistent. You need to do this especially to be able to contribute changes to the project.

1. Open *Window* -> *Preferences* (Windows) or *Eclipse* -> *Preferences* (Mac)
@@ -56,12 +54,10 @@ Indentation size: 4

Running a UI test
------
TODO
=====
The *vaadin* project includes an embedded Jetty (*com.vaadin.launcher.DevelopmentServerLauncher*) which is used for running the UI tests.
In Eclipse you can launch it using the included launch configuration: Right click on *eclipse/Development Server (vaadin).launch" and select *Debug As* -> *Development Server (vaadin)*.

This launches a Jetty on port 8888 which allows you to run any UI class in the project by opening http://localhost:8888/run/<UI class name>?restartApplication in your browser, e.g. [http://localhost:8888/run/com.vaadin.tests.components.label.LabelModes?restartApplication](http://localhost:8888/run/com.vaadin.tests.components.label.LabelModes?restartApplication) (Use ?restartApplication to ensure the correct UI is shown).
1. In a Project Explorer right-click *vaadin-uitest*
1. Open *Run As* -> *Maven build...*
1. Type in <code>jetty:run-exploded</code> into *Goals* and click *Run*
1. Open URL *http://localhost:8080/run/<testUI>*

Building a package
=====
@@ -72,37 +68,18 @@ in the project root directory.
To use a specific version number, modify <code>&lt;version&gt;</code> tag in root pom.xml file.
This goal runs all project tests TestBench tests, which require access to a a TestBench cluster, currently only available internally at Vaadin Ltd.

Running TestBench tests
=====
TODO
=====
The unit tests for the projects can be run using
<pre><code>ant test</code></pre>

Setting up IntelliJ IDEA to Develop Vaadin 7
=========
1. Intall and run IDEA. Ultimate Edition is better but Community Edition should also work.
1. Ensure if Git and Maven plugins are installed, properly configured and enabled.
1. Formatting settings _TODO_
1. Clone the repository, using menu VCS -> Checkout from Version Control -> Git -> Git Repository URL -> https://github.com/vaadin/vaadin.git.
When the repository is cloned, do **NOT** open it as a project.
1. Open cloned repository as a maven object. Use File -> Open and choose root _pom.xml_ file
1. Have a coffee break while IDEA is loading dependencies and indexing the project
1. Use Maven tool window to compile modules and the whole project
1. Run UI tests
1. Open *File* -> *Project Structure* -> *vaadin-uitest*
1. Click *Dependencies* tab
1. Click green *+* -> *Library...*
1. From project libraries select *Maven: com.vaadin.external.gwt:gwt-** and click *Add selected*
1. Compile default themes and widgetset (see above)
1. Click *Run* -> *Edit Configurations...* -> Green *+* -> *Application*
1. Set *Main class* into `com.vaadin.launcher.DevelopmentServerLauncher`, *Working dir* into `$MODULE_DIR$`,
*Use classpath of module* into `vaadin-uitest` and click *Apply*. Now you have a run configuration for UI tests


1. Run SuperDev mode _TODO_
1. Run Maven targets <code>clean</code> and <code>install</code> using *Maven Projects* tool window to compile the whole project

TODO remove following & ask Sauli to add a notification about outdated instructions
=============
- Unofficial instructions
- IntelliJ IDEA: http://github.com/Saulis/vaadin-idea-workspace/
Running a UI test
------
1. Open *Maven Projects*
1. Open *vaadin-uitest* -> *Plugins* -> *jetty* -> *jetty:run-exploded*
1. Open URL *http://localhost:8080/run/<testUI>*

+ 3
- 1
all/src/main/templates/release-notes.html View File

@@ -112,7 +112,9 @@
<ul>
<li>Vaadin artifacts no longer bring a transitive dependency to javax.servlet:servlet-api.</li>
<li>System properties now override application parameters for settings such as production mode (see above).</li>
<li>The return type of UIProvider.getWidgetset() and BootstrapHandler.getWidgetsetForUI() has changed.</li>
<li>The return type of BootstrapHandler.getWidgetsetForUI() has changed.</li>
<li>Vaadin shared no longer depends on a custom build of Guava. Any project that depends on Guava as a transitive dependency should use standard Guava.</li>
<li>Valo theme field error styles now apply to NativeSelect, ListSelect and TwinColSelect as well.</li>
</ul>
<h3 id="knownissues">Known Issues and Limitations</h3>
<ul>

+ 1
- 1
checkstyle/vaadin-checkstyle.xml View File

@@ -172,7 +172,7 @@
<module name="GenericWhitespace" />
<module name="MethodParamPad" />
<module name="NoWhitespaceAfter">
<property name="tokens" value="BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS,TYPECAST"/>
<property name="tokens" value="BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS"/>
</module>
<module name="NoWhitespaceBefore" />
<module name="OperatorWrap" />

+ 1
- 0
client-compiled/pom.xml View File

@@ -92,6 +92,7 @@
</modules>
<webappDirectory>${project.build.outputDirectory}/VAADIN/widgetsets</webappDirectory>
<persistentunitcachedir>${project.build.directory}/gwt-unitCache</persistentunitcachedir>
<style>${widgetset.style}</style>
</configuration>
<executions>
<execution>

+ 1
- 1
client-compiler/pom.xml View File

@@ -187,7 +187,6 @@
<version>${vaadin.gwt.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -227,6 +226,7 @@
com/google/gwt/lang/**,
com/google/gwt/soyc/**,
com/google/gwt/thirdparty/json/**,
com/google/gwt/thirdparty/guava/**,
com/google/gwt/util/**,
license/LICENSE.sax.txt,
netscape/**,

+ 8
- 0
client/src/main/java/com/vaadin/client/BrowserInfo.java View File

@@ -165,6 +165,14 @@ public class BrowserInfo {
minorVersionClass = majorVersionClass
+ browserDetails.getBrowserMinorVersion();
browserEngineClass = ENGINE_WEBKIT;
} else if (browserDetails.isPhantomJS()) {
// Safari needed for theme
browserIdentifier = BROWSER_SAFARI;
majorVersionClass = browserIdentifier
+ getBrowserMajorVersion();
minorVersionClass = majorVersionClass
+ browserDetails.getBrowserMinorVersion();
browserEngineClass = ENGINE_WEBKIT;
} else if (browserDetails.isIE()) {
browserIdentifier = BROWSER_IE;
majorVersionClass = browserIdentifier

+ 30
- 0
client/src/main/java/com/vaadin/client/ConnectorHierarchyChangeEvent.java View File

@@ -22,6 +22,7 @@ import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler;
import com.vaadin.client.communication.AbstractServerConnectorEvent;
import com.vaadin.client.ui.AbstractHasComponentsConnector;

/**
* Event for containing data related to a change in the {@link ServerConnector}
@@ -84,8 +85,37 @@ public class ConnectorHierarchyChangeEvent extends
super.setConnector(connector);
}

/**
* Handles connector hierarchy events. You should typically not directly
* implement this interface, but instead make your connector class extend
* {@link AbstractHasComponentsConnector} or an appropriate subclass.
*/
public interface ConnectorHierarchyChangeHandler extends Serializable,
EventHandler {
/**
* Called by the framework when the list of child components of the
* connector implementing this interface has changed. The implementation
* is responsible for attaching the widgets of any new children and
* detaching the widgets of any removed children. Implementations should
* typically also make sure that the child widgets are attached
* according to the ordering of the child components.
* <p>
* This method is called after the shared state and hierarchy data (i.e.
* {@link AbstractHasComponentsConnector#setChildComponents(List)}) been
* updated for all affected connectors, but before updating captions,
* firing state change events, invoking updateFromUIDL for legacy
* connectors, invoking RPC and starting the layout phase.
* <p>
* Please note that hierarchy change events are fired in a
* non-deterministic order when a message from the server causes
* multiple parts of the hierarchy to change. This means that the old
* parent connector might not yet have detached a child widget and that
* the widget of a removed child might already have been attached by its
* new parent.
*
* @param connectorHierarchyChangeEvent
* the event with information about the hierarchy change
*/
public void onConnectorHierarchyChange(
ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent);
}

+ 51
- 2
client/src/main/java/com/vaadin/client/VTooltip.java View File

@@ -20,7 +20,19 @@ import com.google.gwt.aria.client.RelevantValue;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
@@ -462,6 +474,8 @@ public class VTooltip extends VOverlay {
// tooltip
closeTimer.cancel();
closing = false;
} else if (type == Event.ONMOUSEOUT) {
tooltipEventHandler.handleOnMouseOut(DOM.eventGetTarget(event));
}
}

@@ -481,7 +495,8 @@ public class VTooltip extends VOverlay {
}

private class TooltipEventHandler implements MouseMoveHandler,
KeyDownHandler, FocusHandler, BlurHandler, MouseDownHandler {
KeyDownHandler, FocusHandler, BlurHandler, MouseDownHandler,
MouseOutHandler {

/**
* Marker for handling of tooltip through focus
@@ -629,6 +644,39 @@ public class VTooltip extends VOverlay {
handledByFocus = isFocused;
currentElement = element;
}

@Override
public void onMouseOut(MouseOutEvent moe) {
Element element = WidgetUtil.getElementUnderMouse(moe
.getNativeEvent());
handleOnMouseOut(element);
}

private void handleOnMouseOut(Element element) {
if (element == null) {
// hide if mouse is outside of browser window
handleHideEvent();
} else {
Widget owner = getOwner();
if (owner != null && !owner.getElement().isOrHasChild(element)
&& !hasCommonOwner(owner, element)) {
// hide if mouse is no longer within the UI nor an overlay
// that belongs to the UI, e.g. a Window
handleHideEvent();
}
}
}

private boolean hasCommonOwner(Widget owner, Element element) {
ComponentConnector connector = Util.findPaintable(
getApplicationConnection(), element);
if (connector != null && connector.getConnection() != null
&& connector.getConnection().getUIConnector() != null) {
return owner.equals(connector.getConnection().getUIConnector()
.getWidget());
}
return false;
}
}

private final TooltipEventHandler tooltipEventHandler = new TooltipEventHandler();
@@ -641,6 +689,7 @@ public class VTooltip extends VOverlay {
*/
public void connectHandlersToWidget(Widget widget) {
Profiler.enter("VTooltip.connectHandlersToWidget");
widget.addDomHandler(tooltipEventHandler, MouseOutEvent.getType());
widget.addDomHandler(tooltipEventHandler, MouseMoveEvent.getType());
widget.addDomHandler(tooltipEventHandler, MouseDownEvent.getType());
widget.addDomHandler(tooltipEventHandler, KeyDownEvent.getType());

+ 24
- 11
client/src/main/java/com/vaadin/client/ui/VFilterSelect.java View File

@@ -28,6 +28,7 @@ import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style;
@@ -657,7 +658,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
debug("VFS.SP: setPosition(" + offsetWidth + ", " + offsetHeight
+ ")");

int top = topPosition;
int top;
int left = getPopupLeft();

// reset menu size and retrieve its "natural" size
@@ -705,19 +706,31 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
getContainerElement().getStyle().setWidth(rootWidth, Unit.PX);
}

final int vfsHeight = VFilterSelect.this.getOffsetHeight();
final int spaceAvailableAbove = top - vfsHeight;
final int spaceAvailableBelow = Window.getClientHeight() - top;
if (spaceAvailableBelow < offsetHeight
&& spaceAvailableBelow < spaceAvailableAbove) {
final int textInputHeight = VFilterSelect.this.getOffsetHeight();
final int textInputTopOnPage = tb.getAbsoluteTop();
final int viewportOffset = Document.get().getScrollTop();
final int textInputTopInViewport = textInputTopOnPage
- viewportOffset;
final int textInputBottomInViewport = textInputTopInViewport
+ textInputHeight;

final int spaceAboveInViewport = textInputTopInViewport;
final int spaceBelowInViewport = Window.getClientHeight()
- textInputBottomInViewport;

if (spaceBelowInViewport < offsetHeight
&& spaceBelowInViewport < spaceAboveInViewport) {
// popup on top of input instead
top -= offsetHeight + vfsHeight;
if (top < 0) {
offsetHeight += top;
top = 0;
if (offsetHeight > spaceAboveInViewport) {
// Shrink popup height to fit above
offsetHeight = spaceAboveInViewport;
}
top = textInputTopOnPage - offsetHeight;
} else {
offsetHeight = Math.min(offsetHeight, spaceAvailableBelow);
// Show below, position calculated in showSuggestions for some
// strange reason
top = topPosition;
offsetHeight = Math.min(offsetHeight, spaceBelowInViewport);
}

// fetch real width (mac FF bugs here due GWT popups overflow:auto )

+ 15
- 17
client/src/main/java/com/vaadin/client/ui/VGridLayout.java View File

@@ -61,10 +61,10 @@ public class VGridLayout extends ComplexPanel {
public int[] rowHeights;

/** For internal use only. May be removed or replaced in the future. */
public int[] colExpandRatioArray;
public float[] colExpandRatioArray;

/** For internal use only. May be removed or replaced in the future. */
public int[] rowExpandRatioArray;
public float[] rowExpandRatioArray;

int[] minColumnWidths;

@@ -142,7 +142,7 @@ public class VGridLayout extends ComplexPanel {
void expandRows() {
if (!isUndefinedHeight()) {
int usedSpace = calcRowUsedSpace();
int[] actualExpandRatio = calcRowExpandRatio();
float[] actualExpandRatio = calcRowExpandRatio();
// Round down to avoid problems with fractions (100.1px available ->
// can use 100, not 101)
int availableSpace = (int) LayoutManager.get(client)
@@ -150,13 +150,12 @@ public class VGridLayout extends ComplexPanel {
int excessSpace = availableSpace - usedSpace;
int distributed = 0;
if (excessSpace > 0) {
int expandRatioSum = 0;
float expandRatioSum = 0;
for (int i = 0; i < rowHeights.length; i++) {
expandRatioSum += actualExpandRatio[i];
}
for (int i = 0; i < rowHeights.length; i++) {
int ew = excessSpace * actualExpandRatio[i]
/ expandRatioSum;
int ew = (int) (excessSpace * actualExpandRatio[i] / expandRatioSum);
rowHeights[i] = minRowHeights[i] + ew;
distributed += ew;
}
@@ -171,8 +170,8 @@ public class VGridLayout extends ComplexPanel {
}
}

private int[] calcRowExpandRatio() {
int[] actualExpandRatio = new int[minRowHeights.length];
private float[] calcRowExpandRatio() {
float[] actualExpandRatio = new float[minRowHeights.length];
for (int i = 0; i < minRowHeights.length; i++) {
if (hiddenEmptyRow(i)) {
actualExpandRatio[i] = 0;
@@ -224,7 +223,7 @@ public class VGridLayout extends ComplexPanel {
void expandColumns() {
if (!isUndefinedWidth()) {
int usedSpace = calcColumnUsedSpace();
int[] actualExpandRatio = calcColumnExpandRatio();
float[] actualExpandRatio = calcColumnExpandRatio();
// Round down to avoid problems with fractions (100.1px available ->
// can use 100, not 101)
int availableSpace = (int) LayoutManager.get(client)
@@ -232,13 +231,12 @@ public class VGridLayout extends ComplexPanel {
int excessSpace = availableSpace - usedSpace;
int distributed = 0;
if (excessSpace > 0) {
int expandRatioSum = 0;
float expandRatioSum = 0;
for (int i = 0; i < columnWidths.length; i++) {
expandRatioSum += actualExpandRatio[i];
}
for (int i = 0; i < columnWidths.length; i++) {
int ew = excessSpace * actualExpandRatio[i]
/ expandRatioSum;
int ew = (int) (excessSpace * actualExpandRatio[i] / expandRatioSum);
columnWidths[i] = minColumnWidths[i] + ew;
distributed += ew;
}
@@ -256,8 +254,8 @@ public class VGridLayout extends ComplexPanel {
/**
* Calculates column expand ratio.
*/
private int[] calcColumnExpandRatio() {
int[] actualExpandRatio = new int[minColumnWidths.length];
private float[] calcColumnExpandRatio() {
float[] actualExpandRatio = new float[minColumnWidths.length];
for (int i = 0; i < minColumnWidths.length; i++) {
if (!hiddenEmptyColumn(i)) {
actualExpandRatio[i] = colExpandRatioArray[i];
@@ -537,7 +535,7 @@ public class VGridLayout extends ComplexPanel {

private static void distributeSpanSize(int[] dimensions,
int spanStartIndex, int spanSize, int spacingSize, int size,
int[] expansionRatios) {
float[] expansionRatios) {
int allocated = dimensions[spanStartIndex];
for (int i = 1; i < spanSize; i++) {
allocated += spacingSize + dimensions[spanStartIndex + i];
@@ -563,8 +561,8 @@ public class VGridLayout extends ComplexPanel {
// expansion ratios
expansion = neededExtraSpace / spanSize;
} else {
expansion = neededExtraSpace * expansionRatios[itemIndex]
/ totalExpansion;
expansion = (int) (neededExtraSpace
* expansionRatios[itemIndex] / totalExpansion);
}
dimensions[itemIndex] += expansion;
allocatedExtraSpace += expansion;

+ 51
- 13
client/src/main/java/com/vaadin/client/ui/VListSelect.java View File

@@ -17,11 +17,14 @@
package com.vaadin.client.ui;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.user.client.ui.ListBox;
import com.vaadin.client.UIDL;
import com.vaadin.shared.util.SharedUtil;

public class VListSelect extends VOptionGroupBase {

@@ -67,34 +70,69 @@ public class VListSelect extends VOptionGroupBase {

@Override
public void buildOptions(UIDL uidl) {
int scrollTop = select.getElement().getScrollTop();
int rowCount = getRows();
select.setMultipleSelect(isMultiselect());
select.clear();

Set<String> previousKeys = new HashSet<String>();
for (int i = 0; i < select.getItemCount(); i++) {
previousKeys.add(select.getValue(i));
}

int nextIndex = 0;
if (!isMultiselect() && isNullSelectionAllowed()
&& !isNullSelectionItemAvailable()) {
// can't unselect last item in singleselect mode
updateOrCreateItem("", "null", nextIndex++, previousKeys);
select.addItem("", (String) null);

// Null select item can't be selected programmatically, but will
// remain selected if it was selected by the user. There's no
// need to deselect when something else is selected since it's only
// used in single select mode.
}
for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) {
final UIDL optionUidl = (UIDL) i.next();
select.addItem(optionUidl.getStringAttribute("caption"),
optionUidl.getStringAttribute("key"));
updateOrCreateItem(optionUidl.getStringAttribute("caption"),
optionUidl.getStringAttribute("key"), nextIndex,
previousKeys);
if (optionUidl.hasAttribute("selected")) {
int itemIndex = select.getItemCount() - 1;
select.setItemSelected(itemIndex, true);
lastSelectedIndex = itemIndex;
select.setItemSelected(nextIndex, true);
lastSelectedIndex = nextIndex;
} else {
select.setItemSelected(nextIndex, false);
}
nextIndex++;
}

// Remove any trailing items not in the UIDL
while (select.getItemCount() > nextIndex) {
select.removeItem(nextIndex);
}

if (getRows() > 0) {
select.setVisibleItemCount(getRows());
}
// FIXME: temporary hack for preserving the scroll state when the
// contents haven't been changed obviously. This should be dealt with in
// the rewrite.
if (rowCount == getRows()) {
select.getElement().setScrollTop(scrollTop);
}

private void updateOrCreateItem(String caption, String key, int index,
Set<String> previousKeys) {
if (previousKeys.remove(key)) {
while (select.getItemCount() >= index) {
String keyAtIndex = select.getValue(index);
if (SharedUtil.equals(key, keyAtIndex)) {
select.setItemText(index, caption);
return;
} else {
// Assume the item we're looking at has simply been removed
// and that the next item will match our key
select.removeItem(index);
previousKeys.remove(keyAtIndex);
}
}
}

// We end up here for new items or if we removed all following items
// while looking for a match
select.insertItem(caption, key, index);
}

@Override

+ 2
- 0
client/src/main/java/com/vaadin/client/ui/VMenuBar.java View File

@@ -590,8 +590,10 @@ public class VMenuBar extends SimpleFocusablePanel implements
popup.setOwner(this);
} else {
VMenuBar parent = parentMenu;
popup.addAutoHidePartner(parent.getSelected().getElement());
while (parent.getParentMenu() != null) {
parent = parent.getParentMenu();
popup.addAutoHidePartner(parent.getSelected().getElement());
}
popup.setOwner(parent);
}

+ 1
- 1
client/src/main/java/com/vaadin/client/ui/VTextField.java View File

@@ -423,7 +423,7 @@ public class VTextField extends TextBoxBase implements Field, ChangeHandler,
*/
protected boolean updateCursorPosition() {
if (WidgetUtil.isAttachedAndDisplayed(this)) {
int cursorPos = getCursorPos();
int cursorPos = prompting ? 0 : getCursorPos();
if (lastCursorPos != cursorPos) {
client.updateVariable(paintableId,
TextFieldConstants.VAR_CURSOR, cursorPos, false);

+ 20
- 7
client/src/main/java/com/vaadin/client/ui/VWindow.java View File

@@ -989,7 +989,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
} else if (header.isOrHasChild(target) && !dragging) {
// dblclick handled in connector
if (type != Event.ONDBLCLICK && draggable) {
if (type == Event.ONMOUSEDOWN) {
if (type == Event.ONMOUSEDOWN || type == Event.ONTOUCHSTART) {
/**
* Prevents accidental selection of window caption or
* content. (#12726)
@@ -997,6 +997,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
event.preventDefault();

headerDragPending = event;
bubble = false;
} else if (type == Event.ONMOUSEMOVE
&& headerDragPending != null) {
// ie won't work unless this is set here
@@ -1004,14 +1005,27 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
onDragEvent(headerDragPending);
onDragEvent(event);
headerDragPending = null;
bubble = false;
} else if (type != Event.ONMOUSEMOVE) {
// The event can propagate to the parent in case it is a
// mouse move event. This is needed for tooltips to work in
// header and footer, see Ticket #19073
headerDragPending = null;
bubble = false;
} else {
headerDragPending = null;
}
bubble = false;
}
if (type == Event.ONCLICK) {
activateOnClick();
}
} else if (footer.isOrHasChild(target) && !dragging) {
onDragEvent(event);
if (type != Event.ONMOUSEMOVE) {
// This is needed for tooltips to work in header and footer, see
// Ticket #19073
bubble = false;
}
} else if (dragging || !contents.isOrHasChild(target)) {
onDragEvent(event);
bubble = false;
@@ -1023,7 +1037,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* If clicking on other than the content, move focus to the window.
* After that this windows e.g. gets all keyboard shortcuts.
*/
if (type == Event.ONMOUSEDOWN
if ((type == Event.ONMOUSEDOWN || type == Event.ONTOUCHSTART)
&& !contentPanel.getElement().isOrHasChild(target)
&& target != closeBox && target != maximizeRestoreBox) {
contentPanel.focus();
@@ -1031,11 +1045,10 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,

if (!bubble) {
event.stopPropagation();
} else {
// Super.onBrowserEvent takes care of Handlers added by the
// ClickEventHandler
super.onBrowserEvent(event);
}
// Super.onBrowserEvent takes care of Handlers added by the
// ClickEventHandler
super.onBrowserEvent(event);
}

private void activateOnClick() {

+ 25
- 0
client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java View File

@@ -24,10 +24,12 @@ import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.LayoutManager;
import com.vaadin.client.TooltipInfo;
import com.vaadin.client.Util;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractFieldConnector;
import com.vaadin.client.ui.AbstractLayoutConnector;
import com.vaadin.client.ui.LayoutClickEventHandler;
import com.vaadin.client.ui.PostLayoutListener;
import com.vaadin.client.ui.VFormLayout;
import com.vaadin.client.ui.VFormLayout.Caption;
@@ -36,7 +38,9 @@ import com.vaadin.client.ui.VFormLayout.VFormLayoutTable;
import com.vaadin.client.ui.layout.ElementResizeEvent;
import com.vaadin.client.ui.layout.ElementResizeListener;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.LayoutClickRpc;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutServerRpc;
import com.vaadin.shared.ui.orderedlayout.FormLayoutState;
import com.vaadin.ui.FormLayout;

@@ -44,6 +48,26 @@ import com.vaadin.ui.FormLayout;
public class FormLayoutConnector extends AbstractLayoutConnector implements
PostLayoutListener {

/*
* Handlers & Listeners
*/

private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
this) {

@Override
protected ComponentConnector getChildComponent(
com.google.gwt.user.client.Element element) {
return Util.getConnectorForElement(getConnection(), getWidget(),
element);
}

@Override
protected LayoutClickRpc getLayoutClickRPC() {
return getRpcProxy(AbstractOrderedLayoutServerRpc.class);
}
};

private Map<ComponentConnector, String> oldMaxWidths = null;

private static final ElementResizeListener dummyFirstCellResizeListener = new ElementResizeListener() {
@@ -143,6 +167,7 @@ public class FormLayoutConnector extends AbstractLayoutConnector implements
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);

clickEventHandler.handleEventHandlerRegistration();
VFormLayoutTable formLayoutTable = getWidget().table;

formLayoutTable.setMargins(new MarginInfo(getState().marginsBitmask));

+ 4
- 13
client/src/main/java/com/vaadin/client/ui/gridlayout/GridLayoutConnector.java View File

@@ -42,7 +42,7 @@ import com.vaadin.ui.GridLayout;

@Connect(GridLayout.class)
public class GridLayoutConnector extends AbstractComponentContainerConnector
implements Paintable, DirectionalManagedLayout {
implements DirectionalManagedLayout {

private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
this) {
@@ -95,16 +95,6 @@ public class GridLayoutConnector extends AbstractComponentContainerConnector

getWidget().hideEmptyRowsAndColumns = getState().hideEmptyRowsAndColumns;

}

@Override
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
VGridLayout layout = getWidget();

if (!isRealUpdate(uidl)) {
return;
}

initSize();

for (Entry<Connector, ChildComponentData> entry : getState().childData
@@ -117,8 +107,9 @@ public class GridLayoutConnector extends AbstractComponentContainerConnector
cell.updateCell(childComponentData);
}

layout.colExpandRatioArray = uidl.getIntArrayAttribute("colExpand");
layout.rowExpandRatioArray = uidl.getIntArrayAttribute("rowExpand");
VGridLayout layout = getWidget();
layout.colExpandRatioArray = getState().colExpand;
layout.rowExpandRatioArray = getState().rowExpand;

layout.updateMarginStyleNames(new MarginInfo(getState().marginsBitmask));
layout.updateSpacingStyleName(getState().spacing);

+ 46
- 0
client/src/main/java/com/vaadin/client/widget/grid/events/GridEnabledEvent.java View File

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

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

/**
* An enabled/disabled event, fired by the Grid when it is disabled or enabled.
*
* @since
* @author Vaadin Ltd
*/
public class GridEnabledEvent extends GwtEvent<GridEnabledHandler> {
/**
* The type of this event
*/
public static final Type<GridEnabledHandler> TYPE = new Type<GridEnabledHandler>();
private final boolean enabled;

public GridEnabledEvent(boolean enabled) {
this.enabled = enabled;
}

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

@Override
protected void dispatch(final GridEnabledHandler handler) {
handler.onEnabled(enabled);
}
}

+ 36
- 0
client/src/main/java/com/vaadin/client/widget/grid/events/GridEnabledHandler.java View File

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

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

/**
* Handler for a Grid enabled/disabled event, called when the Grid is enabled
* or disabled.
*
* @since
* @author Vaadin Ltd
*/
public interface GridEnabledHandler extends EventHandler {

/**
* Called when Grid is enabled or disabled.
*
* @param enabled
* true if status changes from disabled to enabled, otherwise false.
*/
public void onEnabled(boolean enabled);
}

+ 20
- 5
client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java View File

@@ -42,6 +42,8 @@ import com.vaadin.client.WidgetUtil;
import com.vaadin.client.renderers.ClickableRenderer;
import com.vaadin.client.widget.grid.CellReference;
import com.vaadin.client.widget.grid.RendererCellReference;
import com.vaadin.client.widget.grid.events.GridEnabledEvent;
import com.vaadin.client.widget.grid.events.GridEnabledHandler;
import com.vaadin.client.widget.grid.selection.SelectionModel.Multi.Batched;
import com.vaadin.client.widgets.Grid;

@@ -76,7 +78,7 @@ public class MultiSelectionRenderer<T> extends
* @since 7.5
*/
private final class CheckBoxEventHandler implements MouseDownHandler,
TouchStartHandler, ClickHandler {
TouchStartHandler, ClickHandler, GridEnabledHandler {
private final CheckBox checkBox;

/**
@@ -89,14 +91,18 @@ public class MultiSelectionRenderer<T> extends

@Override
public void onMouseDown(MouseDownEvent event) {
if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) {
startDragSelect(event.getNativeEvent(), checkBox.getElement());
if(checkBox.isEnabled()) {
if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) {
startDragSelect(event.getNativeEvent(), checkBox.getElement());
}
}
}

@Override
public void onTouchStart(TouchStartEvent event) {
startDragSelect(event.getNativeEvent(), checkBox.getElement());
if(checkBox.isEnabled()) {
startDragSelect(event.getNativeEvent(), checkBox.getElement());
}
}

@Override
@@ -105,6 +111,11 @@ public class MultiSelectionRenderer<T> extends
event.preventDefault();
event.stopPropagation();
}

@Override
public void onEnabled(boolean enabled) {
checkBox.setEnabled(enabled);
}
}

/**
@@ -595,6 +606,7 @@ public class MultiSelectionRenderer<T> extends
final CheckBox checkBox = GWT.create(CheckBox.class);
checkBox.setStylePrimaryName(grid.getStylePrimaryName()
+ SELECTION_CHECKBOX_CLASSNAME);

CheckBoxEventHandler handler = new CheckBoxEventHandler(checkBox);

// Sink events
@@ -606,6 +618,9 @@ public class MultiSelectionRenderer<T> extends
checkBox.addMouseDownHandler(handler);
checkBox.addTouchStartHandler(handler);
checkBox.addClickHandler(handler);
grid.addHandler(handler, GridEnabledEvent.TYPE);

checkBox.setEnabled(grid.isEnabled());

return checkBox;
}
@@ -614,7 +629,7 @@ public class MultiSelectionRenderer<T> extends
public void render(final RendererCellReference cell, final Boolean data,
CheckBox checkBox) {
checkBox.setValue(data, false);
checkBox.setEnabled(!grid.isEditorActive());
checkBox.setEnabled(grid.isEnabled() && !grid.isEditorActive());
checkBox.getElement().setPropertyInt(LOGICAL_ROW_PROPERTY_INT,
cell.getRowIndex());
}

+ 39
- 1
client/src/main/java/com/vaadin/client/widgets/Grid.java View File

@@ -140,6 +140,8 @@ import com.vaadin.client.widget.grid.events.FooterKeyPressHandler;
import com.vaadin.client.widget.grid.events.FooterKeyUpHandler;
import com.vaadin.client.widget.grid.events.GridClickEvent;
import com.vaadin.client.widget.grid.events.GridDoubleClickEvent;
import com.vaadin.client.widget.grid.events.GridEnabledEvent;
import com.vaadin.client.widget.grid.events.GridEnabledHandler;
import com.vaadin.client.widget.grid.events.GridKeyDownEvent;
import com.vaadin.client.widget.grid.events.GridKeyPressEvent;
import com.vaadin.client.widget.grid.events.GridKeyUpEvent;
@@ -2845,7 +2847,8 @@ public class Grid<T> extends ResizeComposite implements
}
}

public final class SelectionColumn extends Column<Boolean, T> {
public final class SelectionColumn extends Column<Boolean, T>
implements GridEnabledHandler {

private boolean initDone = false;
private boolean selected = false;
@@ -2853,6 +2856,8 @@ public class Grid<T> extends ResizeComposite implements

SelectionColumn(final Renderer<Boolean> selectColumnRenderer) {
super(selectColumnRenderer);

addEnabledHandler(this);
}

void initDone() {
@@ -3002,6 +3007,24 @@ public class Grid<T> extends ResizeComposite implements
super.setEditable(editable);
return this;
}

/**
* Sets whether the selection column is enabled.
*
* @since
* @param enabled <code>true</code> to enable the column,
* <code>false</code> to disable it.
*/
public void setEnabled(boolean enabled) {
if(selectAllCheckBox != null) {
selectAllCheckBox.setEnabled(enabled);
}
}

@Override
public void onEnabled(boolean enabled) {
setEnabled(enabled);
}
}

/**
@@ -5971,6 +5994,8 @@ public class Grid<T> extends ResizeComposite implements
getEscalator().setScrollLocked(Direction.VERTICAL,
!enabled || editorOpen);
getEscalator().setScrollLocked(Direction.HORIZONTAL, !enabled);

fireEvent(new GridEnabledEvent(enabled));
}

@Override
@@ -7538,6 +7563,8 @@ public class Grid<T> extends ResizeComposite implements
selectionColumn = new SelectionColumn(selectColumnRenderer);

addColumnSkipSelectionColumnCheck(selectionColumn, 0);

selectionColumn.setEnabled(isEnabled());
selectionColumn.initDone();
} else {
selectionColumn = null;
@@ -8099,6 +8126,17 @@ public class Grid<T> extends ResizeComposite implements
return addHandler(handler, ColumnResizeEvent.getType());
}

/**
* Register a enabled status change handler to this Grid.
* The event for this handler is fired when the Grid changes from disabled
* to enabled and vice-versa.
* @param handler the handler for the event
* @return the registration for the event
*/
public HandlerRegistration addEnabledHandler(GridEnabledHandler handler) {
return addHandler(handler, GridEnabledEvent.TYPE);
}

/**
* Apply sorting to data source.
*/

+ 2
- 2
client/src/main/java/com/vaadin/client/widgets/Overlay.java View File

@@ -1115,7 +1115,7 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
* it will be shrunk to fit and assume that scrolling e.g. using
* <code>overflow:auto</code>, is taken care of by the overlay user.
*
* @since
* @since 7.6.6
* @param fitInWindow
* <code>true</code> to ensure that no part of the popup is
* outside the visible view, <code>false</code> to use the
@@ -1131,7 +1131,7 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
*
* @see #setFitInWindow(boolean)
*
* @since
* @since 7.6.6
* @return <code>true</code> if the popup will be moved and/or shrunk to fit
* inside the window, <code>false</code> otherwise
*/

+ 29
- 0
client/src/test/java/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java View File

@@ -61,6 +61,8 @@ public class VBrowserDetailsUserAgentParserTest {

private static final String EDGE_WINDOWS_10 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240";

private static final String PHANTOMJS_211_MAC = "Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1";

@Test
public void testSafari3() {
VBrowserDetails bd = new VBrowserDetails(SAFARI3_WINDOWS);
@@ -471,6 +473,16 @@ public class VBrowserDetailsUserAgentParserTest {
assertWindows(bd, false);
}

@Test
public void testPhantomJs211() {
VBrowserDetails bd = new VBrowserDetails(PHANTOMJS_211_MAC);
assertPhantomJS(bd);
assertWebKit(bd);
assertBrowserMajorVersion(bd, 2);
assertBrowserMinorVersion(bd, 1);
assertMacOSX(bd);
}

/*
* Helper methods below
*/
@@ -525,6 +537,17 @@ public class VBrowserDetailsUserAgentParserTest {
assertFalse(browserDetails.isTrident());
}

private void assertPhantomJS(VBrowserDetails browserDetails) {
// Browser
assertFalse(browserDetails.isFirefox());
assertFalse(browserDetails.isChrome());
assertFalse(browserDetails.isIE());
assertFalse(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
assertFalse(browserDetails.isEdge());
assertTrue(browserDetails.isPhantomJS());
}

private void assertFirefox(VBrowserDetails browserDetails) {
// Browser
assertTrue(browserDetails.isFirefox());
@@ -533,6 +556,7 @@ public class VBrowserDetailsUserAgentParserTest {
assertFalse(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
assertFalse(browserDetails.isEdge());
assertFalse(browserDetails.isPhantomJS());
}

private void assertChrome(VBrowserDetails browserDetails) {
@@ -543,6 +567,7 @@ public class VBrowserDetailsUserAgentParserTest {
assertFalse(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
assertFalse(browserDetails.isEdge());
assertFalse(browserDetails.isPhantomJS());
}

private void assertIE(VBrowserDetails browserDetails) {
@@ -553,6 +578,7 @@ public class VBrowserDetailsUserAgentParserTest {
assertFalse(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
assertFalse(browserDetails.isEdge());
assertFalse(browserDetails.isPhantomJS());
}

private void assertOpera(VBrowserDetails browserDetails) {
@@ -563,6 +589,7 @@ public class VBrowserDetailsUserAgentParserTest {
assertTrue(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
assertFalse(browserDetails.isEdge());
assertFalse(browserDetails.isPhantomJS());
}

private void assertSafari(VBrowserDetails browserDetails) {
@@ -573,6 +600,7 @@ public class VBrowserDetailsUserAgentParserTest {
assertFalse(browserDetails.isOpera());
assertTrue(browserDetails.isSafari());
assertFalse(browserDetails.isEdge());
assertFalse(browserDetails.isPhantomJS());
}

private void assertEdge(VBrowserDetails browserDetails) {
@@ -583,6 +611,7 @@ public class VBrowserDetailsUserAgentParserTest {
assertFalse(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
assertTrue(browserDetails.isEdge());
assertFalse(browserDetails.isPhantomJS());
}

private void assertMacOSX(VBrowserDetails browserDetails) {

+ 1
- 1
documentation/advanced/advanced-dragndrop.asciidoc View File

@@ -296,7 +296,7 @@ components, including [classname]#Tree# and [classname]#Table#.
[classname]#AcceptItem#:: Accepts only specific items from a specific selection component. The selection component, which must inherit [classname]#AbstractSelect#, is given as the first parameter for the constructor. It is followed by a list of allowed item identifiers in the drag source.
[classname]#AcceptItem.ALL#:: Accepts all transferables as long as they are items.
[classname]#TargetItemIs#:: Accepts all drops on the specified target items. The constructor requires the target component ( [classname]#AbstractSelect#) followed by a list of allowed item identifiers.
[classname]#VerticalLocationIs.MIDDLE#,[classname]#TOP#, and[classname]#BOTTOM#:: The three static criteria accepts drops on, above, or below an item. For example, you could accept drops only in between items with the following:
[classname]#VerticalLocationIs.MIDDLE#, [classname]#TOP#, and [classname]#BOTTOM#:: The three static criteria accepts drops on, above, or below an item. For example, you could accept drops only in between items with the following:
[source, java]
----
public AcceptCriterion getAcceptCriterion() {

+ 0
- 20
documentation/advanced/advanced-embedding.asciidoc View File

@@ -34,7 +34,6 @@ different widget sets and different themes.
Embedding an UI requires the following basic tasks:

* Set up the page header
* Include a GWT history frame in the page
* Call the [filename]#vaadinBootstrap.js# file
* Define the [literal]#++<div>++# element for the UI
* Configure and initialize the UI
@@ -95,18 +94,6 @@ relative to the path of the embedding page.
The bootstrap script is served by the Vaadin servlet from inside the
[filename]#vaadin-server# JAR.

Vaadin, or more precisely GWT, requires an invisible history frame, which is
used for tracking the page or fragment history in the browser.


[source, html]
----
<iframe tabindex="-1" id="__gwt_historyFrame"
style="position: absolute; width: 0; height: 0;
border: 0; overflow: hidden"
src="javascript:false"></iframe>
----

endif::web[]

ifdef::web[]
@@ -255,13 +242,6 @@ element.
<script type="text/javascript"
src="VAADIN/vaadinBootstrap.js"></script>

<!-- GWT requires an invisible history frame. It is -->
<!-- needed for page/fragment history in the browser. -->
<iframe tabindex="-1" id="__gwt_historyFrame"
style="position: absolute; width: 0; height: 0;
border: 0; overflow: hidden"
src="javascript:false"></iframe>

<h1>Embedding a Vaadin UI</h1>
<p>This is a static web page that contains an embedded Vaadin

+ 1
- 1
documentation/clientside/clientside-debugging.asciidoc View File

@@ -116,7 +116,7 @@ Chrome supports source maps, which allow debugging Java source code from which
the JavaScript was compiled.

Open the Chrome Inspector by right-clicking and selecting [guilabel]#Inspect
Element#. Click the settings icon in the lower corner of the window and check
Element#. Click the settings icon in the upper right corner of the window and check
the "Scripts > Enable source maps" option. Refresh the page with the Inspector
open, and you will see Java code instead of JavaScript in the scripts tab.


+ 1
- 1
documentation/gwt/gwt-rpc.asciidoc View File

@@ -51,7 +51,7 @@ doesn't.
=== Making a Call

Before making a call, you need to instantiate the server RPC object with
[methodname]#RpcProxy.create()#. After that, you can make calls through the
[methodname]#RpcProxy.create()#. This is usually done transparently by using [methodname]#getRpcProxy()#. After that, you can make calls through the
server RPC interface that you defined, for example as follows:



+ 1
- 1
documentation/tutorial.adoc View File

@@ -58,7 +58,7 @@ image::img/finalUI.jpg[]
You need about 20 to 60 minutes to complete the tutorial, depending on your existing experience.
Naturally, you can just do the beginning of the exercise or pick any of the steps you want.
To start from a specific step, we have prepared the example code after each step to be downloaded as a zip file.
If do not want to do the exercise at all, you can also just https://github.com/vaadin/tutorial/[download the final application] and play around with it.
If you do not want to do the exercise at all, you can also just https://github.com/vaadin/tutorial/[download the final application] and play around with it.

[[framework.tutorial.overview.tools]]
=== Installing the Development Tools

+ 3
- 3
pom.xml View File

@@ -25,7 +25,6 @@
<!-- Used version numbers for dependencies -->
<commons-io.version>2.4</commons-io.version>
<google.appengine.version>1.7.7</google.appengine.version>
<guava.version>16.0.1.vaadin1</guava.version>
<jsoup.version>1.8.3</jsoup.version>
<liferay.portal.version>6.0.2</liferay.portal.version>

@@ -41,8 +40,9 @@
<junit.version>4.11</junit.version>

<!-- Atmosphere versions -->
<atmosphere.runtime.version>2.2.7.vaadin1</atmosphere.runtime.version>
<atmosphere.js.version>2.2.6.vaadin4</atmosphere.js.version>
<!-- Note that this should be kept in sync with the class Constants -->
<atmosphere.runtime.version>2.2.9.vaadin2</atmosphere.runtime.version>
<atmosphere.js.version>2.2.13.vaadin3</atmosphere.js.version>

<!-- Dependency unpack directory -->
<dependency.unpack.directory>${project.build.directory}/dependency-unpack</dependency.unpack.directory>

+ 1
- 1
server/pom.xml View File

@@ -273,7 +273,7 @@
javax.portlet;version="[${javax.portlet.version},3)";resolution:=optional,
javax.portlet.filter;version="[${javax.portlet.version},3)";resolution:=optional,
com.liferay.portal.kernel.util;resolution:=optional</Import-Package>
<Require-Bundle>com.google.gwt.thirdparty.guava;bundle-version="${guava.version}",
<Require-Bundle>
com.vaadin.shared;bundle-version="${project.version}",
com.vaadin.push;bundle-version="${project.version}";resolution:=optional,
com.vaadin.sass-compiler;bundle-version="${vaadin.sass.version}";resolution:=optional"</Require-Bundle>

+ 1
- 2
server/src/main/java/com/vaadin/data/util/ContainerHierarchicalWrapper.java View File

@@ -538,10 +538,9 @@ public class ContainerHierarchicalWrapper implements Container.Hierarchical,
*/
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {

// Null ids are not accepted
if (itemId == null) {
throw new NullPointerException("Container item id can not be null");
return null;
}

final Item item = container.addItem(itemId);

+ 17
- 1
server/src/main/java/com/vaadin/data/util/ContainerOrderedWrapper.java View File

@@ -16,10 +16,12 @@

package com.vaadin.data.util;

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

import com.vaadin.data.Container;
import com.vaadin.data.Item;
@@ -464,7 +466,21 @@ public class ContainerOrderedWrapper implements Container.Ordered,
*/
@Override
public Collection<?> getItemIds() {
return container.getItemIds();
if (ordered) {
return ((Container.Ordered) container).getItemIds();
} else if (first == null) {
return new ArrayList<Object>();
} else {
List<Object> itemIds = new ArrayList<Object>();
itemIds.add(first);
Object current = first;
while (next.containsKey(current)) {
current = next.get(current);
itemIds.add(current);
}
return itemIds;
}

}

/*

+ 10
- 18
server/src/main/java/com/vaadin/data/util/GeneratedPropertyContainer.java View File

@@ -27,7 +27,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.google.gwt.thirdparty.guava.common.collect.Sets;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
@@ -146,10 +145,11 @@ public class GeneratedPropertyContainer extends AbstractContainer implements

@Override
public Collection<?> getItemPropertyIds() {
Set<?> wrappedProperties = asSet(wrappedItem.getItemPropertyIds());
return Sets.union(
Sets.difference(wrappedProperties, removedProperties),
propertyGenerators.keySet());
Set<Object> wrappedProperties = new LinkedHashSet<Object>(
wrappedItem.getItemPropertyIds());
wrappedProperties.removeAll(removedProperties);
wrappedProperties.addAll(propertyGenerators.keySet());
return wrappedProperties;
}

@Override
@@ -366,14 +366,6 @@ public class GeneratedPropertyContainer extends AbstractContainer implements
return new GeneratedProperty<T>(item, propertyId, itemId, generator);
}

private static <T> LinkedHashSet<T> asSet(Collection<T> collection) {
if (collection instanceof LinkedHashSet) {
return (LinkedHashSet<T>) collection;
} else {
return new LinkedHashSet<T>(collection);
}
}

/* Listener functionality */

@Override
@@ -618,11 +610,11 @@ public class GeneratedPropertyContainer extends AbstractContainer implements
*/
@Override
public Collection<?> getContainerPropertyIds() {
Set<?> wrappedProperties = asSet(wrappedContainer
.getContainerPropertyIds());
return Sets.union(
Sets.difference(wrappedProperties, removedProperties),
propertyGenerators.keySet());
Set<Object> wrappedProperties = new LinkedHashSet<Object>(
wrappedContainer.getContainerPropertyIds());
wrappedProperties.removeAll(removedProperties);
wrappedProperties.addAll(propertyGenerators.keySet());
return wrappedProperties;
}

/**

+ 3
- 6
server/src/main/java/com/vaadin/data/util/IndexedContainer.java View File

@@ -269,7 +269,9 @@ public class IndexedContainer extends
public Item addItem(Object itemId) {
Item item = internalAddItemAtEnd(itemId, new IndexedContainerItem(
itemId), false);
if (!isFiltered()) {
if (item == null) {
return null;
} else if (!isFiltered()) {
// always the last item
fireItemAdded(size() - 1, itemId, item);
} else if (passesFilters(itemId) && !containsId(itemId)) {
@@ -726,11 +728,6 @@ public class IndexedContainer extends
* the Item ID of the new Item.
*/
private IndexedContainerItem(Object itemId) {

// Gets the item contents from the host
if (itemId == null) {
throw new NullPointerException();
}
this.itemId = itemId;
}


+ 22
- 4
server/src/main/java/com/vaadin/event/SelectionEvent.java View File

@@ -22,8 +22,6 @@ import java.util.EventObject;
import java.util.LinkedHashSet;
import java.util.Set;

import com.google.gwt.thirdparty.guava.common.collect.Sets;

/**
* An event that specifies what in a selection has changed, and where the
* selection took place.
@@ -52,7 +50,7 @@ public class SelectionEvent extends EventObject {
* @return a Collection of the itemIds that became selected
*/
public Set<Object> getAdded() {
return Sets.difference(newSelection, oldSelection);
return setDifference(newSelection, oldSelection);
}

/**
@@ -64,7 +62,27 @@ public class SelectionEvent extends EventObject {
* @return a Collection of the itemIds that became deselected
*/
public Set<Object> getRemoved() {
return Sets.difference(oldSelection, newSelection);
return setDifference(oldSelection, newSelection);
}

/**
* Slightly optimized set difference that can return the original set or a
* modified one.
*
* @param set1
* original set
* @param set2
* the set to subtract
* @return the difference set
*/
private static <T> Set<T> setDifference(Set<T> set1, Set<T> set2) {
if (set2.isEmpty()) {
return set1;
} else {
LinkedHashSet<T> set = new LinkedHashSet<T>(set1);
set.removeAll(set2);
return set;
}
}

/**

+ 11
- 3
server/src/main/java/com/vaadin/server/BootstrapHandler.java View File

@@ -20,6 +20,8 @@ import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@@ -37,7 +39,6 @@ import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.parser.Tag;

import com.google.gwt.thirdparty.guava.common.net.UrlEscapers;
import com.vaadin.annotations.JavaScript;
import com.vaadin.annotations.StyleSheet;
import com.vaadin.annotations.Viewport;
@@ -227,7 +228,14 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {

@Override
protected String encodeQueryStringParameterValue(String queryString) {
return UrlEscapers.urlFormParameterEscaper().escape(queryString);
String encodedString = null;
try {
encodedString = URLEncoder.encode(queryString, "UTF-8");
} catch (UnsupportedEncodingException e) {
// should never happen
throw new RuntimeException("Could not find UTF-8", e);
}
return encodedString;
}
}

@@ -470,7 +478,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
UICreateEvent event = new UICreateEvent(context.getRequest(),
context.getUIClass());
WidgetsetInfo widgetset = context.getBootstrapResponse()
.getUIProvider().getWidgetset(event);
.getUIProvider().getWidgetsetInfo(event);
if (widgetset == null) {
// TODO do we want to move WidgetsetInfoImpl elsewhere?
widgetset = new WidgetsetInfoImpl(request.getService()

+ 1
- 1
server/src/main/java/com/vaadin/server/ClientConnector.java View File

@@ -51,7 +51,7 @@ public interface ClientConnector extends Connector {
}

/**
* Interface for listening {@link DetachEvent connector detach events}.
* Interface for listening {@link AttachEvent connector attach events}.
*
*/
public static interface AttachListener extends ConnectorEventListener {

+ 2
- 3
server/src/main/java/com/vaadin/server/Constants.java View File

@@ -66,9 +66,8 @@ public interface Constants {
+ " Widgetset version: %s\n"
+ "=================================================================";

// Keep the version number in sync with push/build.xml and other locations
// listed in that file
static final String REQUIRED_ATMOSPHERE_RUNTIME_VERSION = "2.2.7.vaadin1";
// Keep the version number in sync with pom.xml
static final String REQUIRED_ATMOSPHERE_RUNTIME_VERSION = "2.2.9.vaadin2";

static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n"
+ "=================================================================\n"

+ 14
- 0
server/src/main/java/com/vaadin/server/KeyMapper.java View File

@@ -93,4 +93,18 @@ public class KeyMapper<V> implements Serializable {
objectKeyMap.clear();
keyObjectMap.clear();
}

/**
* Checks if the given key is mapped to an object.
*
* @since
*
* @param key
* the key to check
* @return <code>true</code> if the key is currently mapped,
* <code>false</code> otherwise
*/
public boolean containsKey(String key) {
return keyObjectMap.containsKey(key);
}
}

+ 28
- 6
server/src/main/java/com/vaadin/server/UIProvider.java View File

@@ -123,6 +123,30 @@ public abstract class UIProvider implements Serializable {
}
}

/**
* Finds the widgetset to use for a specific UI. If no specific widgetset is
* required, <code>null</code> is returned.
* <p>
* This method uses the Widgetset definition priority order from
* {@link #getWidgetsetInfo(UICreateEvent)}.
* <p>
* <strong>Note:</strong> This method exists only for backwards
* compatibility and overriding it won't have the effect it used to.
*
* @param event
* the UI create event with information about the UI and the
* current request.
* @return the name of the widgetset, or <code>null</code> if the default
* widgetset should be used
* @deprecated This method has been replaced by
* {@link #getWidgetsetInfo(UICreateEvent)} in 7.7
*/
@Deprecated
public String getWidgetset(UICreateEvent event) {
WidgetsetInfo widgetsetInfo = getWidgetsetInfo(event);
return widgetsetInfo != null ? widgetsetInfo.getWidgetsetName() : null;
}

/**
* Finds the widgetset to use for a specific UI. If no specific widgetset is
* required, <code>null</code> is returned.
@@ -137,17 +161,15 @@ public abstract class UIProvider implements Serializable {
* <li>null to use the default widgetset otherwise</li>
* </ul>
*
* Note that the return type of this method changed in Vaadin 7.7.
* @since 7.7
*
* @param event
* the UI create event with information about the UI and the
* current request.
* @return the name of the widgetset, or <code>null</code> if the default
* widgetset should be used
*
* @since 7.7
* @return the widgetset info, or <code>null</code> if the default widgetset
* should be used
*/
public WidgetsetInfo getWidgetset(UICreateEvent event) {
public WidgetsetInfo getWidgetsetInfo(UICreateEvent event) {
Widgetset uiWidgetset = getAnnotationFor(event.getUIClass(),
Widgetset.class);


+ 35
- 3
server/src/main/java/com/vaadin/server/VaadinPortletResponse.java View File

@@ -30,8 +30,6 @@ import javax.portlet.PortletResponse;
import javax.portlet.ResourceResponse;
import javax.servlet.http.Cookie;

import com.google.gwt.thirdparty.guava.common.html.HtmlEscapers;

/**
* Wrapper for {@link PortletResponse} and its subclasses.
*
@@ -139,11 +137,45 @@ public class VaadinPortletResponse implements VaadinResponse {
public void sendError(int errorCode, String message) throws IOException {
setStatus(errorCode);
if (message != null) {
message = HtmlEscapers.htmlEscaper().escape(message);
message = escapeHtml(message);
}
getWriter().write(message);
}

/**
* Perform minimal HTML escaping similar to Guava HtmlEscapers.
*
* @param input
* string to escape
* @return minimally escaped HTML safe string
*/
private static String escapeHtml(String input) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
switch (c) {
case '"':
sb.append("&quot;");
break;
case '\'':
sb.append("&#39;");
break;
case '&':
sb.append("&amp;");
break;
case '<':
sb.append("&lt;");
break;
case '>':
sb.append("&gt;");
break;
default:
sb.append(c);
}
}
return sb.toString();
}

@Override
public VaadinPortletService getService() {
return vaadinService;

+ 12
- 7
server/src/main/java/com/vaadin/server/VaadinService.java View File

@@ -1085,17 +1085,22 @@ public abstract class VaadinService implements Serializable {
}

/**
* TODO PUSH Document
*
* TODO Pass UI or VaadinSession?
*
* @param uI
* Finds the given theme resource from the web content folder or using the
* class loader and returns a stream for it
*
* @param ui
* The ui for which to find the resource
* @param themeName
* The name of the theme
* @param resource
* @return
* The name of the resource, e.g. "layouts/mycustomlayout.html"
* @return A stream for the resource or null if the resource was not found
* @throws IOException
* if a problem occurred while finding or opening the resource
*/
public abstract InputStream getThemeResourceAsStream(UI uI,
String themeName, String resource);
public abstract InputStream getThemeResourceAsStream(UI ui,
String themeName, String resource) throws IOException;

/**
* Creates and returns a unique ID for the DIV where the UI is to be

+ 54
- 11
server/src/main/java/com/vaadin/server/VaadinServlet.java View File

@@ -17,7 +17,9 @@ package com.vaadin.server;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -26,10 +28,11 @@ import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -48,8 +51,6 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gwt.thirdparty.guava.common.base.Charsets;
import com.google.gwt.thirdparty.guava.common.io.Files;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.annotations.VaadinServletConfiguration.InitParameterName;
import com.vaadin.sass.internal.ScssStylesheet;
@@ -745,7 +746,7 @@ public class VaadinServlet extends HttpServlet implements Constants {
throws IOException, ServletException {

final ServletContext sc = getServletContext();
URL resourceUrl = findResourceURL(filename, sc);
URL resourceUrl = findResourceURL(filename);

if (resourceUrl == null) {
// File not found, if this was a css request we still look for a
@@ -974,11 +975,21 @@ public class VaadinServlet extends HttpServlet implements Constants {
}
}

private URL findResourceURL(String filename, ServletContext sc)
throws MalformedURLException {
URL resourceUrl = sc.getResource(filename);
/**
* Finds the given resource from the web content folder or using the class
* loader.
*
* @since
* @param filename
* The file to find, starting with a "/"
* @return The URL to the given file, or null if the file was not found
* @throws IOException
* if there was a problem while locating the file
*/
protected URL findResourceURL(String filename) throws IOException {
URL resourceUrl = getServletContext().getResource(filename);
if (resourceUrl == null) {
// try if requested file is found from classloader
// try if requested file is found from class loader

// strip leading "/" otherwise stream from JAR wont work
if (filename.startsWith("/")) {
@@ -999,7 +1010,7 @@ public class VaadinServlet extends HttpServlet implements Constants {

String scssFilename = filename.substring(0, filename.length() - 4)
+ ".scss";
URL scssUrl = findResourceURL(scssFilename, sc);
URL scssUrl = findResourceURL(scssFilename);
if (scssUrl == null) {
// Is a css request but no scss file was found
return false;
@@ -1069,7 +1080,7 @@ public class VaadinServlet extends HttpServlet implements Constants {
return null;
}

String jsonString = Files.toString(scssCacheFile, Charsets.UTF_8);
String jsonString = readFile(scssCacheFile, Charset.forName("UTF-8"));

JsonObject entryJson = Json.parse(jsonString);

@@ -1379,13 +1390,45 @@ public class VaadinServlet extends HttpServlet implements Constants {
String cacheEntryJsonString = cacheEntry.asJson();

try {
Files.write(cacheEntryJsonString, cacheFile, Charsets.UTF_8);
writeFile(cacheEntryJsonString, cacheFile, Charset.forName("UTF-8"));
} catch (IOException e) {
getLogger().log(Level.WARNING,
"Error persisting scss cache " + cacheFile, e);
}
}

private static String readFile(File file, Charset charset)
throws IOException {
InputStream in = new FileInputStream(file);
try {
// no point in reading files over 2GB to a String
byte[] b = new byte[(int) file.length()];
int len = b.length;
int total = 0;

while (total < len) {
int result = in.read(b, total, len - total);
if (result == -1) {
break;
}
total += result;
}
return new String(b, charset);
} finally {
in.close();
}
}

private static void writeFile(String content, File file, Charset charset)
throws IOException {
FileOutputStream fos = new FileOutputStream(file);
try {
fos.write(content.getBytes(charset));
} finally {
fos.close();
}
}

private static File getScssCacheFile(File scssFile) {
return new File(scssFile.getParentFile(), scssFile.getName() + ".cache");
}

+ 21
- 9
server/src/main/java/com/vaadin/server/VaadinServletService.java View File

@@ -17,6 +17,7 @@
package com.vaadin.server;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
@@ -24,8 +25,8 @@ import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.vaadin.server.communication.PushRequestHandler;
import com.vaadin.server.communication.ServletBootstrapHandler;
@@ -201,14 +202,25 @@ public class VaadinServletService extends VaadinService {

@Override
public InputStream getThemeResourceAsStream(UI uI, String themeName,
String resource) {
VaadinServletService service = (VaadinServletService) uI.getSession()
.getService();
ServletContext servletContext = service.getServlet()
.getServletContext();
return servletContext.getResourceAsStream("/"
+ VaadinServlet.THEME_DIR_PATH + '/' + themeName + "/"
+ resource);
String resource) throws IOException {
String filename = "/" + VaadinServlet.THEME_DIR_PATH + '/' + themeName
+ "/" + resource;
URL resourceUrl = servlet.findResourceURL(filename);

if (resourceUrl != null) {
// security check: do not permit navigation out of the VAADIN
// directory
if (!servlet.isAllowedVAADINResourceUrl(null, resourceUrl)) {
throw new IOException(
String.format(
"Requested resource [{0}] not accessible in the VAADIN directory or access to it is forbidden.",
filename));
}

return resourceUrl.openStream();
} else {
return null;
}
}

@Override

+ 2
- 4
server/src/main/java/com/vaadin/server/communication/ResourceWriter.java View File

@@ -69,10 +69,8 @@ public class ResourceWriter implements Serializable {
final String resource = (String) i.next();
InputStream is = null;
try {
is = ui.getSession()
.getService()
.getThemeResourceAsStream(ui, manager.getTheme(ui),
resource);
is = ui.getSession().getService()
.getThemeResourceAsStream(ui, ui.getTheme(), resource);
} catch (final Exception e) {
// FIXME: Handle exception
getLogger().log(Level.FINER,

+ 8
- 8
server/src/main/java/com/vaadin/server/communication/ServerRpcHandler.java View File

@@ -157,7 +157,7 @@ public class ServerRpcHandler implements Serializable {

/**
* Checks if this is a request to resynchronize the client side
*
*
* @return true if this is a resynchronization request, false otherwise
*/
public boolean isResynchronize() {
@@ -166,7 +166,7 @@ public class ServerRpcHandler implements Serializable {

/**
* Gets the id of the client to server message
*
*
* @since 7.6
* @return the server message id
*/
@@ -190,7 +190,7 @@ public class ServerRpcHandler implements Serializable {

/**
* Gets the widget set version reported by the client
*
*
* @since 7.6
* @return The widget set version reported by the client or null if the
* message did not contain a widget set version
@@ -286,7 +286,7 @@ public class ServerRpcHandler implements Serializable {
/**
* Checks that the version reported by the client (widgetset) matches that
* of the server.
*
*
* @param widgetsetVersion
* the widget set version reported by the client or null
*/
@@ -422,7 +422,7 @@ public class ServerRpcHandler implements Serializable {

/**
* Handles the given RPC method invocation for the given connector
*
*
* @since 7.7
* @param ui
* the UI containing the connector
@@ -445,7 +445,7 @@ public class ServerRpcHandler implements Serializable {
/**
* Handles the given Legacy variable change RPC method invocation for the
* given connector
*
*
* @since 7.7
* @param ui
* the UI containing the connector
@@ -463,11 +463,11 @@ public class ServerRpcHandler implements Serializable {
changeVariables(null, (VariableOwner) connector, changes);
} else {
throw new IllegalStateException(
"Received legacy variable change for "
"Received a legacy variable change for "
+ connector.getClass().getName()
+ " ("
+ connector.getConnectorId()
+ ") which is not a VariableOwner. The client-side connector sent these legacy varaibles: "
+ ") which is not a VariableOwner. The client-side connector sent these legacy variables: "
+ changes.keySet());
}
} catch (Exception e) {

+ 1
- 3
server/src/main/java/com/vaadin/ui/AbstractComponent.java View File

@@ -1382,9 +1382,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
}

public void removeShortcutListener(ShortcutListener shortcut) {
if (actionManager != null) {
actionManager.removeAction(shortcut);
}
getActionManager().removeAction(shortcut);
}

/**

+ 8
- 0
server/src/main/java/com/vaadin/ui/AbstractOrderedLayout.java View File

@@ -328,6 +328,10 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements
* @param component
* the component in this layout which expand ratio is to be set
* @param ratio
* new expand ratio (greater or equal to 0)
* @throws IllegalArgumentException
* if the expand ratio is negative or the component is not a
* direct child of the layout
*/
public void setExpandRatio(Component component, float ratio) {
ChildComponentData childData = getState().childData.get(component);
@@ -335,6 +339,10 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements
throw new IllegalArgumentException(
"The given component is not a child of this layout");
}
if (ratio < 0.0f) {
throw new IllegalArgumentException(
"Expand ratio can't be less than 0.0");
}

childData.expandRatio = ratio;
}

+ 10
- 7
server/src/main/java/com/vaadin/ui/AbstractSelect.java View File

@@ -530,18 +530,21 @@ public abstract class AbstractSelect extends AbstractField<Object> implements
setValue(null, true);
}
} else {
final Object id = itemIdMapper
.get(clientSideSelectedKeys[0]);

if (id != null) {
if (isNullSelectionAllowed()
String clientSelectedKey = clientSideSelectedKeys[0];
if ("null".equals(clientSelectedKey)
|| itemIdMapper.containsKey(clientSelectedKey)) {
// Happens to work for nullselection
// (get ("null") -> null))
final Object id = itemIdMapper.get(clientSelectedKey);

if (!isNullSelectionAllowed() && id == null) {
markAsDirty();
} else if (id != null
&& id.equals(getNullSelectionItemId())) {
setValue(null, true);
} else {
setValue(id, true);
}
} else {
markAsDirty();
}
}
}

+ 27
- 55
server/src/main/java/com/vaadin/ui/GridLayout.java View File

@@ -75,7 +75,7 @@ import com.vaadin.ui.declarative.DesignContext;
@SuppressWarnings("serial")
public class GridLayout extends AbstractLayout implements
Layout.AlignmentHandler, Layout.SpacingHandler, Layout.MarginHandler,
LayoutClickNotifier, LegacyComponent {
LayoutClickNotifier {

private GridLayoutServerRpc rpc = new GridLayoutServerRpc() {

@@ -446,73 +446,35 @@ public class GridLayout extends AbstractLayout implements
return components.size();
}

@Override
public void changeVariables(Object source, Map<String, Object> variables) {
// TODO Remove once LegacyComponent is no longer implemented
}

/**
* Paints the contents of this component.
*
* @param target
* the Paint Event.
* @throws PaintException
* if the paint operation failed.
*/
@Override
public void paintContent(PaintTarget target) throws PaintException {
final Integer[] columnExpandRatioArray = new Integer[getColumns()];
final Integer[] rowExpandRatioArray = new Integer[getRows()];
public void beforeClientResponse(boolean initial) {
super.beforeClientResponse(initial);

int realColExpandRatioSum = 0;
getState().colExpand = new float[getColumns()];
float colSum = getExpandRatioSum(columnExpandRatio);
if (colSum == 0) {
// no columns has been expanded, all cols have same expand
// rate
float equalSize = 1 / (float) getColumns();
int myRatio = Math.round(equalSize * 1000);
// no cols have been expanded
for (int i = 0; i < getColumns(); i++) {
columnExpandRatioArray[i] = myRatio;
getState().colExpand[i] = 1f;
}
realColExpandRatioSum = myRatio * getColumns();
} else {
for (int i = 0; i < getColumns(); i++) {
int myRatio = Math
.round((getColumnExpandRatio(i) / colSum) * 1000);
columnExpandRatioArray[i] = myRatio;
realColExpandRatioSum += myRatio;
getState().colExpand[i] = getColumnExpandRatio(i);
}
}

int realRowExpandRatioSum = 0;
getState().rowExpand = new float[getRows()];
float rowSum = getExpandRatioSum(rowExpandRatio);
if (rowSum == 0) {
// no rows have been expanded
float equalSize = 1 / (float) getRows();
int myRatio = Math.round(equalSize * 1000);
for (int i = 0; i < getRows(); i++) {
rowExpandRatioArray[i] = myRatio;
getState().rowExpand[i] = 1f;
}
realRowExpandRatioSum = myRatio * getRows();
} else {
for (int cury = 0; cury < getRows(); cury++) {
int myRatio = Math
.round((getRowExpandRatio(cury) / rowSum) * 1000);
rowExpandRatioArray[cury] = myRatio;
realRowExpandRatioSum += myRatio;
for (int i = 0; i < getRows(); i++) {
getState().rowExpand[i] = getRowExpandRatio(i);
}
}

// correct possible rounding error
if (rowExpandRatioArray.length > 0) {
rowExpandRatioArray[0] -= realRowExpandRatioSum - 1000;
}
if (columnExpandRatioArray.length > 0) {
columnExpandRatioArray[0] -= realColExpandRatioSum - 1000;
}
target.addAttribute("colExpand", columnExpandRatioArray);
target.addAttribute("rowExpand", rowExpandRatioArray);

}

private float getExpandRatioSum(Map<Integer, Float> ratioMap) {
@@ -1082,9 +1044,14 @@ public class GridLayout extends AbstractLayout implements
* </p>
*
* <p>
* Note that the component width of the GridLayout must be defined (fixed or
* relative, as opposed to undefined) for this method to have any effect.
* </p>
* Note, that width of this GridLayout needs to be defined (fixed or
* relative, as opposed to undefined height) for this method to have any
* effect.
* <p>
* Note that checking for relative width for the child components is done on
* the server so you cannot set a child component to have undefined width on
* the server and set it to <code>100%</code> in CSS. You must set it to
* <code>100%</code> on the server.
*
* @see #setWidth(float, int)
*
@@ -1120,9 +1087,14 @@ public class GridLayout extends AbstractLayout implements
* </p>
*
* <p>
* Note, that height needs to be defined (fixed or relative, as opposed to
* undefined height) for this method to have any effect.
* </p>
* Note, that height of this GridLayout needs to be defined (fixed or
* relative, as opposed to undefined height) for this method to have any
* effect.
* <p>
* Note that checking for relative height for the child components is done
* on the server so you cannot set a child component to have undefined
* height on the server and set it to <code>100%</code> in CSS. You must set
* it to <code>100%</code> on the server.
*
* @see #setHeight(float, int)
*

+ 3
- 0
server/src/main/java/com/vaadin/ui/Table.java View File

@@ -2221,6 +2221,9 @@ public class Table extends AbstractSelect implements Action.Container,
List<?> itemIds = getItemIds(firstIndex, rows);
for (int i = 0; i < rows && i < itemIds.size(); i++) {
Object id = itemIds.get(i);
if (id == null) {
throw new IllegalStateException("Null itemId returned from container");
}
// Start by parsing the values, id should already be set
parseItemIdToCells(cells, id, i, firstIndex, headmode, cols,
colids, firstIndexNotInCache, iscomponent,

+ 2
- 2
server/src/main/java/com/vaadin/ui/declarative/DesignContext.java View File

@@ -796,7 +796,7 @@ public class DesignContext implements Serializable {
/**
* Gets the attributes that the component did not handle
*
* @since
* @since 7.7
* @param component
* the component to get the attributes for
* @return map of the attributes which were not recognized by the component
@@ -809,7 +809,7 @@ public class DesignContext implements Serializable {
* Sets a custom attribute not handled by the component. These attributes
* are directly written to the component tag.
*
* @since
* @since 7.7
* @param component
* the component to set the attribute for
* @param attribute

+ 4
- 5
server/src/test/java/com/vaadin/data/util/AbstractContainerTestBase.java View File

@@ -219,6 +219,9 @@ public abstract class AbstractContainerTestBase {
// Add again
Item item2 = container.addItem("foo");
Assert.assertNull(item2);

// Null is not a valid itemId
Assert.assertNull(container.addItem(null));
} catch (UnsupportedOperationException e) {
// Ignore contains which do not support addItem*
}
@@ -258,10 +261,6 @@ public abstract class AbstractContainerTestBase {
// Doesn't work as bean container requires beans
return;
}
if (container instanceof ContainerOrderedWrapper) {
// Doesn't work because of #19427
return;
}

try {
container.removeAllItems();
@@ -534,7 +533,7 @@ public abstract class AbstractContainerTestBase {
/**
* Override in subclasses to return false if the container getItem() method
* returns a non-null value for an item that has been filtered out.
*
*
* @return
*/
protected boolean isFilteredOutItemNull() {

+ 4
- 2
server/src/test/java/com/vaadin/tests/data/converter/DateToLongConverterTest.java View File

@@ -19,7 +19,9 @@ public class DateToLongConverterTest {

@Test
public void testValueConversion() {
Assert.assertEquals(Long.valueOf(946677600000l),
converter.convertToModel(new Date(100, 0, 1), Long.class, null));
Date d = new Date(100, 0, 1);
Assert.assertEquals(
Long.valueOf(946677600000l + (d.getTimezoneOffset() + 120) * 60 * 1000L),
converter.convertToModel(d, Long.class, null));
}
}

+ 3
- 1
server/src/test/java/com/vaadin/tests/data/converter/DefaultConverterFactoryTest.java View File

@@ -75,7 +75,9 @@ public class DefaultConverterFactoryTest {
@SuppressWarnings("deprecation")
@Test
public void longToDate() {
assertConverter(1413061200000L, new Date(2014 - 1900, 10 - 1, 12));
Date d = new Date(2014 - 1900, 10 - 1, 12);
assertConverter(
1413061200000L + (d.getTimezoneOffset() + 180) * 60 * 1000L, d);
}

public enum Foo {

+ 6
- 2
server/src/test/java/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java View File

@@ -17,14 +17,18 @@ public class StringToBooleanConverterTest {
StringToBooleanConverter localeConverter = new StringToBooleanConverter() {
@Override
public String getFalseString(Locale locale) {
Date d = new Date(3000000000000L);
return SimpleDateFormat.getDateInstance(SimpleDateFormat.LONG,
locale).format(new Date(3000000000000L));
locale).format(
d.getTime() + (d.getTimezoneOffset() + 120) * 60 * 1000L);
}

@Override
public String getTrueString(Locale locale) {
Date d = new Date(2000000000000L);
return SimpleDateFormat.getDateInstance(SimpleDateFormat.LONG,
locale).format(new Date(2000000000000L));
locale).format(
d.getTime() + (d.getTimezoneOffset() + 120) * 60 * 1000L);
}
};


+ 2
- 6
shared/pom.xml View File

@@ -31,11 +31,7 @@
<artifactId>streamhtmlparser-jsilver</artifactId>
<version>${streamhtmlparser.version}</version>
</dependency>
<dependency>
<groupId>com.vaadin.external.google</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>


<!-- Needed GWT dependencies. Required parts are packaged to jar -->
<dependency>
@@ -156,7 +152,7 @@
org.w3c.flute.parser;version="${flute.version}",
org.w3c.flute.parser.selectors;version="${flute.version}",
org.w3c.flute.util;version="${flute.version}"</Import-Package>
<Require-Bundle>com.google.gwt.thirdparty.guava;bundle-version="${guava.version}"</Require-Bundle>
<Require-Bundle></Require-Bundle>
</instructions>
</configuration>
<executions>

+ 9
- 1
shared/src/main/java-templates/com/vaadin/shared/Version.java View File

@@ -55,7 +55,15 @@ public class Version implements Serializable {
final String[] digits = VERSION.split("[-.]", 4);
VERSION_MAJOR = Integer.parseInt(digits[0]);
VERSION_MINOR = Integer.parseInt(digits[1]);
VERSION_REVISION = Integer.parseInt(digits[2]);

int revision;
try {
revision = Integer.parseInt(digits[2]);
} catch (NumberFormatException e) {
revision = 0;
}
VERSION_REVISION = revision;

if (digits.length == 4) {
VERSION_BUILD = digits[3];
} else {

+ 8
- 2
shared/src/main/java/com/vaadin/shared/VBrowserDetails.java View File

@@ -86,9 +86,10 @@ public class VBrowserDetails implements Serializable {
// IE 11 no longer contains MSIE in the user agent
isIE = isIE || isTrident;

isSafari = !isChrome && !isIE && userAgent.indexOf("safari") != -1;
isFirefox = userAgent.indexOf(" firefox/") != -1;
isPhantomJS = userAgent.indexOf("phantomjs/") != -1;
isSafari = !isChrome && !isIE && !isPhantomJS
&& userAgent.indexOf("safari") != -1;
isFirefox = userAgent.indexOf(" firefox/") != -1;
if (userAgent.indexOf(" edge/") != -1) {
isEdge = true;
isChrome = false;
@@ -98,6 +99,7 @@ public class VBrowserDetails implements Serializable {
isFirefox = false;
isWebKit = false;
isGecko = false;
isPhantomJS = false;
}

// chromeframe
@@ -174,6 +176,10 @@ public class VBrowserDetails implements Serializable {
} else if (isEdge) {
int i = userAgent.indexOf(" edge/") + 6;
parseVersionString(safeSubstring(userAgent, i, i + 8));
} else if (isPhantomJS) {
String prefix = " phantomjs/";
int i = userAgent.indexOf(prefix) + prefix.length();
parseVersionString(safeSubstring(userAgent, i, i + 5));
}
} catch (Exception e) {
// Browser version parsing failed

+ 15
- 0
shared/src/main/java/com/vaadin/shared/ui/MarginInfo.java View File

@@ -49,7 +49,9 @@ public class MarginInfo implements Serializable {
*
* @param bitMask
* bits to set
* @deprecated use other constructors instead of this one
*/
@Deprecated
public MarginInfo(int bitMask) {
this.bitMask = bitMask;
}
@@ -85,6 +87,16 @@ public class MarginInfo implements Serializable {
this(vertical, horizontal, vertical, horizontal);
}

/**
* Creates a MarginInfo with the same values as another MarginInfo object.
*
* @param other
* another MarginInfo object
*/
public MarginInfo(MarginInfo other) {
setMargins(other);
}

/**
* Enables or disables margins on all edges simultaneously.
*
@@ -172,9 +184,12 @@ public class MarginInfo implements Serializable {

/**
* Returns the current bit mask that make up the margin settings.
* <p>
* This method is for internal use by the framework.
*
* @return an integer bit mask
*/
@Deprecated
public int getBitMask() {
return bitMask;
}

+ 2
- 0
shared/src/main/java/com/vaadin/shared/ui/gridlayout/GridLayoutState.java View File

@@ -40,6 +40,8 @@ public class GridLayoutState extends AbstractLayoutState {
public Set<Integer> explicitColRatios = new HashSet<Integer>();
public Map<Connector, ChildComponentData> childData = new HashMap<Connector, GridLayoutState.ChildComponentData>();
public boolean hideEmptyRowsAndColumns = false;
public float[] rowExpand;
public float[] colExpand;

public static class ChildComponentData implements Serializable {
public int column1;

+ 4
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_label.scss View File

@@ -109,6 +109,10 @@ $v-letter-spacing--h4: 0 !default;

.#{$primary-stylename} {
@include user-select(text);

&.v-disabled {
@include opacity($v-disabled-opacity);
}
}

.#{$primary-stylename}-undef-w {

+ 5
- 2
themes/src/main/themes/VAADIN/themes/valo/components/_nativeselect.scss View File

@@ -23,10 +23,13 @@
}
}
}
.#{$primary-stylename}-error {
.#{$primary-stylename}-select {
@include valo-textfield-error-style;
}
}
}



/**
*
*

+ 4
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_table.scss View File

@@ -456,6 +456,10 @@ $v-table-background-color: null !default;
div {
display: inline;
}

&.v-disabled {
@include opacity($v-disabled-opacity);
}
}
.v-off:before {
visibility: hidden;

+ 7
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_twincolselect.scss View File

@@ -78,6 +78,13 @@
}
}

.#{$primary-stylename}-error {
.#{$primary-stylename}-options,
.#{$primary-stylename}-selections {
@include valo-textfield-error-style;
}
}

}



+ 5
- 13
uitest/build.xml View File

@@ -31,19 +31,11 @@
<target name="test-server" depends="clean-testbench-errors">
<property name="war.file"
location="${vaadin.basedir}/uitest/target/vaadin-uitest-${vaadin.version}.war" />
<parallel>
<daemons>
<ant antfile="${uitest.dir}/vaadin-server.xml"
inheritall="true" inheritrefs="true" target="deploy-and-start" />
</daemons>
<sequential>
<ant antfile="${uitest.dir}/integration_tests.xml"
target="integration-test-all" inheritall="false"
inheritrefs="false">
<property name="demo.war" value="${war.file}" />
</ant>
</sequential>
</parallel>
<ant antfile="${uitest.dir}/integration_tests.xml"
target="integration-test-all" inheritall="false"
inheritrefs="false">
<property name="demo.war" value="${war.file}" />
</ant>
</target>

<target name="test-tb3" depends="clean-testbench-errors">

+ 8
- 1
uitest/integration_tests.xml View File

@@ -40,9 +40,9 @@
<ivy:resolve file="ivy.xml" conf="build, build-provided" />
<ivy:cachepath pathid="classpath.tb3.lib" conf="build, build-provided" />
<path id="classpath.tb3">
<path location="target/test-classes" />
<path refid="classpath.tb3.lib" />
<path location="target/classes" />
<path location="target/test-classes" />
</path>

<!-- Upload war to deploy to ssh host -->
@@ -233,6 +233,12 @@
<param name="target-server" value="glassfish4" />
</antcall>
</target>
<target name="integration-test-payara">
<antcall target="run-generic-integration-test">
<param name="startDelay" value="10" />
<param name="target-server" value="payara" />
</antcall>
</target>


<target name="integration-test-liferay6">
@@ -326,6 +332,7 @@
<antcall target="integration-test-weblogic12" />
<antcall target="integration-test-glassfish3" />
<antcall target="integration-test-glassfish4" />
<antcall target="integration-test-payara" />
<antcall target="integration-test-jboss4" />
<antcall target="integration-test-jboss5" />
<antcall target="integration-test-jboss6" />

+ 28
- 86
uitest/pom.xml View File

@@ -11,7 +11,7 @@
<name>vaadin-uitest</name>
<packaging>war</packaging>
<properties>
<jetty.version>8.1.12.v20130726</jetty.version>
<jetty.version>9.3.9.v20160517</jetty.version>
<skip.uitest.deployment>true</skip.uitest.deployment>
</properties>

@@ -112,19 +112,13 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>orbit</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<!-- jetty-servlets needed by ProxyTest, but not by jetty-runner -->
@@ -132,64 +126,32 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>${jetty.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>orbit</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-websocket</artifactId>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
<version>${jetty.version}</version>

<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>orbit</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>orbit</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>orbit</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-runner</artifactId>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-proxy</artifactId>
<version>${jetty.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>orbit</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -227,7 +189,7 @@
<groupId>com.vaadin</groupId>
<artifactId>vaadin-testbench</artifactId>
<version>4.0.3</version>
<scope>test</scope>
<scope>test</scope>
</dependency>
<!-- This should be removed once tests have been updated to use lang3 -->
<dependency>
@@ -255,13 +217,26 @@
</dependencies>

<build>
<resources>
<resource>
<directory>src/main/themes</directory>
<excludes>
<exclude>**/*.scss</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>


<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<configuration>
<warSourceDirectory>${project.build.directory}/compile-themes</warSourceDirectory>
<webappDirectory>${project.build.directory}/${project.build.finalName}/VAADIN/widgetsets</webappDirectory>
<warSourceDirectory>src/main/themes</warSourceDirectory>
<webappDirectory>${project.build.outputDirectory}/VAADIN/widgetsets</webappDirectory>
<persistentunitcachedir>${project.build.directory}/gwt-unitCache</persistentunitcachedir>
</configuration>
<executions>
@@ -275,47 +250,14 @@
</plugin>

<plugin>
<groupId>org.mortbay.jetty</groupId>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
</plugin>

<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-theme-sources</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/compile-themes</outputDirectory>
<resources>
<resource>
<directory>src/main/themes</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-compiled-themes</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/${project.build.finalName}</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/compile-themes</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
<configuration>
<httpConnector>
<port>8888</port>
</httpConnector>
</configuration>
</plugin>

<plugin>

+ 9
- 8
uitest/src/main/java/com/vaadin/launcher/DevelopmentServerLauncher.java View File

@@ -46,8 +46,7 @@ import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.util.log.JavaUtilLog;
import org.eclipse.jetty.util.ssl.SslContextFactory;
@@ -166,18 +165,20 @@ public class DevelopmentServerLauncher {

final Server server = new Server();

final Connector connector = new SelectChannelConnector();
final ServerConnector connector = new ServerConnector(server);

connector.setPort(port);
if (serverArgs.containsKey("withssl")) {
final SslSocketConnector sslConnector = new SslSocketConnector();
sslConnector.setPort(8444);
SslContextFactory sslFact = sslConnector.getSslContextFactory();
sslFact.setTrustStore(KEYSTORE);
SslContextFactory sslFact = new SslContextFactory();
sslFact.setTrustStorePath(KEYSTORE);
sslFact.setTrustStorePassword("password");
sslFact.setKeyStorePath(KEYSTORE);
sslFact.setKeyManagerPassword("password");
sslFact.setKeyStorePassword("password");

ServerConnector sslConnector = new ServerConnector(server, sslFact);
sslConnector.setPort(8444);

server.setConnectors(new Connector[] { connector, sslConnector });
} else {
server.setConnectors(new Connector[] { connector });
@@ -272,7 +273,7 @@ public class DevelopmentServerLauncher {

scanner.setScanDirs(classFolders);
scanner.start();
server.getContainer().addBean(scanner);
server.addBean(scanner);
}
}


+ 51
- 0
uitest/src/main/java/com/vaadin/tests/components/combobox/ComboBoxPopupWhenBodyScrolls.java View File

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

import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Label;

public class ComboBoxPopupWhenBodyScrolls extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
getPage().getStyles().add(
"body.v-generated-body { overflow: auto;height:auto;}");
getPage()
.getStyles()
.add("body.v-generated-body .v-ui.v-scrollable{ overflow: visible;height:auto !important;}");
ComboBox cb = new ComboBox();
for (int i = 0; i < 10; i++) {
cb.addItem("Item " + i);
}

Label spacer = new Label("foo");
spacer.setHeight("2000px");
addComponent(spacer);
addComponent(cb);
spacer = new Label("foo");
spacer.setHeight("2000px");
addComponent(spacer);
// Chrome requires document.scrollTop (<body>)
// Firefox + IE wants document.documentElement.scrollTop (<html>)
getPage()
.getJavaScript()
.execute(
"document.body.scrollTop=1800;document.documentElement.scrollTop=1800;");
}
}

+ 71
- 0
uitest/src/main/java/com/vaadin/tests/components/formlayout/FormLayoutClickListener.java View File

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

import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.Label;

/**
* Test UI for Form layout click listener.
*
* @author Vaadin Ltd
*/
public class FormLayoutClickListener extends AbstractTestUIWithLog {

@Override
protected void setup(VaadinRequest request) {
FormLayout layout = new FormLayout();
layout.setMargin(true);
layout.setSpacing(true);

layout.setId("form");

Label label = new Label("target");
label.setId("label");
layout.addComponent(label);

layout.addLayoutClickListener(new LayoutClickListener() {

@Override
public void layoutClick(LayoutClickEvent event) {
log("Child component: "
+ (event.getChildComponent() == null ? null : event
.getChildComponent().getId()));
log("Clicked component: "
+ (event.getClickedComponent() == null ? null : event
.getClickedComponent().getId()));
log("Source component: " + event.getComponent().getId());
}
});

addComponent(layout);
}

@Override
protected String getTestDescription() {
return "LayoutClickListener should work in FormLayout";
}

@Override
protected Integer getTicketNumber() {
return 6346;
}

}

+ 32
- 0
uitest/src/main/java/com/vaadin/tests/components/grid/GridDisabledMultiselect.java View File

@@ -0,0 +1,32 @@
package com.vaadin.tests.components.grid;

import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Grid;

public class GridDisabledMultiselect extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
final Grid grid = new Grid();
grid.addColumn("foo", String.class);
grid.addRow("bar");
grid.setSelectionMode(Grid.SelectionMode.SINGLE);
addComponent(grid);

addButton("Multi", new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
grid.setSelectionMode(Grid.SelectionMode.MULTI);
}
});

addButton("Disable", new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
grid.setEnabled(!grid.isEnabled());
}
});
}
}

+ 57
- 0
uitest/src/main/java/com/vaadin/tests/components/gridlayout/GridLayoutExpandWithManyRows.java View File

@@ -0,0 +1,57 @@
package com.vaadin.tests.components.gridlayout;

import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Component;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.UI;

@Theme("tests-valo")
public class GridLayoutExpandWithManyRows extends UI {

static final int POPULATED_ROWS = 20;
static int ROW_COUNT = 58;

public static class ColoredLabel extends Label {
private static int colorNumber = 0;

public ColoredLabel() {
super();
addStyleName("color-label");
addStyleName("color-" + (colorNumber++) % 10);
}
}

@Override
protected void init(VaadinRequest request) {
for (int i = 0; i < 10; i++) {
getPage().getStyles().add(".color-" + i + " {" //
+ "background-color: hsl(" + (i * 90) + ", 60%, 70%);" //
+ "}");
}

GridLayout gridLayout = new GridLayout(6, ROW_COUNT);
for (int i = 0; i < ROW_COUNT; i++) {
gridLayout.setRowExpandRatio(i, 1);
}
gridLayout.setSizeFull();
for (int i = 0; i < POPULATED_ROWS; i++) {
int upperLeftRow = i * 2;
int upperLeftCol = 0;
int lowerRightCol = 5;
int lowerRightRow = upperLeftRow + 1;
ColoredLabel coloredLabel = new ColoredLabel();
coloredLabel.setSizeFull();
gridLayout.addComponent(coloredLabel, upperLeftCol, upperLeftRow,
lowerRightCol, lowerRightRow);
}

gridLayout.setHeight("500%");
Component root = new Panel(gridLayout);
root.setSizeFull();
setContent(root);

}
}

+ 140
- 0
uitest/src/main/java/com/vaadin/tests/components/listselect/ListSelectAddRemoveItems.java View File

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

import com.vaadin.data.util.IndexedContainer;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.ListSelect;

public class ListSelectAddRemoveItems extends AbstractTestUIWithLog {

private IndexedContainer container = new IndexedContainer();

@Override
protected void setup(VaadinRequest request) {
ListSelect listSelect = new ListSelect("ListSelect", container);
listSelect.setWidth("100px");
listSelect.setRows(10);

resetContainer();
logContainer();

addComponent(listSelect);
addComponent(new Button("Reset", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
resetContainer();
log.clear();
logContainer();
}
}));

addComponent(new Button("Add first", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
container.addItemAt(0, "first");
logContainer();
}
}));

addComponent(new Button("Add middle", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
container.addItemAt(container.size() / 2, "middle");
logContainer();
}
}));

addComponent(new Button("Add last", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
container.addItem("last");
logContainer();
}
}));

addComponent(new Button("Swap", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
Object lastItem = container.lastItemId();
Object firstItem = container.firstItemId();
if (lastItem != firstItem) {
container.removeItem(lastItem);
container.removeItem(firstItem);

container.addItemAt(0, lastItem);
container.addItem(firstItem);
}

logContainer();
}
}));

addComponent(new Button("Remove first", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
container.removeItem(container.firstItemId());
logContainer();
}
}));

addComponent(new Button("Remove middle", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
container.removeItem(container.getIdByIndex(container.size() / 2));
logContainer();
}
}));

addComponent(new Button("Remove last", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
container.removeItem(container.lastItemId());
logContainer();
}
}));

}

private void logContainer() {
StringBuilder b = new StringBuilder();
for (int i = 0; i < container.size(); i++) {
Object id = container.getIdByIndex(i);
if (i != 0) {
b.append(", ");
}
b.append(id);
}

log(b.toString());
}

public void resetContainer() {
container.removeAllItems();
for (String value : new String[] { "a", "b", "c" }) {
container.addItem(value);
}
}

@Override
protected String getTestDescription() {
return "Test for verifying that items are added to and removed from the correct locations";
}

}

+ 70
- 0
uitest/src/main/java/com/vaadin/tests/components/listselect/ListSelectPushSelectionChanges.java View File

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

import java.util.Arrays;
import java.util.Collection;

import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.ListSelect;
import com.vaadin.ui.OptionGroup;

public class ListSelectPushSelectionChanges extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
Collection<String> options = Arrays.asList("a", "b", "c");

final ListSelect listSelect = new ListSelect("ListSelect", options);
listSelect.setNullSelectionAllowed(true);

final OptionGroup optionGroup = new OptionGroup("OptionGroup", options);

// Option group changes propagate to the list select
listSelect.setPropertyDataSource(optionGroup);

final OptionGroup modeSelect = new OptionGroup("Mode", Arrays.asList(
"Single", "Multi"));
modeSelect.setValue("Single");
modeSelect.addValueChangeListener(new ValueChangeListener() {
@Override
public void valueChange(ValueChangeEvent event) {
optionGroup.setValue(null);

boolean multiSelect = "Multi".equals(modeSelect.getValue());

listSelect.setMultiSelect(multiSelect);
optionGroup.setMultiSelect(multiSelect);
}
});

Button selectNullButton = new Button("Select null",
new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
listSelect.setValue(null);
listSelect.markAsDirty();
}
});

addComponents(modeSelect, listSelect, optionGroup, selectNullButton);
}
}

+ 63
- 0
uitest/src/main/java/com/vaadin/tests/components/menubar/MenuBarClickOpenedMenu.java View File

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

import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.Command;
import com.vaadin.ui.MenuBar.MenuItem;

/**
* Test UI for top click on expanded top level menu and sub-menus.
*
* @author Vaadin Ltd
*/
public class MenuBarClickOpenedMenu extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
MenuBar menuBar = new MenuBar();
menuBar.addStyleName("top-level");
MenuItem file = menuBar.addItem("File", null);
file.setStyleName("first-level");
MenuItem open = file.addItem("Open", null);
open.setStyleName("second-level");
MenuItem as = open.addItem("as", null);
as.setStyleName("third-level");
MenuItem leaf = as.addItem("Text", new MenuBarCommand());
leaf.setStyleName("leaf");
addComponent(menuBar);
}

@Override
protected String getTestDescription() {
return "Top level menu item should always close menu on click. "
+ "Submenu should not close if it's already opened";
}

@Override
protected Integer getTicketNumber() {
return 14568;
}

private class MenuBarCommand implements Command {
@Override
public void menuSelected(MenuItem selectedItem) {
}
}

}

+ 25
- 0
uitest/src/main/java/com/vaadin/tests/components/nativeselect/NativeSelectNull.java View File

@@ -0,0 +1,25 @@
package com.vaadin.tests.components.nativeselect;

import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.NativeSelect;

public class NativeSelectNull extends AbstractTestUIWithLog {
@Override
protected void setup(VaadinRequest request) {
NativeSelect nativeSelect = new NativeSelect();
nativeSelect.addItem("Item");
nativeSelect.addValueChangeListener(new ValueChangeListener() {

@Override
public void valueChange(ValueChangeEvent event) {
log("Value: " + event.getProperty().getValue());

}
});
addComponent(nativeSelect);
}

}

+ 84
- 0
uitest/src/main/java/com/vaadin/tests/components/panel/PanelRemoveShortcutListener.java View File

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

import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextField;

/**
* Test for removing a shortcut listener from Panel.
*
* @author Vaadin Ltd
*/
public class PanelRemoveShortcutListener extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
final Panel panel = new Panel("No shortcut effects (press 'A')");
panel.setWidth("200px");
addComponent(panel);
TextField textField = new TextField();
panel.setContent(textField);
ShortcutListener shortcut = createShortcutListener(panel);
panel.addShortcutListener(shortcut);
addButton("Remove shortcut", createClickListener(panel, shortcut));
}

private ShortcutListener createShortcutListener(final Panel panel) {
return new ShortcutListener("A", KeyCode.A, null) {

@Override
public void handleAction(Object sender, Object target) {
if ("A on".equals(panel.getCaption())) {
panel.setCaption("A off");
} else {
panel.setCaption("A on");
}
}
};
}

private ClickListener createClickListener(final Panel panel,
final ShortcutListener shortcut) {
return new Button.ClickListener() {

@Override
public void buttonClick(ClickEvent event) {
panel.removeShortcutListener(shortcut);
addComponent(new Label("shortcut removed"));
}
};
}

@Override
protected Integer getTicketNumber() {
return 16498;
}

@Override
protected String getTestDescription() {
return "Should be possible to remove shortcut listener from Panel";
}

}

+ 42
- 0
uitest/src/main/java/com/vaadin/tests/components/textfield/InputPromptAndCursorPosition.java View File

@@ -0,0 +1,42 @@
package com.vaadin.tests.components.textfield;

import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Label;
import com.vaadin.ui.TextField;

public class InputPromptAndCursorPosition extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
final TextField tf = new TextField();
tf.setColumns(40);
tf.setValue("Delete this text to reveal input prompt and update cursor position.");
tf.setInputPrompt("This is an input prompt");

final Label l = new Label("Cursor position: ?");
Button button = new Button("Update cursor position", new Button.ClickListener() {

@Override
public void buttonClick(ClickEvent event) {
l.setValue("Cursor position: " + tf.getCursorPosition());
}
});

addComponent(tf);
addComponent(l);
addComponent(button);
}

@Override
protected String getTestDescription() {
return "Cursor position should always be zero when input prompt is displayed.";
}

@Override
protected Integer getTicketNumber() {
return 19766;
}
}

+ 46
- 0
uitest/src/main/java/com/vaadin/tests/components/window/ToolTipInWindow.java View File

@@ -0,0 +1,46 @@
/*
* Copyright 2000-2015 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.window;

import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Label;
import com.vaadin.ui.Window;

/**
* Test to demonstrate that tooltips are shown for both Window header and
* content
*
* @author Vaadin Ltd
*/
public class ToolTipInWindow extends AbstractTestUI {

Window window;

@Override
protected void setup(VaadinRequest request) {

window = new Window("Caption", new Label("A label content"));
window.setPositionX(300);
window.setPositionY(200);
window.setWidth("200px");
window.setHeight("200px");
window.setDescription("Tooltip");
addWindow(window);

}

}

+ 3
- 3
uitest/src/main/java/com/vaadin/tests/integration/ProxyTest.java View File

@@ -20,10 +20,10 @@ import javax.servlet.http.HttpServletRequest;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlets.ProxyServlet;
import org.eclipse.jetty.proxy.ProxyServlet;

import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.server.ExternalResource;
@@ -88,7 +88,7 @@ public class ProxyTest extends AbstractTestUI {

// Set up a server
server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
ServerConnector connector = new ServerConnector(server);
// Uses random available port by default, uncomment this to make local
// testing easier (you can just reload old tab after restarting proxy)
// connector.setPort(8889);

+ 80
- 0
uitest/src/main/java/com/vaadin/tests/themes/valo/CollapsibleTableColumn.java View File

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

import com.vaadin.annotations.Theme;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Table;

/**
* Test UI for non-collapsible column distinction in the table.
*
* @author Vaadin Ltd
*/
@Theme("valo")
public class CollapsibleTableColumn extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
Table table = new Table();
BeanItemContainer<Bean> container = new BeanItemContainer<Bean>(
Bean.class);
Bean bean = new Bean();
bean.setName("name");
bean.setId(1);
container.addBean(bean);
table.setContainerDataSource(container);
table.setColumnCollapsingAllowed(true);
table.setColumnCollapsible("name", false);
addComponent(table);
}

@Override
protected Integer getTicketNumber() {
return 15489;
}

@Override
protected String getTestDescription() {
return "Non-collapsible column should be visibly distinct (has an opacity) from "
+ "collapsible column in table column config menu.";
}

public static class Bean {

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

private String name;

private int id;
}
}

+ 54
- 0
uitest/src/main/java/com/vaadin/tests/themes/valo/DisabledLabel.java View File

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

import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Label;

/**
* Test UI for disbaled label.
*
* @author Vaadin Ltd
*/
@Theme("valo")
public class DisabledLabel extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
Label enabled = new Label("enabled");
enabled.addStyleName("my-enabled");
addComponent(enabled);

Label disabled = new Label("disabled");
disabled.setEnabled(false);
disabled.addStyleName("my-disabled");

addComponent(disabled);
}

@Override
protected Integer getTicketNumber() {
return 15489;
}

@Override
protected String getTestDescription() {
return "Disabled label should be visibly disabled (has an opacity).";
}

}

+ 115
- 0
uitest/src/main/java/com/vaadin/tests/validation/FieldErrorIndication.java View File

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

import java.util.Set;

import com.vaadin.data.Validator;
import com.vaadin.data.validator.StringLengthValidator;
import com.vaadin.server.UserError;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.Field;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.ListSelect;
import com.vaadin.ui.NativeSelect;
import com.vaadin.ui.PasswordField;
import com.vaadin.ui.RichTextArea;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.TwinColSelect;
import com.vaadin.ui.VerticalLayout;

public class FieldErrorIndication extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
HorizontalLayout hl = new HorizontalLayout();
addComponent(hl);

VerticalLayout vl = new VerticalLayout();
hl.addComponent(vl);

ComboBox comboBox = new ComboBox("ComboBox");
comboBox.addItem("ok");
comboBox.addItem("error");
comboBox.addValidator(new StringLengthValidator("fail", 0, 2, false));
comboBox.setValue("error");

ListSelect listSelect = new ListSelect("ListSelect");
listSelect.addItem("ok");
listSelect.addItem("error");
listSelect.addValidator(new StringLengthValidator("fail", 0, 2, false));
listSelect.setValue("error");

NativeSelect nativeSelect = new NativeSelect("NativeSelect");
nativeSelect.addItem("ok");
nativeSelect.addItem("error");
nativeSelect
.addValidator(new StringLengthValidator("fail", 0, 2, false));
nativeSelect.setValue("error");
TwinColSelect twinColSelect = new TwinColSelect("TwinColSelect");
twinColSelect.addItem("ok");
twinColSelect.addItem("error");
twinColSelect.addValidator(new Validator() {

@Override
public void validate(Object value) throws InvalidValueException {
if (value instanceof Set && ((Set) value).size() == 1
&& ((Set) value).contains("ok")) {
return;
}

throw new InvalidValueException("fail");
}

});
twinColSelect.setValue("error");

vl.addComponents(comboBox, listSelect, nativeSelect, twinColSelect);

Class<? extends AbstractField>[] textFields = new Class[] {
TextField.class, TextArea.class, RichTextArea.class,
PasswordField.class };
vl = new VerticalLayout();
hl.addComponent(vl);
for (Class<? extends Field> fieldClass : textFields) {
vl.addComponent(getField(fieldClass));
}

}

/**
* @since
* @param fieldClass
* @return
*/
private Component getField(Class<? extends Field> fieldClass) {
AbstractField f;
try {
f = (AbstractField) fieldClass.newInstance();
f.setCaption(fieldClass.getSimpleName());
f.setComponentError(new UserError("fail"));
return f;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

+ 5
- 6
uitest/src/test/java/com/vaadin/tests/VerifyBrowserVersionTest.java View File

@@ -1,12 +1,12 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
*
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -39,9 +39,8 @@ public class VerifyBrowserVersionTest extends MultiBrowserTest {
if (BrowserUtil.isChrome(getDesiredCapabilities())) {
// Chrome version does not necessarily match the desired version
// because of auto updates...
// TODO - replace fixed number with a range?
browserIdentifier = getExpectedUserAgentString(
getDesiredCapabilities()) + "49";
browserIdentifier = getExpectedUserAgentString(getDesiredCapabilities())
+ "50";
} else {
browserIdentifier = getExpectedUserAgentString(desiredCapabilities)
+ desiredCapabilities.getVersion();

+ 6
- 0
uitest/src/test/java/com/vaadin/tests/application/CriticalNotificationsTest.java View File

@@ -72,6 +72,12 @@ public class CriticalNotificationsTest extends MultiBrowserThemeTest {
click($(CheckBoxElement.class).caption("Include details").first());
}
$(ButtonElement.class).caption(buttonCaption).first().click();

// some critical notifications invalidate the session, and if a
// screenshot does not match, waitForVaadin would cause the screenshot
// comparison to crash because of a missing session
testBench().disableWaitForVaadin();

// Give the notification some time to animate
sleep(1000);
compareScreen($(NotificationElement.class).first(),

+ 40
- 0
uitest/src/test/java/com/vaadin/tests/components/combobox/ComboBoxPopupWhenBodyScrollsTest.java View File

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

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.WebElement;

import com.vaadin.tests.tb3.MultiBrowserTest;
import com.vaadin.tests.tb3.newelements.ComboBoxElement;

public class ComboBoxPopupWhenBodyScrollsTest extends MultiBrowserTest {

@Test
public void popupBelow() {
openTestURL();
ComboBoxElement combobox = $(ComboBoxElement.class).first();
combobox.openPopup();
WebElement popup = $(ComboBoxElement.class).first()
.getSuggestionPopup();

int comboboxTop = combobox.getLocation().getY();
int popupTop = popup.getLocation().getY();
Assert.assertTrue("Popup should be below combobox",
popupTop > comboboxTop);
}
}

+ 87
- 0
uitest/src/test/java/com/vaadin/tests/components/formlayout/FormLayoutClickListenerTest.java View File

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

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedCondition;

import com.vaadin.testbench.elements.FormLayoutElement;
import com.vaadin.tests.tb3.MultiBrowserTest;

/**
* Test for form layout click listener.
*
* @author Vaadin Ltd
*/
public class FormLayoutClickListenerTest extends MultiBrowserTest {

@Before
public void setUp() {
openTestURL();
waitForElementPresent(By.id("label"));
}

@Test
public void layoutClickListener_clickOnLayout_childAndClickedComponentsAreNull() {
FormLayoutElement element = $(FormLayoutElement.class).first();
Actions actions = new Actions(getDriver());
actions.moveByOffset(element.getLocation().getX() + 2,
element.getLocation().getY() + 2).click().build().perform();
waitForLogRowUpdate();

Assert.assertEquals("Source component for click event must be form",
"3. Source component: form", getLogRow(0));
Assert.assertEquals("Clicked component for click event must be null",
"2. Clicked component: null", getLogRow(1));
Assert.assertEquals("Child component for click event must be null",
"1. Child component: null", getLogRow(2));
}

@Test
public void layoutClickListener_clickOnLabel_lableIsChildAndClickedComponent() {
findElement(By.id("label")).click();
waitForLogRowUpdate();

Assert.assertEquals("Source component for click event must be form",
"3. Source component: form", getLogRow(0));
Assert.assertEquals("Clicked component for click event must be label",
"2. Clicked component: label", getLogRow(1));
Assert.assertEquals("Child component for click event must be label",
"1. Child component: label", getLogRow(2));
}

private void waitForLogRowUpdate() {
waitUntil(new ExpectedCondition<Boolean>() {

@Override
public Boolean apply(WebDriver input) {
return !getLogRow(2).trim().isEmpty();
}

@Override
public String toString() {
// Timed out after 10 seconds waiting for ...
return "log rows to be updated";
}
});
}

}

+ 81
- 0
uitest/src/test/java/com/vaadin/tests/components/grid/GridDisabledMultiselectTest.java View File

@@ -0,0 +1,81 @@
package com.vaadin.tests.components.grid;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;

import java.util.List;

import org.junit.Test;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

import com.vaadin.testbench.By;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.tests.tb3.MultiBrowserTest;

public class GridDisabledMultiselectTest extends MultiBrowserTest {

@Override
public void setup() throws Exception {
super.setup();

openTestURL();
}

private void disable() {
$(ButtonElement.class).caption("Disable").first().click();
}

private void setMultiselect() {
$(ButtonElement.class).caption("Multi").first().click();
}

private WebElement getSelectAllCheckBox() {
return findCheckBoxes().get(0);
}

private List<WebElement> findCheckBoxes() {
return findElements(By.cssSelector("span input"));
}

private WebElement getFirstSelectCheckBox() {
return findCheckBoxes().get(1);
}

@Test
public void checkBoxesAreDisabledAfterModeChange() {
disable();

setMultiselect();

assertThat(getSelectAllCheckBox().isEnabled(), is(false));
assertThat(getFirstSelectCheckBox().isEnabled(), is(false));
}

@Test
public void checkBoxesAreDisabledAfterDisabled() {
setMultiselect();

assertThat(getSelectAllCheckBox().isEnabled(), is(true));
assertThat(getFirstSelectCheckBox().isEnabled(), is(true));

disable();

assertThat(getSelectAllCheckBox().isEnabled(), is(false));
assertThat(getFirstSelectCheckBox().isEnabled(), is(false));
}

@Test
public void parentSpanCannotBeClickedWhenDisabled() {
setMultiselect();
disable();

WebElement firstCheckBoxSpan
= findElements(By.cssSelector("span")).get(1);
new Actions(driver).moveToElement(firstCheckBoxSpan, 1, 1)
.click()
.perform();

assertThat(getFirstSelectCheckBox().isSelected(), is(false));
}
}

+ 40
- 0
uitest/src/test/java/com/vaadin/tests/components/gridlayout/GridLayoutExpandWithManyRowsTest.java View File

@@ -0,0 +1,40 @@
package com.vaadin.tests.components.gridlayout;

import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import com.vaadin.testbench.elements.GridLayoutElement;
import com.vaadin.tests.tb3.SingleBrowserTest;

public class GridLayoutExpandWithManyRowsTest extends SingleBrowserTest {

@Test
public void equalRowHeights() {
openTestURL();
GridLayoutElement gridlayout = $(GridLayoutElement.class).first();

// Rows are expanded using integer pixels and leftover pixels are added
// to the first N rows.
// The tests uses rowspan=2 so one row in the DOM should be max 2 pixels
// lower than the first row
List<WebElement> slots = gridlayout.findElements(By
.className("v-gridlayout-slot"));
Assert.assertEquals(GridLayoutExpandWithManyRows.POPULATED_ROWS,
slots.size());

int firstRowHeight = slots.get(0).getSize().height;
int lastRowHeight = firstRowHeight;
for (int i = 1; i < GridLayoutExpandWithManyRows.POPULATED_ROWS; i++) {
int rowHeight = slots.get(i).getSize().height;
Assert.assertTrue(rowHeight <= firstRowHeight);
Assert.assertTrue(rowHeight >= firstRowHeight - 2);
Assert.assertTrue(rowHeight <= lastRowHeight);

lastRowHeight = rowHeight;
}
}
}

+ 63
- 0
uitest/src/test/java/com/vaadin/tests/components/listselect/ListSelectAddRemoveItemsTest.java View File

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

import java.util.Arrays;

import org.junit.Assert;
import org.junit.Test;

import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.ListSelectElement;
import com.vaadin.tests.tb3.SingleBrowserTest;

public class ListSelectAddRemoveItemsTest extends SingleBrowserTest {
@Test
public void testAddAndRemove() {
openTestURL();
assertOptions("", "a", "b", "c");

click("Add first");
assertOptions("", "first", "a", "b", "c");

click("Swap");
assertOptions("", "c", "a", "b", "first");

click("Remove first");
assertOptions("", "a", "b", "first");

click("Add middle");
assertOptions("", "a", "middle", "b", "first");

click("Add last");
assertOptions("", "a", "middle", "b", "first", "last");

click("Remove middle");
assertOptions("", "a", "middle", "first", "last");

click("Reset");
assertOptions("", "a", "b", "c");
}

private void assertOptions(String... options) {
Assert.assertEquals(Arrays.asList(options), $(ListSelectElement.class)
.first().getOptions());
}

private void click(String caption) {
$(ButtonElement.class).caption(caption).first().click();
}
}

+ 70
- 0
uitest/src/test/java/com/vaadin/tests/components/listselect/ListSelectNoDomRebuildTest.java View File

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

import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

import com.vaadin.testbench.elements.ListSelectElement;
import com.vaadin.tests.tb3.SingleBrowserTest;

public class ListSelectNoDomRebuildTest extends SingleBrowserTest {
@Override
protected Class<?> getUIClass() {
return ListSelects.class;
}

@Test
public void testNoDomRebuild() {
openTestURL();

// Testbench doesn't seem to support sending key events to the right
// location, so we will just verify that the DOM is not rebuilt
selectMenuPath("Component", "Selection", "Multi select");
selectMenuPath("Component", "Listeners", "Value change listener");

ListSelectElement list = $(ListSelectElement.class).first();
List<WebElement> options = list.findElements(By.tagName("option"));

assertNotStale(options);

options.get(4).click();

assertNotStale(options);

new Actions(driver).keyDown(Keys.SHIFT).perform();
options.get(2).click();
options.get(6).click();
new Actions(driver).keyUp(Keys.SHIFT).perform();

assertNotStale(options);
}

private void assertNotStale(List<WebElement> options) {
for (WebElement element : options) {
// We really don't expect the text to be null, mainly doing this
// since getText() will throw if the element is detached.
Assert.assertNotNull(element.getText());
}
}

}

+ 135
- 0
uitest/src/test/java/com/vaadin/tests/components/listselect/ListSelectPushSelectionChangesTest.java View File

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

import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Select;

import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.ListSelectElement;
import com.vaadin.testbench.elements.OptionGroupElement;
import com.vaadin.tests.tb3.SingleBrowserTestPhantomJS2;

public class ListSelectPushSelectionChangesTest extends
SingleBrowserTestPhantomJS2 {
@Test
public void testMultiSelectBehavior() {
openTestURL();

Assert.assertEquals(
"Should have null item + 3 options in single selection mode",
4, getListSelect().getOptions().size());

$(OptionGroupElement.class).caption("Mode").first()
.selectByText("Multi");

Assert.assertEquals(
"Should have 3 options but no null item in multi selection mode",
3, getListSelect().getOptions().size());

selectOptionGroup("a");
Assert.assertEquals("a", getSelectValue());

selectOptionGroup("b");
Assert.assertEquals("a,b", getSelectValue());

selectOptionGroup("a");
Assert.assertEquals(
"Clicking selected item should deselct in multi selection mode",
"b", getSelectValue());

selectNull();
Assert.assertEquals("", getSelectValue());
}

@Test
public void testSingleSelectBehavior() {
openTestURL();

selectOptionGroup("a");
Assert.assertEquals("a", getSelectValue());

selectOptionGroup("b");
Assert.assertEquals("b", getSelectValue());

selectOptionGroup("b");
Assert.assertEquals(
"Selecting the selected item again should not deselect in single selection mode",
"b", getSelectValue());

selectNull();
Assert.assertEquals("", getSelectValue());
Assert.assertEquals(
"Not even the single select item should be selected after setValue(null)",
0, getSelectCount());

selectOptionGroup("c");
Assert.assertEquals("c", getSelectValue());

getListSelect().selectByText("");
Assert.assertEquals("", getSelectValue());
Assert.assertEquals(
"Null select item should remain selected if clicked by the user",
1, getSelectCount());

selectNull();
Assert.assertEquals("", getSelectValue());
Assert.assertEquals(
"Null select item should remain selected even after a repaint",
1, getSelectCount());
}

private ListSelectElement getListSelect() {
return $(ListSelectElement.class).first();
}

private int getSelectCount() {
return getSelectedOptions().size();
}

private void selectNull() {
$(ButtonElement.class).first().click();
}

private String getSelectValue() {
List<WebElement> selectedOptions = getSelectedOptions();

StringBuilder value = new StringBuilder();
for (int i = 0; i < selectedOptions.size(); i++) {
if (i != 0) {
value.append(',');
}
value.append(selectedOptions.get(i).getText());
}
return value.toString();
}

private List<WebElement> getSelectedOptions() {
ListSelectElement listSelect = getListSelect();
Select select = new Select(listSelect.findElement(By.tagName("select")));
return select.getAllSelectedOptions();
}

private void selectOptionGroup(String value) {
$(OptionGroupElement.class).caption("OptionGroup").first()
.selectByText(value);
}
}

+ 89
- 0
uitest/src/test/java/com/vaadin/tests/components/menubar/MenuBarClickOpenedMenuTest.java View File

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

import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;

import com.vaadin.testbench.By;
import com.vaadin.tests.tb3.MultiBrowserTest;

/**
* Test for top level menu item which should close its sub-menus each time when
* it's clicked. Also it checks sub-menu item which should not close its
* sub-menus if they are opened on click.
*
* @author Vaadin Ltd
*/
public class MenuBarClickOpenedMenuTest extends MultiBrowserTest {

@Before
@Override
public void setup() throws Exception {
super.setup();
openTestURL();
expand("v-menubar-menuitem-first-level");
expand("v-menubar-menuitem-second-level");
expand("v-menubar-menuitem-third-level");
checkPresence("v-menubar-menuitem-leaf", true);
}

@Test
public void testTopLevelMenuClickClosesSubMenus() {
click("v-menubar-menuitem-first-level");
checkSubMenus(false);
}

@Test
public void testSubMenuClickDoesNotCloseSubMenus() {
click("v-menubar-menuitem-second-level");
checkSubMenus(true);
}

private void expand(String menuItemClassName) {
checkPresence(menuItemClassName, true);
click(menuItemClassName);
}

private void click(String menuItemClassName) {
findElement(By.className(menuItemClassName)).click();
}

private void checkSubMenus(boolean present) {
checkPresence("v-menubar-menuitem-second-level", present);
checkPresence("v-menubar-menuitem-third-level", present);
checkPresence("v-menubar-menuitem-leaf", present);
}

private void checkPresence(final String menuItemClassName,
final boolean present) {
waitUntil(new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver input) {
return isElementPresent(By.className(menuItemClassName)) == present;
}

@Override
public String toString() {
// Timed out after 10 seconds waiting for ...
return menuItemClassName + " to " + (present ? "" : "not ")
+ "be present";
}
});
}
}

+ 20
- 0
uitest/src/test/java/com/vaadin/tests/components/nativeselect/NativeSelectNullTest.java View File

@@ -0,0 +1,20 @@
package com.vaadin.tests.components.nativeselect;

import org.junit.Assert;
import org.junit.Test;

import com.vaadin.testbench.elements.NativeSelectElement;
import com.vaadin.tests.tb3.SingleBrowserTest;
import com.vaadin.tests.tb3.SingleBrowserTestPhantomJS2;

public class NativeSelectNullTest extends SingleBrowserTestPhantomJS2 {
@Test
public void selectNull() {
openTestURL();
NativeSelectElement select = $(NativeSelectElement.class).first();
select.selectByText("Item");
Assert.assertEquals("1. Value: Item", getLogRow(0));
select.selectByText("");
Assert.assertEquals("2. Value: null", getLogRow(0));
}
}

+ 114
- 0
uitest/src/test/java/com/vaadin/tests/components/panel/PanelRemoveShortcutListenerTest.java View File

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

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.util.List;

import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedCondition;

import com.google.common.base.Objects;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.PanelElement;
import com.vaadin.testbench.elements.TextFieldElement;
import com.vaadin.testbench.parallel.Browser;
import com.vaadin.tests.tb3.MultiBrowserTest;

/**
* Test for removing a shortcut listener from Panel.
*
* @author Vaadin Ltd
*/
public class PanelRemoveShortcutListenerTest extends MultiBrowserTest {

private PanelElement panel;

@Override
public void setup() throws Exception {
super.setup();
openTestURL();
waitForElementPresent(By.className("v-panel"));
panel = $(PanelElement.class).first();
}

@Override
public List<DesiredCapabilities> getBrowsersToTest() {
List<DesiredCapabilities> list = super.getBrowsersToTest();
// For some reason the shortcut isn't working for these browsers when
// tested through TestBench:
list.remove(Browser.IE8.getDesiredCapabilities());
list.remove(Browser.FIREFOX.getDesiredCapabilities());
list.remove(Browser.CHROME.getDesiredCapabilities());
return list;
}

@Test
public void testToggleWithShortcut() {
assertThat(panel.findElement(By.className("v-panel-caption"))
.findElement(By.tagName("span")).getText(),
is("No shortcut effects (press 'A')"));

attemptShortcut("A on");
attemptShortcut("A off");
}

@Test
public void testShortcutGetsRemoved() {
attemptShortcut("A on");

$(ButtonElement.class).first().click();
waitForElementPresent(By.className("v-label"));

attemptShortcut("A on");

// add a bit more delay to make sure the caption doesn't change later
try {
sleep(2000);
} catch (InterruptedException ignore) {
}

assertThat(panel.findElement(By.className("v-panel-caption"))
.findElement(By.tagName("span")).getText(), is("A on"));
}

private void attemptShortcut(final String expectedCaption) {
$(TextFieldElement.class).first().sendKeys("A");
waitUntil(new ExpectedCondition<Boolean>() {
private String actualCaption;

@Override
public Boolean apply(WebDriver input) {
actualCaption = panel
.findElement(By.className("v-panel-caption"))
.findElement(By.tagName("span")).getText();
return Objects.equal(actualCaption, expectedCaption);
}

@Override
public String toString() {
// Timed out after 10 seconds waiting for ...
return "panel's caption to become " + expectedCaption
+ " (was: " + actualCaption + ")";
}
});
}
}

+ 30
- 0
uitest/src/test/java/com/vaadin/tests/components/textfield/InputPromptAndCursorPositionTest.java View File

@@ -0,0 +1,30 @@
package com.vaadin.tests.components.textfield;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.testbench.elements.TextFieldElement;
import com.vaadin.tests.tb3.MultiBrowserTest;

public class InputPromptAndCursorPositionTest extends MultiBrowserTest {

@Test
public void verifyDatePattern() {
openTestURL();

// Clear the current value and reveal the input prompt.
TextFieldElement textFieldElement = $(TextFieldElement.class).get(0);
textFieldElement.setValue("");

// Update cursor position.
$(ButtonElement.class).get(0).click();

// The cursor position should now be zero (not the input prompt length).
LabelElement cursorPosLabel = $(LabelElement.class).get(1);
assertEquals(cursorPosLabel.getText(), "Cursor position: 0");
}

}

+ 77
- 0
uitest/src/test/java/com/vaadin/tests/components/window/ToolTipInWindowTest.java View File

@@ -0,0 +1,77 @@
/*
* Copyright 2000-2015 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.window;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.util.List;

import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.DesiredCapabilities;

import com.vaadin.tests.tb3.MultiBrowserTest;

public class ToolTipInWindowTest extends MultiBrowserTest {

@Test
public void testToolTipInHeader() throws Exception {

openTestURL();

WebElement header = driver.findElement(By
.className("v-window-outerheader"));
new Actions(driver).moveToElement(
driver.findElement(By.className("v-ui")), 0, 0).perform();
sleep(500);
new Actions(driver).moveToElement(header).perform();
sleep(1100);

WebElement ttip = findElement(By.className("v-tooltip"));
assertNotNull(ttip);
assertEquals("Tooltip", ttip.getText());

}

@Test
public void testToolTipInContent() throws Exception {

openTestURL();

WebElement header = driver.findElement(By
.className("v-window-contents"));
new Actions(driver).moveToElement(
driver.findElement(By.className("v-ui")), 0, 300).perform();
sleep(500);
new Actions(driver).moveToElement(header).perform();
sleep(1000);

WebElement ttip = findElement(By.className("v-tooltip"));
assertNotNull(ttip);
assertEquals("Tooltip", ttip.getText());

}

@Override
public List<DesiredCapabilities> getBrowsersToTest() {
// Test with the same browsers as in the other tooltip tests
return getBrowsersExcludingIE();
}

}

+ 1
- 2
uitest/src/test/java/com/vaadin/tests/tb3/AbstractTB3Test.java View File

@@ -59,7 +59,6 @@ import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import com.google.gwt.thirdparty.guava.common.base.Joiner;
import com.thoughtworks.selenium.webdriven.WebDriverBackedSelenium;
import com.vaadin.server.LegacyApplication;
import com.vaadin.server.UIProvider;
@@ -279,7 +278,7 @@ public abstract class AbstractTB3Test extends ParallelTest {
}

if (parameters.size() > 0) {
url += "?" + Joiner.on("&").join(parameters);
url += "?" + StringUtils.join(parameters, "&");
}

driver.get(url);

+ 0
- 0
uitest/src/test/java/com/vaadin/tests/tb3/ScreenshotTB3Test.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save