diff options
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="2.4.0",javax.servlet.http;version="2.4.0",org.jsoup;version="1.6.3",org.jsoup.parser;version="1.6.3",org.jsoup.nodes;version="1.6.3",org.jsoup.helper;version="1.6.3",org.jsoup.safety;version="1.6.3",org.json;version="0.0.20080701"" /> + <property name="server.osgi.import" value="javax.servlet;version="2.4.0",javax.servlet.http;version="2.4.0",javax.validation;version="1.0.0.GA";resolution:=optional,org.jsoup;version="1.6.3",org.jsoup.parser;version="1.6.3",org.jsoup.nodes;version="1.6.3",org.jsoup.helper;version="1.6.3",org.jsoup.safety;version="1.6.3",org.json;version="0.0.20080701"" /> <property name="server.osgi.require" value="com.vaadin.shared;bundle-version="${vaadin.version}",com.vaadin.push;bundle-version="${vaadin.version}";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() { |