@@ -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 | |||
@@ -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><version></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>* |
@@ -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> |
@@ -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" /> |
@@ -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> |
@@ -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/**, |
@@ -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 |
@@ -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); | |||
} |
@@ -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()); |
@@ -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 ) |
@@ -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; |
@@ -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 |
@@ -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); | |||
} |
@@ -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); |
@@ -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() { |
@@ -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)); |
@@ -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); |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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()); | |||
} |
@@ -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. | |||
*/ |
@@ -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 | |||
*/ |
@@ -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) { |
@@ -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() { |
@@ -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 |
@@ -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. | |||
@@ -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: | |||
@@ -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 |
@@ -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> |
@@ -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> |
@@ -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); |
@@ -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; | |||
} | |||
} | |||
/* |
@@ -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; | |||
} | |||
/** |
@@ -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,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; | |||
} | |||
} | |||
/** |
@@ -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() |
@@ -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 { |
@@ -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" |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
@@ -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("""); | |||
break; | |||
case '\'': | |||
sb.append("'"); | |||
break; | |||
case '&': | |||
sb.append("&"); | |||
break; | |||
case '<': | |||
sb.append("<"); | |||
break; | |||
case '>': | |||
sb.append(">"); | |||
break; | |||
default: | |||
sb.append(c); | |||
} | |||
} | |||
return sb.toString(); | |||
} | |||
@Override | |||
public VaadinPortletService getService() { | |||
return vaadinService; |
@@ -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 |
@@ -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"); | |||
} |
@@ -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 |
@@ -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, |
@@ -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) { |
@@ -1382,9 +1382,7 @@ public abstract class AbstractComponent extends AbstractClientConnector | |||
} | |||
public void removeShortcutListener(ShortcutListener shortcut) { | |||
if (actionManager != null) { | |||
actionManager.removeAction(shortcut); | |||
} | |||
getActionManager().removeAction(shortcut); | |||
} | |||
/** |
@@ -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; | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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) | |||
* |
@@ -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, |
@@ -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 |
@@ -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() { |
@@ -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)); | |||
} | |||
} |
@@ -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 { |
@@ -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); | |||
} | |||
}; | |||
@@ -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> |
@@ -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 { |
@@ -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 |
@@ -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; | |||
} |
@@ -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; |
@@ -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 { |
@@ -23,10 +23,13 @@ | |||
} | |||
} | |||
} | |||
.#{$primary-stylename}-error { | |||
.#{$primary-stylename}-select { | |||
@include valo-textfield-error-style; | |||
} | |||
} | |||
} | |||
/** | |||
* | |||
* |
@@ -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; |
@@ -78,6 +78,13 @@ | |||
} | |||
} | |||
.#{$primary-stylename}-error { | |||
.#{$primary-stylename}-options, | |||
.#{$primary-stylename}-selections { | |||
@include valo-textfield-error-style; | |||
} | |||
} | |||
} | |||
@@ -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"> |
@@ -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" /> |
@@ -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> |
@@ -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); | |||
} | |||
} | |||
@@ -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;"); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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()); | |||
} | |||
}); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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"; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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) { | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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"; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); |
@@ -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; | |||
} | |||
} |
@@ -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)."; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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(); |
@@ -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(), |
@@ -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); | |||
} | |||
} |
@@ -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"; | |||
} | |||
}); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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"; | |||
} | |||
}); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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 + ")"; | |||
} | |||
}); | |||
} | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); |