import java.lang.annotation.Target;
import com.vaadin.server.UIProvider;
+import com.vaadin.ui.UI;
/**
* Marks a UI that should be retained when the user refreshed the browser
* adding this annotation to a UI class, the framework will instead reuse the
* current UI instance when a reload is detected.
* <p>
+ * Whenever a request is received that reloads a preserved UI, the UI's
+ * {@link UI#reinit(com.vaadin.server.VaadinRequest) reinit} method is invoked
+ * by the framework.
+ * <p>
* By using
* {@link UIProvider#isPreservedOnRefresh(com.vaadin.server.UICreateEvent)}, the
* decision can also be made dynamically based on other parameters than only
import com.vaadin.shared.ui.ui.PageState;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.shared.ui.ui.UIState;
+import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.JavaScript;
import com.vaadin.ui.LegacyWindow;
import com.vaadin.ui.Link;
}
public void init(VaadinRequest request) {
+ // NOTE: UI.reinit makes assumptions about the semantics of this method.
+ // It should be kept in sync if this method is changed.
+
// Extract special parameter sent by vaadinBootstrap.js
String location = request.getParameter("v-loc");
String clientWidth = request.getParameter("v-cw");
}
/**
- * Updates the internal state with the given values. Does not resize the
- * Page or browser window.
- *
+ * For internal use only. Updates the internal state with the given values.
+ * Does not resize the Page or browser window.
+ *
+ * @deprecated As of 7.2, use
+ * {@link #updateBrowserWindowSize(int, int, boolean)} instead.
+ *
* @param width
- * The new width
+ * the new browser window width
* @param height
- * The new height
+ * the new browse window height
*/
+ @Deprecated
public void updateBrowserWindowSize(int width, int height) {
- boolean fireEvent = false;
+ updateBrowserWindowSize(width, height, true);
+ }
+
+ /**
+ * For internal use only. Updates the internal state with the given values.
+ * Does not resize the Page or browser window.
+ *
+ * @since 7.2
+ *
+ * @param width
+ * the new browser window width
+ * @param height
+ * the new browser window height
+ * @param fireEvents
+ * whether to fire {@link BrowserWindowResizeEvent} if the size
+ * changes
+ */
+ public void updateBrowserWindowSize(int width, int height,
+ boolean fireEvents) {
+ boolean sizeChanged = false;
if (width != browserWindowWidth) {
browserWindowWidth = width;
- fireEvent = true;
+ sizeChanged = true;
}
if (height != browserWindowHeight) {
browserWindowHeight = height;
- fireEvent = true;
+ sizeChanged = true;
}
- if (fireEvent) {
+ if (fireEvents && sizeChanged) {
fireEvent(new BrowserWindowResizeEvent(this, browserWindowWidth,
browserWindowHeight));
}
/**
* For internal use only. Used to update the server-side location when the
* client-side location changes.
+ *
+ * @deprecated As of 7.2, use {@link #updateLocation(String, boolean)}
+ * instead.
+ *
+ * @param location
+ * the new location URI
*/
+ @Deprecated
public void updateLocation(String location) {
+ updateLocation(location, true);
+ }
+
+ /**
+ * For internal use only. Used to update the server-side location when the
+ * client-side location changes.
+ *
+ * @since 7.2
+ *
+ * @param location
+ * the new location URI
+ * @param fireEvents
+ * whether to fire {@link UriFragmentChangedEvent} if the URI
+ * fragment changes
+ */
+ public void updateLocation(String location, boolean fireEvents) {
try {
String oldUriFragment = this.location.getFragment();
this.location = new URI(location);
String newUriFragment = this.location.getFragment();
- if (newUriFragment == null ? oldUriFragment != null
- : !newUriFragment.equals(oldUriFragment)) {
+ if (fireEvents
+ && !SharedUtil.equals(oldUriFragment, newUriFragment)) {
fireEvent(new UriFragmentChangedEvent(this, newUriFragment));
}
} catch (URISyntaxException e) {
* detect that the application is opened in a browser window where it has
* previously been open. The framework attempts to discover this by checking
* the value of window.name in the browser.
+ * <p>
+ * Whenever a preserved UI is reused, its
+ * {@link UI#reinit(com.vaadin.server.VaadinRequest) reinit} method is
+ * invoked by the framework first.
+ *
*
* @param event
* the UI create event with information about the UI and the
*/
private void reinitUI(UI ui, VaadinRequest request) {
UI.setCurrent(ui);
-
- // Fire fragment change if the fragment has changed
- String location = request.getParameter("v-loc");
- if (location != null) {
- ui.getPage().updateLocation(location);
- }
+ ui.doReinit(request);
}
/**
package com.vaadin.ui;
+import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
+import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler;
import com.vaadin.event.ActionManager;
public void resize(int viewWidth, int viewHeight, int windowWidth,
int windowHeight) {
// TODO We're not doing anything with the view dimensions
- getPage().updateBrowserWindowSize(windowWidth, windowHeight);
+ getPage().updateBrowserWindowSize(windowWidth, windowHeight, true);
}
@Override
if (variables.containsKey(UIConstants.LOCATION_VARIABLE)) {
String location = (String) variables
.get(UIConstants.LOCATION_VARIABLE);
- getPage().updateLocation(location);
+ getPage().updateLocation(location, true);
}
}
*/
protected abstract void init(VaadinRequest request);
+ /**
+ * Internal reinitialization method, should not be overridden.
+ *
+ * @since 7.2
+ * @param request
+ * the request that caused this UI to be reloaded
+ */
+ public void doReinit(VaadinRequest request) {
+ // This is a horrible hack. We want to have the most recent location and
+ // browser window size available in reinit(), but we want to call
+ // listeners, if any, only after reinit(). So we momentarily assign the
+ // old values back before setting the new values again to ensure the
+ // events are properly fired.
+
+ Page page = getPage();
+
+ URI oldLocation = page.getLocation();
+ int oldWidth = page.getBrowserWindowWidth();
+ int oldHeight = page.getBrowserWindowHeight();
+
+ page.init(request);
+
+ reinit(request);
+
+ URI newLocation = page.getLocation();
+ int newWidth = page.getBrowserWindowWidth();
+ int newHeight = page.getBrowserWindowHeight();
+
+ page.updateLocation(oldLocation.toString(), false);
+ page.updateBrowserWindowSize(oldWidth, oldHeight, false);
+
+ page.updateLocation(newLocation.toString(), true);
+ page.updateBrowserWindowSize(newWidth, newHeight, true);
+ }
+
+ /**
+ * Reinitializes this UI after a browser refresh if the UI is set to be
+ * preserved on refresh, typically using the {@link PreserveOnRefresh}
+ * annotation. This method is intended to be overridden by subclasses if
+ * needed; the default implementation is empty.
+ * <p>
+ * The {@link VaadinRequest} can be used to get information about the
+ * request that caused this UI to be reloaded.
+ *
+ * @since 7.2
+ * @param request
+ * the request that caused this UI to be reloaded
+ */
+ protected void reinit(VaadinRequest request) {
+ }
+
/**
* Sets the thread local for the current UI. This method is used by the
* framework to set the current application whenever a new request is
--- /dev/null
+/*
+ * 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 org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.server.Page.BrowserWindowResizeEvent;
+import com.vaadin.server.Page.BrowserWindowResizeListener;
+import com.vaadin.server.Page.UriFragmentChangedEvent;
+import com.vaadin.server.Page.UriFragmentChangedListener;
+import com.vaadin.server.VaadinRequest;
+
+public class UIInitReinitTest {
+
+ private boolean initCalled;
+ private boolean reinitCalled;
+ private boolean fragmentChangeCalled;
+ private boolean browserWindowResizeCalled;
+
+ private class TestUI extends UI implements UriFragmentChangedListener,
+ BrowserWindowResizeListener {
+ @Override
+ protected void init(VaadinRequest request) {
+ getPage().addBrowserWindowResizeListener(this);
+ getPage().addUriFragmentChangedListener(this);
+
+ initCalled = true;
+
+ Assert.assertEquals("foo", getPage().getUriFragment());
+ Assert.assertEquals(100, getPage().getBrowserWindowWidth());
+ Assert.assertEquals(100, getPage().getBrowserWindowHeight());
+
+ Assert.assertFalse(fragmentChangeCalled);
+ Assert.assertFalse(browserWindowResizeCalled);
+ }
+
+ @Override
+ protected void reinit(VaadinRequest request) {
+ reinitCalled = true;
+
+ Assert.assertEquals("bar", getPage().getUriFragment());
+ Assert.assertEquals(200, getPage().getBrowserWindowWidth());
+ Assert.assertEquals(200, getPage().getBrowserWindowHeight());
+
+ Assert.assertFalse(fragmentChangeCalled);
+ Assert.assertFalse(browserWindowResizeCalled);
+ }
+
+ @Override
+ public void browserWindowResized(BrowserWindowResizeEvent event) {
+ Assert.assertEquals(200, event.getWidth());
+ Assert.assertEquals(200, event.getHeight());
+ browserWindowResizeCalled = true;
+ }
+
+ @Override
+ public void uriFragmentChanged(UriFragmentChangedEvent event) {
+ Assert.assertEquals("bar", event.getUriFragment());
+ fragmentChangeCalled = true;
+ }
+ };
+
+ @Before
+ public void setUp() {
+ initCalled = reinitCalled = fragmentChangeCalled = browserWindowResizeCalled = false;
+ }
+
+ @Test
+ public void testListenersCalled() {
+ IMocksControl control = EasyMock.createNiceControl();
+
+ VaadinRequest initRequest = control.createMock(VaadinRequest.class);
+ EasyMock.expect(initRequest.getParameter("v-loc")).andReturn(
+ "http://example.com/#foo");
+ EasyMock.expect(initRequest.getParameter("v-cw")).andReturn("100");
+ EasyMock.expect(initRequest.getParameter("v-ch")).andReturn("100");
+
+ VaadinRequest reinitRequest = control.createMock(VaadinRequest.class);
+ EasyMock.expect(reinitRequest.getParameter("v-loc")).andReturn(
+ "http://example.com/#bar");
+ EasyMock.expect(reinitRequest.getParameter("v-cw")).andReturn("200");
+ EasyMock.expect(reinitRequest.getParameter("v-ch")).andReturn("200");
+
+ control.replay();
+
+ UI ui = new TestUI();
+ ui.doInit(initRequest, 0, "");
+
+ Assert.assertTrue(initCalled);
+ Assert.assertFalse(fragmentChangeCalled);
+ Assert.assertFalse(browserWindowResizeCalled);
+
+ ui.doReinit(reinitRequest);
+
+ Assert.assertTrue(reinitCalled);
+ Assert.assertTrue(fragmentChangeCalled);
+ Assert.assertTrue(browserWindowResizeCalled);
+ }
+}
--- /dev/null
+/*
+ * 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.ui;
+
+import com.vaadin.annotations.PreserveOnRefresh;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Label;
+
+@PreserveOnRefresh
+public class UIReinit extends AbstractTestUI {
+
+ public static final String REINIT_ID = "reinit";
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ }
+
+ @Override
+ protected void reinit(VaadinRequest request) {
+ Label l = new Label("Reinit!");
+ l.setId(REINIT_ID);
+ addComponent(l);
+ }
+
+ @Override
+ public String getTestDescription() {
+ return "UI reinit after refresh";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(12191);
+ }
+}
--- /dev/null
+/*
+ * 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.ui;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.testbench.By;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class UIReinitTest extends MultiBrowserTest {
+
+ @Test
+ public void testUIReinit() {
+ openTestURL();
+ Assert.assertFalse(reinitLabelExists());
+ // Reload the page; UI.reinit should be invoked
+ openTestURL();
+ Assert.assertTrue(reinitLabelExists());
+ }
+
+ private boolean reinitLabelExists() {
+ return !getDriver().findElements(By.id(UIReinit.REINIT_ID)).isEmpty();
+ }
+}