summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebContent/VAADIN/jquery.atmosphere.js11
-rw-r--r--client/src/com/vaadin/client/ApplicationConfiguration.java24
-rw-r--r--client/src/com/vaadin/client/ui/Action.java12
-rw-r--r--client/src/com/vaadin/client/ui/calendar/CalendarConnector.java107
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java3
-rw-r--r--client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java39
-rw-r--r--client/src/com/vaadin/client/ui/ui/UIConnector.java23
-rw-r--r--server/build.xml2
-rw-r--r--server/ivy.xml3
-rw-r--r--server/src/com/vaadin/annotations/JavaScript.java14
-rw-r--r--server/src/com/vaadin/annotations/StyleSheet.java14
-rw-r--r--server/src/com/vaadin/data/util/converter/StringToIntegerConverter.java17
-rw-r--r--server/src/com/vaadin/server/Page.java67
-rw-r--r--server/src/com/vaadin/ui/Calendar.java10
-rw-r--r--server/src/com/vaadin/ui/Embedded.java16
-rw-r--r--server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java11
-rw-r--r--server/tests/src/com/vaadin/tests/data/converter/TestStringToIntegerConverter.java18
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarActionsMenuTest.html71
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarActionsMenuTest.java141
-rw-r--r--uitest/src/com/vaadin/tests/components/orderedlayout/ErrorIndicator.html82
-rw-r--r--uitest/src/com/vaadin/tests/components/orderedlayout/ErrorIndicator.java79
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.html61
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.java15
23 files changed, 778 insertions, 62 deletions
diff --git a/WebContent/VAADIN/jquery.atmosphere.js b/WebContent/VAADIN/jquery.atmosphere.js
index 28a7d033bd..b2dd99f5d2 100644
--- a/WebContent/VAADIN/jquery.atmosphere.js
+++ b/WebContent/VAADIN/jquery.atmosphere.js
@@ -1219,8 +1219,15 @@ jQuery.atmosphere = function() {
messages.push(message.substring(0, messageLength));
}
- if (messages.length == 0 || (messageStart != -1 && message.length != 0 && messageLength != message.length)){
- response.partialMessage = messageLength + request.messageDelimiter + message ;
+ if (messages.length == 0 || (message.length != 0 && messageLength != message.length)){
+ if (messageStart == -1) {
+ // http://dev.vaadin.com/ticket/12197
+ // partialMessage must contain length header of next message
+ // it starts at the end of the last message
+ response.partialMessage = message.substring(messageLength);
+ } else {
+ response.partialMessage = messageLength + request.messageDelimiter + message ;
+ }
} else {
response.partialMessage = "";
}
diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java
index ecd957194d..da8f521799 100644
--- a/client/src/com/vaadin/client/ApplicationConfiguration.java
+++ b/client/src/com/vaadin/client/ApplicationConfiguration.java
@@ -610,6 +610,11 @@ public class ApplicationConfiguration implements EntryPoint {
getLogger().log(Level.SEVERE, e.getMessage(), e);
}
});
+
+ if (isProductionMode()) {
+ // Disable all logging if in production mode
+ Logger.getLogger("").setLevel(Level.OFF);
+ }
}
Profiler.leave("ApplicationConfiguration.onModuleLoad");
@@ -649,7 +654,11 @@ public class ApplicationConfiguration implements EntryPoint {
/**
* Checks if client side is in debug mode. Practically this is invoked by
- * adding ?debug parameter to URI.
+ * adding ?debug parameter to URI. Please note that debug mode is always
+ * disabled if production mode is enabled, but disabling production mode
+ * does not automatically enable debug mode.
+ *
+ * @see #isProductionMode()
*
* @return true if client side is currently been debugged
*/
@@ -658,6 +667,19 @@ public class ApplicationConfiguration implements EntryPoint {
&& Window.Location.getParameter("debug") != null;
}
+ /**
+ * Checks if production mode is enabled. When production mode is enabled,
+ * client-side logging is disabled. There may also be other performance
+ * optimizations.
+ *
+ * @since 7.1.2
+ * @return <code>true</code> if production mode is enabled; otherwise
+ * <code>false</code>.
+ */
+ public static boolean isProductionMode() {
+ return !isDebugAvailable();
+ }
+
private native static boolean isDebugAvailable()
/*-{
if($wnd.vaadin.debug) {
diff --git a/client/src/com/vaadin/client/ui/Action.java b/client/src/com/vaadin/client/ui/Action.java
index ffc3c4c7d4..e1b85dcb82 100644
--- a/client/src/com/vaadin/client/ui/Action.java
+++ b/client/src/com/vaadin/client/ui/Action.java
@@ -67,4 +67,16 @@ public abstract class Action implements Command {
public void setIconUrl(String url) {
iconUrl = url;
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "Action [owner=" + owner + ", iconUrl=" + iconUrl + ", caption="
+ + caption + "]";
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java
index 5a83579d46..49cd2386ac 100644
--- a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java
+++ b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java
@@ -17,6 +17,7 @@ package com.vaadin.client.ui.calendar;
import java.text.ParseException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
@@ -267,6 +268,18 @@ public class CalendarConnector extends AbstractComponentConnector implements
return CalendarConnector.this.getActionsBetween(
start, end);
+
+ } else if (widget instanceof MonthEventLabel) {
+ MonthEventLabel mel = (MonthEventLabel) widget;
+ CalendarEvent event = mel.getCalendarEvent();
+ Action[] actions = CalendarConnector.this
+ .getActionsBetween(event.getStartTime(),
+ event.getEndTime());
+ for (Action action : actions) {
+ ((VCalendarAction) action).setEvent(event);
+ }
+ return actions;
+
} else if (widget instanceof DateCell) {
/*
* Week and Day view
@@ -284,22 +297,15 @@ public class CalendarConnector extends AbstractComponentConnector implements
*/
DateCellDayEvent dayEvent = (DateCellDayEvent) widget;
CalendarEvent event = dayEvent.getCalendarEvent();
+
Action[] actions = CalendarConnector.this
.getActionsBetween(event.getStartTime(),
event.getEndTime());
+
for (Action action : actions) {
((VCalendarAction) action).setEvent(event);
}
- return actions;
- } else if (widget instanceof MonthEventLabel) {
- MonthEventLabel mel = (MonthEventLabel) widget;
- CalendarEvent event = mel.getCalendarEvent();
- Action[] actions = CalendarConnector.this
- .getActionsBetween(event.getStartTime(),
- event.getEndTime());
- for (Action action : actions) {
- ((VCalendarAction) action).setEvent(event);
- }
+
return actions;
}
return null;
@@ -456,27 +462,55 @@ public class CalendarConnector extends AbstractComponentConnector implements
private Action[] getActionsBetween(Date start, Date end) {
List<Action> actions = new ArrayList<Action>();
+ List<String> ids = new ArrayList<String>();
+
for (int i = 0; i < actionKeys.size(); i++) {
- final String actionKey = actionKeys.get(i);
- Date actionStartDate;
- Date actionEndDate;
- try {
- actionStartDate = getActionStartDate(actionKey);
- actionEndDate = getActionEndDate(actionKey);
- } catch (ParseException pe) {
- VConsole.error("Failed to parse action date");
- continue;
- }
+ String actionKey = actionKeys.get(i);
+ String id = getActionID(actionKey);
+ if (!ids.contains(id)) {
+
+ Date actionStartDate;
+ Date actionEndDate;
+ try {
+ actionStartDate = getActionStartDate(actionKey);
+ actionEndDate = getActionEndDate(actionKey);
+ } catch (ParseException pe) {
+ VConsole.error("Failed to parse action date");
+ continue;
+ }
- boolean startIsValid = start.compareTo(actionStartDate) >= 0;
- boolean endIsValid = end.compareTo(actionEndDate) <= 0;
- if (startIsValid && endIsValid) {
- VCalendarAction a = new VCalendarAction(this, rpc, actionKey);
- a.setCaption(getActionCaption(actionKey));
- a.setIconUrl(getActionIcon(actionKey));
- a.setActionStartDate(start);
- a.setActionEndDate(end);
- actions.add(a);
+ // Case 0: action inside event timeframe
+ // Action should start AFTER or AT THE SAME TIME as the event,
+ // and
+ // Action should end BEFORE or AT THE SAME TIME as the event
+ boolean test0 = actionStartDate.compareTo(start) >= 0
+ && actionEndDate.compareTo(end) <= 0;
+
+ // Case 1: action intersects start of timeframe
+ // Action end time must be between start and end of event
+ boolean test1 = actionEndDate.compareTo(start) > 0
+ && actionEndDate.compareTo(end) <= 0;
+
+ // Case 2: action intersects end of timeframe
+ // Action start time must be between start and end of event
+ boolean test2 = actionStartDate.compareTo(start) >= 0
+ && actionStartDate.compareTo(end) < 0;
+
+ // Case 3: event inside action timeframe
+ // Action should start AND END before the event is complete
+ boolean test3 = start.compareTo(actionStartDate) >= 0
+ && end.compareTo(actionEndDate) <= 0;
+
+ if (test0 || test1 || test2 || test3) {
+ VCalendarAction a = new VCalendarAction(this, rpc,
+ actionKey);
+ a.setCaption(getActionCaption(actionKey));
+ a.setIconUrl(getActionIcon(actionKey));
+ a.setActionStartDate(start);
+ a.setActionEndDate(end);
+ actions.add(a);
+ ids.add(id);
+ }
}
}
@@ -496,6 +530,7 @@ public class CalendarConnector extends AbstractComponentConnector implements
for (CalendarState.Action action : actions) {
String id = action.actionKey + "-" + action.startDate + "-"
+ action.endDate;
+ actionMap.put(id + "_k", action.actionKey);
actionMap.put(id + "_c", action.caption);
actionMap.put(id + "_s", action.startDate);
actionMap.put(id + "_e", action.endDate);
@@ -507,6 +542,20 @@ public class CalendarConnector extends AbstractComponentConnector implements
actionMap.remove(id + "_i");
}
}
+
+ Collections.sort(actionKeys);
+ }
+
+ /**
+ * Get the original action ID that was passed in from the shared state
+ *
+ * @since 7.1.2
+ * @param actionKey
+ * the unique action key
+ * @return
+ */
+ public String getActionID(String actionKey) {
+ return actionMap.get(actionKey + "_k");
}
/**
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java
index c56566bf25..b69d2a4fe7 100644
--- a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java
@@ -244,7 +244,8 @@ public class DateCellDayEvent extends FocusableHTML implements
@Override
public void onMouseUp(MouseUpEvent event) {
- if (mouseMoveCanceled) {
+ if (mouseMoveCanceled
+ || event.getNativeButton() != NativeEvent.BUTTON_LEFT) {
return;
}
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
index cb6ad25e97..cea993310f 100644
--- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
+++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
@@ -25,6 +25,7 @@ import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.LayoutManager;
import com.vaadin.client.Profiler;
import com.vaadin.client.ServerConnector;
+import com.vaadin.client.TooltipInfo;
import com.vaadin.client.Util;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
@@ -349,6 +350,44 @@ public abstract class AbstractOrderedLayoutConnector extends
updateInternalState();
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.client.ui.AbstractComponentConnector#getTooltipInfo(com.google
+ * .gwt.dom.client.Element)
+ */
+ @Override
+ public TooltipInfo getTooltipInfo(com.google.gwt.dom.client.Element element) {
+ if (element != getWidget().getElement()) {
+ Slot slot = Util.findWidget(
+ (com.google.gwt.user.client.Element) element, Slot.class);
+ if (slot != null && slot.getCaptionElement() != null
+ && slot.getCaptionElement().isOrHasChild(element)) {
+ ComponentConnector connector = Util.findConnectorFor(slot
+ .getWidget());
+ if (connector != null) {
+ return connector.getTooltipInfo(element);
+ }
+ }
+ }
+ return super.getTooltipInfo(element);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.client.ui.AbstractComponentConnector#hasTooltip()
+ */
+ @Override
+ public boolean hasTooltip() {
+ /*
+ * Tooltips are fetched from child connectors -> there's no quick way of
+ * checking whether there might a tooltip hiding somewhere
+ */
+ return true;
+ }
+
/**
* Updates DOM properties and listeners based on the current state of this
* layout and its children.
diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java
index ba291e7e1f..45005ddd9f 100644
--- a/client/src/com/vaadin/client/ui/ui/UIConnector.java
+++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java
@@ -40,6 +40,7 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.Window.Location;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.HandlerRegistration;
@@ -348,14 +349,30 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
if (uidl.hasAttribute(UIConstants.LOCATION_VARIABLE)) {
String location = uidl
.getStringAttribute(UIConstants.LOCATION_VARIABLE);
+ String newFragment;
+
int fragmentIndex = location.indexOf('#');
if (fragmentIndex >= 0) {
// Decode fragment to avoid double encoding (#10769)
- getWidget().currentFragment = URL.decodePathSegment(location
+ newFragment = URL.decodePathSegment(location
.substring(fragmentIndex + 1));
+
+ if (newFragment.isEmpty()
+ && Location.getHref().indexOf('#') == -1) {
+ // Ensure there is a trailing # even though History and
+ // Location.getHash() treat null and "" the same way.
+ Location.assign(Location.getHref() + "#");
+ }
+ } else {
+ // No fragment in server-side location, but can't completely
+ // remove the browser fragment since that would reload the page
+ newFragment = "";
}
- if (!getWidget().currentFragment.equals(History.getToken())) {
- History.newItem(getWidget().currentFragment, true);
+
+ getWidget().currentFragment = newFragment;
+
+ if (!newFragment.equals(History.getToken())) {
+ History.newItem(newFragment, true);
}
}
diff --git a/server/build.xml b/server/build.xml
index 057f65a0d3..98ee2342cf 100644
--- a/server/build.xml
+++ b/server/build.xml
@@ -23,7 +23,7 @@
</union>
<target name="jar">
- <property name="server.osgi.import" value="javax.servlet;version=&quot;2.4.0&quot;,javax.servlet.http;version=&quot;2.4.0&quot;,org.jsoup;version=&quot;1.6.3&quot;,org.jsoup.parser;version=&quot;1.6.3&quot;,org.jsoup.nodes;version=&quot;1.6.3&quot;,org.jsoup.helper;version=&quot;1.6.3&quot;,org.jsoup.safety;version=&quot;1.6.3&quot;,org.json;version=&quot;0.0.20080701&quot;" />
+ <property name="server.osgi.import" value="javax.servlet;version=&quot;2.4.0&quot;,javax.servlet.http;version=&quot;2.4.0&quot;,javax.validation;version=&quot;1.0.0.GA&quot;;resolution:=optional,org.jsoup;version=&quot;1.6.3&quot;,org.jsoup.parser;version=&quot;1.6.3&quot;,org.jsoup.nodes;version=&quot;1.6.3&quot;,org.jsoup.helper;version=&quot;1.6.3&quot;,org.jsoup.safety;version=&quot;1.6.3&quot;,org.json;version=&quot;0.0.20080701&quot;" />
<property name="server.osgi.require" value="com.vaadin.shared;bundle-version=&quot;${vaadin.version}&quot;,com.vaadin.push;bundle-version=&quot;${vaadin.version}&quot;;resolution:=optional" />
<antcall target="common.jar">
<param name="require-bundle" value="${server.osgi.require}" />
diff --git a/server/ivy.xml b/server/ivy.xml
index db7e953371..b78541c52f 100644
--- a/server/ivy.xml
+++ b/server/ivy.xml
@@ -25,6 +25,7 @@
<!-- Liferay Portal Service -->
<dependency org="com.liferay.portal" name="portal-service"
rev="6.0.2" conf="build-provided,ide -> default" />
+
<!--Servlet API version 2.4 -->
<dependency org="javax.servlet" name="servlet-api"
rev="2.4" conf="build-provided,ide,test -> default" />
@@ -36,6 +37,8 @@
<!-- Google App Engine -->
<dependency org="com.google.appengine" name="appengine-api-1.0-sdk"
rev="1.2.1" conf="build-provided,ide,test -> default" />
+
+ <!-- Bean Validation API -->
<dependency org="javax.validation" name="validation-api"
rev="1.0.0.GA" conf="build-provided,ide,test -> default" />
diff --git a/server/src/com/vaadin/annotations/JavaScript.java b/server/src/com/vaadin/annotations/JavaScript.java
index f2085556c7..bdba70c095 100644
--- a/server/src/com/vaadin/annotations/JavaScript.java
+++ b/server/src/com/vaadin/annotations/JavaScript.java
@@ -29,9 +29,21 @@ import com.vaadin.server.ClientConnector;
* method for the corresponding client-side connector is invoked.
* <p>
* Absolute URLs including protocol and host are used as is on the client-side.
- * Relative urls are mapped to APP/PUBLISHED/[url] which are by default served
+ * Relative URLs are mapped to APP/PUBLISHED/[url] which are by default served
* from the classpath relative to the class where the annotation is defined.
* <p>
+ * The file is only loaded if it has not already been loaded, determined as
+ * follows:
+ * <ul>
+ * <li>For absolute URLs, the URL is considered loaded if the same URL has
+ * previously been loaded using {@code @JavaScript} or if a script tag loaded
+ * from the same URL was present in the DOM when the Vaadin client-side was
+ * initialized.
+ * <li>For relative URLs, the URL is considered loaded if another file with the
+ * same name has already been loaded using {@code @JavaScript}, even if that
+ * file was loaded from a different folder.
+ * </ul>
+ * <p>
* Example: {@code @JavaScript( "http://host.com/file1.js", "file2.js"})} on the
* class com.example.MyConnector would load the file http://host.com/file1.js as
* is and file2.js from /com/example/file2.js on the server's classpath using
diff --git a/server/src/com/vaadin/annotations/StyleSheet.java b/server/src/com/vaadin/annotations/StyleSheet.java
index 2e15d9481c..6540633f8f 100644
--- a/server/src/com/vaadin/annotations/StyleSheet.java
+++ b/server/src/com/vaadin/annotations/StyleSheet.java
@@ -29,9 +29,21 @@ import com.vaadin.server.ClientConnector;
* method for the corresponding client-side connector is invoked.
* <p>
* Absolute URLs including protocol and host are used as is on the client-side.
- * Relative urls are mapped to APP/PUBLISHED/[url] which are by default served
+ * Relative URLs are mapped to APP/PUBLISHED/[url] which are by default served
* from the classpath relative to the class where the annotation is defined.
* <p>
+ * The file is only loaded if it has not already been loaded, determined as
+ * follows:
+ * <ul>
+ * <li>For absolute URLs, the URL is considered loaded if the same URL has
+ * previously been loaded using {@code StyleSheet} or if a
+ * {@code <link rel="stylesheet">} tag using the same URL was present in the DOM
+ * when the Vaadin client-side was initialized.
+ * <li>For relative URLs, the URL is considered loaded if another file with the
+ * same name has already been loaded using {@code StyleSheet}, even if that file
+ * was loaded from a different folder.
+ * </ul>
+ * <p>
* Special Vaadin urls are also supported. The most useful is vaadin:// which
* maps to the location of the automatically published VAADIN folder. Using the
* VAADIN folder and vaadin:// you can publish stylesheets which use images or
diff --git a/server/src/com/vaadin/data/util/converter/StringToIntegerConverter.java b/server/src/com/vaadin/data/util/converter/StringToIntegerConverter.java
index bc436112fe..f6f668ad4d 100644
--- a/server/src/com/vaadin/data/util/converter/StringToIntegerConverter.java
+++ b/server/src/com/vaadin/data/util/converter/StringToIntegerConverter.java
@@ -62,7 +62,22 @@ public class StringToIntegerConverter extends
Class<? extends Integer> targetType, Locale locale)
throws ConversionException {
Number n = convertToNumber(value, targetType, locale);
- return n == null ? null : n.intValue();
+
+ if (n == null) {
+ return null;
+ }
+
+ int intValue = n.intValue();
+ if (intValue == n.longValue()) {
+ // If the value of n is outside the range of long, the return value
+ // of longValue() is either Long.MIN_VALUE or Long.MAX_VALUE. The
+ // above comparison promotes int to long and thus does not need to
+ // consider wrap-around.
+ return intValue;
+ }
+
+ throw new ConversionException("Could not convert '" + value + "' to "
+ + Integer.class.getName() + ": value out of range");
}
diff --git a/server/src/com/vaadin/server/Page.java b/server/src/com/vaadin/server/Page.java
index 4c19d28b9c..5c8b1aeb42 100644
--- a/server/src/com/vaadin/server/Page.java
+++ b/server/src/com/vaadin/server/Page.java
@@ -244,9 +244,23 @@ public class Page implements Serializable {
public static final BorderStyle BORDER_DEFAULT = BorderStyle.DEFAULT;
/**
- * Listener that listens to changes in URI fragment.
+ * Listener that that gets notified when the URI fragment of the page
+ * changes.
+ *
+ * @see Page#addUriFragmentChangedListener(UriFragmentChangedListener)
*/
public interface UriFragmentChangedListener extends Serializable {
+ /**
+ * Event handler method invoked when the URI fragment of the page
+ * changes. Please note that the initial URI fragment has already been
+ * set when a new UI is initialized, so there will not be any initial
+ * event for listeners added during {@link UI#init(VaadinRequest)}.
+ *
+ * @see Page#addUriFragmentChangedListener(UriFragmentChangedListener)
+ *
+ * @param event
+ * the URI fragment changed event
+ */
public void uriFragmentChanged(UriFragmentChangedEvent event);
}
@@ -267,12 +281,14 @@ public class Page implements Serializable {
private List<Notification> notifications;
/**
- * Event fired when uri fragment changes.
+ * Event fired when the URI fragment of a <code>Page</code> changes.
+ *
+ * @see Page#addUriFragmentChangedListener(UriFragmentChangedListener)
*/
public static class UriFragmentChangedEvent extends EventObject {
/**
- * The new uri fragment
+ * The new URI fragment
*/
private final String uriFragment;
@@ -281,6 +297,8 @@ public class Page implements Serializable {
*
* @param source
* the Source of the event.
+ * @param uriFragment
+ * the new uriFragment
*/
public UriFragmentChangedEvent(Page source, String uriFragment) {
super(source);
@@ -288,16 +306,16 @@ public class Page implements Serializable {
}
/**
- * Gets the uI in which the fragment has changed.
+ * Gets the page in which the fragment has changed.
*
- * @return the uI in which the fragment has changed
+ * @return the page in which the fragment has changed
*/
public Page getPage() {
return (Page) getSource();
}
/**
- * Get the new fragment
+ * Get the new URI fragment
*
* @return the new fragment
*/
@@ -478,6 +496,19 @@ public class Page implements Serializable {
}
}
+ /**
+ * Adds a listener that gets notified every time the URI fragment of this
+ * page is changed. Please note that the initial URI fragment has already
+ * been set when a new UI is initialized, so there will not be any initial
+ * event for listeners added during {@link UI#init(VaadinRequest)}.
+ *
+ * @see #getUriFragment()
+ * @see #setUriFragment(String)
+ * @see #removeUriFragmentChangedListener(UriFragmentChangedListener)
+ *
+ * @param listener
+ * the URI fragment listener to add
+ */
public void addUriFragmentChangedListener(
Page.UriFragmentChangedListener listener) {
addListener(UriFragmentChangedEvent.class, listener,
@@ -493,6 +524,14 @@ public class Page implements Serializable {
addUriFragmentChangedListener(listener);
}
+ /**
+ * Removes a URI fragment listener that was previously added to this page.
+ *
+ * @param listener
+ * the URI fragment listener to remove
+ *
+ * @see Page#addUriFragmentChangedListener(UriFragmentChangedListener)
+ */
public void removeUriFragmentChangedListener(
Page.UriFragmentChangedListener listener) {
removeListener(UriFragmentChangedEvent.class, listener,
@@ -515,14 +554,15 @@ public class Page implements Serializable {
* The fragment is the optional last component of a URI, prefixed with a
* hash sign ("#").
* <p>
- * Passing <code>null</code> as <code>newFragment</code> clears the fragment
- * (no "#" in the URI); passing an empty string sets an empty fragment (a
- * trailing "#" in the URI.) This is consistent with the semantics of
- * {@link java.net.URI}.
+ * Passing an empty string as <code>newFragment</code> sets an empty
+ * fragment (a trailing "#" in the URI.) Passing <code>null</code> if there
+ * is already a non-null fragment will leave a trailing # in the URI since
+ * removing it would cause the browser to reload the page. This is not fully
+ * consistent with the semantics of {@link java.net.URI}.
*
* @param newUriFragment
* The new fragment.
- * @param fireEvent
+ * @param fireEvents
* true to fire event
*
* @see #getUriFragment()
@@ -533,6 +573,11 @@ public class Page implements Serializable {
*/
public void setUriFragment(String newUriFragment, boolean fireEvents) {
String oldUriFragment = location.getFragment();
+ if (newUriFragment == null && getUriFragment() != null) {
+ // Can't completely remove the fragment once it has been set, will
+ // instead set it to the empty string
+ newUriFragment = "";
+ }
if (newUriFragment == oldUriFragment
|| (newUriFragment != null && newUriFragment
.equals(oldUriFragment))) {
diff --git a/server/src/com/vaadin/ui/Calendar.java b/server/src/com/vaadin/ui/Calendar.java
index c3385baa2c..9ccc8ea2d9 100644
--- a/server/src/com/vaadin/ui/Calendar.java
+++ b/server/src/com/vaadin/ui/Calendar.java
@@ -26,7 +26,7 @@ import java.util.Date;
import java.util.EventListener;
import java.util.GregorianCalendar;
import java.util.HashMap;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -535,6 +535,7 @@ public class Calendar extends AbstractComponent implements
// Get day start and end times
Date start = cal.getTime();
cal.add(java.util.Calendar.DATE, 1);
+ cal.add(java.util.Calendar.SECOND, -1);
Date end = cal.getTime();
boolean monthView = (durationInDays > 7);
@@ -572,7 +573,7 @@ public class Calendar extends AbstractComponent implements
CalendarDateRange range = new CalendarDateRange(s, e, getTimeZone());
Action[] actions = actionHandler.getActions(range, this);
if (actions != null) {
- Set<Action> actionSet = new HashSet<Action>(
+ Set<Action> actionSet = new LinkedHashSet<Action>(
Arrays.asList(actions));
actionMap.put(range, actionSet);
}
@@ -586,7 +587,8 @@ public class Calendar extends AbstractComponent implements
getTimeZone());
Action[] actions = actionHandler.getActions(range, this);
if (actions != null) {
- Set<Action> actionSet = new HashSet<Action>(Arrays.asList(actions));
+ Set<Action> actionSet = new LinkedHashSet<Action>(
+ Arrays.asList(actions));
actionMap.put(range, actionSet);
}
}
@@ -1871,4 +1873,4 @@ public class Calendar extends AbstractComponent implements
dropHandler.getAcceptCriterion().paint(target);
}
}
-} \ No newline at end of file
+}
diff --git a/server/src/com/vaadin/ui/Embedded.java b/server/src/com/vaadin/ui/Embedded.java
index c9b64af415..53354db0f4 100644
--- a/server/src/com/vaadin/ui/Embedded.java
+++ b/server/src/com/vaadin/ui/Embedded.java
@@ -31,13 +31,17 @@ import com.vaadin.shared.ui.embedded.EmbeddedConstants;
import com.vaadin.shared.ui.embedded.EmbeddedServerRpc;
/**
- * Component for embedding external objects.
+ * A component for embedding external objects.
* <p>
- * As of Vaadin 7.0, the {@link Image}, {@link Flash}, and {@link BrowserFrame}
- * components should be used instead of <code>Embedded</code> for displaying
- * images, Adobe Flash objects, and embedded web pages, respectively.
- * <code>Embedded</code> is still useful for displaying other multimedia content
- * such as applets and PDF documents.
+ * The {@code Embedded} component is used to display various types of multimedia
+ * content using the HTML {@code <object>} element. This includes PDF documents,
+ * Java applets, and QuickTime videos. Installing a browser plug-in is usually
+ * required to actually view the embedded content.
+ * <p>
+ * Note that before Vaadin 7, {@code Embedded} was also used to display images,
+ * Adobe Flash objects, and embedded web pages. This use of the component is
+ * deprecated in Vaadin 7; the {@link Image}, {@link Flash}, and
+ * {@link BrowserFrame} components should be used instead, respectively.
*
* @see Video
* @see Audio
diff --git a/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java b/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java
index 01b766a6db..b78fda3136 100644
--- a/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java
+++ b/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java
@@ -83,4 +83,15 @@ public class CalendarDateRange implements Serializable {
return date.compareTo(start) >= 0 && date.compareTo(end) <= 0;
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "CalendarDateRange [start=" + start + ", end=" + end + "]";
+ }
+
}
diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestStringToIntegerConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestStringToIntegerConverter.java
index c73853578e..e810106631 100644
--- a/server/tests/src/com/vaadin/tests/data/converter/TestStringToIntegerConverter.java
+++ b/server/tests/src/com/vaadin/tests/data/converter/TestStringToIntegerConverter.java
@@ -2,6 +2,7 @@ package com.vaadin.tests.data.converter;
import junit.framework.TestCase;
+import com.vaadin.data.util.converter.Converter.ConversionException;
import com.vaadin.data.util.converter.StringToIntegerConverter;
public class TestStringToIntegerConverter extends TestCase {
@@ -16,6 +17,23 @@ public class TestStringToIntegerConverter extends TestCase {
assertEquals(null, converter.convertToModel("", Integer.class, null));
}
+ public void testValueOutOfRange() {
+ Double[] values = new Double[] { Integer.MAX_VALUE * 2.0,
+ Integer.MIN_VALUE * 2.0, Long.MAX_VALUE * 2.0,
+ Long.MIN_VALUE * 2.0 };
+
+ boolean accepted = false;
+ for (Number value : values) {
+ try {
+ converter.convertToModel(String.format("%.0f", value),
+ Integer.class, null);
+ accepted = true;
+ } catch (ConversionException expected) {
+ }
+ }
+ assertFalse("Accepted value outside range of int", accepted);
+ }
+
public void testValueConversion() {
assertEquals(Integer.valueOf(10),
converter.convertToModel("10", Integer.class, null));
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarActionsMenuTest.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarActionsMenuTest.html
new file mode 100644
index 0000000000..3830faa7de
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarActionsMenuTest.html
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarActionsMenuTest?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>contextmenu</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsMenuTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>//td[@id='gwt-uid-5']/div</td>
+ <td>ACTION</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsMenuTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[2]</td>
+ <td>127,5</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsMenuTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>155,9</td>
+</tr>
+<tr>
+ <td>contextmenu</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsMenuTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]/domChild[34]/domChild[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>//td[@id='gwt-uid-6']/div</td>
+ <td>ACTION</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsMenuTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]/domChild[13]</td>
+ <td>139,0</td>
+</tr>
+<tr>
+ <td>contextmenu</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsMenuTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]/domChild[14]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>//td[@id='gwt-uid-14']/div</td>
+ <td>ACTION</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsMenuTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]/domChild[13]</td>
+ <td>139,0</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarActionsMenuTest.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarActionsMenuTest.java
new file mode 100644
index 0000000000..77225b2e4c
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarActionsMenuTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.calendar;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.vaadin.event.Action;
+import com.vaadin.event.Action.Handler;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.Calendar.TimeFormat;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClick;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClickHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventMoveHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResizeHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.MoveEvent;
+import com.vaadin.ui.components.calendar.event.BasicEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEventProvider;
+
+public class CalendarActionsMenuTest extends AbstractTestUI {
+
+ private Calendar calendar;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ calendar = new Calendar(new CalendarEventProvider() {
+
+ @Override
+ public List<com.vaadin.ui.components.calendar.event.CalendarEvent> getEvents(
+ Date startDate, Date endDate) {
+
+ List<CalendarEvent> events = new ArrayList<CalendarEvent>();
+
+ CalendarEvent event = null;
+ try {
+ event = new BasicEvent("NAME", "TOOLTIP",
+ new SimpleDateFormat("yyyy-MM-dd hh:mm")
+ .parse("2013-01-01 07:00"),
+ new SimpleDateFormat("yyyy-MM-dd hh:mm")
+ .parse("2013-01-01 11:00"));
+ } catch (ParseException e) {
+ // Nothing to do
+ }
+ events.add(event);
+
+ try {
+ event = new BasicEvent("NAME 2", "TOOLTIP2",
+ new SimpleDateFormat("yyyy-MM-dd hh:mm")
+ .parse("2013-01-03 07:00"),
+ new SimpleDateFormat("yyyy-MM-dd hh:mm")
+ .parse("2013-01-04 11:00"));
+ } catch (ParseException e) {
+ // Nothing to do
+ }
+ events.add(event);
+
+ return events;
+ }
+
+ });
+ try {
+ calendar.setStartDate(new SimpleDateFormat("yyyy-MM-dd")
+ .parse("2013-01-01"));
+ calendar.setEndDate(new SimpleDateFormat("yyyy-MM-dd")
+ .parse("2013-01-31"));
+ } catch (ParseException e) {
+ // Nothing to do
+ }
+ calendar.setImmediate(true);
+ calendar.setFirstVisibleHourOfDay(6);
+ calendar.setLastVisibleHourOfDay(22);
+ calendar.setTimeFormat(TimeFormat.Format24H);
+ calendar.setHandler((EventResizeHandler) null);
+
+ setEnabled(true);
+ calendar.addActionHandler(new Handler() {
+ @Override
+ public void handleAction(Action action, Object sender, Object target) {
+ Notification.show("ACTION CLICKED");
+
+ }
+
+ @Override
+ public Action[] getActions(Object target, Object sender) {
+ return new Action[] { new Action("ACTION") };
+ }
+ });
+ calendar.setHandler(new EventClickHandler() {
+ private static final long serialVersionUID = -177173530105538438L;
+
+ @Override
+ public void eventClick(EventClick event) {
+ Notification.show("EVENT CLICKED");
+ }
+ });
+
+ calendar.setHandler(new EventMoveHandler() {
+ @Override
+ public void eventMove(MoveEvent event) {
+ Notification.show("EVENT MOVED");
+ }
+ });
+ addComponent(calendar);
+ calendar.setSizeFull();
+ setSizeFull();
+
+ }
+
+ @Override
+ protected String getTestDescription() {
+ // TODO Auto-generated method stub
+ return "The context should appear if you right click on a calendar event regardless of view mode";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return 12181;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/ErrorIndicator.html b/uitest/src/com/vaadin/tests/components/orderedlayout/ErrorIndicator.html
new file mode 100644
index 0000000000..81da3b897e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/orderedlayout/ErrorIndicator.html
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>Required error tootlip</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">Required error tooltip</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.orderedlayout.ErrorIndicator?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>showTooltip</td>
+ <td>//div[@id='gwt-uid-4']/span</td>
+ <td>43,4</td>
+</tr>
+
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>tooltipVertivcalCaption</td>
+</tr>
+<tr>
+ <td>waitForVaadin</td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>showTooltip</td>
+ <td>//div[@id='gwt-uid-4']/span[2]</td>
+ <td>3,6</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>tooltipVertivcalRequiredIndicator</td>
+</tr>
+<tr>
+ <td>waitForVaadin</td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>showTooltip</td>
+ <td>//div[@id='gwt-uid-6']/span</td>
+ <td>38,11</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>tooltipHorizontalCaption</td>
+</tr>
+<tr>
+ <td>waitForVaadin</td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>showTooltip</td>
+ <td>//div[@id='gwt-uid-6']/span[2]</td>
+ <td>3,4</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>tooltipHorizontalRequiredIndicator</td>
+</tr>
+<tr>
+ <td>waitForVaadin</td>
+ <td></td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/ErrorIndicator.java b/uitest/src/com/vaadin/tests/components/orderedlayout/ErrorIndicator.java
new file mode 100644
index 0000000000..9964e1ee78
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/orderedlayout/ErrorIndicator.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ *
+ */
+package com.vaadin.tests.components.orderedlayout;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class ErrorIndicator extends AbstractTestUI {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server.
+ * VaadinRequest)
+ */
+ @Override
+ protected void setup(VaadinRequest request) {
+ VerticalLayout layout = new VerticalLayout();
+
+ TextField inVertical = new TextField();
+ inVertical.setRequired(true);
+ inVertical.setRequiredError("Vertical layout tooltip");
+ inVertical.setCaption("Vertical layout caption");
+
+ layout.addComponent(inVertical);
+ addComponent(layout);
+
+ HorizontalLayout horizontalLayout = new HorizontalLayout();
+
+ TextField inHorizontal = new TextField();
+ inHorizontal.setRequired(true);
+ inHorizontal.setRequiredError("Horizontal layout tooltip");
+ inHorizontal.setCaption("Horizontal layout caption");
+
+ horizontalLayout.addComponent(inHorizontal);
+ layout.addComponent(horizontalLayout);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription()
+ */
+ @Override
+ protected String getTestDescription() {
+ return "Show tooltip for caption and required indicator";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber()
+ */
+ @Override
+ protected Integer getTicketNumber() {
+ return 10046;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.html b/uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.html
index bcb9f52afe..ba24b55f64 100644
--- a/uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.html
+++ b/uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.html
@@ -71,7 +71,66 @@
<td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td>
<td>Current URI fragment: test</td>
</tr>
-
+<!--Open other URL in between to ensure the page is loaded again (testbench doesn't like opening a URI that only changes the fragment)-->
+<tr>
+ <td>open</td>
+ <td>/run/</td>
+ <td></td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.ui.UriFragmentTest?restartApplication</td>
+ <td></td>
+</tr>
+<!--Empty initial fragment-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>No URI fragment set</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Still no # after setting to null-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>No URI fragment set</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Empty # is added when setting to ""-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>Current URI fragment:</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>Current URI fragment: test</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Setting to null when there is a fragment actually sets it to #-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>Current URI fragment:</td>
+</tr>
</tbody></table>
</body>
</html>
diff --git a/uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.java b/uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.java
index 2172b00ee3..bfd784280a 100644
--- a/uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.java
+++ b/uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.java
@@ -29,6 +29,21 @@ public class UriFragmentTest extends AbstractTestUI {
getPage().setUriFragment("test");
}
}));
+
+ addComponent(new Button("Navigate to #", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ getPage().setUriFragment("");
+ }
+ }));
+
+ addComponent(new Button("setUriFragment(null)",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ getPage().setUriFragment(null);
+ }
+ }));
}
private void updateLabel() {