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.

Slot.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  1. /*
  2. * Copyright 2000-2014 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.aria.client.Roles;
  19. import com.google.gwt.core.client.GWT;
  20. import com.google.gwt.dom.client.Document;
  21. import com.google.gwt.dom.client.Element;
  22. import com.google.gwt.user.client.DOM;
  23. import com.google.gwt.user.client.Event;
  24. import com.google.gwt.user.client.Timer;
  25. import com.google.gwt.user.client.ui.SimplePanel;
  26. import com.google.gwt.user.client.ui.Widget;
  27. import com.vaadin.client.BrowserInfo;
  28. import com.vaadin.client.LayoutManager;
  29. import com.vaadin.client.StyleConstants;
  30. import com.vaadin.client.WidgetUtil;
  31. import com.vaadin.client.ui.FontIcon;
  32. import com.vaadin.client.ui.Icon;
  33. import com.vaadin.client.ui.ImageIcon;
  34. import com.vaadin.client.ui.layout.ElementResizeEvent;
  35. import com.vaadin.client.ui.layout.ElementResizeListener;
  36. import com.vaadin.shared.ui.AlignmentInfo;
  37. /**
  38. * Represents a slot which contains the actual widget in the layout.
  39. */
  40. public class Slot extends SimplePanel {
  41. private static final String ALIGN_CLASS_PREFIX = "v-align-";
  42. // this must be set at construction time and not changed afterwards
  43. private VAbstractOrderedLayout layout;
  44. public static final String SLOT_CLASSNAME = "v-slot";
  45. private Element spacer;
  46. private Element captionWrap;
  47. private Element caption;
  48. private Element captionText;
  49. private Icon icon;
  50. private Element errorIcon;
  51. private Element requiredIcon;
  52. private ElementResizeListener captionResizeListener;
  53. private ElementResizeListener widgetResizeListener;
  54. private ElementResizeListener spacingResizeListener;
  55. /*
  56. * This listener is applied only in IE8 to workaround browser issue where
  57. * IE8 forgets to update the error indicator position when the slot gets
  58. * resized by widget resizing itself. #11693
  59. */
  60. private ElementResizeListener ie8CaptionElementResizeUpdateListener = new ElementResizeListener() {
  61. @Override
  62. public void onElementResize(ElementResizeEvent e) {
  63. Element caption = getCaptionElement();
  64. if (caption != null) {
  65. WidgetUtil.forceIE8Redraw(caption);
  66. }
  67. }
  68. };
  69. // Caption is placed after component unless there is some part which
  70. // moves it above.
  71. private CaptionPosition captionPosition = CaptionPosition.RIGHT;
  72. private AlignmentInfo alignment;
  73. private double expandRatio = -1;
  74. /**
  75. * Constructs a slot.
  76. *
  77. * When using this constructor, the layout and widget must be set before any
  78. * other operations are performed on the slot.
  79. *
  80. * @since 7.6
  81. */
  82. public Slot() {
  83. setStyleName(SLOT_CLASSNAME);
  84. }
  85. /**
  86. * Set the layout in which this slot is. This method must be called exactly
  87. * once at slot construction time when using the default constructor.
  88. *
  89. * The method should normally only be called by
  90. * {@link VAbstractOrderedLayout#createSlot(Widget)}.
  91. *
  92. * @since 7.6
  93. * @param layout
  94. * the layout containing the slot
  95. */
  96. public void setLayout(VAbstractOrderedLayout layout) {
  97. this.layout = layout;
  98. }
  99. /**
  100. * Constructs a slot.
  101. *
  102. * @param layout
  103. * The layout to which this slot belongs
  104. * @param widget
  105. * The widget to put in the slot
  106. * @deprecated use {@link GWT#create(Class)}, {@link #setWidget(Widget)} and
  107. * {@link #setLayout(VAbstractOrderedLayout)} instead
  108. */
  109. @Deprecated
  110. public Slot(VAbstractOrderedLayout layout, Widget widget) {
  111. setLayout(layout);
  112. setStyleName(SLOT_CLASSNAME);
  113. setWidget(widget);
  114. }
  115. /*
  116. * (non-Javadoc)
  117. *
  118. * @see com.google.gwt.user.client.ui.SimplePanel#remove(com.google.gwt.user
  119. * .client.ui.Widget)
  120. */
  121. @Override
  122. public boolean remove(Widget w) {
  123. detachListeners();
  124. return super.remove(w);
  125. }
  126. /*
  127. * (non-Javadoc)
  128. *
  129. * @see com.google.gwt.user.client.ui.SimplePanel#setWidget(com.google.gwt
  130. * .user.client.ui.Widget)
  131. */
  132. @Override
  133. public void setWidget(Widget w) {
  134. detachListeners();
  135. super.setWidget(w);
  136. attachListeners();
  137. }
  138. /**
  139. * Attaches resize listeners to the widget, caption and spacing elements
  140. */
  141. private void attachListeners() {
  142. if (getWidget() != null && layout.getLayoutManager() != null) {
  143. LayoutManager lm = layout.getLayoutManager();
  144. if (getCaptionElement() != null && captionResizeListener != null) {
  145. lm.addElementResizeListener(getCaptionElement(),
  146. captionResizeListener);
  147. }
  148. if (widgetResizeListener != null) {
  149. lm.addElementResizeListener(getWidget().getElement(),
  150. widgetResizeListener);
  151. }
  152. if (getSpacingElement() != null && spacingResizeListener != null) {
  153. lm.addElementResizeListener(getSpacingElement(),
  154. spacingResizeListener);
  155. }
  156. if (BrowserInfo.get().isIE8()) {
  157. lm.addElementResizeListener(getWidget().getElement(),
  158. ie8CaptionElementResizeUpdateListener);
  159. }
  160. }
  161. }
  162. /**
  163. * Detaches resize listeners from the widget, caption and spacing elements
  164. */
  165. private void detachListeners() {
  166. if (getWidget() != null && layout.getLayoutManager() != null) {
  167. LayoutManager lm = layout.getLayoutManager();
  168. if (getCaptionElement() != null && captionResizeListener != null) {
  169. lm.removeElementResizeListener(getCaptionElement(),
  170. captionResizeListener);
  171. }
  172. if (widgetResizeListener != null) {
  173. lm.removeElementResizeListener(getWidget().getElement(),
  174. widgetResizeListener);
  175. }
  176. // in many cases, the listener has already been removed by
  177. // setSpacing(false)
  178. if (getSpacingElement() != null && spacingResizeListener != null) {
  179. lm.removeElementResizeListener(getSpacingElement(),
  180. spacingResizeListener);
  181. }
  182. if (BrowserInfo.get().isIE8()) {
  183. lm.removeElementResizeListener(getWidget().getElement(),
  184. ie8CaptionElementResizeUpdateListener);
  185. }
  186. }
  187. }
  188. public ElementResizeListener getCaptionResizeListener() {
  189. return captionResizeListener;
  190. }
  191. public void setCaptionResizeListener(
  192. ElementResizeListener captionResizeListener) {
  193. detachListeners();
  194. this.captionResizeListener = captionResizeListener;
  195. attachListeners();
  196. }
  197. public ElementResizeListener getWidgetResizeListener() {
  198. return widgetResizeListener;
  199. }
  200. public void setWidgetResizeListener(
  201. ElementResizeListener widgetResizeListener) {
  202. detachListeners();
  203. this.widgetResizeListener = widgetResizeListener;
  204. attachListeners();
  205. }
  206. public ElementResizeListener getSpacingResizeListener() {
  207. return spacingResizeListener;
  208. }
  209. public void setSpacingResizeListener(
  210. ElementResizeListener spacingResizeListener) {
  211. detachListeners();
  212. this.spacingResizeListener = spacingResizeListener;
  213. attachListeners();
  214. }
  215. /**
  216. * Returns the alignment for the slot
  217. *
  218. */
  219. public AlignmentInfo getAlignment() {
  220. return alignment;
  221. }
  222. /**
  223. * Sets the style names for the slot containing the widget
  224. *
  225. * @param stylenames
  226. * The style names for the slot
  227. */
  228. protected void setStyleNames(String... stylenames) {
  229. setStyleName(SLOT_CLASSNAME);
  230. if (stylenames != null) {
  231. for (String stylename : stylenames) {
  232. addStyleDependentName(stylename);
  233. }
  234. }
  235. // Ensure alignment style names are correct
  236. setAlignment(alignment);
  237. }
  238. /**
  239. * Sets how the widget is aligned inside the slot
  240. *
  241. * @param alignment
  242. * The alignment inside the slot
  243. */
  244. public void setAlignment(AlignmentInfo alignment) {
  245. this.alignment = alignment;
  246. if (alignment != null && alignment.isHorizontalCenter()) {
  247. addStyleName(ALIGN_CLASS_PREFIX + "center");
  248. removeStyleName(ALIGN_CLASS_PREFIX + "right");
  249. } else if (alignment != null && alignment.isRight()) {
  250. addStyleName(ALIGN_CLASS_PREFIX + "right");
  251. removeStyleName(ALIGN_CLASS_PREFIX + "center");
  252. } else {
  253. removeStyleName(ALIGN_CLASS_PREFIX + "right");
  254. removeStyleName(ALIGN_CLASS_PREFIX + "center");
  255. }
  256. if (alignment != null && alignment.isVerticalCenter()) {
  257. addStyleName(ALIGN_CLASS_PREFIX + "middle");
  258. removeStyleName(ALIGN_CLASS_PREFIX + "bottom");
  259. } else if (alignment != null && alignment.isBottom()) {
  260. addStyleName(ALIGN_CLASS_PREFIX + "bottom");
  261. removeStyleName(ALIGN_CLASS_PREFIX + "middle");
  262. } else {
  263. removeStyleName(ALIGN_CLASS_PREFIX + "middle");
  264. removeStyleName(ALIGN_CLASS_PREFIX + "bottom");
  265. }
  266. }
  267. /**
  268. * Set how the slot should be expanded relative to the other slots. 0 means
  269. * that the slot should not participate in the division of space based on
  270. * the expand ratios but instead be allocated space based on its natural
  271. * size. Other values causes the slot to get a share of the otherwise
  272. * unallocated space in proportion to the slot's expand ratio value.
  273. *
  274. * @param expandRatio
  275. * The ratio of the space the slot should occupy
  276. *
  277. */
  278. public void setExpandRatio(double expandRatio) {
  279. this.expandRatio = expandRatio;
  280. }
  281. /**
  282. * Get the expand ratio for the slot. The expand ratio describes how the
  283. * slot should be resized compared to other slots in the layout
  284. *
  285. * @return the expand ratio of the slot
  286. *
  287. * @see #setExpandRatio(double)
  288. */
  289. public double getExpandRatio() {
  290. return expandRatio;
  291. }
  292. /**
  293. * Set the spacing for the slot. The spacing determines if there should be
  294. * empty space around the slot when the slot.
  295. *
  296. * @param spacing
  297. * Should spacing be enabled
  298. */
  299. public void setSpacing(boolean spacing) {
  300. if (spacing && spacer == null) {
  301. spacer = DOM.createDiv();
  302. spacer.addClassName("v-spacing");
  303. /*
  304. * This has to be done here for the initial render. In other cases
  305. * where the spacer already exists onAttach will handle it.
  306. */
  307. getElement().getParentElement().insertBefore(spacer, getElement());
  308. } else if (!spacing && spacer != null) {
  309. // Remove listener before spacer to avoid memory leak
  310. LayoutManager lm = layout.getLayoutManager();
  311. if (lm != null && spacingResizeListener != null) {
  312. lm.removeElementResizeListener(spacer, spacingResizeListener);
  313. }
  314. spacer.removeFromParent();
  315. spacer = null;
  316. }
  317. }
  318. /**
  319. * Get the element which is added to make the spacing
  320. *
  321. * @return
  322. */
  323. public com.google.gwt.user.client.Element getSpacingElement() {
  324. return DOM.asOld(spacer);
  325. }
  326. /**
  327. * Does the slot have spacing
  328. */
  329. public boolean hasSpacing() {
  330. return getSpacingElement() != null;
  331. }
  332. /**
  333. * Get the vertical amount in pixels of the spacing
  334. */
  335. protected int getVerticalSpacing() {
  336. if (spacer == null) {
  337. return 0;
  338. } else if (layout.getLayoutManager() != null) {
  339. return layout.getLayoutManager().getOuterHeight(spacer);
  340. }
  341. return spacer.getOffsetHeight();
  342. }
  343. /**
  344. * Get the horizontal amount of pixels of the spacing
  345. *
  346. * @return
  347. */
  348. protected int getHorizontalSpacing() {
  349. if (spacer == null) {
  350. return 0;
  351. } else if (layout.getLayoutManager() != null) {
  352. return layout.getLayoutManager().getOuterWidth(spacer);
  353. }
  354. return spacer.getOffsetWidth();
  355. }
  356. /**
  357. * Set the position of the caption relative to the slot
  358. *
  359. * @param captionPosition
  360. * The position of the caption
  361. */
  362. public void setCaptionPosition(CaptionPosition captionPosition) {
  363. if (caption == null) {
  364. return;
  365. }
  366. captionWrap.removeClassName("v-caption-on-"
  367. + this.captionPosition.name().toLowerCase());
  368. this.captionPosition = captionPosition;
  369. if (captionPosition == CaptionPosition.BOTTOM
  370. || captionPosition == CaptionPosition.RIGHT) {
  371. captionWrap.appendChild(caption);
  372. } else {
  373. captionWrap.insertFirst(caption);
  374. }
  375. captionWrap.addClassName("v-caption-on-"
  376. + captionPosition.name().toLowerCase());
  377. }
  378. /**
  379. * Get the position of the caption relative to the slot
  380. */
  381. public CaptionPosition getCaptionPosition() {
  382. return captionPosition;
  383. }
  384. /**
  385. * Set the caption of the slot
  386. *
  387. * @param captionText
  388. * The text of the caption
  389. * @param iconUrl
  390. * The icon URL, must already be run trough translateVaadinUri()
  391. * @param styles
  392. * The style names
  393. * @param error
  394. * The error message
  395. * @param showError
  396. * Should the error message be shown
  397. * @param required
  398. * Is the (field) required
  399. * @param enabled
  400. * Is the component enabled
  401. *
  402. * @deprecated Use
  403. * {@link #setCaption(String, Icon, List, String, boolean, boolean, boolean)}
  404. * instead
  405. */
  406. @Deprecated
  407. public void setCaption(String captionText, String iconUrl,
  408. List<String> styles, String error, boolean showError,
  409. boolean required, boolean enabled) {
  410. Icon icon;
  411. if (FontIcon.isFontIconUri(iconUrl)) {
  412. icon = GWT.create(FontIcon.class);
  413. } else {
  414. icon = GWT.create(ImageIcon.class);
  415. }
  416. icon.setUri(iconUrl);
  417. setCaption(captionText, icon, styles, error, showError, required,
  418. enabled);
  419. }
  420. /**
  421. * Set the caption of the slot as text
  422. *
  423. * @param captionText
  424. * The text of the caption
  425. * @param icon
  426. * The icon
  427. * @param styles
  428. * The style names
  429. * @param error
  430. * The error message
  431. * @param showError
  432. * Should the error message be shown
  433. * @param required
  434. * Is the (field) required
  435. * @param enabled
  436. * Is the component enabled
  437. */
  438. public void setCaption(String captionText, Icon icon, List<String> styles,
  439. String error, boolean showError, boolean required, boolean enabled) {
  440. setCaption(captionText, icon, styles, error, showError, required,
  441. enabled, false);
  442. }
  443. /**
  444. * Set the caption of the slot
  445. *
  446. * @param captionText
  447. * The text of the caption
  448. * @param icon
  449. * The icon
  450. * @param styles
  451. * The style names
  452. * @param error
  453. * The error message
  454. * @param showError
  455. * Should the error message be shown
  456. * @param required
  457. * Is the (field) required
  458. * @param enabled
  459. * Is the component enabled
  460. * @param captionAsHtml
  461. * true if the caption should be rendered as HTML, false
  462. * otherwise
  463. */
  464. public void setCaption(String captionText, Icon icon, List<String> styles,
  465. String error, boolean showError, boolean required, boolean enabled,
  466. boolean captionAsHtml) {
  467. // TODO place for optimization: check if any of these have changed
  468. // since last time, and only run those changes
  469. // Caption wrappers
  470. Widget widget = getWidget();
  471. final Element focusedElement = WidgetUtil.getFocusedElement();
  472. // By default focus will not be lost
  473. boolean focusLost = false;
  474. if (captionText != null || icon != null || error != null || required) {
  475. if (caption == null) {
  476. caption = DOM.createDiv();
  477. captionWrap = DOM.createDiv();
  478. captionWrap.addClassName(StyleConstants.UI_WIDGET);
  479. captionWrap.addClassName("v-has-caption");
  480. getElement().appendChild(captionWrap);
  481. orphan(widget);
  482. captionWrap.appendChild(widget.getElement());
  483. adopt(widget);
  484. // Made changes to DOM. Focus can be lost if it was in the
  485. // widget.
  486. focusLost = (focusedElement == null ? false : widget
  487. .getElement().isOrHasChild(focusedElement));
  488. }
  489. } else if (caption != null) {
  490. orphan(widget);
  491. getElement().appendChild(widget.getElement());
  492. adopt(widget);
  493. captionWrap.removeFromParent();
  494. caption = null;
  495. captionWrap = null;
  496. // Made changes to DOM. Focus can be lost if it was in the widget.
  497. focusLost = (focusedElement == null ? false : widget.getElement()
  498. .isOrHasChild(focusedElement));
  499. }
  500. // Caption text
  501. if (captionText != null) {
  502. if (this.captionText == null) {
  503. this.captionText = DOM.createSpan();
  504. this.captionText.addClassName("v-captiontext");
  505. caption.appendChild(this.captionText);
  506. }
  507. if (captionText.trim().equals("")) {
  508. this.captionText.setInnerHTML("&nbsp;");
  509. } else {
  510. if (captionAsHtml) {
  511. this.captionText.setInnerHTML(captionText);
  512. } else {
  513. this.captionText.setInnerText(captionText);
  514. }
  515. }
  516. } else if (this.captionText != null) {
  517. this.captionText.removeFromParent();
  518. this.captionText = null;
  519. }
  520. // Icon
  521. if (this.icon != null) {
  522. this.icon.getElement().removeFromParent();
  523. }
  524. if (icon != null) {
  525. caption.insertFirst(icon.getElement());
  526. }
  527. this.icon = icon;
  528. // Required
  529. if (required) {
  530. if (requiredIcon == null) {
  531. requiredIcon = DOM.createSpan();
  532. // TODO decide something better (e.g. use CSS to insert the
  533. // character)
  534. requiredIcon.setInnerHTML("*");
  535. requiredIcon.setClassName("v-required-field-indicator");
  536. // The star should not be read by the screen reader, as it is
  537. // purely visual. Required state is set at the element level for
  538. // the screen reader.
  539. Roles.getTextboxRole().setAriaHiddenState(requiredIcon, true);
  540. }
  541. caption.appendChild(requiredIcon);
  542. } else if (requiredIcon != null) {
  543. requiredIcon.removeFromParent();
  544. requiredIcon = null;
  545. }
  546. // Error
  547. if (error != null && showError) {
  548. if (errorIcon == null) {
  549. errorIcon = DOM.createSpan();
  550. errorIcon.setClassName("v-errorindicator");
  551. }
  552. caption.appendChild(errorIcon);
  553. } else if (errorIcon != null) {
  554. errorIcon.removeFromParent();
  555. errorIcon = null;
  556. }
  557. if (caption != null) {
  558. // Styles
  559. caption.setClassName("v-caption");
  560. if (styles != null) {
  561. for (String style : styles) {
  562. caption.addClassName("v-caption-" + style);
  563. }
  564. }
  565. if (enabled) {
  566. caption.removeClassName("v-disabled");
  567. } else {
  568. caption.addClassName("v-disabled");
  569. }
  570. // Caption position
  571. if (captionText != null || icon != null) {
  572. setCaptionPosition(CaptionPosition.TOP);
  573. } else {
  574. setCaptionPosition(CaptionPosition.RIGHT);
  575. }
  576. }
  577. if (focusLost) {
  578. // Find out what element is currently focused.
  579. Element currentFocus = WidgetUtil.getFocusedElement();
  580. if (currentFocus != null
  581. && currentFocus.equals(Document.get().getBody())) {
  582. // Focus has moved to BodyElement and should be moved back to
  583. // original location. This happened because of adding or
  584. // removing the captionWrap
  585. focusedElement.focus();
  586. } else if (currentFocus != focusedElement) {
  587. // Focus is either moved somewhere else on purpose or IE has
  588. // lost it. Investigate further.
  589. Timer focusTimer = new Timer() {
  590. @Override
  591. public void run() {
  592. if (WidgetUtil.getFocusedElement() == null) {
  593. // This should never become an infinite loop and
  594. // even if it does it will be stopped once something
  595. // is done with the browser.
  596. schedule(25);
  597. } else if (WidgetUtil.getFocusedElement().equals(
  598. Document.get().getBody())) {
  599. // Focus found it's way to BodyElement. Now it can
  600. // be restored
  601. focusedElement.focus();
  602. }
  603. }
  604. };
  605. if (BrowserInfo.get().isIE8()) {
  606. // IE8 can't fix the focus immediately. It will fail.
  607. focusTimer.schedule(25);
  608. } else {
  609. // Newer IE versions can handle things immediately.
  610. focusTimer.run();
  611. }
  612. }
  613. }
  614. }
  615. /**
  616. * Does the slot have a caption
  617. */
  618. public boolean hasCaption() {
  619. return caption != null;
  620. }
  621. /**
  622. * Get the slots caption element
  623. */
  624. public com.google.gwt.user.client.Element getCaptionElement() {
  625. return DOM.asOld(caption);
  626. }
  627. private boolean relativeWidth = false;
  628. /**
  629. * Set if the slot has a relative width
  630. *
  631. * @param relativeWidth
  632. * True if slot uses relative width, false if the slot has a
  633. * static width
  634. */
  635. public void setRelativeWidth(boolean relativeWidth) {
  636. this.relativeWidth = relativeWidth;
  637. updateRelativeSize(relativeWidth, "width");
  638. }
  639. public boolean hasRelativeWidth() {
  640. return relativeWidth;
  641. }
  642. private boolean relativeHeight = false;
  643. /**
  644. * Set if the slot has a relative height
  645. *
  646. * @param relativeHeight
  647. * True if the slot uses a relative height, false if the slot has
  648. * a static height
  649. */
  650. public void setRelativeHeight(boolean relativeHeight) {
  651. this.relativeHeight = relativeHeight;
  652. updateRelativeSize(relativeHeight, "height");
  653. }
  654. public boolean hasRelativeHeight() {
  655. return relativeHeight;
  656. }
  657. /**
  658. * Updates the captions size if the slot is relative
  659. *
  660. * @param isRelativeSize
  661. * Is the slot relatively sized
  662. * @param direction
  663. * The direction of the caption
  664. */
  665. private void updateRelativeSize(boolean isRelativeSize, String direction) {
  666. if (isRelativeSize && hasCaption()) {
  667. captionWrap.getStyle().setProperty(direction,
  668. getWidget().getElement().getStyle().getProperty(direction));
  669. captionWrap.addClassName("v-has-" + direction);
  670. } else if (hasCaption()) {
  671. if (direction.equals("height")) {
  672. captionWrap.getStyle().clearHeight();
  673. } else {
  674. captionWrap.getStyle().clearWidth();
  675. }
  676. captionWrap.removeClassName("v-has-" + direction);
  677. captionWrap.getStyle().clearPaddingTop();
  678. captionWrap.getStyle().clearPaddingRight();
  679. captionWrap.getStyle().clearPaddingBottom();
  680. captionWrap.getStyle().clearPaddingLeft();
  681. caption.getStyle().clearMarginTop();
  682. caption.getStyle().clearMarginRight();
  683. caption.getStyle().clearMarginBottom();
  684. caption.getStyle().clearMarginLeft();
  685. }
  686. }
  687. /*
  688. * (non-Javadoc)
  689. *
  690. * @see com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt
  691. * .user.client.Event)
  692. */
  693. @Override
  694. public void onBrowserEvent(Event event) {
  695. super.onBrowserEvent(event);
  696. if (DOM.eventGetType(event) == Event.ONLOAD
  697. && icon.getElement() == DOM.eventGetTarget(event)) {
  698. if (layout.getLayoutManager() != null) {
  699. layout.getLayoutManager().layoutLater();
  700. } else {
  701. layout.updateCaptionOffset(caption);
  702. }
  703. }
  704. }
  705. /*
  706. * (non-Javadoc)
  707. *
  708. * @see com.google.gwt.user.client.ui.SimplePanel#getContainerElement()
  709. */
  710. @Override
  711. protected com.google.gwt.user.client.Element getContainerElement() {
  712. if (captionWrap == null) {
  713. return getElement();
  714. } else {
  715. return DOM.asOld(captionWrap);
  716. }
  717. }
  718. /*
  719. * (non-Javadoc)
  720. *
  721. * @see com.google.gwt.user.client.ui.Widget#onDetach()
  722. */
  723. @Override
  724. protected void onDetach() {
  725. if (spacer != null) {
  726. spacer.removeFromParent();
  727. }
  728. super.onDetach();
  729. }
  730. /*
  731. * (non-Javadoc)
  732. *
  733. * @see com.google.gwt.user.client.ui.Widget#onAttach()
  734. */
  735. @Override
  736. protected void onAttach() {
  737. super.onAttach();
  738. if (spacer != null) {
  739. getElement().getParentElement().insertBefore(spacer, getElement());
  740. }
  741. }
  742. public boolean isRelativeInDirection(boolean vertical) {
  743. if (vertical) {
  744. return hasRelativeHeight();
  745. } else {
  746. return hasRelativeWidth();
  747. }
  748. }
  749. }