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.

IExpandLayout.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.itmill.toolkit.terminal.gwt.client.ui;
  5. import java.util.ArrayList;
  6. import java.util.HashMap;
  7. import java.util.Iterator;
  8. import com.google.gwt.user.client.Command;
  9. import com.google.gwt.user.client.DOM;
  10. import com.google.gwt.user.client.DeferredCommand;
  11. import com.google.gwt.user.client.Element;
  12. import com.google.gwt.user.client.ui.ComplexPanel;
  13. import com.google.gwt.user.client.ui.RootPanel;
  14. import com.google.gwt.user.client.ui.UIObject;
  15. import com.google.gwt.user.client.ui.Widget;
  16. import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
  17. import com.itmill.toolkit.terminal.gwt.client.BrowserInfo;
  18. import com.itmill.toolkit.terminal.gwt.client.Container;
  19. import com.itmill.toolkit.terminal.gwt.client.ContainerResizedListener;
  20. import com.itmill.toolkit.terminal.gwt.client.ICaption;
  21. import com.itmill.toolkit.terminal.gwt.client.Paintable;
  22. import com.itmill.toolkit.terminal.gwt.client.StyleConstants;
  23. import com.itmill.toolkit.terminal.gwt.client.UIDL;
  24. import com.itmill.toolkit.terminal.gwt.client.Util;
  25. /**
  26. * @author IT Mill Ltd
  27. */
  28. public class IExpandLayout extends ComplexPanel implements
  29. ContainerResizedListener, Container {
  30. public static final String CLASSNAME = "i-expandlayout";
  31. public static final int ORIENTATION_HORIZONTAL = 1;
  32. public static final int ORIENTATION_VERTICAL = 0;
  33. /**
  34. * Minimum pixels reserved for expanded element to avoid "odd" situations
  35. * where expanded element is 0 size. Default is 5 pixels to show user a hint
  36. * that there is a component. Then user can often use splitpanel or resize
  37. * window to show component properly. This value may be insane in some
  38. * applications. Override this to specify a proper for your case.
  39. */
  40. protected static final int EXPANDED_ELEMENTS_MIN_WIDTH = 5;
  41. /**
  42. * Contains reference to Element where Paintables are wrapped.
  43. */
  44. protected Element childContainer;
  45. protected ApplicationConnection client;
  46. protected HashMap componentToCaption = new HashMap();
  47. /*
  48. * Elements that provides the Layout interface implementation.
  49. */
  50. protected Element element;
  51. private Widget expandedWidget;
  52. private UIDL expandedWidgetUidl;
  53. int orientationMode = ORIENTATION_VERTICAL;
  54. protected int topMargin = -1;
  55. private String width;
  56. private String height;
  57. private Element marginElement;
  58. private Element breakElement;
  59. private int bottomMargin = -1;
  60. private boolean hasComponentSpacing;
  61. private int spacingSize = -1;
  62. private boolean rendering;
  63. public IExpandLayout() {
  64. this(IExpandLayout.ORIENTATION_VERTICAL);
  65. }
  66. public IExpandLayout(int orientation) {
  67. orientationMode = orientation;
  68. constructDOM();
  69. setStyleName(CLASSNAME);
  70. }
  71. public void add(Widget w) {
  72. final WidgetWrapper wrapper = createWidgetWrappper();
  73. DOM.appendChild(childContainer, wrapper.getElement());
  74. super.add(w, wrapper.getContainerElement());
  75. }
  76. protected void constructDOM() {
  77. element = DOM.createDiv();
  78. // DOM.setStyleAttribute(element, "overflow", "hidden");
  79. if (orientationMode == ORIENTATION_HORIZONTAL) {
  80. marginElement = DOM.createDiv();
  81. if (BrowserInfo.get().isIE()) {
  82. DOM.setStyleAttribute(marginElement, "zoom", "1");
  83. DOM.setStyleAttribute(marginElement, "overflow", "hidden");
  84. }
  85. childContainer = DOM.createDiv();
  86. if (BrowserInfo.get().isIE()) {
  87. DOM.setStyleAttribute(childContainer, "zoom", "1");
  88. DOM.setStyleAttribute(childContainer, "overflow", "hidden");
  89. }
  90. DOM.setStyleAttribute(childContainer, "height", "100%");
  91. breakElement = DOM.createDiv();
  92. DOM.setStyleAttribute(breakElement, "overflow", "hidden");
  93. DOM.setStyleAttribute(breakElement, "height", "0px");
  94. DOM.setStyleAttribute(breakElement, "clear", "both");
  95. DOM.appendChild(marginElement, childContainer);
  96. DOM.appendChild(marginElement, breakElement);
  97. DOM.appendChild(element, marginElement);
  98. } else {
  99. childContainer = DOM.createDiv();
  100. DOM.appendChild(element, childContainer);
  101. marginElement = childContainer;
  102. }
  103. setElement(element);
  104. }
  105. protected WidgetWrapper createWidgetWrappper() {
  106. if (orientationMode == ORIENTATION_HORIZONTAL) {
  107. return new HorizontalWidgetWrapper();
  108. } else {
  109. return new VerticalWidgetWrapper();
  110. }
  111. }
  112. /**
  113. * Returns given widgets WidgetWrapper
  114. *
  115. * @param child
  116. * @return
  117. */
  118. public WidgetWrapper getWidgetWrapperFor(Widget child) {
  119. final Element containerElement = DOM.getParent(child.getElement());
  120. if (orientationMode == ORIENTATION_HORIZONTAL) {
  121. return new HorizontalWidgetWrapper(containerElement);
  122. } else {
  123. return new VerticalWidgetWrapper(DOM.getParent(containerElement));
  124. }
  125. }
  126. abstract class WidgetWrapper extends UIObject {
  127. /**
  128. * @return element that contains Widget
  129. */
  130. public Element getContainerElement() {
  131. return getElement();
  132. }
  133. public Element getCaptionContainer() {
  134. return getElement();
  135. }
  136. abstract void setExpandedSize(int pixels);
  137. abstract void setAlignment(String verticalAlignment,
  138. String horizontalAlignment);
  139. abstract void setSpacingEnabled(boolean b);
  140. }
  141. class VerticalWidgetWrapper extends WidgetWrapper {
  142. public VerticalWidgetWrapper(Element div) {
  143. setElement(div);
  144. }
  145. public VerticalWidgetWrapper() {
  146. setElement(DOM.createDiv());
  147. DOM.appendChild(getElement(), DOM.createDiv());
  148. DOM.setStyleAttribute(getElement(), "overflow", "hidden");
  149. // Set to 'hidden' at first (prevent IE6 content overflows), and set
  150. // to 'auto' later.
  151. DOM.setStyleAttribute(getContainerElement(), "overflow", "hidden");
  152. }
  153. public void setExpandedSize(int pixels) {
  154. Element firstChild = DOM.getFirstChild(getElement());
  155. int captionHeight = 0;
  156. if (firstChild != getContainerElement()) {
  157. captionHeight = firstChild.getOffsetHeight();
  158. }
  159. int fixedInnerSize = pixels - captionHeight;
  160. if (fixedInnerSize < 0) {
  161. fixedInnerSize = 0;
  162. }
  163. DOM.setStyleAttribute(getContainerElement(), "height",
  164. fixedInnerSize + "px");
  165. }
  166. void setAlignment(String verticalAlignment, String horizontalAlignment) {
  167. DOM.setStyleAttribute(getElement(), "textAlign",
  168. horizontalAlignment);
  169. // ignoring vertical alignment
  170. }
  171. void setSpacingEnabled(boolean b) {
  172. setStyleName(getElement(), CLASSNAME + "-"
  173. + StyleConstants.VERTICAL_SPACING, b);
  174. }
  175. public Element getContainerElement() {
  176. return getElement().getLastChild().cast();
  177. }
  178. public Element getCaptionElement() {
  179. return getElement();
  180. }
  181. }
  182. class HorizontalWidgetWrapper extends WidgetWrapper {
  183. private Element td;
  184. private String valign = "top";
  185. private String align = "left";
  186. public HorizontalWidgetWrapper(Element element) {
  187. if (DOM.getElementProperty(element, "nodeName").equals("TD")) {
  188. td = element;
  189. setElement(DOM.getParent(DOM.getParent(DOM.getParent(DOM
  190. .getParent(td)))));
  191. } else {
  192. setElement(element);
  193. }
  194. }
  195. public HorizontalWidgetWrapper() {
  196. setElement(DOM.createDiv());
  197. DOM.setStyleAttribute(getElement(), "cssFloat", "left");
  198. if (BrowserInfo.get().isIE()) {
  199. DOM.setStyleAttribute(getElement(), "styleFloat", "left");
  200. }
  201. DOM.setStyleAttribute(getElement(), "height", "100%");
  202. }
  203. public void setExpandedSize(int pixels) {
  204. setWidth(pixels + "px");
  205. DOM.setStyleAttribute(getElement(), "overflow", "hidden");
  206. }
  207. void setAlignment(String verticalAlignment, String horizontalAlignment) {
  208. DOM.setStyleAttribute(getElement(), "verticalAlign",
  209. verticalAlignment);
  210. if (!valign.equals(verticalAlignment)) {
  211. if (verticalAlignment.equals("top")) {
  212. // remove table, move content to div
  213. } else {
  214. if (td == null) {
  215. // build one cell table
  216. final Element table = DOM.createTable();
  217. final Element tBody = DOM.createTBody();
  218. final Element tr = DOM.createTR();
  219. td = DOM.createTD();
  220. DOM.appendChild(table, tBody);
  221. DOM.appendChild(tBody, tr);
  222. DOM.appendChild(tr, td);
  223. DOM.setElementProperty(table, "className", CLASSNAME
  224. + "-valign");
  225. DOM.setElementProperty(tr, "className", CLASSNAME
  226. + "-valign");
  227. DOM.setElementProperty(td, "className", CLASSNAME
  228. + "-valign");
  229. // move possible content to cell
  230. final Element content = DOM.getFirstChild(getElement());
  231. if (content != null) {
  232. DOM.removeChild(getElement(), content);
  233. DOM.appendChild(td, content);
  234. }
  235. DOM.appendChild(getElement(), table);
  236. }
  237. // set alignment
  238. DOM.setStyleAttribute(td, "verticalAlign",
  239. verticalAlignment);
  240. }
  241. valign = verticalAlignment;
  242. }
  243. if (!align.equals(horizontalAlignment)) {
  244. DOM.setStyleAttribute(getContainerElement(), "textAlign",
  245. horizontalAlignment);
  246. align = horizontalAlignment;
  247. }
  248. }
  249. public Element getContainerElement() {
  250. if (td == null) {
  251. return super.getContainerElement();
  252. } else {
  253. return td;
  254. }
  255. }
  256. void setSpacingEnabled(boolean b) {
  257. setStyleName(getElement(), CLASSNAME + "-"
  258. + StyleConstants.HORIZONTAL_SPACING, b);
  259. }
  260. }
  261. protected ArrayList getPaintables() {
  262. final ArrayList al = new ArrayList();
  263. final Iterator it = iterator();
  264. while (it.hasNext()) {
  265. final Widget w = (Widget) it.next();
  266. if (w instanceof Paintable) {
  267. al.add(w);
  268. }
  269. }
  270. return al;
  271. }
  272. public Widget getWidget(int index) {
  273. return getChildren().get(index);
  274. }
  275. public int getWidgetCount() {
  276. return getChildren().size();
  277. }
  278. public int getWidgetIndex(Widget child) {
  279. return getChildren().indexOf(child);
  280. }
  281. protected void handleAlignments(UIDL uidl) {
  282. // Component alignments as a comma separated list.
  283. // See com.itmill.toolkit.terminal.gwt.client.ui.AlignmentInfo.java for
  284. // possible values.
  285. final int[] alignments = uidl.getIntArrayAttribute("alignments");
  286. int alignmentIndex = 0;
  287. // Set alignment attributes
  288. final Iterator it = getPaintables().iterator();
  289. boolean first = true;
  290. while (it.hasNext()) {
  291. // Calculate alignment info
  292. final AlignmentInfo ai = new AlignmentInfo(
  293. alignments[alignmentIndex++]);
  294. final WidgetWrapper wr = getWidgetWrapperFor((Widget) it.next());
  295. wr.setAlignment(ai.getVerticalAlignment(), ai
  296. .getHorizontalAlignment());
  297. if (first) {
  298. wr.setSpacingEnabled(false);
  299. first = false;
  300. } else {
  301. wr.setSpacingEnabled(hasComponentSpacing);
  302. }
  303. }
  304. }
  305. protected void handleMargins(UIDL uidl) {
  306. if (uidl.hasAttribute("margins")) {
  307. final MarginInfo margins = new MarginInfo(uidl
  308. .getIntAttribute("margins"));
  309. setStyleName(marginElement, CLASSNAME + "-"
  310. + StyleConstants.MARGIN_TOP, margins.hasTop());
  311. setStyleName(marginElement, CLASSNAME + "-"
  312. + StyleConstants.MARGIN_RIGHT, margins.hasRight());
  313. setStyleName(marginElement, CLASSNAME + "-"
  314. + StyleConstants.MARGIN_BOTTOM, margins.hasBottom());
  315. setStyleName(marginElement, CLASSNAME + "-"
  316. + StyleConstants.MARGIN_LEFT, margins.hasLeft());
  317. }
  318. }
  319. public boolean hasChildComponent(Widget component) {
  320. return getWidgetIndex(component) >= 0;
  321. }
  322. private void iLayout() {
  323. iLayout(-1, -1);
  324. }
  325. public void iLayout(int availableWidth, int availableHeight) {
  326. if (orientationMode == ORIENTATION_HORIZONTAL) {
  327. int pixels;
  328. if ("".equals(height)) {
  329. // try to find minimum height by looping all widgets
  330. int maxHeight = 0;
  331. Iterator iterator = getPaintables().iterator();
  332. while (iterator.hasNext()) {
  333. Widget w = (Widget) iterator.next();
  334. int h = w.getOffsetHeight();
  335. if (h > maxHeight) {
  336. maxHeight = h;
  337. }
  338. }
  339. pixels = maxHeight;
  340. } else {
  341. pixels = getOffsetHeight() - getTopMargin() - getBottomMargin();
  342. if (pixels < 0) {
  343. pixels = 0;
  344. }
  345. }
  346. DOM.setStyleAttribute(marginElement, "height", pixels + "px");
  347. DOM.setStyleAttribute(marginElement, "overflow", "hidden");
  348. }
  349. if (expandedWidget == null) {
  350. return;
  351. }
  352. final int availableSpace = getAvailableSpace();
  353. final int usedSpace = getUsedSpace();
  354. int spaceForExpandedWidget = availableSpace - usedSpace;
  355. if (spaceForExpandedWidget < EXPANDED_ELEMENTS_MIN_WIDTH) {
  356. // TODO fire warning for developer
  357. spaceForExpandedWidget = EXPANDED_ELEMENTS_MIN_WIDTH;
  358. }
  359. final WidgetWrapper wr = getWidgetWrapperFor(expandedWidget);
  360. wr.setExpandedSize(spaceForExpandedWidget);
  361. // setting overflow auto lazy off during layout function
  362. DOM.setStyleAttribute(DOM.getParent(expandedWidget.getElement()),
  363. "overflow", "hidden");
  364. // TODO save previous size and only propagate if really changed
  365. Util.runDescendentsLayout(this);
  366. // setting overflow back to auto
  367. DOM.setStyleAttribute(DOM.getParent(expandedWidget.getElement()),
  368. "overflow", "auto");
  369. }
  370. private int getTopMargin() {
  371. if (topMargin < 0) {
  372. topMargin = DOM.getElementPropertyInt(childContainer, "offsetTop")
  373. - DOM.getElementPropertyInt(getElement(), "offsetTop");
  374. }
  375. if (topMargin < 0) {
  376. // FIXME shouldn't happen
  377. return 0;
  378. } else {
  379. return topMargin;
  380. }
  381. }
  382. private int getBottomMargin() {
  383. if (bottomMargin < 0) {
  384. bottomMargin = DOM
  385. .getElementPropertyInt(marginElement, "offsetTop")
  386. + DOM.getElementPropertyInt(marginElement, "offsetHeight")
  387. - DOM.getElementPropertyInt(breakElement, "offsetTop");
  388. if (bottomMargin < 0) {
  389. // FIXME shouldn't happen
  390. return 0;
  391. }
  392. }
  393. return bottomMargin;
  394. }
  395. private int getUsedSpace() {
  396. int total = 0;
  397. final int widgetCount = getWidgetCount();
  398. final Iterator it = iterator();
  399. while (it.hasNext()) {
  400. final Widget w = (Widget) it.next();
  401. if (w instanceof Paintable && w != expandedWidget) {
  402. final WidgetWrapper wr = getWidgetWrapperFor(w);
  403. if (orientationMode == ORIENTATION_VERTICAL) {
  404. total += wr.getOffsetHeight();
  405. } else {
  406. total += wr.getOffsetWidth();
  407. }
  408. }
  409. }
  410. total += getSpacingSize() * (widgetCount - 1);
  411. return total;
  412. }
  413. private int getSpacingSize() {
  414. if (hasComponentSpacing) {
  415. if (spacingSize < 0) {
  416. final Element temp = DOM.createDiv();
  417. final WidgetWrapper wr = createWidgetWrappper();
  418. wr.setSpacingEnabled(true);
  419. DOM.appendChild(temp, wr.getElement());
  420. DOM.setStyleAttribute(temp, "position", "absolute");
  421. DOM.setStyleAttribute(temp, "top", "0");
  422. DOM.setStyleAttribute(temp, "visibility", "hidden");
  423. DOM.appendChild(RootPanel.getBodyElement(), temp);
  424. if (orientationMode == ORIENTATION_HORIZONTAL) {
  425. spacingSize = DOM.getElementPropertyInt(wr.getElement(),
  426. "offsetLeft");
  427. } else {
  428. spacingSize = DOM.getElementPropertyInt(wr.getElement(),
  429. "offsetTop");
  430. }
  431. DOM.removeChild(RootPanel.getBodyElement(), temp);
  432. }
  433. return spacingSize;
  434. } else {
  435. return 0;
  436. }
  437. }
  438. private int getAvailableSpace() {
  439. int size;
  440. if (orientationMode == ORIENTATION_VERTICAL) {
  441. if (BrowserInfo.get().isIE6()) {
  442. DOM.setStyleAttribute(getElement(), "overflow", "hidden");
  443. }
  444. size = getOffsetHeight();
  445. if (BrowserInfo.get().isIE6()) {
  446. DOM.setStyleAttribute(getElement(), "overflow", "visible");
  447. }
  448. final int marginTop = DOM.getElementPropertyInt(DOM
  449. .getFirstChild(marginElement), "offsetTop")
  450. - DOM.getElementPropertyInt(element, "offsetTop");
  451. final Element lastElement = DOM.getChild(marginElement, (DOM
  452. .getChildCount(marginElement) - 1));
  453. final int marginBottom = DOM.getElementPropertyInt(marginElement,
  454. "offsetHeight")
  455. + DOM.getElementPropertyInt(marginElement, "offsetTop")
  456. - (DOM.getElementPropertyInt(lastElement, "offsetTop") + DOM
  457. .getElementPropertyInt(lastElement, "offsetHeight"));
  458. size -= (marginTop + marginBottom);
  459. } else {
  460. // horizontal mode
  461. size = DOM.getElementPropertyInt(breakElement, "offsetWidth");
  462. }
  463. return size;
  464. }
  465. protected void insert(Widget w, int beforeIndex) {
  466. if (w instanceof ICaption) {
  467. final ICaption c = (ICaption) w;
  468. WidgetWrapper wrapper = getWidgetWrapperFor((Widget) c.getOwner());
  469. Element captionContainer = wrapper.getCaptionContainer();
  470. final Element captionElement = DOM.createDiv();
  471. DOM.insertChild(captionContainer, captionElement, 0);
  472. insert(w, captionElement, beforeIndex, false);
  473. } else {
  474. final WidgetWrapper wrapper = createWidgetWrappper();
  475. DOM.insertChild(childContainer, wrapper.getElement(), beforeIndex);
  476. insert(w, wrapper.getContainerElement(), beforeIndex, false);
  477. }
  478. }
  479. public boolean remove(int index) {
  480. return remove(getWidget(index));
  481. }
  482. public boolean remove(Widget w) {
  483. final WidgetWrapper ww = getWidgetWrapperFor(w);
  484. final boolean removed = super.remove(w);
  485. if (removed) {
  486. if (!(w instanceof ICaption)) {
  487. DOM.removeChild(childContainer, ww.getElement());
  488. }
  489. return true;
  490. }
  491. return false;
  492. }
  493. public void removeCaption(Widget w) {
  494. final ICaption c = (ICaption) componentToCaption.get(w);
  495. if (c != null) {
  496. this.remove(c);
  497. componentToCaption.remove(w);
  498. }
  499. }
  500. public boolean removePaintable(Paintable p) {
  501. final ICaption c = (ICaption) componentToCaption.get(p);
  502. if (c != null) {
  503. componentToCaption.remove(c);
  504. remove(c);
  505. }
  506. client.unregisterPaintable(p);
  507. if (expandedWidget == p) {
  508. expandedWidget = null;
  509. }
  510. return remove((Widget) p);
  511. }
  512. public void replaceChildComponent(Widget from, Widget to) {
  513. client.unregisterPaintable((Paintable) from);
  514. final ICaption c = (ICaption) componentToCaption.get(from);
  515. if (c != null) {
  516. remove(c);
  517. componentToCaption.remove(c);
  518. }
  519. final int index = getWidgetIndex(from);
  520. if (index >= 0) {
  521. remove(index);
  522. insert(to, index);
  523. }
  524. }
  525. public void updateCaption(Paintable component, UIDL uidl) {
  526. ICaption c = (ICaption) componentToCaption.get(component);
  527. boolean captionSizeMayHaveChanged = false;
  528. if (ICaption.isNeeded(uidl)) {
  529. if (c == null) {
  530. final int index = getWidgetIndex((Widget) component);
  531. c = new ICaption(component, client);
  532. insert(c, index);
  533. componentToCaption.put(component, c);
  534. captionSizeMayHaveChanged = true;
  535. }
  536. c.updateCaption(uidl);
  537. } else {
  538. if (c != null) {
  539. remove(c);
  540. componentToCaption.remove(component);
  541. captionSizeMayHaveChanged = true;
  542. }
  543. }
  544. if (!rendering && captionSizeMayHaveChanged) {
  545. iLayout();
  546. }
  547. }
  548. public void setWidth(String newWidth) {
  549. if (newWidth.equals(width)) {
  550. return;
  551. }
  552. width = newWidth;
  553. super.setWidth(width);
  554. }
  555. public void setHeight(String newHeight) {
  556. if (newHeight.equals(height)) {
  557. return;
  558. }
  559. height = newHeight;
  560. super.setHeight(height);
  561. if (orientationMode == ORIENTATION_HORIZONTAL) {
  562. iLayout();
  563. }
  564. }
  565. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  566. rendering = true;
  567. this.client = client;
  568. // Modify layout margins
  569. handleMargins(uidl);
  570. if (client.updateComponent(this, uidl, true)) {
  571. rendering = false;
  572. return;
  573. }
  574. hasComponentSpacing = uidl.getBooleanAttribute("spacing");
  575. final ArrayList uidlWidgets = new ArrayList();
  576. for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
  577. final UIDL cellUidl = (UIDL) it.next();
  578. final Paintable child = client.getPaintable(cellUidl
  579. .getChildUIDL(0));
  580. uidlWidgets.add(child);
  581. if (cellUidl.hasAttribute("expanded")) {
  582. expandedWidget = (Widget) child;
  583. expandedWidgetUidl = cellUidl.getChildUIDL(0);
  584. }
  585. }
  586. final ArrayList oldWidgets = getPaintables();
  587. final Iterator oldIt = oldWidgets.iterator();
  588. final Iterator newIt = uidlWidgets.iterator();
  589. final Iterator newUidl = uidl.getChildIterator();
  590. Widget oldChild = null;
  591. while (newIt.hasNext()) {
  592. final Widget child = (Widget) newIt.next();
  593. final UIDL childUidl = ((UIDL) newUidl.next()).getChildUIDL(0);
  594. if (oldChild == null && oldIt.hasNext()) {
  595. // search for next old Paintable which still exists in layout
  596. // and delete others
  597. while (oldIt.hasNext()) {
  598. oldChild = (Widget) oldIt.next();
  599. // now oldChild is an instance of Paintable
  600. if (uidlWidgets.contains(oldChild)) {
  601. break;
  602. } else {
  603. removePaintable((Paintable) oldChild);
  604. oldChild = null;
  605. }
  606. }
  607. }
  608. if (oldChild == null) {
  609. // we are adding components to layout
  610. add(child);
  611. } else if (child == oldChild) {
  612. // child already attached and updated
  613. oldChild = null;
  614. } else if (hasChildComponent(child)) {
  615. // current child has been moved, re-insert before current
  616. // oldChild
  617. // TODO this might be optimized by moving only container element
  618. // to correct position
  619. removeCaption(child);
  620. int index = getWidgetIndex(oldChild);
  621. if (componentToCaption.containsKey(oldChild)) {
  622. index--;
  623. }
  624. remove(child);
  625. insert(child, index);
  626. } else {
  627. // insert new child before old one
  628. final int index = getWidgetIndex(oldChild);
  629. insert(child, index);
  630. }
  631. if (child != expandedWidget) {
  632. ((Paintable) child).updateFromUIDL(childUidl, client);
  633. }
  634. }
  635. // remove possibly remaining old Paintable object which were not updated
  636. while (oldIt.hasNext()) {
  637. oldChild = (Widget) oldIt.next();
  638. final Paintable p = (Paintable) oldChild;
  639. if (!uidlWidgets.contains(p)) {
  640. removePaintable(p);
  641. }
  642. }
  643. if (uidlWidgets.size() == 0) {
  644. return;
  645. }
  646. // Set component alignments
  647. handleAlignments(uidl);
  648. iLayout();
  649. /*
  650. * Expanded widget is updated after layout function so it has its
  651. * container fixed at the moment of updateFromUIDL.
  652. */
  653. if (expandedWidget != null) {
  654. ((Paintable) expandedWidget).updateFromUIDL(expandedWidgetUidl,
  655. client);
  656. // setting overflow auto lazy, not to disturb possible layout
  657. // functions
  658. DOM.setStyleAttribute(DOM.getParent(expandedWidget.getElement()),
  659. "overflow", "auto");
  660. }
  661. // workaround for safari bug #1870
  662. float wkv = BrowserInfo.get().getWebkitVersion();
  663. if (wkv > 0 && wkv < 526.9) {
  664. DeferredCommand.addCommand(new Command() {
  665. public void execute() {
  666. iLayout();
  667. }
  668. });
  669. }
  670. rendering = false;
  671. }
  672. public boolean childComponentSizesUpdated() {
  673. // TODO Auto-generated method stub
  674. return false;
  675. }
  676. }