diff options
Diffstat (limited to 'server/src/com/vaadin/ui')
-rw-r--r-- | server/src/com/vaadin/ui/AbstractComponent.java | 9 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/AbstractField.java | 15 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/Calendar.java | 31 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/Label.java | 9 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/LegacyWindow.java | 2 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/LoginForm.java | 2 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/ProgressBar.java | 152 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/ProgressIndicator.java | 105 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/PushConfiguration.java | 282 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/UI.java | 238 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java | 2 |
11 files changed, 671 insertions, 176 deletions
diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java index 06060dbf91..9ff36a42d2 100644 --- a/server/src/com/vaadin/ui/AbstractComponent.java +++ b/server/src/com/vaadin/ui/AbstractComponent.java @@ -291,7 +291,10 @@ public abstract class AbstractComponent extends AbstractClientConnector public void setLocale(Locale locale) { this.locale = locale; - // FIXME: Reload value if there is a converter + if (locale != null && isAttached()) { + getUI().getLocaleService().addLocale(locale); + } + markAsDirty(); } @@ -556,6 +559,10 @@ public abstract class AbstractComponent extends AbstractClientConnector focus(); } setActionManagerViewer(); + if (locale != null) { + getUI().getLocaleService().addLocale(locale); + } + } /* diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java index 3bca63a3b7..606bf5fb21 100644 --- a/server/src/com/vaadin/ui/AbstractField.java +++ b/server/src/com/vaadin/ui/AbstractField.java @@ -616,17 +616,14 @@ public abstract class AbstractField<T> extends AbstractComponent implements // Check if the current converter is compatible. if (newDataSource != null - && !ConverterUtil.canConverterHandle(getConverter(), getType(), - newDataSource.getType())) { - // Changing from e.g. Number -> Double should set a new converter, - // changing from Double -> Number can keep the old one (Property - // accepts Number) - - // Set a new converter if there is a new data source and - // there is no old converter or the old is incompatible. + && !ConverterUtil.canConverterPossiblyHandle(getConverter(), + getType(), newDataSource.getType())) { + // There is no converter set or there is no way the current + // converter can be compatible. setConverter(newDataSource.getType()); } - // Gets the value from source + // Gets the value from source. This requires that a valid converter has + // been set. try { if (dataSource != null) { T fieldValue = convertFromModel(getDataSourceValue()); diff --git a/server/src/com/vaadin/ui/Calendar.java b/server/src/com/vaadin/ui/Calendar.java index 38fa355dd8..c3385baa2c 100644 --- a/server/src/com/vaadin/ui/Calendar.java +++ b/server/src/com/vaadin/ui/Calendar.java @@ -45,6 +45,8 @@ import com.vaadin.event.dd.DropHandler; import com.vaadin.event.dd.DropTarget; import com.vaadin.event.dd.TargetDetails; import com.vaadin.server.KeyMapper; +import com.vaadin.server.PaintException; +import com.vaadin.server.PaintTarget; import com.vaadin.shared.ui.calendar.CalendarEventId; import com.vaadin.shared.ui.calendar.CalendarServerRpc; import com.vaadin.shared.ui.calendar.CalendarState; @@ -114,7 +116,7 @@ public class Calendar extends AbstractComponent implements CalendarComponentEvents.RangeSelectNotifier, CalendarComponentEvents.EventResizeNotifier, CalendarEventProvider.EventSetChangeListener, DropTarget, - CalendarEditableEventProvider, Action.Container { + CalendarEditableEventProvider, Action.Container, LegacyComponent { /** * Calendar can use either 12 hours clock or 24 hours clock. @@ -1842,4 +1844,31 @@ public class Calendar extends AbstractComponent implements } } } + + /* + * (non-Javadoc) + * + * @see com.vaadin.server.VariableOwner#changeVariables(java.lang.Object, + * java.util.Map) + */ + @Override + public void changeVariables(Object source, Map<String, Object> variables) { + /* + * Only defined to fulfill the LegacyComponent interface used for + * calendar drag & drop. No implementation required. + */ + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.LegacyComponent#paintContent(com.vaadin.server.PaintTarget) + */ + @Override + public void paintContent(PaintTarget target) throws PaintException { + if (dropHandler != null) { + dropHandler.getAcceptCriterion().paint(target); + } + } }
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/Label.java b/server/src/com/vaadin/ui/Label.java index d037652a09..d7cee2a80d 100644 --- a/server/src/com/vaadin/ui/Label.java +++ b/server/src/com/vaadin/ui/Label.java @@ -242,14 +242,17 @@ public class Label extends AbstractComponent implements Property<String>, ((Property.ValueChangeNotifier) dataSource).removeListener(this); } + // Check if the current converter is compatible. if (newDataSource != null - && !ConverterUtil.canConverterHandle(getConverter(), - String.class, newDataSource.getType())) { - // Try to find a converter + && !ConverterUtil.canConverterPossiblyHandle(getConverter(), + getType(), newDataSource.getType())) { + // There is no converter set or there is no way the current + // converter can be compatible. Converter<String, ?> c = ConverterUtil.getConverter(String.class, newDataSource.getType(), getSession()); setConverter(c); } + dataSource = newDataSource; if (dataSource != null) { // Update the value from the data source. If data source was set to diff --git a/server/src/com/vaadin/ui/LegacyWindow.java b/server/src/com/vaadin/ui/LegacyWindow.java index 1b66b608c1..458b09390d 100644 --- a/server/src/com/vaadin/ui/LegacyWindow.java +++ b/server/src/com/vaadin/ui/LegacyWindow.java @@ -125,7 +125,7 @@ public class LegacyWindow extends UI { public void setName(String name) { this.name = name; // The name can not be changed in application - if (getSession() != null) { + if (isAttached()) { throw new IllegalStateException( "Window name can not be changed while " + "the window is in application"); diff --git a/server/src/com/vaadin/ui/LoginForm.java b/server/src/com/vaadin/ui/LoginForm.java index d06882927e..67d7182ecb 100644 --- a/server/src/com/vaadin/ui/LoginForm.java +++ b/server/src/com/vaadin/ui/LoginForm.java @@ -68,7 +68,7 @@ public class LoginForm extends CustomComponent { } final StringBuilder responseBuilder = new StringBuilder(); - getUI().access(new Runnable() { + getUI().accessSynchronously(new Runnable() { @Override public void run() { String method = VaadinServletService.getCurrentServletRequest() diff --git a/server/src/com/vaadin/ui/ProgressBar.java b/server/src/com/vaadin/ui/ProgressBar.java new file mode 100644 index 0000000000..3f8aab6d7c --- /dev/null +++ b/server/src/com/vaadin/ui/ProgressBar.java @@ -0,0 +1,152 @@ +/* + * 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.ui; + +import com.vaadin.data.Property; +import com.vaadin.shared.ui.progressindicator.ProgressBarState; + +/** + * Shows the current progress of a long running task. + * <p> + * The default mode is to show the current progress internally represented by a + * floating point value between 0 and 1 (inclusive). The progress bar can also + * be in an indeterminate mode showing an animation indicating that the task is + * running but without providing any information about the current progress. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class ProgressBar extends AbstractField<Float> implements + Property.Viewer, Property.ValueChangeListener { + + /** + * Creates a new progress bar initially set to 0% progress. + */ + public ProgressBar() { + this(0); + } + + /** + * Creates a new progress bar with the given initial value. + * + * @param progress + * the initial progress value + */ + public ProgressBar(float progress) { + setValue(Float.valueOf(progress)); + } + + /** + * Creates a new progress bar bound to the given data source. + * + * @param dataSource + * the property to bind this progress bar to + */ + public ProgressBar(Property<?> dataSource) { + setPropertyDataSource(dataSource); + } + + @Override + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); + + // Update value in state even if the property hasn't fired any event + getState().state = getValue(); + } + + /** + * Gets the value of this progress bar. The value is a <code>float</code> + * between 0 and 1 where 0 represents no progress at all and 1 represents + * fully completed. + * + * @return the current progress value + */ + @Override + public Float getValue() { + return super.getValue(); + } + + /** + * Sets the value of this progress bar. The value is a <code>float</code> + * between 0 and 1 where 0 represents no progress at all and 1 represents + * fully completed. + * + * @param newValue + * the current progress value + */ + @Override + public void setValue(Float newValue) { + super.setValue(newValue); + } + + @Override + public Class<Float> getType() { + return Float.class; + } + + @Override + protected ProgressBarState getState() { + return (ProgressBarState) super.getState(); + } + + @Override + protected ProgressBarState getState(boolean markAsDirty) { + return (ProgressBarState) super.getState(markAsDirty); + } + + /** + * Sets whether or not this progress indicator is indeterminate. In + * indeterminate mode there is an animation indicating that the task is + * running but without providing any information about the current progress. + * + * @param indeterminate + * <code>true</code> to set to indeterminate mode; otherwise + * <code>false</code> + */ + public void setIndeterminate(boolean indeterminate) { + getState().indeterminate = indeterminate; + } + + /** + * Gets whether or not this progress indicator is indeterminate. In + * indeterminate mode there is an animation indicating that the task is + * running but without providing any information about the current progress. + * + * @return <code>true</code> if set to indeterminate mode; otherwise + * <code>false</code> + */ + public boolean isIndeterminate() { + return getState(false).indeterminate; + } + + /* + * Overridden to keep the shared state in sync with the AbstractField + * internal value. Should be removed once AbstractField is refactored to use + * shared state. + * + * See tickets #10921 and #11064. + */ + @Override + protected void setInternalValue(Float newValue) { + super.setInternalValue(newValue); + if (newValue == null) { + newValue = Float.valueOf(0); + } + getState().state = newValue; + } + +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/ProgressIndicator.java b/server/src/com/vaadin/ui/ProgressIndicator.java index c481aa1e8f..6da18fc29d 100644 --- a/server/src/com/vaadin/ui/ProgressIndicator.java +++ b/server/src/com/vaadin/ui/ProgressIndicator.java @@ -17,24 +17,27 @@ package com.vaadin.ui; import com.vaadin.data.Property; +import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.ui.progressindicator.ProgressIndicatorServerRpc; import com.vaadin.shared.ui.progressindicator.ProgressIndicatorState; /** - * <code>ProgressIndicator</code> is component that shows user state of a - * process (like long computing or file upload) - * - * <code>ProgressIndicator</code> has two main modes. One for indeterminate - * processes and other (default) for processes which progress can be measured - * - * May view an other property that indicates progress 0...1 + * A {@link ProgressBar} which polls the server for updates. + * <p> + * Polling in this way is generally not recommended since there is no + * centralized management of when messages are sent to the server. Furthermore, + * polling might not be needed at all if {@link UI#setPushMode(PushMode)} or + * {@link UI#setPollInterval(int)} is used. * * @author Vaadin Ltd. * @since 4 + * @deprecated as of 7.1, use {@link ProgressBar} combined with + * {@link UI#setPushMode(PushMode)} or + * {@link UI#setPollInterval(int)} instead. */ +@Deprecated @SuppressWarnings("serial") -public class ProgressIndicator extends AbstractField<Float> implements - Property.Viewer, Property.ValueChangeListener { +public class ProgressIndicator extends ProgressBar { private ProgressIndicatorServerRpc rpc = new ProgressIndicatorServerRpc() { @@ -57,7 +60,7 @@ public class ProgressIndicator extends AbstractField<Float> implements * @param value */ public ProgressIndicator(float value) { - setValue(value); + super(value); registerRpc(rpc); } @@ -68,74 +71,18 @@ public class ProgressIndicator extends AbstractField<Float> implements * @param contentSource */ public ProgressIndicator(Property contentSource) { - setPropertyDataSource(contentSource); + super(contentSource); registerRpc(rpc); } @Override - public void beforeClientResponse(boolean initial) { - super.beforeClientResponse(initial); - - getState().state = getValue(); - } - - /** - * Gets the value of the ProgressIndicator. Value of the ProgressIndicator - * is Float between 0 and 1. - * - * @return the Value of the ProgressIndicator. - * @see com.vaadin.ui.AbstractField#getValue() - */ - @Override - public Float getValue() { - return super.getValue(); - } - - /** - * Sets the value of the ProgressIndicator. Value of the ProgressIndicator - * is the Float between 0 and 1. - * - * @param newValue - * the New value of the ProgressIndicator. - * @see com.vaadin.ui.AbstractField#setValue() - */ - @Override - public void setValue(Float newValue) { - super.setValue(newValue); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.AbstractField#getType() - */ - @Override - public Class<Float> getType() { - return Float.class; - } - - @Override protected ProgressIndicatorState getState() { return (ProgressIndicatorState) super.getState(); } - /** - * Sets whether or not the ProgressIndicator is indeterminate. - * - * @param indeterminate - * true to set to indeterminate mode. - */ - public void setIndeterminate(boolean indeterminate) { - getState().indeterminate = indeterminate; - } - - /** - * Gets whether or not the ProgressIndicator is indeterminate. - * - * @return true to set to indeterminate mode. - */ - public boolean isIndeterminate() { - return getState().indeterminate; + @Override + protected ProgressIndicatorState getState(boolean markAsDirty) { + return (ProgressIndicatorState) super.getState(markAsDirty); } /** @@ -154,22 +101,6 @@ public class ProgressIndicator extends AbstractField<Float> implements * @return the interval in milliseconds. */ public int getPollingInterval() { - return getState().pollingInterval; - } - - /* - * Overridden to keep the shared state in sync with the AbstractField - * internal value. Should be removed once AbstractField is refactored to use - * shared state. - * - * See tickets #10921 and #11064. - */ - @Override - protected void setInternalValue(Float newValue) { - super.setInternalValue(newValue); - if (newValue == null) { - newValue = 0.0f; - } - getState().state = newValue; + return getState(false).pollingInterval; } } diff --git a/server/src/com/vaadin/ui/PushConfiguration.java b/server/src/com/vaadin/ui/PushConfiguration.java new file mode 100644 index 0000000000..a592b39bef --- /dev/null +++ b/server/src/com/vaadin/ui/PushConfiguration.java @@ -0,0 +1,282 @@ +/* + * 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.ui; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; + +import com.vaadin.server.VaadinSession; +import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.Transport; +import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; + +/** + * Provides method for configuring the push channel. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public interface PushConfiguration extends Serializable { + + /** + * Returns the mode of bidirectional ("push") communication that is used. + * + * @return The push mode. + */ + public PushMode getPushMode(); + + /** + * Sets the mode of bidirectional ("push") communication that should be + * used. + * <p> + * Add-on developers should note that this method is only meant for the + * application developer. An add-on should not set the push mode directly, + * rather instruct the user to set it. + * </p> + * + * @param pushMode + * The push mode to use. + * + * @throws IllegalArgumentException + * if the argument is null. + * @throws IllegalStateException + * if push support is not available. + */ + public void setPushMode(PushMode pushMode); + + /** + * Returns the primary transport type for push. + * <p> + * Note that if you set the transport type using + * {@link #setParameter(String, String)} to an unsupported type this method + * will return null. Supported types are defined by {@link Transport}. + * + * @return The primary transport type + */ + public Transport getTransport(); + + /** + * Sets the primary transport type for push. + * <p> + * Note that the new transport type will not be used until the push channel + * is disconnected and reconnected if already active. + * + * @param transport + * The primary transport type + */ + public void setTransport(Transport transport); + + /** + * Returns the fallback transport type for push. + * <p> + * Note that if you set the transport type using + * {@link #setParameter(String, String)} to an unsupported type this method + * will return null. Supported types are defined by {@link Transport}. + * + * @return The fallback transport type + */ + public Transport getFallbackTransport(); + + /** + * Sets the fallback transport type for push. + * <p> + * Note that the new transport type will not be used until the push channel + * is disconnected and reconnected if already active. + * + * @param fallbackTransport + * The fallback transport type + */ + public void setFallbackTransport(Transport fallbackTransport); + + /** + * Returns the given parameter, if set. + * <p> + * This method provides low level access to push parameters and is typically + * not needed for normal application development. + * + * @since 7.1 + * @param parameter + * The parameter name + * @return The parameter value or null if not set + */ + public String getParameter(String parameter); + + /** + * Returns the parameters which have been defined. + * + * @since 7.1 + * @return A collection of parameter names + */ + public Collection<String> getParameterNames(); + + /** + * Sets the given parameter. + * <p> + * This method provides low level access to push parameters and is typically + * not needed for normal application development. + * + * @since 7.1 + * @param parameter + * The parameter name + * @param value + * The value + */ + public void setParameter(String parameter, String value); + +} + +class PushConfigurationImpl implements PushConfiguration { + private UI ui; + + public PushConfigurationImpl(UI ui) { + this.ui = ui; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#getPushMode() + */ + @Override + public PushMode getPushMode() { + return getState(false).mode; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.PushConfiguration#setPushMode(com.vaadin.shared.communication + * .PushMode) + */ + @Override + public void setPushMode(PushMode pushMode) { + if (pushMode == null) { + throw new IllegalArgumentException("Push mode cannot be null"); + } + + if (pushMode.isEnabled()) { + VaadinSession session = ui.getSession(); + if (session != null && !session.getService().ensurePushAvailable()) { + throw new IllegalStateException( + "Push is not available. See previous log messages for more information."); + } + } + + /* + * Client-side will open a new connection or disconnect the old + * connection, so there's nothing more to do on the server at this + * point. + */ + getState().mode = pushMode; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#getTransport() + */ + @Override + public Transport getTransport() { + try { + return Transport + .valueOf(getParameter(PushConfigurationState.TRANSPORT_PARAM)); + } catch (IllegalArgumentException e) { + return null; + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.PushConfiguration#setTransport(com.vaadin.shared.ui.ui. + * Transport) + */ + @Override + public void setTransport(Transport transport) { + setParameter(PushConfigurationState.TRANSPORT_PARAM, + transport.getIdentifier()); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#getFallbackTransport() + */ + @Override + public Transport getFallbackTransport() { + try { + return Transport + .valueOf(getParameter(PushConfigurationState.FALLBACK_TRANSPORT_PARAM)); + } catch (IllegalArgumentException e) { + return null; + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.PushConfiguration#setFallbackTransport(com.vaadin.shared + * .ui.ui.Transport) + */ + @Override + public void setFallbackTransport(Transport fallbackTransport) { + setParameter(PushConfigurationState.FALLBACK_TRANSPORT_PARAM, + fallbackTransport.getIdentifier()); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#getParameter(java.lang.String) + */ + @Override + public String getParameter(String parameter) { + return getState(false).parameters.get(parameter); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#setParameter(java.lang.String, + * java.lang.String) + */ + @Override + public void setParameter(String parameter, String value) { + getState().parameters.put(parameter, value); + + } + + private PushConfigurationState getState() { + return ui.getState().pushConfiguration; + } + + private PushConfigurationState getState(boolean markAsDirty) { + return ui.getState(markAsDirty).pushConfiguration; + } + + @Override + public Collection<String> getParameterNames() { + return Collections + .unmodifiableCollection(ui.getState(false).pushConfiguration.parameters + .keySet()); + } + +} diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 0a4ed7c491..9135151089 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -21,7 +21,10 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.concurrent.Future; +import java.util.logging.Logger; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; @@ -29,6 +32,10 @@ import com.vaadin.event.ActionManager; import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.MouseEvents.ClickListener; import com.vaadin.navigator.Navigator; +import com.vaadin.server.ClientConnector; +import com.vaadin.server.ComponentSizeValidator; +import com.vaadin.server.ComponentSizeValidator.InvalidLayout; +import com.vaadin.server.LocaleService; import com.vaadin.server.Page; import com.vaadin.server.PaintException; import com.vaadin.server.PaintTarget; @@ -38,15 +45,18 @@ import com.vaadin.server.VaadinService; import com.vaadin.server.VaadinServlet; import com.vaadin.server.VaadinSession; import com.vaadin.server.communication.PushConnection; +import com.vaadin.shared.Connector; import com.vaadin.shared.EventId; import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.DebugWindowClientRpc; +import com.vaadin.shared.ui.ui.DebugWindowServerRpc; import com.vaadin.shared.ui.ui.ScrollClientRpc; import com.vaadin.shared.ui.ui.UIClientRpc; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.shared.ui.ui.UIServerRpc; import com.vaadin.shared.ui.ui.UIState; import com.vaadin.ui.Component.Focusable; +import com.vaadin.util.ConnectorHelper; import com.vaadin.util.CurrentInstance; /** @@ -86,7 +96,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements /** * The application to which this UI belongs */ - private VaadinSession session; + private volatile VaadinSession session; /** * List of windows in this UI. @@ -159,6 +169,40 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ } }; + private DebugWindowServerRpc debugRpc = new DebugWindowServerRpc() { + @Override + public void showServerDebugInfo(Connector connector) { + String info = ConnectorHelper + .getDebugInformation((ClientConnector) connector); + getLogger().info(info); + } + + @Override + public void analyzeLayouts() { + // TODO Move to client side + List<InvalidLayout> invalidSizes = ComponentSizeValidator + .validateLayouts(UI.this); + StringBuilder json = new StringBuilder(); + json.append("{\"invalidLayouts\":"); + json.append("["); + + if (invalidSizes != null) { + boolean first = true; + for (InvalidLayout invalidSize : invalidSizes) { + if (!first) { + json.append(","); + } else { + first = false; + } + invalidSize.reportErrors(json, System.err); + } + } + json.append("]}"); + getRpcProxy(DebugWindowClientRpc.class).reportLayoutProblems( + json.toString()); + } + + }; /** * Timestamp keeping track of the last heartbeat of this UI. Updated to the @@ -171,6 +215,8 @@ public abstract class UI extends AbstractSingleComponentContainer implements private TooltipConfiguration tooltipConfiguration = new TooltipConfigurationImpl( this); + private PushConfiguration pushConfiguration = new PushConfigurationImpl( + this); /** * Creates a new empty UI without a caption. The content of the UI must be @@ -191,6 +237,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ public UI(Component content) { registerRpc(rpc); + registerRpc(debugRpc); setSizeFull(); setContent(content); } @@ -418,7 +465,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements throw new NullPointerException("Argument must not be null"); } - if (window.getUI() != null && window.getUI().getSession() != null) { + if (window.isAttached()) { throw new IllegalArgumentException( "Window is already attached to an application."); } @@ -493,6 +540,9 @@ public abstract class UI extends AbstractSingleComponentContainer implements private boolean hasPendingPush = false; + private LocaleService localeService = new LocaleService(this, + getState(false).localeServiceState); + /** * This method is used by Component.Focusable objects to request focus to * themselves. Focus renders must be handled at window level (instead of @@ -1051,6 +1101,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements @Override public void attach() { super.attach(); + getLocaleService().addLocale(getLocale()); } /** @@ -1098,24 +1149,30 @@ public abstract class UI extends AbstractSingleComponentContainer implements } /** - * Provides exclusive access to this UI from outside a request handling - * thread. - * <p> - * The given runnable is executed while holding the session lock to ensure - * exclusive access to this UI and its session. The UI and related thread - * locals are set properly before executing the runnable. - * </p> + * Locks the session of this UI and runs the provided Runnable right away. * <p> - * RPC handlers for components inside this UI do not need this method as the - * session is automatically locked by the framework during request handling. + * It is generally recommended to use {@link #access(Runnable)} instead of + * this method for accessing a session from a different thread as + * {@link #access(Runnable)} can be used while holding the lock of another + * session. To avoid causing deadlocks, this methods throws an exception if + * it is detected than another session is also locked by the current thread. * </p> * <p> - * Note that calling this method while another session is locked by the - * current thread will cause an exception. This is to prevent deadlock - * situations when two threads have locked one session each and are both - * waiting for the lock for the other session. + * This method behaves differently than {@link #access(Runnable)} in some + * situations: + * <ul> + * <li>If the current thread is currently holding the lock of the session, + * {@link #accessSynchronously(Runnable)} runs the task right away whereas + * {@link #access(Runnable)} defers the task to a later point in time.</li> + * <li>If some other thread is currently holding the lock for the session, + * {@link #accessSynchronously(Runnable)} blocks while waiting for the lock + * to be available whereas {@link #access(Runnable)} defers the task to a + * later point in time.</li> + * </ul> * </p> * + * @since 7.1 + * * @param runnable * the runnable which accesses the UI * @throws UIDetachedException @@ -1124,11 +1181,11 @@ public abstract class UI extends AbstractSingleComponentContainer implements * @throws IllegalStateException * if the current thread holds the lock for another session * - * @see #getCurrent() - * @see VaadinSession#access(Runnable) - * @see VaadinSession#lock() + * @see #access(Runnable) + * @see VaadinSession#accessSynchronously(Runnable) */ - public void access(Runnable runnable) throws UIDetachedException { + public void accessSynchronously(Runnable runnable) + throws UIDetachedException { Map<Class<?>, CurrentInstance> old = null; VaadinSession session = getSession(); @@ -1146,24 +1203,76 @@ public abstract class UI extends AbstractSingleComponentContainer implements // acquired the lock. throw new UIDetachedException(); } - old = CurrentInstance.setThreadLocals(this); + old = CurrentInstance.setCurrent(this); runnable.run(); } finally { session.unlock(); if (old != null) { - CurrentInstance.restoreThreadLocals(old); + CurrentInstance.restoreInstances(old); } } } /** - * @deprecated As of 7.1.0.beta1, use {@link #access(Runnable)} instead. - * This method will be removed before the final 7.1.0 release. + * Provides exclusive access to this UI from outside a request handling + * thread. + * <p> + * The given runnable is executed while holding the session lock to ensure + * exclusive access to this UI. If the session is not locked, the lock will + * be acquired and the runnable is run right away. If the session is + * currently locked, the runnable will be run before that lock is released. + * </p> + * <p> + * RPC handlers for components inside this UI do not need to use this method + * as the session is automatically locked by the framework during RPC + * handling. + * </p> + * <p> + * Please note that the runnable might be invoked on a different thread or + * later on the current thread, which means that custom thread locals might + * not have the expected values when the runnable is executed. Inheritable + * values in {@link CurrentInstance} will have the same values as when this + * method was invoked. {@link UI#getCurrent()}, + * {@link VaadinSession#getCurrent()} and {@link VaadinService#getCurrent()} + * are set according to this UI before executing the runnable. + * Non-inheritable CurrentInstance values including + * {@link VaadinService#getCurrentRequest()} and + * {@link VaadinService#getCurrentResponse()} will not be defined. + * </p> + * <p> + * The returned future can be used to check for task completion and to + * cancel the task. + * </p> + * + * @see #getCurrent() + * @see #accessSynchronously(Runnable) + * @see VaadinSession#access(Runnable) + * @see VaadinSession#lock() + * + * @since 7.1 + * + * @param runnable + * the runnable which accesses the UI + * @throws UIDetachedException + * if the UI is not attached to a session (and locking can + * therefore not be done) + * @return a future that can be used to check for task completion and to + * cancel the task */ - @Deprecated - public void runSafely(Runnable runnable) throws UIDetachedException { - access(runnable); + public Future<Void> access(final Runnable runnable) { + VaadinSession session = getSession(); + + if (session == null) { + throw new UIDetachedException(); + } + + return session.access(new Runnable() { + @Override + public void run() { + accessSynchronously(runnable); + } + }); } /** @@ -1204,12 +1313,20 @@ public abstract class UI extends AbstractSingleComponentContainer implements VaadinSession session = getSession(); if (session != null) { assert session.hasLock(); + + /* + * Purge the pending access queue as it might mark a connector as + * dirty when the push would otherwise be ignored because there are + * no changes to push. + */ + session.getService().runPendingAccessTasks(session); + if (!getConnectorTracker().hasDirtyConnectors()) { // Do not push if there is nothing to push return; } - if (!getPushMode().isEnabled()) { + if (!getPushConfiguration().getPushMode().isEnabled()) { throw new IllegalStateException("Push not enabled"); } @@ -1237,7 +1354,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ public void setPushConnection(PushConnection pushConnection) { // If pushMode is disabled then there should never be a pushConnection - assert (getPushMode().isEnabled() || pushConnection == null); + assert (getPushConfiguration().getPushMode().isEnabled() || pushConnection == null); if (pushConnection == this.pushConnection) { return; @@ -1286,51 +1403,13 @@ public abstract class UI extends AbstractSingleComponentContainer implements } /** - * Returns the mode of bidirectional ("push") communication that is used in - * this UI. - * - * @return The push mode. - */ - public PushMode getPushMode() { - return getState(false).pushMode; - } - - /** - * Sets the mode of bidirectional ("push") communication that should be used - * in this UI. - * <p> - * Add-on developers should note that this method is only meant for the - * application developer. An add-on should not set the push mode directly, - * rather instruct the user to set it. - * </p> - * - * @param pushMode - * The push mode to use. + * Retrieves the object used for configuring the push channel. * - * @throws IllegalArgumentException - * if the argument is null. - * @throws IllegalStateException - * if push support is not available. + * @since 7.1 + * @return The instance used for push configuration */ - public void setPushMode(PushMode pushMode) { - if (pushMode == null) { - throw new IllegalArgumentException("Push mode cannot be null"); - } - - if (pushMode.isEnabled()) { - VaadinSession session = getSession(); - if (session != null && !session.getService().ensurePushAvailable()) { - throw new IllegalStateException( - "Push is not available. See previous log messages for more information."); - } - } - - /* - * Client-side will open a new connection or disconnect the old - * connection, so there's nothing more to do on the server at this - * point. - */ - getState().pushMode = pushMode; + public PushConfiguration getPushConfiguration() { + return pushConfiguration; } /** @@ -1357,4 +1436,19 @@ public abstract class UI extends AbstractSingleComponentContainer implements public void setOverlayContainerLabel(String overlayContainerLabel) { getState().overlayContainerLabel = overlayContainerLabel; } + + /** + * Returns the locale service which handles transmission of Locale data to + * the client. + * + * @since 7.1 + * @return The LocaleService for this UI + */ + public LocaleService getLocaleService() { + return localeService; + } + + private static Logger getLogger() { + return Logger.getLogger(UI.class.getName()); + } } diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java index 2902585f56..de8c5db195 100644 --- a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java @@ -95,7 +95,7 @@ public class ColorPickerHistory extends CustomComponent implements @SuppressWarnings("unchecked") private ArrayBlockingQueue<Color> getColorHistory() { - if (getSession() != null) { + if (isAttached()) { Object colorHistory = getSession().getAttribute( "colorPickerHistory"); if (colorHistory instanceof ArrayBlockingQueue<?>) { |