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

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