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

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