You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RootConnector.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.ui;
  5. import java.util.HashSet;
  6. import java.util.Iterator;
  7. import com.google.gwt.core.client.GWT;
  8. import com.google.gwt.core.client.Scheduler;
  9. import com.google.gwt.event.dom.client.DomEvent.Type;
  10. import com.google.gwt.event.shared.EventHandler;
  11. import com.google.gwt.event.shared.HandlerRegistration;
  12. import com.google.gwt.user.client.Command;
  13. import com.google.gwt.user.client.DOM;
  14. import com.google.gwt.user.client.Event;
  15. import com.google.gwt.user.client.History;
  16. import com.google.gwt.user.client.Window;
  17. import com.google.gwt.user.client.ui.RootPanel;
  18. import com.google.gwt.user.client.ui.Widget;
  19. import com.vaadin.terminal.gwt.client.ApplicationConnection;
  20. import com.vaadin.terminal.gwt.client.BrowserInfo;
  21. import com.vaadin.terminal.gwt.client.ComponentConnector;
  22. import com.vaadin.terminal.gwt.client.ConnectorMap;
  23. import com.vaadin.terminal.gwt.client.Focusable;
  24. import com.vaadin.terminal.gwt.client.UIDL;
  25. import com.vaadin.terminal.gwt.client.Util;
  26. import com.vaadin.terminal.gwt.client.VConsole;
  27. public class RootConnector extends AbstractComponentContainerConnector {
  28. private static final String CLICK_EVENT_IDENTIFIER = PanelConnector.CLICK_EVENT_IDENTIFIER;
  29. @Override
  30. public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
  31. getWidget().rendering = true;
  32. getWidget().id = getId();
  33. boolean firstPaint = getWidget().connection == null;
  34. getWidget().connection = client;
  35. getWidget().immediate = getState().isImmediate();
  36. getWidget().resizeLazy = uidl.hasAttribute(VView.RESIZE_LAZY);
  37. String newTheme = uidl.getStringAttribute("theme");
  38. if (getWidget().theme != null && !newTheme.equals(getWidget().theme)) {
  39. // Complete page refresh is needed due css can affect layout
  40. // calculations etc
  41. getWidget().reloadHostPage();
  42. } else {
  43. getWidget().theme = newTheme;
  44. }
  45. // this also implicitly removes old styles
  46. getWidget()
  47. .setStyleName(
  48. getWidget().getStylePrimaryName() + " "
  49. + getState().getStyle());
  50. clickEventHandler.handleEventHandlerRegistration(client);
  51. if (!getWidget().isEmbedded() && getState().getCaption() != null) {
  52. // only change window title if we're in charge of the whole page
  53. com.google.gwt.user.client.Window.setTitle(getState().getCaption());
  54. }
  55. // Process children
  56. int childIndex = 0;
  57. // Open URL:s
  58. boolean isClosed = false; // was this window closed?
  59. while (childIndex < uidl.getChildCount()
  60. && "open".equals(uidl.getChildUIDL(childIndex).getTag())) {
  61. final UIDL open = uidl.getChildUIDL(childIndex);
  62. final String url = client.translateVaadinUri(open
  63. .getStringAttribute("src"));
  64. final String target = open.getStringAttribute("name");
  65. if (target == null) {
  66. // source will be opened to this browser window, but we may have
  67. // to finish rendering this window in case this is a download
  68. // (and window stays open).
  69. Scheduler.get().scheduleDeferred(new Command() {
  70. public void execute() {
  71. VView.goTo(url);
  72. }
  73. });
  74. } else if ("_self".equals(target)) {
  75. // This window is closing (for sure). Only other opens are
  76. // relevant in this change. See #3558, #2144
  77. isClosed = true;
  78. VView.goTo(url);
  79. } else {
  80. String options;
  81. if (open.hasAttribute("border")) {
  82. if (open.getStringAttribute("border").equals("minimal")) {
  83. options = "menubar=yes,location=no,status=no";
  84. } else {
  85. options = "menubar=no,location=no,status=no";
  86. }
  87. } else {
  88. options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes";
  89. }
  90. if (open.hasAttribute("width")) {
  91. int w = open.getIntAttribute("width");
  92. options += ",width=" + w;
  93. }
  94. if (open.hasAttribute("height")) {
  95. int h = open.getIntAttribute("height");
  96. options += ",height=" + h;
  97. }
  98. Window.open(url, target, options);
  99. }
  100. childIndex++;
  101. }
  102. if (isClosed) {
  103. // don't render the content, something else will be opened to this
  104. // browser view
  105. getWidget().rendering = false;
  106. return;
  107. }
  108. // Draw this application level window
  109. UIDL childUidl = uidl.getChildUIDL(childIndex);
  110. final ComponentConnector lo = client.getPaintable(childUidl);
  111. if (getWidget().layout != null) {
  112. if (getWidget().layout != lo) {
  113. // remove old
  114. client.unregisterPaintable(getWidget().layout);
  115. // add new
  116. getWidget().setWidget(lo.getWidget());
  117. getWidget().layout = lo;
  118. }
  119. } else {
  120. getWidget().setWidget(lo.getWidget());
  121. getWidget().layout = lo;
  122. }
  123. getWidget().layout.updateFromUIDL(childUidl, client);
  124. // Save currently open subwindows to track which will need to be closed
  125. final HashSet<VWindow> removedSubWindows = new HashSet<VWindow>(
  126. getWidget().subWindows);
  127. // Handle other UIDL children
  128. while ((childUidl = uidl.getChildUIDL(++childIndex)) != null) {
  129. String tag = childUidl.getTag().intern();
  130. if (tag == "actions") {
  131. if (getWidget().actionHandler == null) {
  132. getWidget().actionHandler = new ShortcutActionHandler(
  133. getWidget().id, client);
  134. }
  135. getWidget().actionHandler.updateActionMap(childUidl);
  136. } else if (tag == "execJS") {
  137. String script = childUidl.getStringAttribute("script");
  138. VView.eval(script);
  139. } else if (tag == "notifications") {
  140. for (final Iterator<?> it = childUidl.getChildIterator(); it
  141. .hasNext();) {
  142. final UIDL notification = (UIDL) it.next();
  143. VNotification.showNotification(client, notification);
  144. }
  145. } else {
  146. // subwindows
  147. final WindowConnector w = (WindowConnector) client
  148. .getPaintable(childUidl);
  149. VWindow windowWidget = w.getWidget();
  150. if (getWidget().subWindows.contains(windowWidget)) {
  151. removedSubWindows.remove(windowWidget);
  152. } else {
  153. getWidget().subWindows.add(windowWidget);
  154. }
  155. w.updateFromUIDL(childUidl, client);
  156. }
  157. }
  158. // Close old windows which where not in UIDL anymore
  159. for (final Iterator<VWindow> rem = removedSubWindows.iterator(); rem
  160. .hasNext();) {
  161. final VWindow w = rem.next();
  162. client.unregisterPaintable(ConnectorMap.get(getConnection())
  163. .getConnector(w));
  164. getWidget().subWindows.remove(w);
  165. w.hide();
  166. }
  167. if (uidl.hasAttribute("focused")) {
  168. // set focused component when render phase is finished
  169. Scheduler.get().scheduleDeferred(new Command() {
  170. public void execute() {
  171. ComponentConnector paintable = (ComponentConnector) uidl
  172. .getPaintableAttribute("focused", getConnection());
  173. final Widget toBeFocused = paintable.getWidget();
  174. /*
  175. * Two types of Widgets can be focused, either implementing
  176. * GWT HasFocus of a thinner Vaadin specific Focusable
  177. * interface.
  178. */
  179. if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
  180. final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused;
  181. toBeFocusedWidget.setFocus(true);
  182. } else if (toBeFocused instanceof Focusable) {
  183. ((Focusable) toBeFocused).focus();
  184. } else {
  185. VConsole.log("Could not focus component");
  186. }
  187. }
  188. });
  189. }
  190. // Add window listeners on first paint, to prevent premature
  191. // variablechanges
  192. if (firstPaint) {
  193. Window.addWindowClosingHandler(getWidget());
  194. Window.addResizeHandler(getWidget());
  195. }
  196. getWidget().onResize();
  197. // finally set scroll position from UIDL
  198. if (uidl.hasVariable("scrollTop")) {
  199. getWidget().scrollable = true;
  200. getWidget().scrollTop = uidl.getIntVariable("scrollTop");
  201. DOM.setElementPropertyInt(getWidget().getElement(), "scrollTop",
  202. getWidget().scrollTop);
  203. getWidget().scrollLeft = uidl.getIntVariable("scrollLeft");
  204. DOM.setElementPropertyInt(getWidget().getElement(), "scrollLeft",
  205. getWidget().scrollLeft);
  206. } else {
  207. getWidget().scrollable = false;
  208. }
  209. // Safari workaround must be run after scrollTop is updated as it sets
  210. // scrollTop using a deferred command.
  211. if (BrowserInfo.get().isSafari()) {
  212. Util.runWebkitOverflowAutoFix(getWidget().getElement());
  213. }
  214. getWidget().scrollIntoView(uidl);
  215. if (uidl.hasAttribute(VView.FRAGMENT_VARIABLE)) {
  216. getWidget().currentFragment = uidl
  217. .getStringAttribute(VView.FRAGMENT_VARIABLE);
  218. if (!getWidget().currentFragment.equals(History.getToken())) {
  219. History.newItem(getWidget().currentFragment, true);
  220. }
  221. } else {
  222. // Initial request for which the server doesn't yet have a fragment
  223. // (and haven't shown any interest in getting one)
  224. getWidget().currentFragment = History.getToken();
  225. // Include current fragment in the next request
  226. client.updateVariable(getWidget().id, VView.FRAGMENT_VARIABLE,
  227. getWidget().currentFragment, false);
  228. }
  229. getWidget().rendering = false;
  230. }
  231. public void init(String rootPanelId,
  232. ApplicationConnection applicationConnection) {
  233. DOM.sinkEvents(getWidget().getElement(), Event.ONKEYDOWN
  234. | Event.ONSCROLL);
  235. // iview is focused when created so element needs tabIndex
  236. // 1 due 0 is at the end of natural tabbing order
  237. DOM.setElementProperty(getWidget().getElement(), "tabIndex", "1");
  238. RootPanel root = RootPanel.get(rootPanelId);
  239. // Remove the v-app-loading or any splash screen added inside the div by
  240. // the user
  241. root.getElement().setInnerHTML("");
  242. root.addStyleName("v-theme-"
  243. + applicationConnection.getConfiguration().getThemeName());
  244. root.add(getWidget());
  245. if (applicationConnection.getConfiguration().isStandalone()) {
  246. // set focus to iview element by default to listen possible keyboard
  247. // shortcuts. For embedded applications this is unacceptable as we
  248. // don't want to steal focus from the main page nor we don't want
  249. // side-effects from focusing (scrollIntoView).
  250. getWidget().getElement().focus();
  251. }
  252. }
  253. private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
  254. CLICK_EVENT_IDENTIFIER) {
  255. @Override
  256. protected <H extends EventHandler> HandlerRegistration registerHandler(
  257. H handler, Type<H> type) {
  258. return getWidget().addDomHandler(handler, type);
  259. }
  260. };
  261. public void updateCaption(ComponentConnector component, UIDL uidl) {
  262. // NOP The main view never draws caption for its layout
  263. }
  264. @Override
  265. public VView getWidget() {
  266. return (VView) super.getWidget();
  267. }
  268. @Override
  269. protected Widget createWidget() {
  270. return GWT.create(VView.class);
  271. }
  272. }