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.

VViewPaintable.java 14KB

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