From: Artur Signell Date: Wed, 11 Apr 2012 16:13:34 +0000 (+0300) Subject: Moved shared classes out from connector to avoid class loader problems X-Git-Tag: 7.0.0.alpha2~83 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=3efc7b521469aa9cf98d8bdf767278aa96a40335;p=vaadin-framework.git Moved shared classes out from connector to avoid class loader problems --- diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index 6148988b7d..6f3ff6db45 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -45,12 +45,12 @@ import com.vaadin.terminal.gwt.client.communication.MethodInvocation; import com.vaadin.terminal.gwt.client.communication.RpcManager; import com.vaadin.terminal.gwt.client.communication.SharedState; import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; -import com.vaadin.terminal.gwt.client.ui.RootConnector; import com.vaadin.terminal.gwt.client.ui.VContextMenu; import com.vaadin.terminal.gwt.client.ui.VNotification; import com.vaadin.terminal.gwt.client.ui.VNotification.HideEvent; import com.vaadin.terminal.gwt.client.ui.WindowConnector; import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager; +import com.vaadin.terminal.gwt.client.ui.root.RootConnector; import com.vaadin.terminal.gwt.server.AbstractCommunicationManager; /** @@ -140,7 +140,7 @@ public class ApplicationConnection { private Timer loadTimer3; private Element loadElement; - private final RootConnector view; + private final RootConnector rootConnector; protected boolean applicationRunning = false; @@ -192,7 +192,7 @@ public class ApplicationConnection { } public ApplicationConnection() { - view = GWT.create(RootConnector.class); + rootConnector = GWT.create(RootConnector.class); rpcManager = GWT.create(RpcManager.class); layoutManager = GWT.create(LayoutManager.class); layoutManager.setConnection(this); @@ -224,7 +224,7 @@ public class ApplicationConnection { initializeClientHooks(); - view.init(cnf.getRootPanelId(), this); + rootConnector.init(cnf.getRootPanelId(), this); showLoadingIndicator(); } @@ -856,7 +856,7 @@ public class ApplicationConnection { if (loadElement == null) { loadElement = DOM.createDiv(); DOM.setStyleAttribute(loadElement, "position", "absolute"); - DOM.appendChild(view.getWidget().getElement(), loadElement); + DOM.appendChild(rootConnector.getWidget().getElement(), loadElement); VConsole.log("inserting load indicator"); } DOM.setElementProperty(loadElement, "className", "v-loading-indicator"); @@ -1032,7 +1032,7 @@ public class ApplicationConnection { meta = json.getValueMap("meta"); if (meta.containsKey("repaintAll")) { repaintAll = true; - view.getWidget().clear(); + rootConnector.getWidget().clear(); getConnectorMap().clear(); if (meta.containsKey("invalidLayouts")) { validatingLayouts = true; @@ -1226,10 +1226,10 @@ public class ApplicationConnection { if (!cc.getParent().getChildren().contains(cc)) { VConsole.error("ERROR: Connector is connected to a parent but the parent does not contain the connector"); } - } else if ((cc instanceof RootConnector && cc == getView())) { + } else if ((cc instanceof RootConnector && cc == getRootConnector())) { // RootConnector for this connection, leave as-is } else if (cc instanceof WindowConnector - && getView().hasSubWindow((WindowConnector) cc)) { + && getRootConnector().hasSubWindow((WindowConnector) cc)) { // Sub window attached to this RootConnector, leave // as-is } else { @@ -1279,8 +1279,8 @@ public class ApplicationConnection { // RootConnector has been created but not // initialized as the connector id has not been // known - connectorMap.registerConnector(connectorId, view); - view.doInit(connectorId, ApplicationConnection.this); + connectorMap.registerConnector(connectorId, rootConnector); + rootConnector.doInit(connectorId, ApplicationConnection.this); } } catch (final Throwable e) { VConsole.error(e); @@ -2207,8 +2207,8 @@ public class ApplicationConnection { @Override public void run() { - VConsole.log("Running re-layout of " + view.getClass().getName()); - runDescendentsLayout(view.getWidget()); + VConsole.log("Running re-layout of " + rootConnector.getClass().getName()); + runDescendentsLayout(rootConnector.getWidget()); isPending = false; } }; @@ -2243,8 +2243,8 @@ public class ApplicationConnection { * * @return the main view */ - public RootConnector getView() { - return view; + public RootConnector getRootConnector() { + return rootConnector; } /** diff --git a/src/com/vaadin/terminal/gwt/client/ComponentLocator.java b/src/com/vaadin/terminal/gwt/client/ComponentLocator.java index 9e5ed709c7..8226860533 100644 --- a/src/com/vaadin/terminal/gwt/client/ComponentLocator.java +++ b/src/com/vaadin/terminal/gwt/client/ComponentLocator.java @@ -16,9 +16,9 @@ import com.vaadin.terminal.gwt.client.ui.SubPartAware; import com.vaadin.terminal.gwt.client.ui.VGridLayout; import com.vaadin.terminal.gwt.client.ui.VMeasuringOrderedLayout; import com.vaadin.terminal.gwt.client.ui.VTabsheetPanel; -import com.vaadin.terminal.gwt.client.ui.VView; import com.vaadin.terminal.gwt.client.ui.VWindow; import com.vaadin.terminal.gwt.client.ui.WindowConnector; +import com.vaadin.terminal.gwt.client.ui.root.VRoot; /** * ComponentLocator provides methods for generating a String locator for a given @@ -370,12 +370,12 @@ public class ComponentLocator { return null; } - if (w instanceof VView) { + if (w instanceof VRoot) { return ""; } else if (w instanceof VWindow) { Connector windowConnector = ConnectorMap.get(client) .getConnector(w); - List subWindowList = client.getView() + List subWindowList = client.getRootConnector() .getSubWindows(); int indexOfSubWindow = subWindowList.indexOf(windowConnector); return PARENTCHILD_SEPARATOR + "VWindow[" + indexOfSubWindow + "]"; @@ -436,7 +436,7 @@ public class ComponentLocator { if (part.equals(ROOT_ID)) { w = RootPanel.get(); } else if (part.equals("")) { - w = client.getView().getWidget(); + w = client.getRootConnector().getWidget(); } else if (w == null) { String id = part; // Must be old static pid (PID_S*) @@ -445,7 +445,7 @@ public class ComponentLocator { if (connector == null) { // Lookup by debugId // TODO Optimize this - connector = findConnectorById(client.getView(), + connector = findConnectorById(client.getRootConnector(), id.substring(5)); } @@ -541,7 +541,7 @@ public class ComponentLocator { * compatibility */ if (widgetClassName.equals("VWindow")) { - List windows = client.getView() + List windows = client.getRootConnector() .getSubWindows(); List windowWidgets = new ArrayList( windows.size()); diff --git a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java index f815dc29fc..ddf007ef37 100644 --- a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java +++ b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java @@ -52,11 +52,11 @@ import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ui.RootConnector; import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; import com.vaadin.terminal.gwt.client.ui.VNotification; import com.vaadin.terminal.gwt.client.ui.VOverlay; import com.vaadin.terminal.gwt.client.ui.WindowConnector; +import com.vaadin.terminal.gwt.client.ui.root.RootConnector; /** * A helper console for client side development. The debug console can also be @@ -100,7 +100,7 @@ public class VDebugConsole extends VOverlay implements Console { for (ApplicationConnection a : ApplicationConfiguration .getRunningApplications()) { ComponentConnector connector = Util.getConnectorForElement( - a, a.getView().getWidget(), eventTarget); + a, a.getRootConnector().getWidget(), eventTarget); if (connector == null) { connector = Util.getConnectorForElement(a, RootPanel.get(), eventTarget); @@ -129,7 +129,7 @@ public class VDebugConsole extends VOverlay implements Console { for (ApplicationConnection a : ApplicationConfiguration .getRunningApplications()) { ComponentConnector paintable = Util.getConnectorForElement( - a, a.getView().getWidget(), eventTarget); + a, a.getRootConnector().getWidget(), eventTarget); if (paintable == null) { paintable = Util.getConnectorForElement(a, RootPanel.get(), eventTarget); @@ -841,7 +841,7 @@ public class VDebugConsole extends VOverlay implements Console { } protected void dumpConnectorInfo(ApplicationConnection a) { - RootConnector root = a.getView(); + RootConnector root = a.getRootConnector(); log("================"); log("Connector hierarchy for Root: " + root.getState().getCaption() + " (" + root.getConnectorId() + ")"); diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java index 9ea03381c4..57ee8a0bce 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java @@ -22,6 +22,7 @@ import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.communication.ServerRpc; import com.vaadin.terminal.gwt.client.communication.SharedState; import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.root.RootConnector; public abstract class AbstractComponentConnector extends AbstractConnector implements ComponentConnector { diff --git a/src/com/vaadin/terminal/gwt/client/ui/RootConnector.java b/src/com/vaadin/terminal/gwt/client/ui/RootConnector.java deleted file mode 100644 index 21942ed96b..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/RootConnector.java +++ /dev/null @@ -1,417 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.google.gwt.core.client.GWT; -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.shared.HandlerRegistration; -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.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.ComponentConnector; -import com.vaadin.terminal.gwt.client.ComponentState; -import com.vaadin.terminal.gwt.client.Connector; -import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; -import com.vaadin.terminal.gwt.client.ConnectorMap; -import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.communication.RpcProxy; -import com.vaadin.terminal.gwt.client.communication.ServerRpc; -import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; -import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler; -import com.vaadin.terminal.gwt.client.ui.Component.LoadStyle; -import com.vaadin.ui.Root; - -@Component(value = Root.class, loadStyle = LoadStyle.EAGER) -public class RootConnector extends AbstractComponentContainerConnector - implements Paintable { - - public static class RootState extends ComponentState { - private Connector content; - - public Connector getContent() { - return content; - } - - public void setContent(Connector content) { - this.content = content; - } - - } - - public interface RootServerRPC extends ClickRPC, ServerRpc { - - } - - private RootServerRPC rpc; - - private HandlerRegistration childStateChangeHandlerRegistration; - - private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() { - 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(); - rpc = RpcProxy.create(RootServerRPC.class, this); - } - - 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().isImmediate(); - getWidget().resizeLazy = uidl.hasAttribute(VView.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 (getState().hasStyles()) { - for (String style : getState().getStyles()) { - styles += style + " "; - } - } - if (!client.getConfiguration().isStandalone()) { - styles += getWidget().getStylePrimaryName() + "-embedded"; - } - getWidget().setStyleName(styles.trim()); - - clickEventHandler.handleEventHandlerRegistration(); - - if (!getWidget().isEmbedded() && getState().getCaption() != null) { - // only change window title if we're in charge of the whole page - com.google.gwt.user.client.Window.setTitle(getState().getCaption()); - } - - // 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() { - public void execute() { - VView.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; - VView.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 == "execJS") { - String script = childUidl.getStringAttribute("script"); - VView.eval(script); - } 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() { - 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; - } - - // Safari workaround must be run after scrollTop is updated as it sets - // scrollTop using a deferred command. - if (BrowserInfo.get().isSafari()) { - Util.runWebkitOverflowAutoFix(getWidget().getElement()); - } - - getWidget().scrollIntoView(uidl); - - if (uidl.hasAttribute(VView.FRAGMENT_VARIABLE)) { - getWidget().currentFragment = uidl - .getStringAttribute(VView.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, VView.FRAGMENT_VARIABLE, - getWidget().currentFragment, false); - } - - 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); - } - - }; - - public void updateCaption(ComponentConnector component) { - // NOP The main view never draws caption for its layout - } - - @Override - public VView getWidget() { - return (VView) super.getWidget(); - } - - @Override - protected Widget createWidget() { - return GWT.create(VView.class); - } - - protected void onChildSizeChange() { - ComponentConnector child = (ComponentConnector) getState().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 Root 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 getChildren().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 : getChildren()) { - if (child instanceof WindowConnector) { - windows.add((WindowConnector) child); - } - } - return windows; - } - - @Override - public RootState getState() { - return (RootState) super.getState(); - } - - @Override - public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { - super.onConnectorHierarchyChange(event); - - ComponentConnector oldChild = null; - ComponentConnector newChild = (ComponentConnector) getState() - .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 : getChildren()) { - 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(); - } - } - } -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNotification.java b/src/com/vaadin/terminal/gwt/client/ui/VNotification.java index cf62bb2de8..1fc63e6a56 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VNotification.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VNotification.java @@ -21,6 +21,7 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.root.VRoot; public class VNotification extends VOverlay { @@ -364,7 +365,7 @@ public class VNotification extends VOverlay { public static void showNotification(ApplicationConnection client, final UIDL notification) { boolean onlyPlainText = notification - .hasAttribute(VView.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED); + .hasAttribute(VRoot.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED); String html = ""; if (notification.hasAttribute(ATTRIBUTE_NOTIFICATION_ICON)) { final String parsedUri = client.translateVaadinUri(notification diff --git a/src/com/vaadin/terminal/gwt/client/ui/VView.java b/src/com/vaadin/terminal/gwt/client/ui/VView.java deleted file mode 100644 index 2cf446ae41..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VView.java +++ /dev/null @@ -1,335 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; - -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.core.client.Scheduler.ScheduledCommand; -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.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.Timer; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.SimplePanel; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.ComponentConnector; -import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; - -/** - * - */ -public class VView extends SimplePanel implements ResizeHandler, - Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable { - - public static final String FRAGMENT_VARIABLE = "fragment"; - - private static final String CLASSNAME = "v-view"; - - public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain"; - - String theme; - - String id; - - ShortcutActionHandler actionHandler; - - /** stored width for IE resize optimization */ - private int width; - - /** stored height for IE resize optimization */ - private int height; - - ApplicationConnection connection; - - /** Identifies the click event */ - public static final String CLICK_EVENT_ID = "click"; - - /** - * We are postponing resize process with IE. IE bugs with scrollbars in some - * situations, that causes false onWindowResized calls. With Timer we will - * give IE some time to decide if it really wants to keep current size - * (scrollbars). - */ - private Timer resizeTimer; - - int scrollTop; - - int scrollLeft; - - boolean rendering; - - boolean scrollable; - - boolean immediate; - - boolean resizeLazy = false; - - /** - * Attribute name for the lazy resize setting . - */ - public static final String RESIZE_LAZY = "rL"; - - private HandlerRegistration historyHandlerRegistration; - - /** - * 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() { - 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, FRAGMENT_VARIABLE, newFragment, - true); - } - } - }; - - private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200, - new ScheduledCommand() { - public void execute() { - windowSizeMaybeChanged(Window.getClientWidth(), - Window.getClientHeight()); - } - - }); - - public VView() { - 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); - } - - @Override - protected void onAttach() { - super.onAttach(); - historyHandlerRegistration = History - .addValueChangeHandler(historyChangeHandler); - currentFragment = History.getToken(); - } - - @Override - protected void onDetach() { - super.onDetach(); - historyHandlerRegistration.removeHandler(); - historyHandlerRegistration = null; - } - - /** - * Called when the window might have been resized. - * - * @param newWidth - * The new width of the window - * @param newHeight - * The new height of the window - */ - protected void windowSizeMaybeChanged(int newWidth, int newHeight) { - boolean changed = false; - if (width != newWidth) { - width = newWidth; - changed = true; - VConsole.log("New window width: " + width); - } - if (height != newHeight) { - height = newHeight; - changed = true; - VConsole.log("New window height: " + height); - } - if (changed) { - VConsole.log("Running layout functions due to window resize"); - Util.runWebkitOverflowAutoFix(getElement()); - - sendClientResized(); - - connection.doLayout(false); - } - } - - public String getTheme() { - return theme; - } - - /** - * Used to reload host page on theme changes. - */ - static native void reloadHostPage() - /*-{ - $wnd.location.reload(); - }-*/; - - /** - * Evaluate the given script in the browser document. - * - * @param script - * Script to be executed. - */ - static native void eval(String script) - /*-{ - try { - if (script == null) return; - $wnd.eval(script); - } catch (e) { - } - }-*/; - - /** - * 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(ApplicationConnection.GENERATED_BODY_CLASSNAME); - } - - /** - * Tries to scroll paintable referenced from given UIDL snippet to be - * visible. - * - * @param uidl - */ - void scrollIntoView(final UIDL uidl) { - if (uidl.hasAttribute("scrollTo")) { - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - final ComponentConnector paintable = (ComponentConnector) uidl - .getPaintableAttribute("scrollTo", connection); - paintable.getWidget().getElement().scrollIntoView(); - } - }); - } - } - - @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) - */ - public void onResize(ResizeEvent event) { - onResize(); - } - - /** - * Called when a resize event is received. - */ - void onResize() { - /* - * 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 { - windowSizeMaybeChanged(Window.getClientWidth(), - Window.getClientHeight()); - } - } - - /** - * Send new dimensions to the server. - */ - private void sendClientResized() { - connection.updateVariable(id, "height", height, false); - connection.updateVariable(id, "width", width, immediate); - } - - public native static void goTo(String url) - /*-{ - $wnd.location = url; - }-*/; - - 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) { - list.@java.util.Collection::add(Ljava/lang/Object;)(j); - } - }-*/; - - public ShortcutActionHandler getShortcutActionHandler() { - return actionHandler; - } - - public void focus() { - getElement().focus(); - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/WindowConnector.java b/src/com/vaadin/terminal/gwt/client/ui/WindowConnector.java index 34a3f9a94f..4cee6813c7 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/WindowConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/WindowConnector.java @@ -243,8 +243,6 @@ public class WindowConnector extends AbstractComponentContainerConnector getWidget().setHeight(Window.getClientHeight() + "px"); } - client.getView().getWidget().scrollIntoView(uidl); - if (uidl.hasAttribute("bringToFront")) { /* * Focus as a side-efect. Will be overridden by diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java b/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java new file mode 100644 index 0000000000..04bfbf28bd --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java @@ -0,0 +1,429 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.root; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.google.gwt.core.client.GWT; +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.shared.HandlerRegistration; +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.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.Focusable; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.Component; +import com.vaadin.terminal.gwt.client.ui.Component.LoadStyle; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; +import com.vaadin.terminal.gwt.client.ui.VNotification; +import com.vaadin.terminal.gwt.client.ui.WindowConnector; +import com.vaadin.ui.Root; + +@Component(value = Root.class, loadStyle = LoadStyle.EAGER) +public class RootConnector extends AbstractComponentContainerConnector + implements Paintable { + + private RootServerRPC rpc = RpcProxy.create(RootServerRPC.class, this); + + private HandlerRegistration childStateChangeHandlerRegistration; + + private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() { + 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(); + } + + 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().isImmediate(); + getWidget().resizeLazy = uidl.hasAttribute(VRoot.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 (getState().hasStyles()) { + for (String style : getState().getStyles()) { + styles += style + " "; + } + } + if (!client.getConfiguration().isStandalone()) { + styles += getWidget().getStylePrimaryName() + "-embedded"; + } + getWidget().setStyleName(styles.trim()); + + clickEventHandler.handleEventHandlerRegistration(); + + if (!getWidget().isEmbedded() && getState().getCaption() != null) { + // only change window title if we're in charge of the whole page + com.google.gwt.user.client.Window.setTitle(getState().getCaption()); + } + + // 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() { + public void execute() { + VRoot.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; + VRoot.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 == "execJS") { + String script = childUidl.getStringAttribute("script"); + VRoot.eval(script); + } 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() { + 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; + } + + // Safari workaround must be run after scrollTop is updated as it sets + // scrollTop using a deferred command. + if (BrowserInfo.get().isSafari()) { + Util.runWebkitOverflowAutoFix(getWidget().getElement()); + } + + if (uidl.hasAttribute("scrollTo")) { + final ComponentConnector connector = (ComponentConnector) uidl + .getPaintableAttribute("scrollTo", getConnection()); + scrollIntoView(connector); + } + + if (uidl.hasAttribute(VRoot.FRAGMENT_VARIABLE)) { + getWidget().currentFragment = uidl + .getStringAttribute(VRoot.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, VRoot.FRAGMENT_VARIABLE, + getWidget().currentFragment, false); + } + + 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); + } + + }; + + public void updateCaption(ComponentConnector component) { + // NOP The main view never draws caption for its layout + } + + @Override + public VRoot getWidget() { + return (VRoot) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VRoot.class); + } + + protected ComponentConnector getContent() { + return (ComponentConnector) getState().getContent(); + } + + 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 Root 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 getChildren().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 : getChildren()) { + if (child instanceof WindowConnector) { + windows.add((WindowConnector) child); + } + } + return windows; + } + + @Override + public RootState getState() { + return (RootState) 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 : getChildren()) { + 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() { + public void execute() { + componentConnector.getWidget().getElement().scrollIntoView(); + } + }); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRPC.java b/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRPC.java new file mode 100644 index 0000000000..734c624aa1 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRPC.java @@ -0,0 +1,9 @@ +package com.vaadin.terminal.gwt.client.ui.root; + +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector.ClickRPC; + +public interface RootServerRPC extends ClickRPC, ServerRpc { + +} \ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/RootState.java b/src/com/vaadin/terminal/gwt/client/ui/root/RootState.java new file mode 100644 index 0000000000..0bd044c70b --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootState.java @@ -0,0 +1,17 @@ +package com.vaadin.terminal.gwt.client.ui.root; + +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.Connector; + +public class RootState extends ComponentState { + private Connector content; + + public Connector getContent() { + return content; + } + + public void setContent(Connector content) { + this.content = content; + } + +} \ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java new file mode 100644 index 0000000000..20263531a3 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java @@ -0,0 +1,316 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.root; + +import java.util.ArrayList; + +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +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.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.Focusable; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; +import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; +import com.vaadin.terminal.gwt.client.ui.VTextField; + +/** + * + */ +public class VRoot extends SimplePanel implements ResizeHandler, + Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable { + + public static final String FRAGMENT_VARIABLE = "fragment"; + + private static final String CLASSNAME = "v-view"; + + public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain"; + + String theme; + + String id; + + ShortcutActionHandler actionHandler; + + /** stored width for IE resize optimization */ + private int width; + + /** stored height for IE resize optimization */ + private int height; + + ApplicationConnection connection; + + /** Identifies the click event */ + public static final String CLICK_EVENT_ID = "click"; + + /** + * We are postponing resize process with IE. IE bugs with scrollbars in some + * situations, that causes false onWindowResized calls. With Timer we will + * give IE some time to decide if it really wants to keep current size + * (scrollbars). + */ + private Timer resizeTimer; + + int scrollTop; + + int scrollLeft; + + boolean rendering; + + boolean scrollable; + + boolean immediate; + + boolean resizeLazy = false; + + /** + * Attribute name for the lazy resize setting . + */ + public static final String RESIZE_LAZY = "rL"; + + private HandlerRegistration historyHandlerRegistration; + + /** + * 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() { + 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, FRAGMENT_VARIABLE, newFragment, + true); + } + } + }; + + private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200, + new ScheduledCommand() { + public void execute() { + windowSizeMaybeChanged(Window.getClientWidth(), + Window.getClientHeight()); + } + + }); + + public VRoot() { + 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); + } + + @Override + protected void onAttach() { + super.onAttach(); + historyHandlerRegistration = History + .addValueChangeHandler(historyChangeHandler); + currentFragment = History.getToken(); + } + + @Override + protected void onDetach() { + super.onDetach(); + historyHandlerRegistration.removeHandler(); + historyHandlerRegistration = null; + } + + /** + * Called when the window might have been resized. + * + * @param newWidth + * The new width of the window + * @param newHeight + * The new height of the window + */ + protected void windowSizeMaybeChanged(int newWidth, int newHeight) { + boolean changed = false; + if (width != newWidth) { + width = newWidth; + changed = true; + VConsole.log("New window width: " + width); + } + if (height != newHeight) { + height = newHeight; + changed = true; + VConsole.log("New window height: " + height); + } + if (changed) { + VConsole.log("Running layout functions due to window resize"); + Util.runWebkitOverflowAutoFix(getElement()); + + sendClientResized(); + + connection.doLayout(false); + } + } + + public String getTheme() { + return theme; + } + + /** + * Used to reload host page on theme changes. + */ + static native void reloadHostPage() + /*-{ + $wnd.location.reload(); + }-*/; + + /** + * Evaluate the given script in the browser document. + * + * @param script + * Script to be executed. + */ + static native void eval(String script) + /*-{ + try { + if (script == null) return; + $wnd.eval(script); + } catch (e) { + } + }-*/; + + /** + * 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(ApplicationConnection.GENERATED_BODY_CLASSNAME); + } + + @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) + */ + public void onResize(ResizeEvent event) { + onResize(); + } + + /** + * Called when a resize event is received. + */ + void onResize() { + /* + * 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 { + windowSizeMaybeChanged(Window.getClientWidth(), + Window.getClientHeight()); + } + } + + /** + * Send new dimensions to the server. + */ + private void sendClientResized() { + connection.updateVariable(id, "height", height, false); + connection.updateVariable(id, "width", width, immediate); + } + + public native static void goTo(String url) + /*-{ + $wnd.location = url; + }-*/; + + 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) { + list.@java.util.Collection::add(Ljava/lang/Object;)(j); + } + }-*/; + + public ShortcutActionHandler getShortcutActionHandler() { + return actionHandler; + } + + public void focus() { + getElement().focus(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java index 8552168753..2db68ebca2 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java @@ -26,7 +26,7 @@ import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.Connector; import com.vaadin.terminal.gwt.client.ui.Component; import com.vaadin.terminal.gwt.client.ui.Component.LoadStyle; -import com.vaadin.terminal.gwt.client.ui.RootConnector; +import com.vaadin.terminal.gwt.client.ui.root.RootConnector; import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector; import com.vaadin.terminal.gwt.server.ClientConnector; diff --git a/src/com/vaadin/ui/Root.java b/src/com/vaadin/ui/Root.java index 6850c88a81..aab4c1b6e9 100644 --- a/src/com/vaadin/ui/Root.java +++ b/src/com/vaadin/ui/Root.java @@ -31,10 +31,10 @@ import com.vaadin.terminal.Vaadin6Component; import com.vaadin.terminal.WrappedRequest; import com.vaadin.terminal.WrappedRequest.BrowserDetails; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.ui.RootConnector.RootServerRPC; -import com.vaadin.terminal.gwt.client.ui.RootConnector.RootState; import com.vaadin.terminal.gwt.client.ui.VNotification; -import com.vaadin.terminal.gwt.client.ui.VView; +import com.vaadin.terminal.gwt.client.ui.root.RootServerRPC; +import com.vaadin.terminal.gwt.client.ui.root.RootState; +import com.vaadin.terminal.gwt.client.ui.root.VRoot; import com.vaadin.tools.ReflectTools; import com.vaadin.ui.Window.CloseListener; @@ -403,7 +403,7 @@ public abstract class Root extends AbstractComponentContainer implements private int browserWindowHeight = -1; /** Identifies the click event */ - private static final String CLICK_EVENT_ID = VView.CLICK_EVENT_ID; + private static final String CLICK_EVENT_ID = VRoot.CLICK_EVENT_ID; private DirtyConnectorTracker dirtyConnectorTracker = new DirtyConnectorTracker( this); @@ -530,7 +530,7 @@ public abstract class Root extends AbstractComponentContainer implements } if (!n.isHtmlContentAllowed()) { target.addAttribute( - VView.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED, true); + VRoot.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED, true); } target.addAttribute( VNotification.ATTRIBUTE_NOTIFICATION_POSITION, @@ -578,11 +578,11 @@ public abstract class Root extends AbstractComponentContainer implements } if (fragment != null) { - target.addAttribute(VView.FRAGMENT_VARIABLE, fragment); + target.addAttribute(VRoot.FRAGMENT_VARIABLE, fragment); } if (isResizeLazy()) { - target.addAttribute(VView.RESIZE_LAZY, true); + target.addAttribute(VRoot.RESIZE_LAZY, true); } } @@ -609,8 +609,8 @@ public abstract class Root extends AbstractComponentContainer implements actionManager.handleActions(variables, this); } - if (variables.containsKey(VView.FRAGMENT_VARIABLE)) { - String fragment = (String) variables.get(VView.FRAGMENT_VARIABLE); + if (variables.containsKey(VRoot.FRAGMENT_VARIABLE)) { + String fragment = (String) variables.get(VRoot.FRAGMENT_VARIABLE); setFragment(fragment, true); }