From f6b3c140e77c2f27010117ab8bb3876fe492fb2f Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Tue, 4 Sep 2012 13:31:31 +0300 Subject: Removed unused instance variable from button --- client/src/com/vaadin/client/ui/button/VButton.java | 5 ----- 1 file changed, 5 deletions(-) (limited to 'client') diff --git a/client/src/com/vaadin/client/ui/button/VButton.java b/client/src/com/vaadin/client/ui/button/VButton.java index 8e611144e4..d4cd40e2e9 100644 --- a/client/src/com/vaadin/client/ui/button/VButton.java +++ b/client/src/com/vaadin/client/ui/button/VButton.java @@ -91,11 +91,6 @@ public class VButton extends FocusWidget implements ClickHandler { private HandlerRegistration focusHandlerRegistration; private HandlerRegistration blurHandlerRegistration; - /** - * If caption should be rendered in HTML - */ - protected boolean htmlCaption = false; - public VButton() { super(DOM.createDiv()); setTabIndex(0); -- cgit v1.2.3 From c14171d1344f1360ae4a95cd9494ab2829d439d4 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 4 Sep 2012 22:27:23 +0300 Subject: Renamed UI package which accidentally had been renamed to upper case --- .../server/widgetsetutils/WidgetMapGenerator.java | 2 +- .../com/vaadin/client/ApplicationConnection.java | 2 +- client/src/com/vaadin/client/ComponentLocator.java | 2 +- client/src/com/vaadin/client/VDebugConsole.java | 2 +- .../client/ui/AbstractComponentConnector.java | 2 +- .../src/com/vaadin/client/ui/UI/UIConnector.java | 457 -------------------- client/src/com/vaadin/client/ui/UI/VUI.java | 459 --------------------- .../src/com/vaadin/client/ui/ui/UIConnector.java | 457 ++++++++++++++++++++ client/src/com/vaadin/client/ui/ui/VUI.java | 459 +++++++++++++++++++++ 9 files changed, 921 insertions(+), 921 deletions(-) delete mode 100644 client/src/com/vaadin/client/ui/UI/UIConnector.java delete mode 100644 client/src/com/vaadin/client/ui/UI/VUI.java create mode 100644 client/src/com/vaadin/client/ui/ui/UIConnector.java create mode 100644 client/src/com/vaadin/client/ui/ui/VUI.java (limited to 'client') diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/WidgetMapGenerator.java b/client-compiler/src/com/vaadin/server/widgetsetutils/WidgetMapGenerator.java index b90791d61b..c1fb6df883 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/WidgetMapGenerator.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/WidgetMapGenerator.java @@ -37,7 +37,7 @@ import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; 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; diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 6a1474fa45..a4de5dd4ad 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -70,10 +70,10 @@ import com.vaadin.client.metadata.TypeData; 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; diff --git a/client/src/com/vaadin/client/ComponentLocator.java b/client/src/com/vaadin/client/ComponentLocator.java index 0701d4ff21..89e022c179 100644 --- a/client/src/com/vaadin/client/ComponentLocator.java +++ b/client/src/com/vaadin/client/ComponentLocator.java @@ -25,10 +25,10 @@ import com.google.gwt.user.client.ui.HasWidgets; 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; diff --git a/client/src/com/vaadin/client/VDebugConsole.java b/client/src/com/vaadin/client/VDebugConsole.java index 2db5e028cf..51504ae4e1 100644 --- a/client/src/com/vaadin/client/VDebugConsole.java +++ b/client/src/com/vaadin/client/VDebugConsole.java @@ -69,8 +69,8 @@ import com.google.gwt.user.client.ui.VerticalPanel; 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; diff --git a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java index 294d793050..2e30fbbc02 100644 --- a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java +++ b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java @@ -37,8 +37,8 @@ import com.vaadin.client.communication.StateChangeEvent; 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; diff --git a/client/src/com/vaadin/client/ui/UI/UIConnector.java b/client/src/com/vaadin/client/ui/UI/UIConnector.java deleted file mode 100644 index cb8b0ece9e..0000000000 --- a/client/src/com/vaadin/client/ui/UI/UIConnector.java +++ /dev/null @@ -1,457 +0,0 @@ -/* - * 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 getSubWindows() { - ArrayList windows = new ArrayList(); - 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(); - } - }); - } -} diff --git a/client/src/com/vaadin/client/ui/UI/VUI.java b/client/src/com/vaadin/client/ui/UI/VUI.java deleted file mode 100644 index c99dfebdee..0000000000 --- a/client/src/com/vaadin/client/ui/UI/VUI.java +++ /dev/null @@ -1,459 +0,0 @@ -/* - * 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 historyChangeHandler = new ValueChangeHandler() { - - @Override - public void onValueChange(ValueChangeEvent 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 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()); - } - -} diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java new file mode 100644 index 0000000000..3b4e4e1c7c --- /dev/null +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -0,0 +1,457 @@ +/* + * 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 getSubWindows() { + ArrayList windows = new ArrayList(); + 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(); + } + }); + } +} diff --git a/client/src/com/vaadin/client/ui/ui/VUI.java b/client/src/com/vaadin/client/ui/ui/VUI.java new file mode 100644 index 0000000000..9aa3331577 --- /dev/null +++ b/client/src/com/vaadin/client/ui/ui/VUI.java @@ -0,0 +1,459 @@ +/* + * 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 historyChangeHandler = new ValueChangeHandler() { + + @Override + public void onValueChange(ValueChangeEvent 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 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()); + } + +} -- cgit v1.2.3