import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.ui.UnknownComponentConnector;
-import com.vaadin.client.ui.UI.UIConnector;
+import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.server.ClientConnector;
import com.vaadin.shared.Connector;
import com.vaadin.shared.ui.Connect;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.AbstractConnector;
import com.vaadin.client.ui.VContextMenu;
-import com.vaadin.client.ui.UI.UIConnector;
import com.vaadin.client.ui.dd.VDragAndDropManager;
import com.vaadin.client.ui.notification.VNotification;
import com.vaadin.client.ui.notification.VNotification.HideEvent;
+import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.client.ui.window.WindowConnector;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.ComponentState;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ui.SubPartAware;
-import com.vaadin.client.ui.UI.VUI;
import com.vaadin.client.ui.gridlayout.VGridLayout;
import com.vaadin.client.ui.orderedlayout.VMeasuringOrderedLayout;
import com.vaadin.client.ui.tabsheet.VTabsheetPanel;
+import com.vaadin.client.ui.ui.VUI;
import com.vaadin.client.ui.window.VWindow;
import com.vaadin.client.ui.window.WindowConnector;
import com.vaadin.shared.ComponentState;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ui.VLazyExecutor;
import com.vaadin.client.ui.VOverlay;
-import com.vaadin.client.ui.UI.UIConnector;
import com.vaadin.client.ui.notification.VNotification;
+import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.client.ui.window.WindowConnector;
import com.vaadin.shared.Version;
import com.vaadin.client.metadata.NoDataException;
import com.vaadin.client.metadata.Type;
import com.vaadin.client.metadata.TypeData;
-import com.vaadin.client.ui.UI.UIConnector;
import com.vaadin.client.ui.datefield.PopupDateFieldConnector;
+import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.shared.ComponentConstants;
import com.vaadin.shared.ComponentState;
import com.vaadin.shared.Connector;
+++ /dev/null
-/*
- * Copyright 2011 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.client.ui.UI;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.dom.client.NativeEvent;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.dom.client.Style.Position;
-import com.google.gwt.event.logical.shared.ResizeEvent;
-import com.google.gwt.event.logical.shared.ResizeHandler;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.History;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.web.bindery.event.shared.HandlerRegistration;
-import com.vaadin.client.ApplicationConnection;
-import com.vaadin.client.BrowserInfo;
-import com.vaadin.client.ComponentConnector;
-import com.vaadin.client.ConnectorHierarchyChangeEvent;
-import com.vaadin.client.ConnectorMap;
-import com.vaadin.client.Focusable;
-import com.vaadin.client.Paintable;
-import com.vaadin.client.UIDL;
-import com.vaadin.client.VConsole;
-import com.vaadin.client.communication.RpcProxy;
-import com.vaadin.client.communication.StateChangeEvent;
-import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
-import com.vaadin.client.ui.AbstractComponentContainerConnector;
-import com.vaadin.client.ui.ClickEventHandler;
-import com.vaadin.client.ui.ShortcutActionHandler;
-import com.vaadin.client.ui.layout.MayScrollChildren;
-import com.vaadin.client.ui.notification.VNotification;
-import com.vaadin.client.ui.window.WindowConnector;
-import com.vaadin.shared.MouseEventDetails;
-import com.vaadin.shared.ui.ComponentStateUtil;
-import com.vaadin.shared.ui.Connect;
-import com.vaadin.shared.ui.Connect.LoadStyle;
-import com.vaadin.shared.ui.ui.PageClientRpc;
-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.UI;
-
-@Connect(value = UI.class, loadStyle = LoadStyle.EAGER)
-public class UIConnector extends AbstractComponentContainerConnector implements
- Paintable, MayScrollChildren {
-
- private UIServerRpc rpc = RpcProxy.create(UIServerRpc.class, this);
-
- private HandlerRegistration childStateChangeHandlerRegistration;
-
- private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
- @Override
- public void onStateChanged(StateChangeEvent stateChangeEvent) {
- // TODO Should use a more specific handler that only reacts to
- // size changes
- onChildSizeChange();
- }
- };
-
- @Override
- protected void init() {
- super.init();
- registerRpc(PageClientRpc.class, new PageClientRpc() {
- @Override
- public void setTitle(String title) {
- com.google.gwt.user.client.Window.setTitle(title);
- }
- });
- getWidget().addResizeHandler(new ResizeHandler() {
- @Override
- public void onResize(ResizeEvent event) {
- rpc.resize(event.getHeight(), event.getWidth(),
- Window.getClientWidth(), Window.getClientHeight());
- if (getState().immediate) {
- getConnection().sendPendingVariableChanges();
- }
- }
- });
- }
-
- @Override
- public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
- ConnectorMap paintableMap = ConnectorMap.get(getConnection());
- getWidget().rendering = true;
- getWidget().id = getConnectorId();
- boolean firstPaint = getWidget().connection == null;
- getWidget().connection = client;
-
- getWidget().immediate = getState().immediate;
- getWidget().resizeLazy = uidl.hasAttribute(UIConstants.RESIZE_LAZY);
- String newTheme = uidl.getStringAttribute("theme");
- if (getWidget().theme != null && !newTheme.equals(getWidget().theme)) {
- // Complete page refresh is needed due css can affect layout
- // calculations etc
- getWidget().reloadHostPage();
- } else {
- getWidget().theme = newTheme;
- }
- // this also implicitly removes old styles
- String styles = "";
- styles += getWidget().getStylePrimaryName() + " ";
- if (ComponentStateUtil.hasStyles(getState())) {
- for (String style : getState().styles) {
- styles += style + " ";
- }
- }
- if (!client.getConfiguration().isStandalone()) {
- styles += getWidget().getStylePrimaryName() + "-embedded";
- }
- getWidget().setStyleName(styles.trim());
-
- getWidget().makeScrollable();
-
- clickEventHandler.handleEventHandlerRegistration();
-
- // Process children
- int childIndex = 0;
-
- // Open URL:s
- boolean isClosed = false; // was this window closed?
- while (childIndex < uidl.getChildCount()
- && "open".equals(uidl.getChildUIDL(childIndex).getTag())) {
- final UIDL open = uidl.getChildUIDL(childIndex);
- final String url = client.translateVaadinUri(open
- .getStringAttribute("src"));
- final String target = open.getStringAttribute("name");
- if (target == null) {
- // source will be opened to this browser window, but we may have
- // to finish rendering this window in case this is a download
- // (and window stays open).
- Scheduler.get().scheduleDeferred(new Command() {
- @Override
- public void execute() {
- VUI.goTo(url);
- }
- });
- } else if ("_self".equals(target)) {
- // This window is closing (for sure). Only other opens are
- // relevant in this change. See #3558, #2144
- isClosed = true;
- VUI.goTo(url);
- } else {
- String options;
- if (open.hasAttribute("border")) {
- if (open.getStringAttribute("border").equals("minimal")) {
- options = "menubar=yes,location=no,status=no";
- } else {
- options = "menubar=no,location=no,status=no";
- }
-
- } else {
- options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes";
- }
-
- if (open.hasAttribute("width")) {
- int w = open.getIntAttribute("width");
- options += ",width=" + w;
- }
- if (open.hasAttribute("height")) {
- int h = open.getIntAttribute("height");
- options += ",height=" + h;
- }
-
- Window.open(url, target, options);
- }
- childIndex++;
- }
- if (isClosed) {
- // don't render the content, something else will be opened to this
- // browser view
- getWidget().rendering = false;
- return;
- }
-
- // Handle other UIDL children
- UIDL childUidl;
- while ((childUidl = uidl.getChildUIDL(childIndex++)) != null) {
- String tag = childUidl.getTag().intern();
- if (tag == "actions") {
- if (getWidget().actionHandler == null) {
- getWidget().actionHandler = new ShortcutActionHandler(
- getWidget().id, client);
- }
- getWidget().actionHandler.updateActionMap(childUidl);
- } else if (tag == "notifications") {
- for (final Iterator<?> it = childUidl.getChildIterator(); it
- .hasNext();) {
- final UIDL notification = (UIDL) it.next();
- VNotification.showNotification(client, notification);
- }
- }
- }
-
- if (uidl.hasAttribute("focused")) {
- // set focused component when render phase is finished
- Scheduler.get().scheduleDeferred(new Command() {
- @Override
- public void execute() {
- ComponentConnector paintable = (ComponentConnector) uidl
- .getPaintableAttribute("focused", getConnection());
-
- final Widget toBeFocused = paintable.getWidget();
- /*
- * Two types of Widgets can be focused, either implementing
- * GWT HasFocus of a thinner Vaadin specific Focusable
- * interface.
- */
- if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
- final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused;
- toBeFocusedWidget.setFocus(true);
- } else if (toBeFocused instanceof Focusable) {
- ((Focusable) toBeFocused).focus();
- } else {
- VConsole.log("Could not focus component");
- }
- }
- });
- }
-
- // Add window listeners on first paint, to prevent premature
- // variablechanges
- if (firstPaint) {
- Window.addWindowClosingHandler(getWidget());
- Window.addResizeHandler(getWidget());
- }
-
- // finally set scroll position from UIDL
- if (uidl.hasVariable("scrollTop")) {
- getWidget().scrollable = true;
- getWidget().scrollTop = uidl.getIntVariable("scrollTop");
- DOM.setElementPropertyInt(getWidget().getElement(), "scrollTop",
- getWidget().scrollTop);
- getWidget().scrollLeft = uidl.getIntVariable("scrollLeft");
- DOM.setElementPropertyInt(getWidget().getElement(), "scrollLeft",
- getWidget().scrollLeft);
- } else {
- getWidget().scrollable = false;
- }
-
- if (uidl.hasAttribute("scrollTo")) {
- final ComponentConnector connector = (ComponentConnector) uidl
- .getPaintableAttribute("scrollTo", getConnection());
- scrollIntoView(connector);
- }
-
- if (uidl.hasAttribute(UIConstants.FRAGMENT_VARIABLE)) {
- getWidget().currentFragment = uidl
- .getStringAttribute(UIConstants.FRAGMENT_VARIABLE);
- if (!getWidget().currentFragment.equals(History.getToken())) {
- History.newItem(getWidget().currentFragment, true);
- }
- } else {
- // Initial request for which the server doesn't yet have a fragment
- // (and haven't shown any interest in getting one)
- getWidget().currentFragment = History.getToken();
-
- // Include current fragment in the next request
- client.updateVariable(getWidget().id,
- UIConstants.FRAGMENT_VARIABLE, getWidget().currentFragment,
- false);
- }
-
- if (firstPaint) {
- // Queue the initial window size to be sent with the following
- // request.
- getWidget().sendClientResized();
- }
- getWidget().rendering = false;
- }
-
- public void init(String rootPanelId,
- ApplicationConnection applicationConnection) {
- DOM.sinkEvents(getWidget().getElement(), Event.ONKEYDOWN
- | Event.ONSCROLL);
-
- // iview is focused when created so element needs tabIndex
- // 1 due 0 is at the end of natural tabbing order
- DOM.setElementProperty(getWidget().getElement(), "tabIndex", "1");
-
- RootPanel root = RootPanel.get(rootPanelId);
-
- // Remove the v-app-loading or any splash screen added inside the div by
- // the user
- root.getElement().setInnerHTML("");
-
- root.addStyleName("v-theme-"
- + applicationConnection.getConfiguration().getThemeName());
-
- root.add(getWidget());
-
- if (applicationConnection.getConfiguration().isStandalone()) {
- // set focus to iview element by default to listen possible keyboard
- // shortcuts. For embedded applications this is unacceptable as we
- // don't want to steal focus from the main page nor we don't want
- // side-effects from focusing (scrollIntoView).
- getWidget().getElement().focus();
- }
- }
-
- private ClickEventHandler clickEventHandler = new ClickEventHandler(this) {
-
- @Override
- protected void fireClick(NativeEvent event,
- MouseEventDetails mouseDetails) {
- rpc.click(mouseDetails);
- }
-
- };
-
- @Override
- public void updateCaption(ComponentConnector component) {
- // NOP The main view never draws caption for its layout
- }
-
- @Override
- public VUI getWidget() {
- return (VUI) super.getWidget();
- }
-
- protected ComponentConnector getContent() {
- return (ComponentConnector) getState().content;
- }
-
- protected void onChildSizeChange() {
- ComponentConnector child = getContent();
- Style childStyle = child.getWidget().getElement().getStyle();
- /*
- * Must set absolute position if the child has relative height and
- * there's a chance of horizontal scrolling as some browsers will
- * otherwise not take the scrollbar into account when calculating the
- * height. Assuming v-view does not have an undefined width for now, see
- * #8460.
- */
- if (child.isRelativeHeight() && !BrowserInfo.get().isIE9()) {
- childStyle.setPosition(Position.ABSOLUTE);
- } else {
- childStyle.clearPosition();
- }
- }
-
- /**
- * Checks if the given sub window is a child of this UI Connector
- *
- * @deprecated Should be replaced by a more generic mechanism for getting
- * non-ComponentConnector children
- * @param wc
- * @return
- */
- @Deprecated
- public boolean hasSubWindow(WindowConnector wc) {
- return getChildComponents().contains(wc);
- }
-
- /**
- * Return an iterator for current subwindows. This method is meant for
- * testing purposes only.
- *
- * @return
- */
- public List<WindowConnector> getSubWindows() {
- ArrayList<WindowConnector> windows = new ArrayList<WindowConnector>();
- for (ComponentConnector child : getChildComponents()) {
- if (child instanceof WindowConnector) {
- windows.add((WindowConnector) child);
- }
- }
- return windows;
- }
-
- @Override
- public UIState getState() {
- return (UIState) super.getState();
- }
-
- @Override
- public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
- super.onConnectorHierarchyChange(event);
-
- ComponentConnector oldChild = null;
- ComponentConnector newChild = getContent();
-
- for (ComponentConnector c : event.getOldChildren()) {
- if (!(c instanceof WindowConnector)) {
- oldChild = c;
- break;
- }
- }
-
- if (oldChild != newChild) {
- if (childStateChangeHandlerRegistration != null) {
- childStateChangeHandlerRegistration.removeHandler();
- childStateChangeHandlerRegistration = null;
- }
- getWidget().setWidget(newChild.getWidget());
- childStateChangeHandlerRegistration = newChild
- .addStateChangeHandler(childStateChangeHandler);
- // Must handle new child here as state change events are already
- // fired
- onChildSizeChange();
- }
-
- for (ComponentConnector c : getChildComponents()) {
- if (c instanceof WindowConnector) {
- WindowConnector wc = (WindowConnector) c;
- wc.setWindowOrderAndPosition();
- }
- }
-
- // Close removed sub windows
- for (ComponentConnector c : event.getOldChildren()) {
- if (c.getParent() != this && c instanceof WindowConnector) {
- ((WindowConnector) c).getWidget().hide();
- }
- }
- }
-
- /**
- * Tries to scroll the viewport so that the given connector is in view.
- *
- * @param componentConnector
- * The connector which should be visible
- *
- */
- public void scrollIntoView(final ComponentConnector componentConnector) {
- if (componentConnector == null) {
- return;
- }
-
- Scheduler.get().scheduleDeferred(new Command() {
- @Override
- public void execute() {
- componentConnector.getWidget().getElement().scrollIntoView();
- }
- });
- }
-}
+++ /dev/null
-/*
- * Copyright 2011 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.client.ui.UI;
-
-import java.util.ArrayList;
-
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.event.logical.shared.HasResizeHandlers;
-import com.google.gwt.event.logical.shared.ResizeEvent;
-import com.google.gwt.event.logical.shared.ResizeHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.DOM;
-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.ui.SimplePanel;
-import com.vaadin.client.ApplicationConnection;
-import com.vaadin.client.BrowserInfo;
-import com.vaadin.client.ComponentConnector;
-import com.vaadin.client.ConnectorMap;
-import com.vaadin.client.Focusable;
-import com.vaadin.client.VConsole;
-import com.vaadin.client.ui.ShortcutActionHandler;
-import com.vaadin.client.ui.TouchScrollDelegate;
-import com.vaadin.client.ui.VLazyExecutor;
-import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
-import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
-import com.vaadin.client.ui.textfield.VTextField;
-import com.vaadin.shared.ApplicationConstants;
-import com.vaadin.shared.ui.ui.UIConstants;
-
-/**
- *
- */
-public class VUI extends SimplePanel implements ResizeHandler,
- Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable,
- HasResizeHandlers {
-
- private static final String CLASSNAME = "v-view";
-
- private static int MONITOR_PARENT_TIMER_INTERVAL = 1000;
-
- String theme;
-
- String id;
-
- ShortcutActionHandler actionHandler;
-
- /*
- * Last known window size used to detect whether VView should be layouted
- * again. Detection must check window size, because the VView size might be
- * fixed and thus not automatically adapt to changed window sizes.
- */
- private int windowWidth;
- private int windowHeight;
-
- /*
- * Last know view size used to detect whether new dimensions should be sent
- * to the server.
- */
- private int viewWidth;
- private int viewHeight;
-
- ApplicationConnection connection;
-
- /**
- * Keep track of possible parent size changes when an embedded application.
- *
- * Uses {@link #parentWidth} and {@link #parentHeight} as an optimization to
- * keep track of when there is a real change.
- */
- private Timer resizeTimer;
-
- /** stored width of parent for embedded application auto-resize */
- private int parentWidth;
-
- /** stored height of parent for embedded application auto-resize */
- private int parentHeight;
-
- int scrollTop;
-
- int scrollLeft;
-
- boolean rendering;
-
- boolean scrollable;
-
- boolean immediate;
-
- boolean resizeLazy = false;
-
- private HandlerRegistration historyHandlerRegistration;
-
- private TouchScrollHandler touchScrollHandler;
-
- /**
- * The current URI fragment, used to avoid sending updates if nothing has
- * changed.
- */
- String currentFragment;
-
- /**
- * Listener for URI fragment changes. Notifies the server of the new value
- * whenever the value changes.
- */
- private final ValueChangeHandler<String> historyChangeHandler = new ValueChangeHandler<String>() {
-
- @Override
- public void onValueChange(ValueChangeEvent<String> event) {
- String newFragment = event.getValue();
-
- // Send the new fragment to the server if it has changed
- if (!newFragment.equals(currentFragment) && connection != null) {
- currentFragment = newFragment;
- connection.updateVariable(id, UIConstants.FRAGMENT_VARIABLE,
- newFragment, true);
- }
- }
- };
-
- private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200,
- new ScheduledCommand() {
-
- @Override
- public void execute() {
- performSizeCheck();
- }
-
- });
-
- public VUI() {
- super();
- setStyleName(CLASSNAME);
-
- // Allow focusing the view by using the focus() method, the view
- // should not be in the document focus flow
- getElement().setTabIndex(-1);
- makeScrollable();
- }
-
- /**
- * Start to periodically monitor for parent element resizes if embedded
- * application (e.g. portlet).
- */
- @Override
- protected void onLoad() {
- super.onLoad();
- if (isMonitoringParentSize()) {
- resizeTimer = new Timer() {
-
- @Override
- public void run() {
- // trigger check to see if parent size has changed,
- // recalculate layouts
- performSizeCheck();
- resizeTimer.schedule(MONITOR_PARENT_TIMER_INTERVAL);
- }
- };
- resizeTimer.schedule(MONITOR_PARENT_TIMER_INTERVAL);
- }
- }
-
- @Override
- protected void onAttach() {
- super.onAttach();
- historyHandlerRegistration = History
- .addValueChangeHandler(historyChangeHandler);
- currentFragment = History.getToken();
- }
-
- @Override
- protected void onDetach() {
- super.onDetach();
- historyHandlerRegistration.removeHandler();
- historyHandlerRegistration = null;
- }
-
- /**
- * Stop monitoring for parent element resizes.
- */
-
- @Override
- protected void onUnload() {
- if (resizeTimer != null) {
- resizeTimer.cancel();
- resizeTimer = null;
- }
- super.onUnload();
- }
-
- /**
- * Called when the window or parent div might have been resized.
- *
- * This immediately checks the sizes of the window and the parent div (if
- * monitoring it) and triggers layout recalculation if they have changed.
- */
- protected void performSizeCheck() {
- windowSizeMaybeChanged(Window.getClientWidth(),
- Window.getClientHeight());
- }
-
- /**
- * Called when the window or parent div might have been resized.
- *
- * This immediately checks the sizes of the window and the parent div (if
- * monitoring it) and triggers layout recalculation if they have changed.
- *
- * @param newWindowWidth
- * The new width of the window
- * @param newWindowHeight
- * The new height of the window
- *
- * @deprecated use {@link #performSizeCheck()}
- */
- @Deprecated
- protected void windowSizeMaybeChanged(int newWindowWidth,
- int newWindowHeight) {
- boolean changed = false;
- ComponentConnector connector = ConnectorMap.get(connection)
- .getConnector(this);
- if (windowWidth != newWindowWidth) {
- windowWidth = newWindowWidth;
- changed = true;
- connector.getLayoutManager().reportOuterWidth(connector,
- newWindowWidth);
- VConsole.log("New window width: " + windowWidth);
- }
- if (windowHeight != newWindowHeight) {
- windowHeight = newWindowHeight;
- changed = true;
- connector.getLayoutManager().reportOuterHeight(connector,
- newWindowHeight);
- VConsole.log("New window height: " + windowHeight);
- }
- Element parentElement = getElement().getParentElement();
- if (isMonitoringParentSize() && parentElement != null) {
- // check also for parent size changes
- int newParentWidth = parentElement.getClientWidth();
- int newParentHeight = parentElement.getClientHeight();
- if (parentWidth != newParentWidth) {
- parentWidth = newParentWidth;
- changed = true;
- VConsole.log("New parent width: " + parentWidth);
- }
- if (parentHeight != newParentHeight) {
- parentHeight = newParentHeight;
- changed = true;
- VConsole.log("New parent height: " + parentHeight);
- }
- }
- if (changed) {
- /*
- * If the window size has changed, layout the VView again and send
- * new size to the server if the size changed. (Just checking VView
- * size would cause us to ignore cases when a relatively sized VView
- * should shrink as the content's size is fixed and would thus not
- * automatically shrink.)
- */
- VConsole.log("Running layout functions due to window or parent resize");
-
- // update size to avoid (most) redundant re-layout passes
- // there can still be an extra layout recalculation if webkit
- // overflow fix updates the size in a deferred block
- if (isMonitoringParentSize() && parentElement != null) {
- parentWidth = parentElement.getClientWidth();
- parentHeight = parentElement.getClientHeight();
- }
-
- sendClientResized();
-
- connector.getLayoutManager().layoutNow();
- }
- }
-
- public String getTheme() {
- return theme;
- }
-
- /**
- * Used to reload host page on theme changes.
- */
- static native void reloadHostPage()
- /*-{
- $wnd.location.reload();
- }-*/;
-
- /**
- * Returns true if the body is NOT generated, i.e if someone else has made
- * the page that we're running in. Otherwise we're in charge of the whole
- * page.
- *
- * @return true if we're running embedded
- */
- public boolean isEmbedded() {
- return !getElement().getOwnerDocument().getBody().getClassName()
- .contains(ApplicationConstants.GENERATED_BODY_CLASSNAME);
- }
-
- /**
- * Returns true if the size of the parent should be checked periodically and
- * the application should react to its changes.
- *
- * @return true if size of parent should be tracked
- */
- protected boolean isMonitoringParentSize() {
- // could also perform a more specific check (Liferay portlet)
- return isEmbedded();
- }
-
- @Override
- public void onBrowserEvent(Event event) {
- super.onBrowserEvent(event);
- int type = DOM.eventGetType(event);
- if (type == Event.ONKEYDOWN && actionHandler != null) {
- actionHandler.handleKeyboardEvent(event);
- return;
- } else if (scrollable && type == Event.ONSCROLL) {
- updateScrollPosition();
- }
- }
-
- /**
- * Updates scroll position from DOM and saves variables to server.
- */
- private void updateScrollPosition() {
- int oldTop = scrollTop;
- int oldLeft = scrollLeft;
- scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop");
- scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft");
- if (connection != null && !rendering) {
- if (oldTop != scrollTop) {
- connection.updateVariable(id, "scrollTop", scrollTop, false);
- }
- if (oldLeft != scrollLeft) {
- connection.updateVariable(id, "scrollLeft", scrollLeft, false);
- }
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.google.gwt.event.logical.shared.ResizeHandler#onResize(com.google
- * .gwt.event.logical.shared.ResizeEvent)
- */
-
- @Override
- public void onResize(ResizeEvent event) {
- triggerSizeChangeCheck();
- }
-
- /**
- * Called when a resize event is received.
- *
- * This may trigger a lazy refresh or perform the size check immediately
- * depending on the browser used and whether the server side requests
- * resizes to be lazy.
- */
- private void triggerSizeChangeCheck() {
- /*
- * IE (pre IE9 at least) will give us some false resize events due to
- * problems with scrollbars. Firefox 3 might also produce some extra
- * events. We postpone both the re-layouting and the server side event
- * for a while to deal with these issues.
- *
- * We may also postpone these events to avoid slowness when resizing the
- * browser window. Constantly recalculating the layout causes the resize
- * operation to be really slow with complex layouts.
- */
- boolean lazy = resizeLazy || BrowserInfo.get().isIE8();
-
- if (lazy) {
- delayedResizeExecutor.trigger();
- } else {
- performSizeCheck();
- }
- }
-
- /**
- * Send new dimensions to the server.
- */
- void sendClientResized() {
- Element parentElement = getElement().getParentElement();
- int viewHeight = parentElement.getClientHeight();
- int viewWidth = parentElement.getClientWidth();
-
- ResizeEvent.fire(this, viewWidth, viewHeight);
- }
-
- public native static void goTo(String url)
- /*-{
- $wnd.location = url;
- }-*/;
-
- @Override
- public void onWindowClosing(Window.ClosingEvent event) {
- // Change focus on this window in order to ensure that all state is
- // collected from textfields
- // TODO this is a naive hack, that only works with text fields and may
- // cause some odd issues. Should be replaced with a decent solution, see
- // also related BeforeShortcutActionListener interface. Same interface
- // might be usable here.
- VTextField.flushChangesFromFocusedTextField();
- }
-
- private native static void loadAppIdListFromDOM(ArrayList<String> list)
- /*-{
- var j;
- for(j in $wnd.vaadin.vaadinConfigurations) {
- // $entry not needed as function is not exported
- list.@java.util.Collection::add(Ljava/lang/Object;)(j);
- }
- }-*/;
-
- @Override
- public ShortcutActionHandler getShortcutActionHandler() {
- return actionHandler;
- }
-
- @Override
- public void focus() {
- getElement().focus();
- }
-
- /**
- * Ensures the root is scrollable eg. after style name changes.
- */
- void makeScrollable() {
- if (touchScrollHandler == null) {
- touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this);
- }
- touchScrollHandler.addElement(getElement());
- }
-
- @Override
- public HandlerRegistration addResizeHandler(ResizeHandler resizeHandler) {
- return addHandler(resizeHandler, ResizeEvent.getType());
- }
-
-}
--- /dev/null
+/*
+ * Copyright 2011 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.client.ui.ui;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.event.logical.shared.ResizeEvent;
+import com.google.gwt.event.logical.shared.ResizeHandler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.History;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.web.bindery.event.shared.HandlerRegistration;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.BrowserInfo;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ConnectorHierarchyChangeEvent;
+import com.vaadin.client.ConnectorMap;
+import com.vaadin.client.Focusable;
+import com.vaadin.client.Paintable;
+import com.vaadin.client.UIDL;
+import com.vaadin.client.VConsole;
+import com.vaadin.client.communication.RpcProxy;
+import com.vaadin.client.communication.StateChangeEvent;
+import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
+import com.vaadin.client.ui.AbstractComponentContainerConnector;
+import com.vaadin.client.ui.ClickEventHandler;
+import com.vaadin.client.ui.ShortcutActionHandler;
+import com.vaadin.client.ui.layout.MayScrollChildren;
+import com.vaadin.client.ui.notification.VNotification;
+import com.vaadin.client.ui.window.WindowConnector;
+import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.ui.ComponentStateUtil;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.Connect.LoadStyle;
+import com.vaadin.shared.ui.ui.PageClientRpc;
+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.UI;
+
+@Connect(value = UI.class, loadStyle = LoadStyle.EAGER)
+public class UIConnector extends AbstractComponentContainerConnector implements
+ Paintable, MayScrollChildren {
+
+ private UIServerRpc rpc = RpcProxy.create(UIServerRpc.class, this);
+
+ private HandlerRegistration childStateChangeHandlerRegistration;
+
+ private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ // TODO Should use a more specific handler that only reacts to
+ // size changes
+ onChildSizeChange();
+ }
+ };
+
+ @Override
+ protected void init() {
+ super.init();
+ registerRpc(PageClientRpc.class, new PageClientRpc() {
+ @Override
+ public void setTitle(String title) {
+ com.google.gwt.user.client.Window.setTitle(title);
+ }
+ });
+ getWidget().addResizeHandler(new ResizeHandler() {
+ @Override
+ public void onResize(ResizeEvent event) {
+ rpc.resize(event.getHeight(), event.getWidth(),
+ Window.getClientWidth(), Window.getClientHeight());
+ if (getState().immediate) {
+ getConnection().sendPendingVariableChanges();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
+ ConnectorMap paintableMap = ConnectorMap.get(getConnection());
+ getWidget().rendering = true;
+ getWidget().id = getConnectorId();
+ boolean firstPaint = getWidget().connection == null;
+ getWidget().connection = client;
+
+ getWidget().immediate = getState().immediate;
+ getWidget().resizeLazy = uidl.hasAttribute(UIConstants.RESIZE_LAZY);
+ String newTheme = uidl.getStringAttribute("theme");
+ if (getWidget().theme != null && !newTheme.equals(getWidget().theme)) {
+ // Complete page refresh is needed due css can affect layout
+ // calculations etc
+ getWidget().reloadHostPage();
+ } else {
+ getWidget().theme = newTheme;
+ }
+ // this also implicitly removes old styles
+ String styles = "";
+ styles += getWidget().getStylePrimaryName() + " ";
+ if (ComponentStateUtil.hasStyles(getState())) {
+ for (String style : getState().styles) {
+ styles += style + " ";
+ }
+ }
+ if (!client.getConfiguration().isStandalone()) {
+ styles += getWidget().getStylePrimaryName() + "-embedded";
+ }
+ getWidget().setStyleName(styles.trim());
+
+ getWidget().makeScrollable();
+
+ clickEventHandler.handleEventHandlerRegistration();
+
+ // Process children
+ int childIndex = 0;
+
+ // Open URL:s
+ boolean isClosed = false; // was this window closed?
+ while (childIndex < uidl.getChildCount()
+ && "open".equals(uidl.getChildUIDL(childIndex).getTag())) {
+ final UIDL open = uidl.getChildUIDL(childIndex);
+ final String url = client.translateVaadinUri(open
+ .getStringAttribute("src"));
+ final String target = open.getStringAttribute("name");
+ if (target == null) {
+ // source will be opened to this browser window, but we may have
+ // to finish rendering this window in case this is a download
+ // (and window stays open).
+ Scheduler.get().scheduleDeferred(new Command() {
+ @Override
+ public void execute() {
+ VUI.goTo(url);
+ }
+ });
+ } else if ("_self".equals(target)) {
+ // This window is closing (for sure). Only other opens are
+ // relevant in this change. See #3558, #2144
+ isClosed = true;
+ VUI.goTo(url);
+ } else {
+ String options;
+ if (open.hasAttribute("border")) {
+ if (open.getStringAttribute("border").equals("minimal")) {
+ options = "menubar=yes,location=no,status=no";
+ } else {
+ options = "menubar=no,location=no,status=no";
+ }
+
+ } else {
+ options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes";
+ }
+
+ if (open.hasAttribute("width")) {
+ int w = open.getIntAttribute("width");
+ options += ",width=" + w;
+ }
+ if (open.hasAttribute("height")) {
+ int h = open.getIntAttribute("height");
+ options += ",height=" + h;
+ }
+
+ Window.open(url, target, options);
+ }
+ childIndex++;
+ }
+ if (isClosed) {
+ // don't render the content, something else will be opened to this
+ // browser view
+ getWidget().rendering = false;
+ return;
+ }
+
+ // Handle other UIDL children
+ UIDL childUidl;
+ while ((childUidl = uidl.getChildUIDL(childIndex++)) != null) {
+ String tag = childUidl.getTag().intern();
+ if (tag == "actions") {
+ if (getWidget().actionHandler == null) {
+ getWidget().actionHandler = new ShortcutActionHandler(
+ getWidget().id, client);
+ }
+ getWidget().actionHandler.updateActionMap(childUidl);
+ } else if (tag == "notifications") {
+ for (final Iterator<?> it = childUidl.getChildIterator(); it
+ .hasNext();) {
+ final UIDL notification = (UIDL) it.next();
+ VNotification.showNotification(client, notification);
+ }
+ }
+ }
+
+ if (uidl.hasAttribute("focused")) {
+ // set focused component when render phase is finished
+ Scheduler.get().scheduleDeferred(new Command() {
+ @Override
+ public void execute() {
+ ComponentConnector paintable = (ComponentConnector) uidl
+ .getPaintableAttribute("focused", getConnection());
+
+ final Widget toBeFocused = paintable.getWidget();
+ /*
+ * Two types of Widgets can be focused, either implementing
+ * GWT HasFocus of a thinner Vaadin specific Focusable
+ * interface.
+ */
+ if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
+ final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused;
+ toBeFocusedWidget.setFocus(true);
+ } else if (toBeFocused instanceof Focusable) {
+ ((Focusable) toBeFocused).focus();
+ } else {
+ VConsole.log("Could not focus component");
+ }
+ }
+ });
+ }
+
+ // Add window listeners on first paint, to prevent premature
+ // variablechanges
+ if (firstPaint) {
+ Window.addWindowClosingHandler(getWidget());
+ Window.addResizeHandler(getWidget());
+ }
+
+ // finally set scroll position from UIDL
+ if (uidl.hasVariable("scrollTop")) {
+ getWidget().scrollable = true;
+ getWidget().scrollTop = uidl.getIntVariable("scrollTop");
+ DOM.setElementPropertyInt(getWidget().getElement(), "scrollTop",
+ getWidget().scrollTop);
+ getWidget().scrollLeft = uidl.getIntVariable("scrollLeft");
+ DOM.setElementPropertyInt(getWidget().getElement(), "scrollLeft",
+ getWidget().scrollLeft);
+ } else {
+ getWidget().scrollable = false;
+ }
+
+ if (uidl.hasAttribute("scrollTo")) {
+ final ComponentConnector connector = (ComponentConnector) uidl
+ .getPaintableAttribute("scrollTo", getConnection());
+ scrollIntoView(connector);
+ }
+
+ if (uidl.hasAttribute(UIConstants.FRAGMENT_VARIABLE)) {
+ getWidget().currentFragment = uidl
+ .getStringAttribute(UIConstants.FRAGMENT_VARIABLE);
+ if (!getWidget().currentFragment.equals(History.getToken())) {
+ History.newItem(getWidget().currentFragment, true);
+ }
+ } else {
+ // Initial request for which the server doesn't yet have a fragment
+ // (and haven't shown any interest in getting one)
+ getWidget().currentFragment = History.getToken();
+
+ // Include current fragment in the next request
+ client.updateVariable(getWidget().id,
+ UIConstants.FRAGMENT_VARIABLE, getWidget().currentFragment,
+ false);
+ }
+
+ if (firstPaint) {
+ // Queue the initial window size to be sent with the following
+ // request.
+ getWidget().sendClientResized();
+ }
+ getWidget().rendering = false;
+ }
+
+ public void init(String rootPanelId,
+ ApplicationConnection applicationConnection) {
+ DOM.sinkEvents(getWidget().getElement(), Event.ONKEYDOWN
+ | Event.ONSCROLL);
+
+ // iview is focused when created so element needs tabIndex
+ // 1 due 0 is at the end of natural tabbing order
+ DOM.setElementProperty(getWidget().getElement(), "tabIndex", "1");
+
+ RootPanel root = RootPanel.get(rootPanelId);
+
+ // Remove the v-app-loading or any splash screen added inside the div by
+ // the user
+ root.getElement().setInnerHTML("");
+
+ root.addStyleName("v-theme-"
+ + applicationConnection.getConfiguration().getThemeName());
+
+ root.add(getWidget());
+
+ if (applicationConnection.getConfiguration().isStandalone()) {
+ // set focus to iview element by default to listen possible keyboard
+ // shortcuts. For embedded applications this is unacceptable as we
+ // don't want to steal focus from the main page nor we don't want
+ // side-effects from focusing (scrollIntoView).
+ getWidget().getElement().focus();
+ }
+ }
+
+ private ClickEventHandler clickEventHandler = new ClickEventHandler(this) {
+
+ @Override
+ protected void fireClick(NativeEvent event,
+ MouseEventDetails mouseDetails) {
+ rpc.click(mouseDetails);
+ }
+
+ };
+
+ @Override
+ public void updateCaption(ComponentConnector component) {
+ // NOP The main view never draws caption for its layout
+ }
+
+ @Override
+ public VUI getWidget() {
+ return (VUI) super.getWidget();
+ }
+
+ protected ComponentConnector getContent() {
+ return (ComponentConnector) getState().content;
+ }
+
+ protected void onChildSizeChange() {
+ ComponentConnector child = getContent();
+ Style childStyle = child.getWidget().getElement().getStyle();
+ /*
+ * Must set absolute position if the child has relative height and
+ * there's a chance of horizontal scrolling as some browsers will
+ * otherwise not take the scrollbar into account when calculating the
+ * height. Assuming v-view does not have an undefined width for now, see
+ * #8460.
+ */
+ if (child.isRelativeHeight() && !BrowserInfo.get().isIE9()) {
+ childStyle.setPosition(Position.ABSOLUTE);
+ } else {
+ childStyle.clearPosition();
+ }
+ }
+
+ /**
+ * Checks if the given sub window is a child of this UI Connector
+ *
+ * @deprecated Should be replaced by a more generic mechanism for getting
+ * non-ComponentConnector children
+ * @param wc
+ * @return
+ */
+ @Deprecated
+ public boolean hasSubWindow(WindowConnector wc) {
+ return getChildComponents().contains(wc);
+ }
+
+ /**
+ * Return an iterator for current subwindows. This method is meant for
+ * testing purposes only.
+ *
+ * @return
+ */
+ public List<WindowConnector> getSubWindows() {
+ ArrayList<WindowConnector> windows = new ArrayList<WindowConnector>();
+ for (ComponentConnector child : getChildComponents()) {
+ if (child instanceof WindowConnector) {
+ windows.add((WindowConnector) child);
+ }
+ }
+ return windows;
+ }
+
+ @Override
+ public UIState getState() {
+ return (UIState) super.getState();
+ }
+
+ @Override
+ public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
+ super.onConnectorHierarchyChange(event);
+
+ ComponentConnector oldChild = null;
+ ComponentConnector newChild = getContent();
+
+ for (ComponentConnector c : event.getOldChildren()) {
+ if (!(c instanceof WindowConnector)) {
+ oldChild = c;
+ break;
+ }
+ }
+
+ if (oldChild != newChild) {
+ if (childStateChangeHandlerRegistration != null) {
+ childStateChangeHandlerRegistration.removeHandler();
+ childStateChangeHandlerRegistration = null;
+ }
+ getWidget().setWidget(newChild.getWidget());
+ childStateChangeHandlerRegistration = newChild
+ .addStateChangeHandler(childStateChangeHandler);
+ // Must handle new child here as state change events are already
+ // fired
+ onChildSizeChange();
+ }
+
+ for (ComponentConnector c : getChildComponents()) {
+ if (c instanceof WindowConnector) {
+ WindowConnector wc = (WindowConnector) c;
+ wc.setWindowOrderAndPosition();
+ }
+ }
+
+ // Close removed sub windows
+ for (ComponentConnector c : event.getOldChildren()) {
+ if (c.getParent() != this && c instanceof WindowConnector) {
+ ((WindowConnector) c).getWidget().hide();
+ }
+ }
+ }
+
+ /**
+ * Tries to scroll the viewport so that the given connector is in view.
+ *
+ * @param componentConnector
+ * The connector which should be visible
+ *
+ */
+ public void scrollIntoView(final ComponentConnector componentConnector) {
+ if (componentConnector == null) {
+ return;
+ }
+
+ Scheduler.get().scheduleDeferred(new Command() {
+ @Override
+ public void execute() {
+ componentConnector.getWidget().getElement().scrollIntoView();
+ }
+ });
+ }
+}
--- /dev/null
+/*
+ * Copyright 2011 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.client.ui.ui;
+
+import java.util.ArrayList;
+
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.logical.shared.HasResizeHandlers;
+import com.google.gwt.event.logical.shared.ResizeEvent;
+import com.google.gwt.event.logical.shared.ResizeHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+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.ui.SimplePanel;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.BrowserInfo;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ConnectorMap;
+import com.vaadin.client.Focusable;
+import com.vaadin.client.VConsole;
+import com.vaadin.client.ui.ShortcutActionHandler;
+import com.vaadin.client.ui.TouchScrollDelegate;
+import com.vaadin.client.ui.VLazyExecutor;
+import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
+import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
+import com.vaadin.client.ui.textfield.VTextField;
+import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.shared.ui.ui.UIConstants;
+
+/**
+ *
+ */
+public class VUI extends SimplePanel implements ResizeHandler,
+ Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable,
+ HasResizeHandlers {
+
+ private static final String CLASSNAME = "v-view";
+
+ private static int MONITOR_PARENT_TIMER_INTERVAL = 1000;
+
+ String theme;
+
+ String id;
+
+ ShortcutActionHandler actionHandler;
+
+ /*
+ * Last known window size used to detect whether VView should be layouted
+ * again. Detection must check window size, because the VView size might be
+ * fixed and thus not automatically adapt to changed window sizes.
+ */
+ private int windowWidth;
+ private int windowHeight;
+
+ /*
+ * Last know view size used to detect whether new dimensions should be sent
+ * to the server.
+ */
+ private int viewWidth;
+ private int viewHeight;
+
+ ApplicationConnection connection;
+
+ /**
+ * Keep track of possible parent size changes when an embedded application.
+ *
+ * Uses {@link #parentWidth} and {@link #parentHeight} as an optimization to
+ * keep track of when there is a real change.
+ */
+ private Timer resizeTimer;
+
+ /** stored width of parent for embedded application auto-resize */
+ private int parentWidth;
+
+ /** stored height of parent for embedded application auto-resize */
+ private int parentHeight;
+
+ int scrollTop;
+
+ int scrollLeft;
+
+ boolean rendering;
+
+ boolean scrollable;
+
+ boolean immediate;
+
+ boolean resizeLazy = false;
+
+ private HandlerRegistration historyHandlerRegistration;
+
+ private TouchScrollHandler touchScrollHandler;
+
+ /**
+ * The current URI fragment, used to avoid sending updates if nothing has
+ * changed.
+ */
+ String currentFragment;
+
+ /**
+ * Listener for URI fragment changes. Notifies the server of the new value
+ * whenever the value changes.
+ */
+ private final ValueChangeHandler<String> historyChangeHandler = new ValueChangeHandler<String>() {
+
+ @Override
+ public void onValueChange(ValueChangeEvent<String> event) {
+ String newFragment = event.getValue();
+
+ // Send the new fragment to the server if it has changed
+ if (!newFragment.equals(currentFragment) && connection != null) {
+ currentFragment = newFragment;
+ connection.updateVariable(id, UIConstants.FRAGMENT_VARIABLE,
+ newFragment, true);
+ }
+ }
+ };
+
+ private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200,
+ new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ performSizeCheck();
+ }
+
+ });
+
+ public VUI() {
+ super();
+ setStyleName(CLASSNAME);
+
+ // Allow focusing the view by using the focus() method, the view
+ // should not be in the document focus flow
+ getElement().setTabIndex(-1);
+ makeScrollable();
+ }
+
+ /**
+ * Start to periodically monitor for parent element resizes if embedded
+ * application (e.g. portlet).
+ */
+ @Override
+ protected void onLoad() {
+ super.onLoad();
+ if (isMonitoringParentSize()) {
+ resizeTimer = new Timer() {
+
+ @Override
+ public void run() {
+ // trigger check to see if parent size has changed,
+ // recalculate layouts
+ performSizeCheck();
+ resizeTimer.schedule(MONITOR_PARENT_TIMER_INTERVAL);
+ }
+ };
+ resizeTimer.schedule(MONITOR_PARENT_TIMER_INTERVAL);
+ }
+ }
+
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+ historyHandlerRegistration = History
+ .addValueChangeHandler(historyChangeHandler);
+ currentFragment = History.getToken();
+ }
+
+ @Override
+ protected void onDetach() {
+ super.onDetach();
+ historyHandlerRegistration.removeHandler();
+ historyHandlerRegistration = null;
+ }
+
+ /**
+ * Stop monitoring for parent element resizes.
+ */
+
+ @Override
+ protected void onUnload() {
+ if (resizeTimer != null) {
+ resizeTimer.cancel();
+ resizeTimer = null;
+ }
+ super.onUnload();
+ }
+
+ /**
+ * Called when the window or parent div might have been resized.
+ *
+ * This immediately checks the sizes of the window and the parent div (if
+ * monitoring it) and triggers layout recalculation if they have changed.
+ */
+ protected void performSizeCheck() {
+ windowSizeMaybeChanged(Window.getClientWidth(),
+ Window.getClientHeight());
+ }
+
+ /**
+ * Called when the window or parent div might have been resized.
+ *
+ * This immediately checks the sizes of the window and the parent div (if
+ * monitoring it) and triggers layout recalculation if they have changed.
+ *
+ * @param newWindowWidth
+ * The new width of the window
+ * @param newWindowHeight
+ * The new height of the window
+ *
+ * @deprecated use {@link #performSizeCheck()}
+ */
+ @Deprecated
+ protected void windowSizeMaybeChanged(int newWindowWidth,
+ int newWindowHeight) {
+ boolean changed = false;
+ ComponentConnector connector = ConnectorMap.get(connection)
+ .getConnector(this);
+ if (windowWidth != newWindowWidth) {
+ windowWidth = newWindowWidth;
+ changed = true;
+ connector.getLayoutManager().reportOuterWidth(connector,
+ newWindowWidth);
+ VConsole.log("New window width: " + windowWidth);
+ }
+ if (windowHeight != newWindowHeight) {
+ windowHeight = newWindowHeight;
+ changed = true;
+ connector.getLayoutManager().reportOuterHeight(connector,
+ newWindowHeight);
+ VConsole.log("New window height: " + windowHeight);
+ }
+ Element parentElement = getElement().getParentElement();
+ if (isMonitoringParentSize() && parentElement != null) {
+ // check also for parent size changes
+ int newParentWidth = parentElement.getClientWidth();
+ int newParentHeight = parentElement.getClientHeight();
+ if (parentWidth != newParentWidth) {
+ parentWidth = newParentWidth;
+ changed = true;
+ VConsole.log("New parent width: " + parentWidth);
+ }
+ if (parentHeight != newParentHeight) {
+ parentHeight = newParentHeight;
+ changed = true;
+ VConsole.log("New parent height: " + parentHeight);
+ }
+ }
+ if (changed) {
+ /*
+ * If the window size has changed, layout the VView again and send
+ * new size to the server if the size changed. (Just checking VView
+ * size would cause us to ignore cases when a relatively sized VView
+ * should shrink as the content's size is fixed and would thus not
+ * automatically shrink.)
+ */
+ VConsole.log("Running layout functions due to window or parent resize");
+
+ // update size to avoid (most) redundant re-layout passes
+ // there can still be an extra layout recalculation if webkit
+ // overflow fix updates the size in a deferred block
+ if (isMonitoringParentSize() && parentElement != null) {
+ parentWidth = parentElement.getClientWidth();
+ parentHeight = parentElement.getClientHeight();
+ }
+
+ sendClientResized();
+
+ connector.getLayoutManager().layoutNow();
+ }
+ }
+
+ public String getTheme() {
+ return theme;
+ }
+
+ /**
+ * Used to reload host page on theme changes.
+ */
+ static native void reloadHostPage()
+ /*-{
+ $wnd.location.reload();
+ }-*/;
+
+ /**
+ * Returns true if the body is NOT generated, i.e if someone else has made
+ * the page that we're running in. Otherwise we're in charge of the whole
+ * page.
+ *
+ * @return true if we're running embedded
+ */
+ public boolean isEmbedded() {
+ return !getElement().getOwnerDocument().getBody().getClassName()
+ .contains(ApplicationConstants.GENERATED_BODY_CLASSNAME);
+ }
+
+ /**
+ * Returns true if the size of the parent should be checked periodically and
+ * the application should react to its changes.
+ *
+ * @return true if size of parent should be tracked
+ */
+ protected boolean isMonitoringParentSize() {
+ // could also perform a more specific check (Liferay portlet)
+ return isEmbedded();
+ }
+
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ int type = DOM.eventGetType(event);
+ if (type == Event.ONKEYDOWN && actionHandler != null) {
+ actionHandler.handleKeyboardEvent(event);
+ return;
+ } else if (scrollable && type == Event.ONSCROLL) {
+ updateScrollPosition();
+ }
+ }
+
+ /**
+ * Updates scroll position from DOM and saves variables to server.
+ */
+ private void updateScrollPosition() {
+ int oldTop = scrollTop;
+ int oldLeft = scrollLeft;
+ scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop");
+ scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft");
+ if (connection != null && !rendering) {
+ if (oldTop != scrollTop) {
+ connection.updateVariable(id, "scrollTop", scrollTop, false);
+ }
+ if (oldLeft != scrollLeft) {
+ connection.updateVariable(id, "scrollLeft", scrollLeft, false);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.logical.shared.ResizeHandler#onResize(com.google
+ * .gwt.event.logical.shared.ResizeEvent)
+ */
+
+ @Override
+ public void onResize(ResizeEvent event) {
+ triggerSizeChangeCheck();
+ }
+
+ /**
+ * Called when a resize event is received.
+ *
+ * This may trigger a lazy refresh or perform the size check immediately
+ * depending on the browser used and whether the server side requests
+ * resizes to be lazy.
+ */
+ private void triggerSizeChangeCheck() {
+ /*
+ * IE (pre IE9 at least) will give us some false resize events due to
+ * problems with scrollbars. Firefox 3 might also produce some extra
+ * events. We postpone both the re-layouting and the server side event
+ * for a while to deal with these issues.
+ *
+ * We may also postpone these events to avoid slowness when resizing the
+ * browser window. Constantly recalculating the layout causes the resize
+ * operation to be really slow with complex layouts.
+ */
+ boolean lazy = resizeLazy || BrowserInfo.get().isIE8();
+
+ if (lazy) {
+ delayedResizeExecutor.trigger();
+ } else {
+ performSizeCheck();
+ }
+ }
+
+ /**
+ * Send new dimensions to the server.
+ */
+ void sendClientResized() {
+ Element parentElement = getElement().getParentElement();
+ int viewHeight = parentElement.getClientHeight();
+ int viewWidth = parentElement.getClientWidth();
+
+ ResizeEvent.fire(this, viewWidth, viewHeight);
+ }
+
+ public native static void goTo(String url)
+ /*-{
+ $wnd.location = url;
+ }-*/;
+
+ @Override
+ public void onWindowClosing(Window.ClosingEvent event) {
+ // Change focus on this window in order to ensure that all state is
+ // collected from textfields
+ // TODO this is a naive hack, that only works with text fields and may
+ // cause some odd issues. Should be replaced with a decent solution, see
+ // also related BeforeShortcutActionListener interface. Same interface
+ // might be usable here.
+ VTextField.flushChangesFromFocusedTextField();
+ }
+
+ private native static void loadAppIdListFromDOM(ArrayList<String> list)
+ /*-{
+ var j;
+ for(j in $wnd.vaadin.vaadinConfigurations) {
+ // $entry not needed as function is not exported
+ list.@java.util.Collection::add(Ljava/lang/Object;)(j);
+ }
+ }-*/;
+
+ @Override
+ public ShortcutActionHandler getShortcutActionHandler() {
+ return actionHandler;
+ }
+
+ @Override
+ public void focus() {
+ getElement().focus();
+ }
+
+ /**
+ * Ensures the root is scrollable eg. after style name changes.
+ */
+ void makeScrollable() {
+ if (touchScrollHandler == null) {
+ touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this);
+ }
+ touchScrollHandler.addElement(getElement());
+ }
+
+ @Override
+ public HandlerRegistration addResizeHandler(ResizeHandler resizeHandler) {
+ return addHandler(resizeHandler, ResizeEvent.getType());
+ }
+
+}