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.

AbstractOrderedLayoutConnector.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  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.List;
  18. import com.google.gwt.core.client.Scheduler;
  19. import com.google.gwt.dom.client.Element;
  20. import com.google.gwt.dom.client.Style.Unit;
  21. import com.google.gwt.user.client.ui.Widget;
  22. import com.vaadin.client.ApplicationConnection;
  23. import com.vaadin.client.ComponentConnector;
  24. import com.vaadin.client.ConnectorHierarchyChangeEvent;
  25. import com.vaadin.client.LayoutManager;
  26. import com.vaadin.client.Profiler;
  27. import com.vaadin.client.ServerConnector;
  28. import com.vaadin.client.TooltipInfo;
  29. import com.vaadin.client.Util;
  30. import com.vaadin.client.WidgetUtil;
  31. import com.vaadin.client.communication.StateChangeEvent;
  32. import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
  33. import com.vaadin.client.ui.AbstractLayoutConnector;
  34. import com.vaadin.client.ui.HasErrorIndicator;
  35. import com.vaadin.client.ui.HasRequiredIndicator;
  36. import com.vaadin.client.ui.Icon;
  37. import com.vaadin.client.ui.LayoutClickEventHandler;
  38. import com.vaadin.client.ui.aria.AriaHelper;
  39. import com.vaadin.client.ui.layout.ElementResizeListener;
  40. import com.vaadin.shared.ComponentConstants;
  41. import com.vaadin.shared.communication.URLReference;
  42. import com.vaadin.shared.ui.AlignmentInfo;
  43. import com.vaadin.shared.ui.LayoutClickRpc;
  44. import com.vaadin.shared.ui.MarginInfo;
  45. import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutServerRpc;
  46. import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutState;
  47. /**
  48. * Base class for vertical and horizontal ordered layouts.
  49. */
  50. public abstract class AbstractOrderedLayoutConnector
  51. extends AbstractLayoutConnector {
  52. /*
  53. * Handlers & Listeners
  54. */
  55. private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
  56. this) {
  57. @Override
  58. protected ComponentConnector getChildComponent(
  59. com.google.gwt.user.client.Element element) {
  60. return Util.getConnectorForElement(getConnection(), getWidget(),
  61. element);
  62. }
  63. @Override
  64. protected LayoutClickRpc getLayoutClickRPC() {
  65. return getRpcProxy(AbstractOrderedLayoutServerRpc.class);
  66. }
  67. };
  68. private StateChangeHandler childStateChangeHandler = event -> {
  69. // Child state has changed, update stuff it hasn't already been done
  70. updateInternalState();
  71. /*
  72. * Some changes must always be done after each child's own state change
  73. * handler has been run because it might have changed some styles that
  74. * are overridden here.
  75. */
  76. ServerConnector child = event.getConnector();
  77. if (child instanceof ComponentConnector) {
  78. ComponentConnector component = (ComponentConnector) child;
  79. Slot slot = getWidget().getSlot(component.getWidget());
  80. slot.setRelativeWidth(component.isRelativeWidth());
  81. slot.setRelativeHeight(component.isRelativeHeight());
  82. }
  83. };
  84. private ElementResizeListener slotCaptionResizeListener = event -> {
  85. // Get all needed element references
  86. Element captionElement = event.getElement();
  87. // Caption position determines if the widget element is the first or
  88. // last child inside the caption wrap
  89. CaptionPosition pos = getWidget().getCaptionPositionFromElement(
  90. captionElement.getParentElement());
  91. // The default is the last child
  92. Element widgetElement = captionElement.getParentElement().getLastChild()
  93. .cast();
  94. // ...but if caption position is bottom or right, the widget is the
  95. // first child
  96. if (pos == CaptionPosition.BOTTOM || pos == CaptionPosition.RIGHT) {
  97. widgetElement = captionElement.getParentElement()
  98. .getFirstChildElement().cast();
  99. }
  100. if (captionElement == widgetElement) {
  101. // Caption element already detached
  102. Slot slot = getWidget().getSlot(widgetElement);
  103. if (slot != null) {
  104. slot.setCaptionResizeListener(null);
  105. }
  106. return;
  107. }
  108. String widgetWidth = widgetElement.getStyle().getWidth();
  109. String widgetHeight = widgetElement.getStyle().getHeight();
  110. if (widgetHeight.endsWith("%") && (pos == CaptionPosition.TOP
  111. || pos == CaptionPosition.BOTTOM)) {
  112. getWidget().updateCaptionOffset(captionElement);
  113. } else if (widgetWidth.endsWith("%") && (pos == CaptionPosition.LEFT
  114. || pos == CaptionPosition.RIGHT)) {
  115. getWidget().updateCaptionOffset(captionElement);
  116. }
  117. updateLayoutHeight();
  118. if (needsExpand()) {
  119. getWidget().updateExpandCompensation();
  120. }
  121. };
  122. private ElementResizeListener childComponentResizeListener = event -> {
  123. updateLayoutHeight();
  124. if (needsExpand()) {
  125. getWidget().updateExpandCompensation();
  126. }
  127. };
  128. private ElementResizeListener spacingResizeListener = event -> {
  129. if (needsExpand()) {
  130. getWidget().updateExpandCompensation();
  131. }
  132. };
  133. /*
  134. * (non-Javadoc)
  135. *
  136. * @see com.vaadin.client.ui.AbstractComponentConnector#init()
  137. */
  138. @Override
  139. public void init() {
  140. super.init();
  141. getWidget().setLayoutManager(getLayoutManager());
  142. }
  143. /*
  144. * (non-Javadoc)
  145. *
  146. * @see com.vaadin.client.ui.AbstractLayoutConnector#getState()
  147. */
  148. @Override
  149. public AbstractOrderedLayoutState getState() {
  150. return (AbstractOrderedLayoutState) super.getState();
  151. }
  152. /*
  153. * (non-Javadoc)
  154. *
  155. * @see com.vaadin.client.ui.AbstractComponentConnector#getWidget()
  156. */
  157. @Override
  158. public VAbstractOrderedLayout getWidget() {
  159. return (VAbstractOrderedLayout) super.getWidget();
  160. }
  161. /**
  162. * Keep track of whether any child has relative height. Used to determine
  163. * whether measurements are needed to make relative child heights work
  164. * together with undefined container height.
  165. */
  166. private boolean hasChildrenWithRelativeHeight = false;
  167. /**
  168. * Keep track of whether any child has relative width. Used to determine
  169. * whether measurements are needed to make relative child widths work
  170. * together with undefined container width.
  171. */
  172. private boolean hasChildrenWithRelativeWidth = false;
  173. /**
  174. * Keep track of whether any child is middle aligned. Used to determine if
  175. * measurements are needed to make middle aligned children work.
  176. */
  177. private boolean hasChildrenWithMiddleAlignment = false;
  178. /**
  179. * Keeps track of whether slots should be expanded based on available space.
  180. */
  181. private boolean needsExpand = false;
  182. /**
  183. * The id of the previous response for which state changes have been
  184. * processed. If this is the same as the
  185. * {@link ApplicationConnection#getLastSeenServerSyncId()}, it means that we
  186. * can skip some quite expensive calculations because we know that the state
  187. * hasn't changed since the last time the values were calculated.
  188. */
  189. private int processedResponseId = -1;
  190. /*
  191. * (non-Javadoc)
  192. *
  193. * @see com.vaadin.client.HasComponentsConnector#updateCaption(com.vaadin
  194. * .client.ComponentConnector)
  195. */
  196. @Override
  197. public void updateCaption(ComponentConnector connector) {
  198. /*
  199. * Don't directly update captions here to avoid calling e.g.
  200. * updateLayoutHeight() before everything is initialized.
  201. * updateInternalState() will ensure all captions are updated when
  202. * appropriate.
  203. */
  204. updateInternalState();
  205. }
  206. private void updateCaptionInternal(ComponentConnector child) {
  207. Slot slot = getWidget().getSlot(child.getWidget());
  208. String caption = child.getState().caption;
  209. URLReference iconUrl = child.getState().resources
  210. .get(ComponentConstants.ICON_RESOURCE);
  211. String iconUrlString = iconUrl != null ? iconUrl.getURL() : null;
  212. Icon icon = child.getConnection().getIcon(iconUrlString);
  213. List<String> styles = child.getState().styles;
  214. String error = child.getState().errorMessage;
  215. boolean showError = false;
  216. if (child instanceof HasErrorIndicator) {
  217. showError = ((HasErrorIndicator) child).isErrorIndicatorVisible();
  218. }
  219. boolean required = false;
  220. if (child instanceof HasRequiredIndicator) {
  221. required = ((HasRequiredIndicator) child)
  222. .isRequiredIndicatorVisible();
  223. }
  224. boolean enabled = child.isEnabled();
  225. if (slot.hasCaption() && null == caption) {
  226. slot.setCaptionResizeListener(null);
  227. }
  228. slot.setCaption(caption, icon, styles, error,
  229. child.getState().errorLevel, showError, required, enabled,
  230. child.getState().captionAsHtml);
  231. AriaHelper.handleInputRequired(child.getWidget(), required);
  232. AriaHelper.handleInputInvalid(child.getWidget(), showError);
  233. AriaHelper.bindCaption(child.getWidget(), slot.getCaptionElement());
  234. if (slot.hasCaption()) {
  235. CaptionPosition pos = slot.getCaptionPosition();
  236. slot.setCaptionResizeListener(slotCaptionResizeListener);
  237. if (child.isRelativeHeight() && (pos == CaptionPosition.TOP
  238. || pos == CaptionPosition.BOTTOM)) {
  239. getWidget().updateCaptionOffset(slot.getCaptionElement());
  240. } else if (child.isRelativeWidth() && (pos == CaptionPosition.LEFT
  241. || pos == CaptionPosition.RIGHT)) {
  242. getWidget().updateCaptionOffset(slot.getCaptionElement());
  243. }
  244. }
  245. }
  246. /*
  247. * (non-Javadoc)
  248. *
  249. * @see com.vaadin.client.ui.AbstractComponentContainerConnector#
  250. * onConnectorHierarchyChange
  251. * (com.vaadin.client.ConnectorHierarchyChangeEvent)
  252. */
  253. @Override
  254. public void onConnectorHierarchyChange(
  255. ConnectorHierarchyChangeEvent event) {
  256. Profiler.enter("AOLC.onConnectorHierarchyChange");
  257. List<ComponentConnector> previousChildren = event.getOldChildren();
  258. int currentIndex = 0;
  259. VAbstractOrderedLayout layout = getWidget();
  260. // remove spacing as it is exists as separate elements that cannot be
  261. // removed easily after reordering the contents
  262. Profiler.enter(
  263. "AOLC.onConnectorHierarchyChange temporarily remove spacing");
  264. layout.setSpacing(false);
  265. Profiler.leave(
  266. "AOLC.onConnectorHierarchyChange temporarily remove spacing");
  267. // first remove extra components to avoid extra detaches and attaches
  268. for (ComponentConnector child : previousChildren) {
  269. Profiler.enter("AOLC.onConnectorHierarchyChange remove children");
  270. if (child.getParent() != this) {
  271. Slot slot = layout.getSlot(child.getWidget());
  272. slot.setWidgetResizeListener(null);
  273. if (slot.hasCaption()) {
  274. slot.setCaptionResizeListener(null);
  275. }
  276. slot.setSpacingResizeListener(null);
  277. child.removeStateChangeHandler(childStateChangeHandler);
  278. layout.removeWidget(child.getWidget());
  279. }
  280. Profiler.leave("AOLC.onConnectorHierarchyChange remove children");
  281. }
  282. Profiler.leave("AOLC.onConnectorHierarchyChange");
  283. // reorder remaining components and add any new components
  284. for (ComponentConnector child : getChildComponents()) {
  285. Profiler.enter("AOLC.onConnectorHierarchyChange add children");
  286. Slot slot = layout.getSlot(child.getWidget());
  287. if (slot.getParent() != layout) {
  288. Profiler.enter(
  289. "AOLC.onConnectorHierarchyChange add state change handler");
  290. child.addStateChangeHandler(childStateChangeHandler);
  291. Profiler.leave(
  292. "AOLC.onConnectorHierarchyChange add state change handler");
  293. }
  294. Profiler.enter("AOLC.onConnectorHierarchyChange addOrMoveSlot");
  295. layout.addOrMoveSlot(slot, currentIndex++, false);
  296. Profiler.leave("AOLC.onConnectorHierarchyChange addOrMoveSlot");
  297. Profiler.leave("AOLC.onConnectorHierarchyChange add children");
  298. }
  299. // re-add spacing for the elements that should have it
  300. Profiler.enter("AOLC.onConnectorHierarchyChange setSpacing");
  301. // spacings were removed above
  302. if (getState().spacing) {
  303. layout.setSpacing(true);
  304. }
  305. Profiler.leave("AOLC.onConnectorHierarchyChange setSpacing");
  306. updateInternalState();
  307. }
  308. /*
  309. * (non-Javadoc)
  310. *
  311. * @see
  312. * com.vaadin.client.ui.AbstractComponentConnector#onStateChanged(com.vaadin
  313. * .client.communication.StateChangeEvent)
  314. */
  315. @Override
  316. public void onStateChanged(StateChangeEvent stateChangeEvent) {
  317. super.onStateChanged(stateChangeEvent);
  318. clickEventHandler.handleEventHandlerRegistration();
  319. getWidget().setMargin(new MarginInfo(getState().marginsBitmask));
  320. getWidget().setSpacing(getState().spacing);
  321. updateInternalState();
  322. }
  323. /*
  324. * (non-Javadoc)
  325. *
  326. * @see
  327. * com.vaadin.client.ui.AbstractComponentConnector#getTooltipInfo(com.google
  328. * .gwt.dom.client.Element)
  329. */
  330. @Override
  331. public TooltipInfo getTooltipInfo(
  332. com.google.gwt.dom.client.Element element) {
  333. if (element != getWidget().getElement()) {
  334. Slot slot = WidgetUtil.findWidget(element, Slot.class);
  335. if (slot != null && slot.getCaptionElement() != null
  336. && slot.getParent() == getWidget()
  337. && slot.getCaptionElement().isOrHasChild(element)) {
  338. ComponentConnector connector = Util
  339. .findConnectorFor(slot.getWidget());
  340. if (connector != null) {
  341. return connector.getTooltipInfo(element);
  342. }
  343. }
  344. }
  345. return super.getTooltipInfo(element);
  346. }
  347. /*
  348. * (non-Javadoc)
  349. *
  350. * @see com.vaadin.client.ui.AbstractComponentConnector#hasTooltip()
  351. */
  352. @Override
  353. public boolean hasTooltip() {
  354. /*
  355. * Tooltips are fetched from child connectors -> there's no quick way of
  356. * checking whether there might a tooltip hiding somewhere
  357. */
  358. return true;
  359. }
  360. /**
  361. * Updates DOM properties and listeners based on the current state of this
  362. * layout and its children.
  363. */
  364. private void updateInternalState() {
  365. // Avoid updating again for the same data
  366. int lastResponseId = getConnection().getLastSeenServerSyncId();
  367. if (processedResponseId == lastResponseId) {
  368. return;
  369. }
  370. Profiler.enter("AOLC.updateInternalState");
  371. // Remember that everything is updated for this response
  372. processedResponseId = lastResponseId;
  373. hasChildrenWithRelativeHeight = false;
  374. hasChildrenWithRelativeWidth = false;
  375. hasChildrenWithMiddleAlignment = false;
  376. needsExpand = getWidget().vertical ? !isUndefinedHeight()
  377. : !isUndefinedWidth();
  378. boolean onlyZeroExpands = true;
  379. if (needsExpand) {
  380. for (ComponentConnector child : getChildComponents()) {
  381. double expandRatio = getState().childData
  382. .get(child).expandRatio;
  383. if (expandRatio != 0) {
  384. onlyZeroExpands = false;
  385. break;
  386. }
  387. }
  388. }
  389. // First update bookkeeping for all children
  390. for (ComponentConnector child : getChildComponents()) {
  391. Slot slot = getWidget().getSlot(child.getWidget());
  392. slot.setRelativeWidth(child.isRelativeWidth());
  393. slot.setRelativeHeight(child.isRelativeHeight());
  394. if (child.delegateCaptionHandling()) {
  395. updateCaptionInternal(child);
  396. }
  397. // Update slot style names
  398. List<String> childStyles = child.getState().styles;
  399. if (childStyles == null) {
  400. getWidget().setSlotStyleNames(child.getWidget(),
  401. (String[]) null);
  402. } else {
  403. getWidget().setSlotStyleNames(child.getWidget(),
  404. childStyles.toArray(new String[childStyles.size()]));
  405. }
  406. AlignmentInfo alignment = new AlignmentInfo(
  407. getState().childData.get(child).alignmentBitmask);
  408. slot.setAlignment(alignment);
  409. if (alignment.isVerticalCenter()) {
  410. hasChildrenWithMiddleAlignment = true;
  411. }
  412. double expandRatio = onlyZeroExpands ? 1
  413. : getState().childData.get(child).expandRatio;
  414. slot.setExpandRatio(expandRatio);
  415. if (child.isRelativeHeight()) {
  416. hasChildrenWithRelativeHeight = true;
  417. }
  418. if (child.isRelativeWidth()) {
  419. hasChildrenWithRelativeWidth = true;
  420. }
  421. }
  422. if (needsFixedHeight()) {
  423. // Add resize listener to ensure the widget itself is measured
  424. getLayoutManager().addElementResizeListener(
  425. getWidget().getElement(), childComponentResizeListener);
  426. } else {
  427. getLayoutManager().removeElementResizeListener(
  428. getWidget().getElement(), childComponentResizeListener);
  429. }
  430. // Then update listeners based on bookkeeping
  431. updateAllSlotListeners();
  432. // Update the layout at this point to ensure it's OK even if we get no
  433. // element resize events
  434. updateLayoutHeight();
  435. if (needsExpand()) {
  436. getWidget().updateExpandedSizes();
  437. // updateExpandedSizes causes fixed size components to temporarily
  438. // lose their size. updateExpandCompensation must be delayed until
  439. // the browser has a chance to measure them.
  440. Scheduler.get().scheduleFinally(
  441. () -> getWidget().updateExpandCompensation());
  442. } else {
  443. getWidget().clearExpand();
  444. }
  445. Profiler.leave("AOLC.updateInternalState");
  446. }
  447. /**
  448. * Does the layout need a fixed height?
  449. */
  450. private boolean needsFixedHeight() {
  451. boolean isVertical = getWidget().vertical;
  452. if (isVertical) {
  453. // Doesn't need height fix for vertical layouts
  454. return false;
  455. } else if (!isUndefinedHeight()) {
  456. // Fix not needed unless the height is undefined
  457. return false;
  458. } else if (!hasChildrenWithRelativeHeight
  459. && !hasChildrenWithMiddleAlignment) {
  460. // Already works if there are no relative heights or middle aligned
  461. // children
  462. return false;
  463. }
  464. return true;
  465. }
  466. /**
  467. * Does the layout need to expand?
  468. */
  469. private boolean needsExpand() {
  470. return needsExpand;
  471. }
  472. /**
  473. * Add slot listeners
  474. */
  475. private void updateAllSlotListeners() {
  476. for (ComponentConnector child : getChildComponents()) {
  477. updateSlotListeners(child);
  478. }
  479. }
  480. /**
  481. * Add/remove necessary ElementResizeListeners for one slot. This should be
  482. * called after each update to the slot's or it's widget.
  483. */
  484. private void updateSlotListeners(ComponentConnector child) {
  485. Slot slot = getWidget().getSlot(child.getWidget());
  486. // Clear all possible listeners first
  487. slot.setWidgetResizeListener(null);
  488. if (slot.hasCaption()) {
  489. slot.setCaptionResizeListener(null);
  490. }
  491. if (slot.hasSpacing()) {
  492. slot.setSpacingResizeListener(null);
  493. }
  494. // Add all necessary listeners
  495. if (needsFixedHeight()) {
  496. slot.setWidgetResizeListener(childComponentResizeListener);
  497. if (slot.hasCaption()) {
  498. slot.setCaptionResizeListener(slotCaptionResizeListener);
  499. }
  500. } else if ((hasChildrenWithRelativeHeight
  501. || hasChildrenWithRelativeWidth) && slot.hasCaption()) {
  502. /*
  503. * If the slot has caption, we need to listen for its size changes
  504. * in order to update the padding/margin offset for relative sized
  505. * components.
  506. *
  507. * TODO might only be needed if the caption is in the same direction
  508. * as the relative size?
  509. */
  510. slot.setCaptionResizeListener(slotCaptionResizeListener);
  511. }
  512. if (needsExpand()) {
  513. // TODO widget resize only be needed for children without expand?
  514. slot.setWidgetResizeListener(childComponentResizeListener);
  515. if (slot.hasSpacing()) {
  516. slot.setSpacingResizeListener(spacingResizeListener);
  517. }
  518. }
  519. }
  520. /**
  521. * Re-calculate the layout height
  522. */
  523. private void updateLayoutHeight() {
  524. if (needsFixedHeight()) {
  525. int h = getMaxHeight();
  526. if (h < 0) {
  527. // Postpone change if there are elements that have not yet been
  528. // measured
  529. return;
  530. }
  531. h += getLayoutManager().getBorderHeight(getWidget().getElement())
  532. + getLayoutManager()
  533. .getPaddingHeight(getWidget().getElement());
  534. getWidget().getElement().getStyle().setHeight(h, Unit.PX);
  535. getLayoutManager().setNeedsMeasure(this);
  536. }
  537. }
  538. /**
  539. * Measures the maximum height of the layout in pixels
  540. */
  541. private int getMaxHeight() {
  542. int highestNonRelative = -1;
  543. int highestRelative = -1;
  544. LayoutManager layoutManager = getLayoutManager();
  545. for (ComponentConnector child : getChildComponents()) {
  546. Widget childWidget = child.getWidget();
  547. Slot slot = getWidget().getSlot(childWidget);
  548. Element captionElement = slot.getCaptionElement();
  549. CaptionPosition captionPosition = slot.getCaptionPosition();
  550. int pixelHeight = layoutManager
  551. .getOuterHeight(childWidget.getElement());
  552. if (pixelHeight == -1) {
  553. // Height has not yet been measured -> postpone actions that
  554. // depend on the max height
  555. return -1;
  556. }
  557. boolean hasRelativeHeight = slot.hasRelativeHeight();
  558. boolean captionSizeShouldBeAddedtoComponentHeight = captionPosition == CaptionPosition.TOP
  559. || captionPosition == CaptionPosition.BOTTOM;
  560. boolean includeCaptionHeight = captionElement != null
  561. && captionSizeShouldBeAddedtoComponentHeight;
  562. if (includeCaptionHeight) {
  563. int captionHeight = layoutManager.getOuterHeight(captionElement)
  564. - getLayoutManager().getMarginHeight(captionElement);
  565. if (captionHeight == -1) {
  566. // Height has not yet been measured -> postpone actions that
  567. // depend on the max height
  568. return -1;
  569. }
  570. pixelHeight += captionHeight;
  571. }
  572. if (!hasRelativeHeight) {
  573. if (pixelHeight > highestNonRelative) {
  574. highestNonRelative = pixelHeight;
  575. }
  576. } else {
  577. if (pixelHeight > highestRelative) {
  578. highestRelative = pixelHeight;
  579. }
  580. }
  581. }
  582. return highestNonRelative > -1 ? highestNonRelative : highestRelative;
  583. }
  584. /*
  585. * (non-Javadoc)
  586. *
  587. * @see com.vaadin.client.ui.AbstractComponentConnector#onUnregister()
  588. */
  589. @Override
  590. public void onUnregister() {
  591. // Cleanup all ElementResizeListeners
  592. for (ComponentConnector child : getChildComponents()) {
  593. Slot slot = getWidget().getSlot(child.getWidget());
  594. if (slot.hasCaption()) {
  595. slot.setCaptionResizeListener(null);
  596. }
  597. if (slot.getSpacingElement() != null) {
  598. slot.setSpacingResizeListener(null);
  599. }
  600. slot.setWidgetResizeListener(null);
  601. }
  602. super.onUnregister();
  603. }
  604. }