Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

VAbstractOrderedLayout.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.ui.orderedlayout;
  17. import java.util.HashMap;
  18. import java.util.Map;
  19. import com.google.gwt.core.client.GWT;
  20. import com.google.gwt.dom.client.Element;
  21. import com.google.gwt.dom.client.Node;
  22. import com.google.gwt.dom.client.Style;
  23. import com.google.gwt.dom.client.Style.Unit;
  24. import com.google.gwt.dom.client.Style.Visibility;
  25. import com.google.gwt.regexp.shared.MatchResult;
  26. import com.google.gwt.regexp.shared.RegExp;
  27. import com.google.gwt.user.client.DOM;
  28. import com.google.gwt.user.client.ui.FlowPanel;
  29. import com.google.gwt.user.client.ui.RequiresResize;
  30. import com.google.gwt.user.client.ui.Widget;
  31. import com.vaadin.client.LayoutManager;
  32. import com.vaadin.client.Profiler;
  33. import com.vaadin.client.Util;
  34. import com.vaadin.shared.ui.MarginInfo;
  35. /**
  36. * Base class for ordered layouts
  37. */
  38. public class VAbstractOrderedLayout extends FlowPanel {
  39. protected boolean spacing = false;
  40. /** For internal use only. May be removed or replaced in the future. */
  41. public boolean vertical = true;
  42. protected boolean definedHeight = false;
  43. private Map<Widget, Slot> widgetToSlot = new HashMap<Widget, Slot>();
  44. private Element expandWrapper;
  45. private LayoutManager layoutManager;
  46. /**
  47. * Keep track of the last allocated expand size to help detecting when it
  48. * changes.
  49. */
  50. private int lastExpandSize = -1;
  51. public VAbstractOrderedLayout(boolean vertical) {
  52. this.vertical = vertical;
  53. }
  54. /**
  55. * See the method {@link #addOrMoveSlot(Slot, int, boolean)}.
  56. *
  57. * <p>
  58. * This method always adjusts spacings for the whole layout.
  59. *
  60. * @param slot
  61. * The slot to move or add
  62. * @param index
  63. * The index where the slot should be placed.
  64. * @deprecated since 7.1.4, use {@link #addOrMoveSlot(Slot, int, boolean)}
  65. */
  66. @Deprecated
  67. public void addOrMoveSlot(Slot slot, int index) {
  68. addOrMoveSlot(slot, index, true);
  69. }
  70. /**
  71. * Add or move a slot to another index.
  72. * <p>
  73. * For internal use only. May be removed or replaced in the future.
  74. * <p>
  75. * You should note that the index does not refer to the DOM index if
  76. * spacings are used. If spacings are used then the index will be adjusted
  77. * to include the spacings when inserted.
  78. * <p>
  79. * For instance when using spacing the index converts to DOM index in the
  80. * following way:
  81. *
  82. * <pre>
  83. * index : 0 -> DOM index: 0
  84. * index : 1 -> DOM index: 1
  85. * index : 2 -> DOM index: 3
  86. * index : 3 -> DOM index: 5
  87. * index : 4 -> DOM index: 7
  88. * </pre>
  89. *
  90. * When using this method never account for spacings.
  91. * <p>
  92. * The caller should remove all spacings before calling this method and
  93. * re-add them (if necessary) after this method. This can be done before and
  94. * after all slots have been added/moved.
  95. * </p>
  96. *
  97. * @since 7.1.4
  98. *
  99. * @param slot
  100. * The slot to move or add
  101. * @param index
  102. * The index where the slot should be placed.
  103. * @param adjustSpacing
  104. * true to recalculate spacings for the whole layout after the
  105. * operation
  106. */
  107. public void addOrMoveSlot(Slot slot, int index, boolean adjustSpacing) {
  108. Profiler.enter(
  109. "VAOL.onConnectorHierarchyChange addOrMoveSlot find index");
  110. if (slot.getParent() == this) {
  111. int currentIndex = getWidgetIndex(slot);
  112. if (index == currentIndex) {
  113. Profiler.leave(
  114. "VAOL.onConnectorHierarchyChange addOrMoveSlot find index");
  115. return;
  116. }
  117. }
  118. Profiler.leave(
  119. "VAOL.onConnectorHierarchyChange addOrMoveSlot find index");
  120. Profiler.enter("VAOL.onConnectorHierarchyChange addOrMoveSlot insert");
  121. insert(slot, index);
  122. Profiler.leave("VAOL.onConnectorHierarchyChange addOrMoveSlot insert");
  123. if (adjustSpacing) {
  124. Profiler.enter(
  125. "VAOL.onConnectorHierarchyChange addOrMoveSlot setSpacing");
  126. setSpacing(spacing);
  127. Profiler.leave(
  128. "VAOL.onConnectorHierarchyChange addOrMoveSlot setSpacing");
  129. }
  130. }
  131. /**
  132. * {@inheritDoc}
  133. *
  134. * @deprecated As of 7.2, use or override
  135. * {@link #insert(Widget, Element, int, boolean)} instead.
  136. */
  137. @Override
  138. @Deprecated
  139. protected void insert(Widget child,
  140. com.google.gwt.user.client.Element container, int beforeIndex,
  141. boolean domInsert) {
  142. // Validate index; adjust if the widget is already a child of this
  143. // panel.
  144. beforeIndex = adjustIndex(child, beforeIndex);
  145. // Detach new child.
  146. child.removeFromParent();
  147. // Logical attach.
  148. getChildren().insert(child, beforeIndex);
  149. // Physical attach.
  150. container = expandWrapper != null ? DOM.asOld(expandWrapper)
  151. : getElement();
  152. if (domInsert) {
  153. if (spacing) {
  154. if (beforeIndex != 0) {
  155. /*
  156. * Since the spacing elements are located at the same DOM
  157. * level as the slots we need to take them into account when
  158. * calculating the slot position.
  159. *
  160. * The spacing elements are always located before the actual
  161. * slot except for the first slot which do not have a
  162. * spacing element like this
  163. *
  164. * |<slot1><spacing2><slot2><spacing3><slot3>...|
  165. */
  166. beforeIndex = beforeIndex * 2 - 1;
  167. }
  168. }
  169. DOM.insertChild(container, child.getElement(), beforeIndex);
  170. } else {
  171. DOM.appendChild(container, child.getElement());
  172. }
  173. // Adopt.
  174. adopt(child);
  175. }
  176. /**
  177. * {@inheritDoc}
  178. *
  179. * @since 7.2
  180. */
  181. @Override
  182. protected void insert(Widget child, Element container, int beforeIndex,
  183. boolean domInsert) {
  184. insert(child, DOM.asOld(container), beforeIndex, domInsert);
  185. }
  186. /**
  187. * Remove a slot from the layout
  188. *
  189. * @param widget
  190. * @return
  191. */
  192. public void removeWidget(Widget widget) {
  193. Slot slot = widgetToSlot.remove(widget);
  194. if (slot != null) {
  195. removeSlot(slot);
  196. }
  197. }
  198. /**
  199. * Remove a slot from the layout.
  200. *
  201. * This method is called automatically by {@link #removeWidget(Widget)} and
  202. * should not be called directly by the user. When overridden, the super
  203. * method must be called.
  204. *
  205. * @since 7.6
  206. * @param Slot
  207. * to remove
  208. */
  209. protected void removeSlot(Slot slot) {
  210. remove(slot);
  211. }
  212. /**
  213. * Get the containing slot for a widget. If no slot is found a new slot is
  214. * created and returned.
  215. *
  216. * @param widget
  217. * The widget whose slot you want to get
  218. *
  219. * @return
  220. */
  221. public Slot getSlot(Widget widget) {
  222. Slot slot = widgetToSlot.get(widget);
  223. if (slot == null) {
  224. slot = createSlot(widget);
  225. widgetToSlot.put(widget, slot);
  226. }
  227. return slot;
  228. }
  229. /**
  230. * Create a slot to be added to the layout.
  231. *
  232. * This method is called automatically by {@link #getSlot(Widget)} when a
  233. * new slot is needed. It should not be called directly by the user, but can
  234. * be overridden to customize slot creation.
  235. *
  236. * @since 7.6
  237. * @param widget
  238. * the widget for which a slot is being created
  239. * @return created Slot
  240. */
  241. protected Slot createSlot(Widget widget) {
  242. Slot slot = GWT.create(Slot.class);
  243. slot.setLayout(this);
  244. slot.setWidget(widget);
  245. return slot;
  246. }
  247. /**
  248. * Gets a slot based on the widget element. If no slot is found then null is
  249. * returned.
  250. *
  251. * @param widgetElement
  252. * The element of the widget ( Same as getWidget().getElement() )
  253. * @return
  254. * @deprecated As of 7.2, call or override {@link #getSlot(Element)} instead
  255. */
  256. @Deprecated
  257. public Slot getSlot(com.google.gwt.user.client.Element widgetElement) {
  258. for (Map.Entry<Widget, Slot> entry : widgetToSlot.entrySet()) {
  259. if (entry.getKey().getElement() == widgetElement) {
  260. return entry.getValue();
  261. }
  262. }
  263. return null;
  264. }
  265. /**
  266. * Gets a slot based on the widget element. If no slot is found then null is
  267. * returned.
  268. *
  269. * @param widgetElement
  270. * The element of the widget ( Same as getWidget().getElement() )
  271. * @return
  272. *
  273. * @since 7.2
  274. */
  275. public Slot getSlot(Element widgetElement) {
  276. return getSlot(DOM.asOld(widgetElement));
  277. }
  278. /**
  279. * Set the layout manager for the layout
  280. *
  281. * @param manager
  282. * The layout manager to use
  283. */
  284. public void setLayoutManager(LayoutManager manager) {
  285. layoutManager = manager;
  286. }
  287. /**
  288. * Get the layout manager used by this layout
  289. *
  290. */
  291. public LayoutManager getLayoutManager() {
  292. return layoutManager;
  293. }
  294. /**
  295. * Deducts the caption position by examining the wrapping element.
  296. * <p>
  297. * For internal use only. May be removed or replaced in the future.
  298. *
  299. * @param captionWrap
  300. * The wrapping element
  301. *
  302. * @return The caption position
  303. * @deprecated As of 7.2, call or override
  304. * {@link #getCaptionPositionFromElement(Element)} instead
  305. */
  306. @Deprecated
  307. public CaptionPosition getCaptionPositionFromElement(
  308. com.google.gwt.user.client.Element captionWrap) {
  309. RegExp captionPositionRegexp = RegExp.compile("v-caption-on-(\\S+)");
  310. // Get caption position from the classname
  311. MatchResult matcher = captionPositionRegexp
  312. .exec(captionWrap.getClassName());
  313. if (matcher == null || matcher.getGroupCount() < 2) {
  314. return CaptionPosition.TOP;
  315. }
  316. String captionClass = matcher.getGroup(1);
  317. CaptionPosition captionPosition = CaptionPosition
  318. .valueOf(CaptionPosition.class, captionClass.toUpperCase());
  319. return captionPosition;
  320. }
  321. /**
  322. * Deducts the caption position by examining the wrapping element.
  323. * <p>
  324. * For internal use only. May be removed or replaced in the future.
  325. *
  326. * @param captionWrap
  327. * The wrapping element
  328. *
  329. * @return The caption position
  330. * @since 7.2
  331. */
  332. public CaptionPosition getCaptionPositionFromElement(Element captionWrap) {
  333. return getCaptionPositionFromElement(DOM.asOld(captionWrap));
  334. }
  335. /**
  336. * Update the offset off the caption relative to the slot
  337. * <p>
  338. * For internal use only. May be removed or replaced in the future.
  339. *
  340. * @param caption
  341. * The caption element
  342. * @deprecated As of 7.2, call or override
  343. * {@link #updateCaptionOffset(Element)} instead
  344. */
  345. @Deprecated
  346. public void updateCaptionOffset(
  347. com.google.gwt.user.client.Element caption) {
  348. Element captionWrap = caption.getParentElement();
  349. Style captionWrapStyle = captionWrap.getStyle();
  350. captionWrapStyle.clearPaddingTop();
  351. captionWrapStyle.clearPaddingRight();
  352. captionWrapStyle.clearPaddingBottom();
  353. captionWrapStyle.clearPaddingLeft();
  354. Style captionStyle = caption.getStyle();
  355. captionStyle.clearMarginTop();
  356. captionStyle.clearMarginRight();
  357. captionStyle.clearMarginBottom();
  358. captionStyle.clearMarginLeft();
  359. // Get caption position from the classname
  360. CaptionPosition captionPosition = getCaptionPositionFromElement(
  361. captionWrap);
  362. if (captionPosition == CaptionPosition.LEFT
  363. || captionPosition == CaptionPosition.RIGHT) {
  364. int captionWidth;
  365. if (layoutManager != null) {
  366. captionWidth = layoutManager.getOuterWidth(caption)
  367. - layoutManager.getMarginWidth(caption);
  368. } else {
  369. captionWidth = caption.getOffsetWidth();
  370. }
  371. if (captionWidth > 0) {
  372. if (captionPosition == CaptionPosition.LEFT) {
  373. captionWrapStyle.setPaddingLeft(captionWidth, Unit.PX);
  374. captionStyle.setMarginLeft(-captionWidth, Unit.PX);
  375. } else {
  376. captionWrapStyle.setPaddingRight(captionWidth, Unit.PX);
  377. captionStyle.setMarginRight(-captionWidth, Unit.PX);
  378. }
  379. }
  380. }
  381. if (captionPosition == CaptionPosition.TOP
  382. || captionPosition == CaptionPosition.BOTTOM) {
  383. int captionHeight;
  384. if (layoutManager != null) {
  385. captionHeight = layoutManager.getOuterHeight(caption)
  386. - layoutManager.getMarginHeight(caption);
  387. } else {
  388. captionHeight = caption.getOffsetHeight();
  389. }
  390. if (captionHeight > 0) {
  391. if (captionPosition == CaptionPosition.TOP) {
  392. captionWrapStyle.setPaddingTop(captionHeight, Unit.PX);
  393. captionStyle.setMarginTop(-captionHeight, Unit.PX);
  394. } else {
  395. captionWrapStyle.setPaddingBottom(captionHeight, Unit.PX);
  396. captionStyle.setMarginBottom(-captionHeight, Unit.PX);
  397. }
  398. }
  399. }
  400. }
  401. /**
  402. * Update the offset off the caption relative to the slot
  403. * <p>
  404. * For internal use only. May be removed or replaced in the future.
  405. *
  406. * @param caption
  407. * The caption element
  408. * @since 7.2
  409. */
  410. public void updateCaptionOffset(Element caption) {
  411. updateCaptionOffset(DOM.asOld(caption));
  412. }
  413. /**
  414. * Set the margin of the layout
  415. *
  416. * @param marginInfo
  417. * The margin information
  418. */
  419. public void setMargin(MarginInfo marginInfo) {
  420. if (marginInfo != null) {
  421. setStyleName("v-margin-top", marginInfo.hasTop());
  422. setStyleName("v-margin-right", marginInfo.hasRight());
  423. setStyleName("v-margin-bottom", marginInfo.hasBottom());
  424. setStyleName("v-margin-left", marginInfo.hasLeft());
  425. }
  426. }
  427. /**
  428. * Turn on or off spacing in the layout
  429. *
  430. * @param spacing
  431. * True if spacing should be used, false if not
  432. */
  433. public void setSpacing(boolean spacing) {
  434. Profiler.enter("VAOL.onConnectorHierarchyChange setSpacing");
  435. this.spacing = spacing;
  436. // first widget does not have spacing on
  437. // optimization to avoid looking up widget indices on every iteration
  438. Widget firstSlot = null;
  439. if (getWidgetCount() > 0) {
  440. firstSlot = getWidget(0);
  441. }
  442. for (Slot slot : widgetToSlot.values()) {
  443. slot.setSpacing(spacing && firstSlot != slot);
  444. }
  445. Profiler.leave("VAOL.onConnectorHierarchyChange setSpacing");
  446. }
  447. /**
  448. * Assigns relative sizes to the children that should expand based on their
  449. * expand ratios.
  450. */
  451. public void updateExpandedSizes() {
  452. // Ensure the expand wrapper is in place
  453. if (expandWrapper == null) {
  454. expandWrapper = DOM.createDiv();
  455. expandWrapper.setClassName("v-expand");
  456. // Detach all widgets before modifying DOM
  457. for (Widget widget : getChildren()) {
  458. orphan(widget);
  459. }
  460. while (getElement().getChildCount() > 0) {
  461. Node el = getElement().getChild(0);
  462. expandWrapper.appendChild(el);
  463. }
  464. getElement().appendChild(expandWrapper);
  465. // Attach all widgets again
  466. for (Widget widget : getChildren()) {
  467. adopt(widget);
  468. }
  469. }
  470. // Sum up expand ratios to get the denominator
  471. double total = 0;
  472. for (Slot slot : widgetToSlot.values()) {
  473. // FIXME expandRatio might be <0
  474. total += slot.getExpandRatio();
  475. }
  476. // Give each expanded child its own share
  477. for (Slot slot : widgetToSlot.values()) {
  478. Element slotElement = slot.getElement();
  479. slotElement.removeAttribute("aria-hidden");
  480. Style slotStyle = slotElement.getStyle();
  481. slotStyle.clearVisibility();
  482. slotStyle.clearMarginLeft();
  483. slotStyle.clearMarginTop();
  484. if (slot.getExpandRatio() != 0) {
  485. // FIXME expandRatio might be <0
  486. double size = 100 * (slot.getExpandRatio() / total);
  487. if (vertical) {
  488. slot.setHeight(size + "%");
  489. if (slot.hasRelativeHeight()) {
  490. Util.notifyParentOfSizeChange(this, true);
  491. }
  492. } else {
  493. slot.setWidth(size + "%");
  494. if (slot.hasRelativeWidth()) {
  495. Util.notifyParentOfSizeChange(this, true);
  496. }
  497. }
  498. } else if (slot.isRelativeInDirection(vertical)) {
  499. // Relative child without expansion gets no space at all
  500. if (vertical) {
  501. slot.setHeight("0");
  502. } else {
  503. slot.setWidth("0");
  504. }
  505. slotStyle.setVisibility(Visibility.HIDDEN);
  506. slotElement.setAttribute("aria-hidden", "true");
  507. } else {
  508. // Non-relative child without expansion should be unconstrained
  509. if (vertical) {
  510. slotStyle.clearHeight();
  511. } else {
  512. slotStyle.clearWidth();
  513. }
  514. }
  515. }
  516. }
  517. /**
  518. * Removes elements used to expand a slot.
  519. * <p>
  520. * For internal use only. May be removed or replaced in the future.
  521. */
  522. public void clearExpand() {
  523. if (expandWrapper != null) {
  524. // Detach all widgets before modifying DOM
  525. for (Widget widget : getChildren()) {
  526. orphan(widget);
  527. }
  528. lastExpandSize = -1;
  529. while (expandWrapper.getChildCount() > 0) {
  530. Element el = expandWrapper.getChild(0).cast();
  531. getElement().appendChild(el);
  532. if (vertical) {
  533. el.getStyle().clearHeight();
  534. el.getStyle().clearMarginTop();
  535. } else {
  536. el.getStyle().clearWidth();
  537. el.getStyle().clearMarginLeft();
  538. }
  539. }
  540. expandWrapper.removeFromParent();
  541. expandWrapper = null;
  542. // Attach children again
  543. for (Widget widget : getChildren()) {
  544. adopt(widget);
  545. }
  546. }
  547. }
  548. /**
  549. * Updates the expand compensation based on the measured sizes of children
  550. * without expand.
  551. */
  552. public void updateExpandCompensation() {
  553. boolean isExpanding = false;
  554. for (Widget slot : getChildren()) {
  555. // FIXME expandRatio might be <0
  556. if (((Slot) slot).getExpandRatio() != 0) {
  557. isExpanding = true;
  558. break;
  559. }
  560. }
  561. if (isExpanding) {
  562. /*
  563. * Expanded slots have relative sizes that together add up to 100%.
  564. * To make room for slots without expand, we will add padding that
  565. * is not considered for relative sizes and a corresponding negative
  566. * margin for the unexpanded slots. We calculate the size by summing
  567. * the size of all non-expanded non-relative slots.
  568. *
  569. * Relatively sized slots without expansion are considered to get
  570. * 0px, but we still keep them visible (causing overflows) to help
  571. * the developer see what's happening. Forcing them to only get 0px
  572. * would make them disappear which would avoid overflows but would
  573. * instead cause confusion as they would then just disappear without
  574. * any obvious reason.
  575. */
  576. int totalSize = 0;
  577. for (Widget w : getChildren()) {
  578. Slot slot = (Slot) w;
  579. if (slot.getExpandRatio() == 0
  580. && !slot.isRelativeInDirection(vertical)) {
  581. if (layoutManager != null) {
  582. // TODO check caption position
  583. if (vertical) {
  584. int size = layoutManager.getOuterHeight(
  585. slot.getWidget().getElement());
  586. if (slot.hasCaption()) {
  587. size += layoutManager.getOuterHeight(
  588. slot.getCaptionElement());
  589. }
  590. if (size > 0) {
  591. totalSize += size;
  592. }
  593. } else {
  594. int max = -1;
  595. max = layoutManager.getOuterWidth(
  596. slot.getWidget().getElement());
  597. if (slot.hasCaption()) {
  598. int max2 = layoutManager.getOuterWidth(
  599. slot.getCaptionElement());
  600. max = Math.max(max, max2);
  601. }
  602. if (max > 0) {
  603. totalSize += max;
  604. }
  605. }
  606. } else {
  607. // FIXME expandRatio might be <0
  608. totalSize += vertical ? slot.getOffsetHeight()
  609. : slot.getOffsetWidth();
  610. }
  611. }
  612. // TODO fails in Opera, always returns 0
  613. int spacingSize = vertical ? slot.getVerticalSpacing()
  614. : slot.getHorizontalSpacing();
  615. if (spacingSize > 0) {
  616. totalSize += spacingSize;
  617. }
  618. }
  619. // When we set the margin to the first child, we don't need
  620. // overflow:hidden in the layout root element, since the wrapper
  621. // would otherwise be placed outside of the layout root element
  622. // and block events on elements below it.
  623. if (vertical) {
  624. expandWrapper.getStyle().setPaddingTop(totalSize, Unit.PX);
  625. expandWrapper.getFirstChildElement().getStyle()
  626. .setMarginTop(-totalSize, Unit.PX);
  627. } else {
  628. expandWrapper.getStyle().setPaddingLeft(totalSize, Unit.PX);
  629. expandWrapper.getFirstChildElement().getStyle()
  630. .setMarginLeft(-totalSize, Unit.PX);
  631. }
  632. // Measure expanded children again if their size might have changed
  633. if (totalSize != lastExpandSize) {
  634. lastExpandSize = totalSize;
  635. for (Widget w : getChildren()) {
  636. Slot slot = (Slot) w;
  637. // FIXME expandRatio might be <0
  638. if (slot.getExpandRatio() != 0) {
  639. if (layoutManager != null) {
  640. layoutManager.setNeedsMeasure(
  641. Util.findConnectorFor(slot.getWidget()));
  642. } else if (slot.getWidget() instanceof RequiresResize) {
  643. ((RequiresResize) slot.getWidget()).onResize();
  644. }
  645. }
  646. }
  647. }
  648. }
  649. }
  650. /**
  651. * {@inheritDoc}
  652. */
  653. @Override
  654. public void setHeight(String height) {
  655. super.setHeight(height);
  656. definedHeight = (height != null && !"".equals(height));
  657. }
  658. /**
  659. * Sets the slots style names. The style names will be prefixed with the
  660. * v-slot prefix.
  661. *
  662. * @param stylenames
  663. * The style names of the slot.
  664. */
  665. public void setSlotStyleNames(Widget widget, String... stylenames) {
  666. Slot slot = getSlot(widget);
  667. if (slot == null) {
  668. throw new IllegalArgumentException(
  669. "A slot for the widget could not be found. Has the widget been added to the layout?");
  670. }
  671. slot.setStyleNames(stylenames);
  672. }
  673. }