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