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 25KB

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