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.

VCaption.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. /*
  2. * Copyright 2000-2021 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;
  17. import java.util.logging.Logger;
  18. import com.google.gwt.aria.client.Roles;
  19. import com.google.gwt.dom.client.Element;
  20. import com.google.gwt.dom.client.Style.Unit;
  21. import com.google.gwt.user.client.DOM;
  22. import com.google.gwt.user.client.Event;
  23. import com.google.gwt.user.client.ui.HTML;
  24. import com.google.gwt.user.client.ui.HasHTML;
  25. import com.vaadin.client.WidgetUtil.ErrorUtil;
  26. import com.vaadin.client.communication.StateChangeEvent;
  27. import com.vaadin.client.ui.HasErrorIndicator;
  28. import com.vaadin.client.ui.HasErrorIndicatorElement;
  29. import com.vaadin.client.ui.HasRequiredIndicator;
  30. import com.vaadin.client.ui.Icon;
  31. import com.vaadin.client.ui.ImageIcon;
  32. import com.vaadin.client.ui.aria.AriaHelper;
  33. import com.vaadin.shared.AbstractComponentState;
  34. import com.vaadin.shared.ComponentConstants;
  35. import com.vaadin.shared.ui.ComponentStateUtil;
  36. import com.vaadin.shared.ui.ErrorLevel;
  37. public class VCaption extends HTML implements HasErrorIndicatorElement {
  38. public static final String CLASSNAME = "v-caption";
  39. private final ComponentConnector owner;
  40. private Element errorIndicatorElement;
  41. private Element requiredFieldIndicator;
  42. private Icon icon;
  43. private String iconAltText = "";
  44. private Element captionText;
  45. private final ApplicationConnection client;
  46. private boolean placedAfterComponent = false;
  47. private int maxWidth = -1;
  48. private enum InsertPosition {
  49. ICON, CAPTION, REQUIRED, ERROR
  50. }
  51. private TooltipInfo tooltipInfo = null;
  52. private boolean captionAsHtml = false;
  53. /**
  54. * Creates a caption that is not linked to a {@link ComponentConnector}.
  55. *
  56. * When using this constructor, {@link #getOwner()} returns null.
  57. *
  58. * @param client
  59. * ApplicationConnection
  60. * @deprecated all captions should be associated with a paintable widget and
  61. * be updated from shared state, not UIDL
  62. */
  63. @Deprecated
  64. public VCaption(ApplicationConnection client) {
  65. super();
  66. this.client = client;
  67. owner = null;
  68. setStyleName(CLASSNAME);
  69. sinkEvents(VTooltip.TOOLTIP_EVENTS);
  70. }
  71. /**
  72. * Creates a caption for a {@link ComponentConnector}.
  73. *
  74. * @param component
  75. * owner of caption, not null
  76. * @param client
  77. * ApplicationConnection
  78. */
  79. public VCaption(ComponentConnector component,
  80. ApplicationConnection client) {
  81. super();
  82. this.client = client;
  83. owner = component;
  84. if (client != null && owner != null) {
  85. setOwnerPid(getElement(), owner.getConnectorId());
  86. }
  87. setStyleName(CLASSNAME);
  88. }
  89. @Override
  90. protected void onAttach() {
  91. super.onAttach();
  92. if (null != owner) {
  93. AriaHelper.bindCaption(owner.getWidget(), getElement());
  94. }
  95. }
  96. @Override
  97. protected void onDetach() {
  98. super.onDetach();
  99. if (null != owner) {
  100. AriaHelper.bindCaption(owner.getWidget(), null);
  101. AriaHelper.handleInputInvalid(owner.getWidget(), false);
  102. AriaHelper.handleInputRequired(owner.getWidget(), false);
  103. }
  104. }
  105. /**
  106. * Updates the caption from UIDL.
  107. *
  108. * This method may only be called when the caption has an owner - otherwise,
  109. * use {@link #updateCaptionWithoutOwner(UIDL, String, boolean, boolean)}.
  110. *
  111. * @return true if the position where the caption should be placed has
  112. * changed
  113. */
  114. public boolean updateCaption() {
  115. boolean wasPlacedAfterComponent = placedAfterComponent;
  116. // Caption is placed after component unless there is some part which
  117. // moves it above.
  118. placedAfterComponent = true;
  119. String style = CLASSNAME;
  120. if (ComponentStateUtil.hasStyles(owner.getState())) {
  121. for (String customStyle : owner.getState().styles) {
  122. style += " " + CLASSNAME + "-" + customStyle;
  123. }
  124. }
  125. if (!owner.isEnabled()) {
  126. style += " " + StyleConstants.DISABLED;
  127. }
  128. setStyleName(style);
  129. boolean hasIcon = owner.getState().resources
  130. .containsKey(ComponentConstants.ICON_RESOURCE);
  131. boolean showRequired = false;
  132. boolean showError = false;
  133. if (owner instanceof HasRequiredIndicator) {
  134. showRequired = ((HasRequiredIndicator) owner)
  135. .isRequiredIndicatorVisible();
  136. }
  137. if (owner instanceof HasErrorIndicator) {
  138. showError = ((HasErrorIndicator) owner).isErrorIndicatorVisible();
  139. }
  140. if (icon != null) {
  141. getElement().removeChild(icon.getElement());
  142. icon = null;
  143. }
  144. if (hasIcon) {
  145. String uri = owner.getState().resources
  146. .get(ComponentConstants.ICON_RESOURCE).getURL();
  147. icon = client.getIcon(uri);
  148. if (icon instanceof ImageIcon) {
  149. // onload will set appropriate size later
  150. icon.setWidth("0");
  151. icon.setHeight("0");
  152. }
  153. DOM.insertChild(getElement(), icon.getElement(),
  154. getInsertPosition(InsertPosition.ICON));
  155. // Icon forces the caption to be above the component
  156. placedAfterComponent = false;
  157. }
  158. if (owner.getState().caption != null) {
  159. // A caption text should be shown if the attribute is set
  160. // If the caption is null the ATTRIBUTE_CAPTION should not be set to
  161. // avoid ending up here.
  162. if (captionText == null) {
  163. captionText = DOM.createDiv();
  164. captionText.setClassName("v-captiontext");
  165. DOM.insertChild(getElement(), captionText,
  166. getInsertPosition(InsertPosition.CAPTION));
  167. }
  168. // Update caption text
  169. String c = owner.getState().caption;
  170. // A text forces the caption to be above the component.
  171. placedAfterComponent = false;
  172. if (c == null || c.trim().isEmpty()) {
  173. // Not sure if c even can be null. Should not.
  174. // This is required to ensure that the caption uses space in all
  175. // browsers when it is set to the empty string. If there is an
  176. // icon, error indicator or required indicator they will ensure
  177. // that space is reserved.
  178. if (!hasIcon && !showRequired && !showError) {
  179. captionText.setInnerHTML(" ");
  180. }
  181. } else {
  182. setCaptionText(captionText, owner.getState());
  183. }
  184. } else if (captionText != null) {
  185. // Remove existing
  186. DOM.removeChild(getElement(), captionText);
  187. captionText = null;
  188. }
  189. if (ComponentStateUtil.hasDescription(owner.getState())
  190. && captionText != null) {
  191. addStyleDependentName("hasdescription");
  192. } else {
  193. removeStyleDependentName("hasdescription");
  194. }
  195. AriaHelper.handleInputRequired(owner.getWidget(), showRequired);
  196. if (showRequired) {
  197. if (requiredFieldIndicator == null) {
  198. requiredFieldIndicator = DOM.createDiv();
  199. requiredFieldIndicator
  200. .setClassName("v-required-field-indicator");
  201. DOM.setInnerText(requiredFieldIndicator, "*");
  202. DOM.insertChild(getElement(), requiredFieldIndicator,
  203. getInsertPosition(InsertPosition.REQUIRED));
  204. // Hide the required indicator from assistive device
  205. Roles.getTextboxRole()
  206. .setAriaHiddenState(requiredFieldIndicator, true);
  207. }
  208. } else if (requiredFieldIndicator != null) {
  209. // Remove existing
  210. DOM.removeChild(getElement(), requiredFieldIndicator);
  211. requiredFieldIndicator = null;
  212. }
  213. AriaHelper.handleInputInvalid(owner.getWidget(), showError);
  214. if (showError) {
  215. setErrorIndicatorElementVisible(true);
  216. // Hide error indicator from assistive devices
  217. Roles.getTextboxRole().setAriaHiddenState(errorIndicatorElement,
  218. true);
  219. ErrorUtil.setErrorLevelStyle(errorIndicatorElement,
  220. StyleConstants.STYLE_NAME_ERROR_INDICATOR,
  221. owner.getState().errorLevel);
  222. } else {
  223. setErrorIndicatorElementVisible(false);
  224. }
  225. return (wasPlacedAfterComponent != placedAfterComponent);
  226. }
  227. private int getInsertPosition(InsertPosition element) {
  228. int pos = 0;
  229. if (InsertPosition.ICON.equals(element)) {
  230. return pos;
  231. }
  232. if (icon != null) {
  233. pos++;
  234. }
  235. if (InsertPosition.CAPTION.equals(element)) {
  236. return pos;
  237. }
  238. if (captionText != null) {
  239. pos++;
  240. }
  241. if (InsertPosition.REQUIRED.equals(element)) {
  242. return pos;
  243. }
  244. if (requiredFieldIndicator != null) {
  245. pos++;
  246. }
  247. // if (InsertPosition.ERROR.equals(element)) {
  248. // }
  249. return pos;
  250. }
  251. @Deprecated
  252. public boolean updateCaptionWithoutOwner(String caption, boolean disabled,
  253. boolean hasDescription, boolean hasError, String iconURL) {
  254. return updateCaptionWithoutOwner(caption, disabled, hasDescription,
  255. hasError, iconURL, "");
  256. }
  257. @Deprecated
  258. public boolean updateCaptionWithoutOwner(String caption, boolean disabled,
  259. boolean hasDescription, boolean hasError, String iconURL,
  260. String iconAltText) {
  261. return updateCaptionWithoutOwner(caption, disabled, hasDescription,
  262. hasError, null, iconURL, iconAltText);
  263. }
  264. @Deprecated
  265. public boolean updateCaptionWithoutOwner(String caption, boolean disabled,
  266. boolean hasDescription, boolean hasError, ErrorLevel errorLevel,
  267. String iconURL, String iconAltText) {
  268. boolean wasPlacedAfterComponent = placedAfterComponent;
  269. // Caption is placed after component unless there is some part which
  270. // moves it above.
  271. placedAfterComponent = true;
  272. String style = VCaption.CLASSNAME;
  273. if (disabled) {
  274. style += " " + StyleConstants.DISABLED;
  275. }
  276. setStyleName(style);
  277. if (hasDescription) {
  278. if (captionText != null) {
  279. addStyleDependentName("hasdescription");
  280. } else {
  281. removeStyleDependentName("hasdescription");
  282. }
  283. }
  284. boolean hasIcon = iconURL != null;
  285. if (icon != null) {
  286. getElement().removeChild(icon.getElement());
  287. icon = null;
  288. }
  289. if (hasIcon) {
  290. icon = client.getIcon(iconURL);
  291. if (icon instanceof ImageIcon) {
  292. // onload sets appropriate size later
  293. icon.setWidth("0");
  294. icon.setHeight("0");
  295. }
  296. icon.setAlternateText(iconAltText);
  297. DOM.insertChild(getElement(), icon.getElement(),
  298. getInsertPosition(InsertPosition.ICON));
  299. // Icon forces the caption to be above the component
  300. placedAfterComponent = false;
  301. }
  302. if (caption != null) {
  303. // A caption text should be shown if the attribute is set
  304. // If the caption is null the ATTRIBUTE_CAPTION should not be set to
  305. // avoid ending up here.
  306. if (captionText == null) {
  307. captionText = DOM.createDiv();
  308. captionText.setClassName("v-captiontext");
  309. DOM.insertChild(getElement(), captionText,
  310. getInsertPosition(InsertPosition.CAPTION));
  311. }
  312. // Update caption text
  313. // A text forces the caption to be above the component.
  314. placedAfterComponent = false;
  315. if (caption.trim().isEmpty()) {
  316. // This is required to ensure that the caption uses space in all
  317. // browsers when it is set to the empty string. If there is an
  318. // icon, error indicator or required indicator they will ensure
  319. // that space is reserved.
  320. if (!hasIcon && !hasError) {
  321. captionText.setInnerHTML(" ");
  322. }
  323. } else {
  324. if (captionAsHtml) {
  325. captionText.setInnerHTML(caption);
  326. } else {
  327. captionText.setInnerText(caption);
  328. }
  329. }
  330. } else if (captionText != null) {
  331. // Remove existing
  332. DOM.removeChild(getElement(), captionText);
  333. captionText = null;
  334. }
  335. if (hasError) {
  336. setErrorIndicatorElementVisible(true);
  337. ErrorUtil.setErrorLevelStyle(errorIndicatorElement,
  338. StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel);
  339. } else {
  340. setErrorIndicatorElementVisible(false);
  341. }
  342. return (wasPlacedAfterComponent != placedAfterComponent);
  343. }
  344. @Override
  345. public void onBrowserEvent(Event event) {
  346. super.onBrowserEvent(event);
  347. final Element target = DOM.eventGetTarget(event);
  348. if (DOM.eventGetType(event) == Event.ONLOAD
  349. && icon.getElement() == target) {
  350. icon.setWidth("");
  351. icon.setHeight("");
  352. // if max width defined, recalculate
  353. if (maxWidth != -1) {
  354. setMaxWidth(maxWidth);
  355. } else {
  356. String width = getElement().getStyle().getProperty("width");
  357. if (width != null && !width.isEmpty()) {
  358. setWidth(getRequiredWidth() + "px");
  359. }
  360. }
  361. /*
  362. * The size of the icon might affect the size of the component so we
  363. * must report the size change to the parent TODO consider moving
  364. * the responsibility of reacting to ONLOAD from VCaption to layouts
  365. */
  366. if (owner != null) {
  367. Util.notifyParentOfSizeChange(owner.getWidget(), true);
  368. } else {
  369. getLogger().warning(
  370. "Warning: Icon load event was not propagated because VCaption owner is unknown.");
  371. }
  372. }
  373. }
  374. public static boolean isNeeded(ComponentConnector connector) {
  375. AbstractComponentState state = connector.getState();
  376. if (state.caption != null) {
  377. return true;
  378. }
  379. if (state.resources.containsKey(ComponentConstants.ICON_RESOURCE)) {
  380. return true;
  381. }
  382. if (connector instanceof HasErrorIndicator
  383. && ((HasErrorIndicator) connector).isErrorIndicatorVisible()) {
  384. return true;
  385. }
  386. if (connector instanceof HasRequiredIndicator
  387. && ((HasRequiredIndicator) connector)
  388. .isRequiredIndicatorVisible()) {
  389. return true;
  390. }
  391. return false;
  392. }
  393. /**
  394. * Checks whether anything in a given state change might cause the caption
  395. * to change.
  396. *
  397. * @param event
  398. * the state change event to check
  399. * @return <code>true</code> if the caption might have changed; otherwise
  400. * <code>false</code>
  401. */
  402. public static boolean mightChange(StateChangeEvent event) {
  403. if (event.hasPropertyChanged("caption")) {
  404. return true;
  405. }
  406. if (event.hasPropertyChanged("resources")) {
  407. return true;
  408. }
  409. if (event.hasPropertyChanged("errorMessage")) {
  410. return true;
  411. }
  412. return false;
  413. }
  414. /**
  415. * Returns Paintable for which this Caption belongs to.
  416. *
  417. * @return owner Widget
  418. */
  419. public ComponentConnector getOwner() {
  420. return owner;
  421. }
  422. public boolean shouldBePlacedAfterComponent() {
  423. return placedAfterComponent;
  424. }
  425. public int getRenderedWidth() {
  426. int width = 0;
  427. if (icon != null) {
  428. width += WidgetUtil.getRequiredWidth(icon.getElement());
  429. }
  430. if (captionText != null) {
  431. width += WidgetUtil.getRequiredWidth(captionText);
  432. }
  433. if (requiredFieldIndicator != null) {
  434. width += WidgetUtil.getRequiredWidth(requiredFieldIndicator);
  435. }
  436. if (errorIndicatorElement != null) {
  437. width += WidgetUtil.getRequiredWidth(errorIndicatorElement);
  438. }
  439. return width;
  440. }
  441. public int getRequiredWidth() {
  442. int width = 0;
  443. if (icon != null) {
  444. width += WidgetUtil.getRequiredWidth(icon.getElement());
  445. }
  446. if (captionText != null) {
  447. int textWidth = captionText.getScrollWidth();
  448. if (BrowserInfo.get().isFirefox() || BrowserInfo.get().isChrome()) {
  449. /*
  450. * The caption might require more space than the scrollWidth
  451. * returns as scrollWidth is rounded down.
  452. */
  453. int requiredWidth = WidgetUtil.getRequiredWidth(captionText);
  454. if (requiredWidth > textWidth) {
  455. textWidth = requiredWidth;
  456. }
  457. }
  458. width += textWidth;
  459. }
  460. if (requiredFieldIndicator != null) {
  461. width += WidgetUtil.getRequiredWidth(requiredFieldIndicator);
  462. }
  463. if (errorIndicatorElement != null) {
  464. width += WidgetUtil.getRequiredWidth(errorIndicatorElement);
  465. }
  466. return width;
  467. }
  468. public int getHeight() {
  469. int height = 0;
  470. int h;
  471. if (icon != null) {
  472. h = WidgetUtil.getRequiredHeight(icon.getElement());
  473. if (h > height) {
  474. height = h;
  475. }
  476. }
  477. if (captionText != null) {
  478. h = WidgetUtil.getRequiredHeight(captionText);
  479. if (h > height) {
  480. height = h;
  481. }
  482. }
  483. if (requiredFieldIndicator != null) {
  484. h = WidgetUtil.getRequiredHeight(requiredFieldIndicator);
  485. if (h > height) {
  486. height = h;
  487. }
  488. }
  489. if (errorIndicatorElement != null) {
  490. h = WidgetUtil.getRequiredHeight(errorIndicatorElement);
  491. if (h > height) {
  492. height = h;
  493. }
  494. }
  495. return height;
  496. }
  497. public void setAlignment(String alignment) {
  498. getElement().getStyle().setProperty("textAlign", alignment);
  499. }
  500. public void setMaxWidth(int maxWidth) {
  501. this.maxWidth = maxWidth;
  502. getElement().getStyle().setWidth(maxWidth, Unit.PX);
  503. if (icon != null) {
  504. icon.getElement().getStyle().clearWidth();
  505. }
  506. if (captionText != null) {
  507. captionText.getStyle().clearWidth();
  508. }
  509. int requiredWidth = getRequiredWidth();
  510. /*
  511. * ApplicationConnection.getConsole().log( "Caption maxWidth: " +
  512. * maxWidth + ", requiredWidth: " + requiredWidth);
  513. */
  514. if (requiredWidth > maxWidth) {
  515. // Needs to truncate and clip
  516. int availableWidth = maxWidth;
  517. // DOM.setStyleAttribute(getElement(), "width", maxWidth + "px");
  518. if (requiredFieldIndicator != null) {
  519. availableWidth -= WidgetUtil
  520. .getRequiredWidth(requiredFieldIndicator);
  521. }
  522. if (errorIndicatorElement != null) {
  523. availableWidth -= WidgetUtil
  524. .getRequiredWidth(errorIndicatorElement);
  525. }
  526. if (availableWidth < 0) {
  527. availableWidth = 0;
  528. }
  529. if (icon != null) {
  530. int iconRequiredWidth = WidgetUtil
  531. .getRequiredWidth(icon.getElement());
  532. if (availableWidth > iconRequiredWidth) {
  533. availableWidth -= iconRequiredWidth;
  534. } else {
  535. icon.getElement().getStyle().setWidth(availableWidth,
  536. Unit.PX);
  537. availableWidth = 0;
  538. }
  539. }
  540. if (captionText != null) {
  541. int captionWidth = WidgetUtil.getRequiredWidth(captionText);
  542. if (availableWidth > captionWidth) {
  543. availableWidth -= captionWidth;
  544. } else {
  545. captionText.getStyle().setWidth(availableWidth, Unit.PX);
  546. availableWidth = 0;
  547. }
  548. }
  549. }
  550. }
  551. /**
  552. * Sets the tooltip that should be shown for the caption.
  553. *
  554. * @param tooltipInfo
  555. * The tooltip that should be shown or null if no tooltip should
  556. * be shown
  557. */
  558. public void setTooltipInfo(TooltipInfo tooltipInfo) {
  559. this.tooltipInfo = tooltipInfo;
  560. }
  561. /**
  562. * Returns the tooltip that should be shown for the caption.
  563. *
  564. * @return The tooltip to show or null if no tooltip should be shown
  565. */
  566. public TooltipInfo getTooltipInfo() {
  567. return tooltipInfo;
  568. }
  569. protected com.google.gwt.user.client.Element getTextElement() {
  570. return DOM.asOld(captionText);
  571. }
  572. public static String getCaptionOwnerPid(Element e) {
  573. return getOwnerPid(e);
  574. }
  575. private static native void setOwnerPid(Element el, String pid)
  576. /*-{
  577. el.vOwnerPid = pid;
  578. }-*/;
  579. public static native String getOwnerPid(Element el)
  580. /*-{
  581. return el.vOwnerPid;
  582. }-*/;
  583. /**
  584. * Sets whether the caption is rendered as HTML.
  585. * <p>
  586. * Default is false
  587. *
  588. * @param captionAsHtml
  589. * true if the captions are rendered as HTML, false if rendered
  590. * as plain text
  591. */
  592. public void setCaptionAsHtml(boolean captionAsHtml) {
  593. this.captionAsHtml = captionAsHtml;
  594. }
  595. /**
  596. * Checks whether captions are rendered as HTML.
  597. * <p>
  598. * Default is false
  599. *
  600. * @return true if the captions are rendered as HTML, false if rendered as
  601. * plain text
  602. */
  603. public boolean isCaptionAsHtml() {
  604. return captionAsHtml;
  605. }
  606. /**
  607. * Sets the text of the given caption element to the caption found in the
  608. * state.
  609. * <p>
  610. * Uses {@link AbstractComponentState#captionAsHtml} to determine whether to
  611. * set the caption as html or plain text
  612. *
  613. * @since 7.4
  614. * @param captionElement
  615. * the target element
  616. * @param state
  617. * the state from which to read the caption text and mode
  618. */
  619. public static void setCaptionText(Element captionElement,
  620. AbstractComponentState state) {
  621. if (state.captionAsHtml) {
  622. captionElement.setInnerHTML(state.caption);
  623. } else {
  624. captionElement.setInnerText(state.caption);
  625. }
  626. }
  627. /**
  628. * Sets the text of the given widget to the caption found in the state.
  629. * <p>
  630. * Uses {@link AbstractComponentState#captionAsHtml} to determine whether to
  631. * set the caption as html or plain text
  632. *
  633. * @since 7.4
  634. * @param widget
  635. * the target widget
  636. * @param state
  637. * the state from which to read the caption text and mode
  638. */
  639. public static void setCaptionText(HasHTML widget,
  640. AbstractComponentState state) {
  641. if (state.captionAsHtml) {
  642. widget.setHTML(state.caption);
  643. } else {
  644. widget.setText(state.caption);
  645. }
  646. }
  647. private static Logger getLogger() {
  648. return Logger.getLogger(VCaption.class.getName());
  649. }
  650. @Override
  651. public Element getErrorIndicatorElement() {
  652. return errorIndicatorElement;
  653. }
  654. @Override
  655. public void setErrorIndicatorElementVisible(boolean visible) {
  656. if (visible) {
  657. if (errorIndicatorElement == null) {
  658. errorIndicatorElement = ErrorUtil.createErrorIndicatorElement();
  659. DOM.insertChild(getElement(), errorIndicatorElement,
  660. getInsertPosition(InsertPosition.ERROR));
  661. }
  662. } else if (errorIndicatorElement != null) {
  663. getElement().removeChild(errorIndicatorElement);
  664. errorIndicatorElement = null;
  665. }
  666. }
  667. }