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.

VView.java 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.ui;
  5. import java.util.ArrayList;
  6. import java.util.HashSet;
  7. import java.util.Iterator;
  8. import java.util.LinkedHashSet;
  9. import java.util.Set;
  10. import com.google.gwt.core.client.Scheduler;
  11. import com.google.gwt.core.client.Scheduler.ScheduledCommand;
  12. import com.google.gwt.dom.client.DivElement;
  13. import com.google.gwt.dom.client.Document;
  14. import com.google.gwt.dom.client.Element;
  15. import com.google.gwt.dom.client.Style;
  16. import com.google.gwt.dom.client.Style.Display;
  17. import com.google.gwt.event.dom.client.DomEvent.Type;
  18. import com.google.gwt.event.logical.shared.ResizeEvent;
  19. import com.google.gwt.event.logical.shared.ResizeHandler;
  20. import com.google.gwt.event.logical.shared.ValueChangeEvent;
  21. import com.google.gwt.event.logical.shared.ValueChangeHandler;
  22. import com.google.gwt.event.shared.EventHandler;
  23. import com.google.gwt.event.shared.HandlerRegistration;
  24. import com.google.gwt.user.client.Command;
  25. import com.google.gwt.user.client.DOM;
  26. import com.google.gwt.user.client.Event;
  27. import com.google.gwt.user.client.History;
  28. import com.google.gwt.user.client.Timer;
  29. import com.google.gwt.user.client.Window;
  30. import com.google.gwt.user.client.ui.RootPanel;
  31. import com.google.gwt.user.client.ui.SimplePanel;
  32. import com.google.gwt.user.client.ui.Widget;
  33. import com.vaadin.terminal.gwt.client.ApplicationConnection;
  34. import com.vaadin.terminal.gwt.client.BrowserInfo;
  35. import com.vaadin.terminal.gwt.client.Container;
  36. import com.vaadin.terminal.gwt.client.Focusable;
  37. import com.vaadin.terminal.gwt.client.RenderSpace;
  38. import com.vaadin.terminal.gwt.client.UIDL;
  39. import com.vaadin.terminal.gwt.client.Util;
  40. import com.vaadin.terminal.gwt.client.VConsole;
  41. import com.vaadin.terminal.gwt.client.VPaintableWidget;
  42. import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
  43. /**
  44. *
  45. */
  46. public class VView extends SimplePanel implements Container, ResizeHandler,
  47. Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable {
  48. public static final String FRAGMENT_VARIABLE = "fragment";
  49. private static final String CLASSNAME = "v-view";
  50. public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain";
  51. private String theme;
  52. private VPaintableWidget layout;
  53. private final LinkedHashSet<VWindow> subWindows = new LinkedHashSet<VWindow>();
  54. private String id;
  55. private ShortcutActionHandler actionHandler;
  56. /** stored width for IE resize optimization */
  57. private int width;
  58. /** stored height for IE resize optimization */
  59. private int height;
  60. private ApplicationConnection connection;
  61. /** Identifies the click event */
  62. public static final String CLICK_EVENT_ID = "click";
  63. /**
  64. * We are postponing resize process with IE. IE bugs with scrollbars in some
  65. * situations, that causes false onWindowResized calls. With Timer we will
  66. * give IE some time to decide if it really wants to keep current size
  67. * (scrollbars).
  68. */
  69. private Timer resizeTimer;
  70. private int scrollTop;
  71. private int scrollLeft;
  72. private boolean rendering;
  73. private boolean scrollable;
  74. private boolean immediate;
  75. private boolean resizeLazy = false;
  76. /**
  77. * Attribute name for the lazy resize setting .
  78. */
  79. public static final String RESIZE_LAZY = "rL";
  80. /**
  81. * Reference to the parent frame/iframe. Null if there is no parent (i)frame
  82. * or if the application and parent frame are in different domains.
  83. */
  84. private Element parentFrame;
  85. private HandlerRegistration historyHandlerRegistration;
  86. /**
  87. * The current URI fragment, used to avoid sending updates if nothing has
  88. * changed.
  89. */
  90. private String currentFragment;
  91. /**
  92. * Listener for URI fragment changes. Notifies the server of the new value
  93. * whenever the value changes.
  94. */
  95. private final ValueChangeHandler<String> historyChangeHandler = new ValueChangeHandler<String>() {
  96. public void onValueChange(ValueChangeEvent<String> event) {
  97. String newFragment = event.getValue();
  98. // Send the new fragment to the server if it has changed
  99. if (!newFragment.equals(currentFragment) && connection != null) {
  100. currentFragment = newFragment;
  101. connection.updateVariable(id, FRAGMENT_VARIABLE, newFragment,
  102. true);
  103. }
  104. }
  105. };
  106. private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
  107. VPanel.CLICK_EVENT_IDENTIFIER) {
  108. @Override
  109. protected <H extends EventHandler> HandlerRegistration registerHandler(
  110. H handler, Type<H> type) {
  111. return addDomHandler(handler, type);
  112. }
  113. };
  114. private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200,
  115. new ScheduledCommand() {
  116. public void execute() {
  117. windowSizeMaybeChanged(Window.getClientWidth(),
  118. Window.getClientHeight());
  119. }
  120. });
  121. public VView() {
  122. super();
  123. setStyleName(CLASSNAME);
  124. // Allow focusing the view by using the focus() method, the view
  125. // should not be in the document focus flow
  126. getElement().setTabIndex(-1);
  127. }
  128. @Override
  129. protected void onAttach() {
  130. super.onAttach();
  131. historyHandlerRegistration = History
  132. .addValueChangeHandler(historyChangeHandler);
  133. currentFragment = History.getToken();
  134. }
  135. @Override
  136. protected void onDetach() {
  137. super.onDetach();
  138. historyHandlerRegistration.removeHandler();
  139. historyHandlerRegistration = null;
  140. }
  141. /**
  142. * Called when the window might have been resized.
  143. *
  144. * @param newWidth
  145. * The new width of the window
  146. * @param newHeight
  147. * The new height of the window
  148. */
  149. protected void windowSizeMaybeChanged(int newWidth, int newHeight) {
  150. boolean changed = false;
  151. if (width != newWidth) {
  152. width = newWidth;
  153. changed = true;
  154. VConsole.log("New window width: " + width);
  155. }
  156. if (height != newHeight) {
  157. height = newHeight;
  158. changed = true;
  159. VConsole.log("New window height: " + height);
  160. }
  161. if (changed) {
  162. VConsole.log("Running layout functions due to window resize");
  163. connection.runDescendentsLayout(VView.this);
  164. Util.runWebkitOverflowAutoFix(getElement());
  165. sendClientResized();
  166. }
  167. }
  168. public String getTheme() {
  169. return theme;
  170. }
  171. /**
  172. * Used to reload host page on theme changes.
  173. */
  174. private static native void reloadHostPage()
  175. /*-{
  176. $wnd.location.reload();
  177. }-*/;
  178. /**
  179. * Evaluate the given script in the browser document.
  180. *
  181. * @param script
  182. * Script to be executed.
  183. */
  184. private static native void eval(String script)
  185. /*-{
  186. try {
  187. if (script == null) return;
  188. $wnd.eval(script);
  189. } catch (e) {
  190. }
  191. }-*/;
  192. /**
  193. * Returns true if the body is NOT generated, i.e if someone else has made
  194. * the page that we're running in. Otherwise we're in charge of the whole
  195. * page.
  196. *
  197. * @return true if we're running embedded
  198. */
  199. public boolean isEmbedded() {
  200. return !getElement().getOwnerDocument().getBody().getClassName()
  201. .contains(ApplicationConnection.GENERATED_BODY_CLASSNAME);
  202. }
  203. public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
  204. rendering = true;
  205. id = uidl.getId();
  206. boolean firstPaint = connection == null;
  207. connection = client;
  208. immediate = uidl.hasAttribute("immediate");
  209. resizeLazy = uidl.hasAttribute(RESIZE_LAZY);
  210. String newTheme = uidl.getStringAttribute("theme");
  211. if (theme != null && !newTheme.equals(theme)) {
  212. // Complete page refresh is needed due css can affect layout
  213. // calculations etc
  214. reloadHostPage();
  215. } else {
  216. theme = newTheme;
  217. }
  218. if (uidl.hasAttribute("style")) {
  219. setStyleName(getStylePrimaryName() + " "
  220. + uidl.getStringAttribute("style"));
  221. }
  222. clickEventHandler.handleEventHandlerRegistration(client);
  223. if (!isEmbedded() && uidl.hasAttribute("caption")) {
  224. // only change window title if we're in charge of the whole page
  225. com.google.gwt.user.client.Window.setTitle(uidl
  226. .getStringAttribute("caption"));
  227. }
  228. // Process children
  229. int childIndex = 0;
  230. // Open URL:s
  231. boolean isClosed = false; // was this window closed?
  232. while (childIndex < uidl.getChildCount()
  233. && "open".equals(uidl.getChildUIDL(childIndex).getTag())) {
  234. final UIDL open = uidl.getChildUIDL(childIndex);
  235. final String url = client.translateVaadinUri(open
  236. .getStringAttribute("src"));
  237. final String target = open.getStringAttribute("name");
  238. if (target == null) {
  239. // source will be opened to this browser window, but we may have
  240. // to finish rendering this window in case this is a download
  241. // (and window stays open).
  242. Scheduler.get().scheduleDeferred(new Command() {
  243. public void execute() {
  244. goTo(url);
  245. }
  246. });
  247. } else if ("_self".equals(target)) {
  248. // This window is closing (for sure). Only other opens are
  249. // relevant in this change. See #3558, #2144
  250. isClosed = true;
  251. goTo(url);
  252. } else {
  253. String options;
  254. if (open.hasAttribute("border")) {
  255. if (open.getStringAttribute("border").equals("minimal")) {
  256. options = "menubar=yes,location=no,status=no";
  257. } else {
  258. options = "menubar=no,location=no,status=no";
  259. }
  260. } else {
  261. options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes";
  262. }
  263. if (open.hasAttribute("width")) {
  264. int w = open.getIntAttribute("width");
  265. options += ",width=" + w;
  266. }
  267. if (open.hasAttribute("height")) {
  268. int h = open.getIntAttribute("height");
  269. options += ",height=" + h;
  270. }
  271. Window.open(url, target, options);
  272. }
  273. childIndex++;
  274. }
  275. if (isClosed) {
  276. // don't render the content, something else will be opened to this
  277. // browser view
  278. rendering = false;
  279. return;
  280. }
  281. // Draw this application level window
  282. UIDL childUidl = uidl.getChildUIDL(childIndex);
  283. final VPaintableWidget lo = client.getPaintable(childUidl);
  284. if (layout != null) {
  285. if (layout != lo) {
  286. // remove old
  287. client.unregisterPaintable(layout);
  288. // add new
  289. setWidget(lo.getWidgetForPaintable());
  290. layout = lo;
  291. }
  292. } else {
  293. setWidget(lo.getWidgetForPaintable());
  294. layout = lo;
  295. }
  296. layout.updateFromUIDL(childUidl, client);
  297. if (!childUidl.getBooleanAttribute("cached")) {
  298. updateParentFrameSize();
  299. }
  300. // Save currently open subwindows to track which will need to be closed
  301. final HashSet<VWindow> removedSubWindows = new HashSet<VWindow>(
  302. subWindows);
  303. // Handle other UIDL children
  304. while ((childUidl = uidl.getChildUIDL(++childIndex)) != null) {
  305. String tag = childUidl.getTag().intern();
  306. if (tag == "actions") {
  307. if (actionHandler == null) {
  308. actionHandler = new ShortcutActionHandler(id, client);
  309. }
  310. actionHandler.updateActionMap(childUidl);
  311. } else if (tag == "execJS") {
  312. String script = childUidl.getStringAttribute("script");
  313. eval(script);
  314. } else if (tag == "notifications") {
  315. for (final Iterator<?> it = childUidl.getChildIterator(); it
  316. .hasNext();) {
  317. final UIDL notification = (UIDL) it.next();
  318. VNotification.showNotification(client, notification);
  319. }
  320. } else {
  321. // subwindows
  322. final VPaintableWidget w = client.getPaintable(childUidl);
  323. if (subWindows.contains(w)) {
  324. removedSubWindows.remove(w);
  325. } else {
  326. subWindows.add((VWindow) w);
  327. }
  328. w.updateFromUIDL(childUidl, client);
  329. }
  330. }
  331. // Close old windows which where not in UIDL anymore
  332. for (final Iterator<VWindow> rem = removedSubWindows.iterator(); rem
  333. .hasNext();) {
  334. final VWindow w = rem.next();
  335. client.unregisterPaintable(w);
  336. subWindows.remove(w);
  337. w.hide();
  338. }
  339. if (uidl.hasAttribute("focused")) {
  340. // set focused component when render phase is finished
  341. Scheduler.get().scheduleDeferred(new Command() {
  342. public void execute() {
  343. VPaintableWidget paintable = (VPaintableWidget) uidl
  344. .getPaintableAttribute("focused", connection);
  345. final Widget toBeFocused = paintable
  346. .getWidgetForPaintable();
  347. /*
  348. * Two types of Widgets can be focused, either implementing
  349. * GWT HasFocus of a thinner Vaadin specific Focusable
  350. * interface.
  351. */
  352. if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
  353. final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused;
  354. toBeFocusedWidget.setFocus(true);
  355. } else if (toBeFocused instanceof Focusable) {
  356. ((Focusable) toBeFocused).focus();
  357. } else {
  358. VConsole.log("Could not focus component");
  359. }
  360. }
  361. });
  362. }
  363. // Add window listeners on first paint, to prevent premature
  364. // variablechanges
  365. if (firstPaint) {
  366. Window.addWindowClosingHandler(this);
  367. Window.addResizeHandler(this);
  368. }
  369. onResize();
  370. // finally set scroll position from UIDL
  371. if (uidl.hasVariable("scrollTop")) {
  372. scrollable = true;
  373. scrollTop = uidl.getIntVariable("scrollTop");
  374. DOM.setElementPropertyInt(getElement(), "scrollTop", scrollTop);
  375. scrollLeft = uidl.getIntVariable("scrollLeft");
  376. DOM.setElementPropertyInt(getElement(), "scrollLeft", scrollLeft);
  377. } else {
  378. scrollable = false;
  379. }
  380. // Safari workaround must be run after scrollTop is updated as it sets
  381. // scrollTop using a deferred command.
  382. if (BrowserInfo.get().isSafari()) {
  383. Util.runWebkitOverflowAutoFix(getElement());
  384. }
  385. scrollIntoView(uidl);
  386. if (uidl.hasAttribute(FRAGMENT_VARIABLE)) {
  387. currentFragment = uidl.getStringAttribute(FRAGMENT_VARIABLE);
  388. if (!currentFragment.equals(History.getToken())) {
  389. History.newItem(currentFragment, true);
  390. }
  391. } else {
  392. // Initial request for which the server doesn't yet have a fragment
  393. // (and haven't shown any interest in getting one)
  394. currentFragment = History.getToken();
  395. // Include current fragment in the next request
  396. client.updateVariable(id, FRAGMENT_VARIABLE, currentFragment, false);
  397. }
  398. rendering = false;
  399. }
  400. /**
  401. * Tries to scroll paintable referenced from given UIDL snippet to be
  402. * visible.
  403. *
  404. * @param uidl
  405. */
  406. void scrollIntoView(final UIDL uidl) {
  407. if (uidl.hasAttribute("scrollTo")) {
  408. Scheduler.get().scheduleDeferred(new Command() {
  409. public void execute() {
  410. final VPaintableWidget paintable = (VPaintableWidget) uidl
  411. .getPaintableAttribute("scrollTo", connection);
  412. paintable.getWidgetForPaintable().getElement()
  413. .scrollIntoView();
  414. }
  415. });
  416. }
  417. }
  418. @Override
  419. public void onBrowserEvent(Event event) {
  420. super.onBrowserEvent(event);
  421. int type = DOM.eventGetType(event);
  422. if (type == Event.ONKEYDOWN && actionHandler != null) {
  423. actionHandler.handleKeyboardEvent(event);
  424. return;
  425. } else if (scrollable && type == Event.ONSCROLL) {
  426. updateScrollPosition();
  427. }
  428. }
  429. /**
  430. * Updates scroll position from DOM and saves variables to server.
  431. */
  432. private void updateScrollPosition() {
  433. int oldTop = scrollTop;
  434. int oldLeft = scrollLeft;
  435. scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop");
  436. scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft");
  437. if (connection != null && !rendering) {
  438. if (oldTop != scrollTop) {
  439. connection.updateVariable(id, "scrollTop", scrollTop, false);
  440. }
  441. if (oldLeft != scrollLeft) {
  442. connection.updateVariable(id, "scrollLeft", scrollLeft, false);
  443. }
  444. }
  445. }
  446. /*
  447. * (non-Javadoc)
  448. *
  449. * @see
  450. * com.google.gwt.event.logical.shared.ResizeHandler#onResize(com.google
  451. * .gwt.event.logical.shared.ResizeEvent)
  452. */
  453. public void onResize(ResizeEvent event) {
  454. onResize();
  455. }
  456. /**
  457. * Called when a resize event is received.
  458. */
  459. private void onResize() {
  460. /*
  461. * IE (pre IE9 at least) will give us some false resize events due to
  462. * problems with scrollbars. Firefox 3 might also produce some extra
  463. * events. We postpone both the re-layouting and the server side event
  464. * for a while to deal with these issues.
  465. *
  466. * We may also postpone these events to avoid slowness when resizing the
  467. * browser window. Constantly recalculating the layout causes the resize
  468. * operation to be really slow with complex layouts.
  469. */
  470. boolean lazy = resizeLazy || BrowserInfo.get().isIE8();
  471. if (lazy) {
  472. delayedResizeExecutor.trigger();
  473. } else {
  474. windowSizeMaybeChanged(Window.getClientWidth(),
  475. Window.getClientHeight());
  476. }
  477. }
  478. /**
  479. * Send new dimensions to the server.
  480. */
  481. private void sendClientResized() {
  482. connection.updateVariable(id, "height", height, false);
  483. connection.updateVariable(id, "width", width, immediate);
  484. }
  485. public native static void goTo(String url)
  486. /*-{
  487. $wnd.location = url;
  488. }-*/;
  489. public void onWindowClosing(Window.ClosingEvent event) {
  490. // Change focus on this window in order to ensure that all state is
  491. // collected from textfields
  492. // TODO this is a naive hack, that only works with text fields and may
  493. // cause some odd issues. Should be replaced with a decent solution, see
  494. // also related BeforeShortcutActionListener interface. Same interface
  495. // might be usable here.
  496. VTextField.flushChangesFromFocusedTextField();
  497. }
  498. private final RenderSpace myRenderSpace = new RenderSpace() {
  499. private int excessHeight = -1;
  500. private int excessWidth = -1;
  501. @Override
  502. public int getHeight() {
  503. return getElement().getOffsetHeight() - getExcessHeight();
  504. }
  505. private int getExcessHeight() {
  506. if (excessHeight < 0) {
  507. detectExcessSize();
  508. }
  509. return excessHeight;
  510. }
  511. private void detectExcessSize() {
  512. // TODO define that iview cannot be themed and decorations should
  513. // get to parent element, then get rid of this expensive and error
  514. // prone function
  515. final String overflow = getElement().getStyle().getProperty(
  516. "overflow");
  517. getElement().getStyle().setProperty("overflow", "hidden");
  518. if (BrowserInfo.get().isIE()
  519. && getElement().getPropertyInt("clientWidth") == 0) {
  520. // can't detect possibly themed border/padding width in some
  521. // situations (with some layout configurations), use empty div
  522. // to measure width properly
  523. DivElement div = Document.get().createDivElement();
  524. div.setInnerHTML("&nbsp;");
  525. div.getStyle().setProperty("overflow", "hidden");
  526. div.getStyle().setProperty("height", "1px");
  527. getElement().appendChild(div);
  528. excessWidth = getElement().getOffsetWidth()
  529. - div.getOffsetWidth();
  530. getElement().removeChild(div);
  531. } else {
  532. excessWidth = getElement().getOffsetWidth()
  533. - getElement().getPropertyInt("clientWidth");
  534. }
  535. excessHeight = getElement().getOffsetHeight()
  536. - getElement().getPropertyInt("clientHeight");
  537. getElement().getStyle().setProperty("overflow", overflow);
  538. }
  539. @Override
  540. public int getWidth() {
  541. if (connection.getConfiguration().isStandalone()) {
  542. return getElement().getOffsetWidth() - getExcessWidth();
  543. }
  544. // If not running standalone, there might be multiple Vaadin apps
  545. // that won't shrink with the browser window as the components have
  546. // calculated widths (#3125)
  547. // Find all Vaadin applications on the page
  548. ArrayList<String> vaadinApps = new ArrayList<String>();
  549. loadAppIdListFromDOM(vaadinApps);
  550. // Store original styles here so they can be restored
  551. ArrayList<String> originalDisplays = new ArrayList<String>(
  552. vaadinApps.size());
  553. String ownAppId = connection.getConfiguration().getRootPanelId();
  554. // Set display: none for all Vaadin apps
  555. for (int i = 0; i < vaadinApps.size(); i++) {
  556. String appId = vaadinApps.get(i);
  557. Element targetElement;
  558. if (appId.equals(ownAppId)) {
  559. // Only hide the contents of current application
  560. targetElement = layout.getWidgetForPaintable().getElement();
  561. } else {
  562. // Hide everything for other applications
  563. targetElement = Document.get().getElementById(appId);
  564. }
  565. Style layoutStyle = targetElement.getStyle();
  566. originalDisplays.add(i, layoutStyle.getDisplay());
  567. layoutStyle.setDisplay(Display.NONE);
  568. }
  569. int w = getElement().getOffsetWidth() - getExcessWidth();
  570. // Then restore the old display style before returning
  571. for (int i = 0; i < vaadinApps.size(); i++) {
  572. String appId = vaadinApps.get(i);
  573. Element targetElement;
  574. if (appId.equals(ownAppId)) {
  575. targetElement = layout.getWidgetForPaintable().getElement();
  576. } else {
  577. targetElement = Document.get().getElementById(appId);
  578. }
  579. Style layoutStyle = targetElement.getStyle();
  580. String originalDisplay = originalDisplays.get(i);
  581. if (originalDisplay.length() == 0) {
  582. layoutStyle.clearDisplay();
  583. } else {
  584. layoutStyle.setProperty("display", originalDisplay);
  585. }
  586. }
  587. return w;
  588. }
  589. private int getExcessWidth() {
  590. if (excessWidth < 0) {
  591. detectExcessSize();
  592. }
  593. return excessWidth;
  594. }
  595. @Override
  596. public int getScrollbarSize() {
  597. return Util.getNativeScrollbarSize();
  598. }
  599. };
  600. private native static void loadAppIdListFromDOM(ArrayList<String> list)
  601. /*-{
  602. var j;
  603. for(j in $wnd.vaadin.vaadinConfigurations) {
  604. list.@java.util.Collection::add(Ljava/lang/Object;)(j);
  605. }
  606. }-*/;
  607. public RenderSpace getAllocatedSpace(Widget child) {
  608. return myRenderSpace;
  609. }
  610. public boolean hasChildComponent(Widget component) {
  611. return (component != null && component == layout);
  612. }
  613. public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
  614. // TODO This is untested as no layouts require this
  615. if (oldComponent != layout) {
  616. return;
  617. }
  618. setWidget(newComponent);
  619. layout = (VPaintableWidget) newComponent;
  620. }
  621. public boolean requestLayout(Set<Widget> children) {
  622. /*
  623. * Can never propagate further and we do not want need to re-layout the
  624. * layout which has caused this request.
  625. */
  626. updateParentFrameSize();
  627. // layout size change may affect its available space (scrollbars)
  628. connection.handleComponentRelativeSize(layout.getWidgetForPaintable());
  629. return true;
  630. }
  631. private void updateParentFrameSize() {
  632. if (parentFrame == null) {
  633. return;
  634. }
  635. int childHeight = Util.getRequiredHeight(getWidget().getElement());
  636. int childWidth = Util.getRequiredWidth(getWidget().getElement());
  637. parentFrame.getStyle().setPropertyPx("width", childWidth);
  638. parentFrame.getStyle().setPropertyPx("height", childHeight);
  639. }
  640. private static native Element getParentFrame()
  641. /*-{
  642. try {
  643. var frameElement = $wnd.frameElement;
  644. if (frameElement == null) {
  645. return null;
  646. }
  647. if (frameElement.getAttribute("autoResize") == "true") {
  648. return frameElement;
  649. }
  650. } catch (e) {
  651. }
  652. return null;
  653. }-*/;
  654. public void updateCaption(VPaintableWidget component, UIDL uidl) {
  655. // NOP Subwindows never draw caption for their first child (layout)
  656. }
  657. /**
  658. * Return an iterator for current subwindows. This method is meant for
  659. * testing purposes only.
  660. *
  661. * @return
  662. */
  663. public ArrayList<VWindow> getSubWindowList() {
  664. ArrayList<VWindow> windows = new ArrayList<VWindow>(subWindows.size());
  665. for (VWindow widget : subWindows) {
  666. windows.add(widget);
  667. }
  668. return windows;
  669. }
  670. public void init(String rootPanelId,
  671. ApplicationConnection applicationConnection) {
  672. DOM.sinkEvents(getElement(), Event.ONKEYDOWN | Event.ONSCROLL);
  673. // iview is focused when created so element needs tabIndex
  674. // 1 due 0 is at the end of natural tabbing order
  675. DOM.setElementProperty(getElement(), "tabIndex", "1");
  676. RootPanel root = RootPanel.get(rootPanelId);
  677. // Remove the v-app-loading or any splash screen added inside the div by
  678. // the user
  679. root.getElement().setInnerHTML("");
  680. // For backwards compatibility with static index pages only.
  681. // No longer added by AbstractApplicationServlet/Portlet
  682. root.removeStyleName("v-app-loading");
  683. String themeUri = applicationConnection.getConfiguration()
  684. .getThemeUri();
  685. String themeName = themeUri.substring(themeUri.lastIndexOf('/'));
  686. themeName = themeName.replaceAll("[^a-zA-Z0-9]", "");
  687. root.addStyleName("v-theme-" + themeName);
  688. root.add(this);
  689. if (applicationConnection.getConfiguration().isStandalone()) {
  690. // set focus to iview element by default to listen possible keyboard
  691. // shortcuts. For embedded applications this is unacceptable as we
  692. // don't want to steal focus from the main page nor we don't want
  693. // side-effects from focusing (scrollIntoView).
  694. getElement().focus();
  695. }
  696. parentFrame = getParentFrame();
  697. }
  698. public ShortcutActionHandler getShortcutActionHandler() {
  699. return actionHandler;
  700. }
  701. public void focus() {
  702. getElement().focus();
  703. }
  704. public Widget getWidgetForPaintable() {
  705. return this;
  706. }
  707. }