summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/com/vaadin/ui')
-rw-r--r--server/src/com/vaadin/ui/AbstractComponent.java9
-rw-r--r--server/src/com/vaadin/ui/AbstractField.java15
-rw-r--r--server/src/com/vaadin/ui/Calendar.java31
-rw-r--r--server/src/com/vaadin/ui/Label.java9
-rw-r--r--server/src/com/vaadin/ui/LegacyWindow.java2
-rw-r--r--server/src/com/vaadin/ui/LoginForm.java2
-rw-r--r--server/src/com/vaadin/ui/ProgressBar.java152
-rw-r--r--server/src/com/vaadin/ui/ProgressIndicator.java105
-rw-r--r--server/src/com/vaadin/ui/PushConfiguration.java282
-rw-r--r--server/src/com/vaadin/ui/UI.java238
-rw-r--r--server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java2
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<?>) {