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.

VRadioButtonGroup.java 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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;
  17. import java.util.ArrayList;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.function.Consumer;
  22. import com.google.gwt.aria.client.Roles;
  23. import com.google.gwt.event.dom.client.ClickEvent;
  24. import com.google.gwt.event.dom.client.ClickHandler;
  25. import com.google.gwt.user.client.DOM;
  26. import com.google.gwt.user.client.ui.FocusWidget;
  27. import com.google.gwt.user.client.ui.HasEnabled;
  28. import com.google.gwt.user.client.ui.RadioButton;
  29. import com.google.gwt.user.client.ui.Widget;
  30. import com.vaadin.client.ApplicationConnection;
  31. import com.vaadin.client.BrowserInfo;
  32. import com.vaadin.client.WidgetUtil;
  33. import com.vaadin.client.widgets.FocusableFlowPanelComposite;
  34. import com.vaadin.shared.Registration;
  35. import com.vaadin.shared.data.DataCommunicatorConstants;
  36. import com.vaadin.shared.ui.ListingJsonConstants;
  37. import elemental.json.JsonObject;
  38. /**
  39. * The client-side widget for the {@code RadioButtonGroup} component.
  40. *
  41. * @author Vaadin Ltd.
  42. * @since 8.0
  43. */
  44. public class VRadioButtonGroup extends FocusableFlowPanelComposite
  45. implements Field, ClickHandler, HasEnabled {
  46. public static final String CLASSNAME = "v-select-optiongroup";
  47. public static final String CLASSNAME_OPTION = "v-select-option";
  48. private final Map<RadioButton, JsonObject> optionsToItems;
  49. private final Map<String, RadioButton> keyToOptions;
  50. /**
  51. * For internal use only. May be removed or replaced in the future.
  52. */
  53. public ApplicationConnection client;
  54. private boolean htmlContentAllowed = false;
  55. private boolean enabled;
  56. private boolean readonly;
  57. private final String groupId;
  58. private List<Consumer<JsonObject>> selectionChangeListeners;
  59. public VRadioButtonGroup() {
  60. groupId = DOM.createUniqueId();
  61. getWidget().setStyleName(CLASSNAME);
  62. optionsToItems = new HashMap<>();
  63. keyToOptions = new HashMap<>();
  64. selectionChangeListeners = new ArrayList<>();
  65. }
  66. /*
  67. * Build all the options
  68. */
  69. public void buildOptions(List<JsonObject> items) {
  70. Roles.getRadiogroupRole().set(getElement());
  71. int i = 0;
  72. int widgetsToRemove = getWidget().getWidgetCount() - items.size();
  73. if (widgetsToRemove < 0) {
  74. widgetsToRemove = 0;
  75. }
  76. List<Widget> remove = new ArrayList<>(widgetsToRemove);
  77. for (Widget widget : getWidget()) {
  78. if (i < items.size()) {
  79. updateItem((RadioButton) widget, items.get(i), false);
  80. i++;
  81. } else {
  82. remove.add(widget);
  83. }
  84. }
  85. remove.stream().forEach(this::remove);
  86. while (i < items.size()) {
  87. updateItem(new RadioButton(groupId), items.get(i), true);
  88. i++;
  89. }
  90. }
  91. private void remove(Widget widget) {
  92. getWidget().remove(widget);
  93. JsonObject item = optionsToItems.remove(widget);
  94. if (item != null) {
  95. String key = item.getString(DataCommunicatorConstants.KEY);
  96. keyToOptions.remove(key);
  97. }
  98. }
  99. private void updateItem(RadioButton button, JsonObject item,
  100. boolean requireInitialization) {
  101. String itemHtml = item
  102. .getString(ListingJsonConstants.JSONKEY_ITEM_VALUE);
  103. if (!isHtmlContentAllowed()) {
  104. itemHtml = WidgetUtil.escapeHTML(itemHtml);
  105. }
  106. String iconUrl = item.getString(ListingJsonConstants.JSONKEY_ITEM_ICON);
  107. if (iconUrl != null && iconUrl.length() != 0) {
  108. Icon icon = client.getIcon(iconUrl);
  109. itemHtml = icon.getElement().getString() + itemHtml;
  110. }
  111. button.setHTML(itemHtml);
  112. button.setValue(
  113. item.getBoolean(ListingJsonConstants.JSONKEY_ITEM_SELECTED));
  114. boolean optionEnabled = !item
  115. .getBoolean(ListingJsonConstants.JSONKEY_ITEM_DISABLED);
  116. boolean enabled = optionEnabled && !isReadonly() && isEnabled();
  117. button.setEnabled(enabled);
  118. String key = item.getString(DataCommunicatorConstants.KEY);
  119. if (requireInitialization) {
  120. getWidget().add(button);
  121. button.setStyleName("v-radiobutton");
  122. button.addStyleName(CLASSNAME_OPTION);
  123. button.addClickHandler(this);
  124. }
  125. optionsToItems.put(button, item);
  126. keyToOptions.put(key, button);
  127. }
  128. @Override
  129. public void onClick(ClickEvent event) {
  130. if (event.getSource() instanceof RadioButton) {
  131. RadioButton source = (RadioButton) event.getSource();
  132. if (!source.isEnabled()) {
  133. // Click events on the text are received even though the
  134. // radiobutton is disabled
  135. return;
  136. }
  137. if (BrowserInfo.get().isWebkit()) {
  138. // Webkit does not focus non-text input elements on click
  139. // (#11854)
  140. source.setFocus(true);
  141. }
  142. JsonObject item = optionsToItems.get(source);
  143. assert item != null;
  144. new ArrayList<>(selectionChangeListeners)
  145. .forEach(listener -> listener.accept(item));
  146. }
  147. }
  148. public void setTabIndex(int tabIndex) {
  149. for (Widget anOptionsContainer : getWidget()) {
  150. FocusWidget widget = (FocusWidget) anOptionsContainer;
  151. widget.setTabIndex(tabIndex);
  152. }
  153. }
  154. protected void updateEnabledState() {
  155. boolean radioButtonEnabled = isEnabled() && !isReadonly();
  156. // sets options enabled according to the widget's enabled,
  157. // readonly and each options own enabled
  158. for (Map.Entry<RadioButton, JsonObject> entry : optionsToItems
  159. .entrySet()) {
  160. RadioButton radioButton = entry.getKey();
  161. JsonObject value = entry.getValue();
  162. Boolean isOptionEnabled = !value
  163. .getBoolean(ListingJsonConstants.JSONKEY_ITEM_DISABLED);
  164. radioButton.setEnabled(radioButtonEnabled && isOptionEnabled);
  165. }
  166. }
  167. public boolean isHtmlContentAllowed() {
  168. return htmlContentAllowed;
  169. }
  170. public void setHtmlContentAllowed(boolean htmlContentAllowed) {
  171. this.htmlContentAllowed = htmlContentAllowed;
  172. }
  173. @Override
  174. public boolean isEnabled() {
  175. return enabled;
  176. }
  177. public boolean isReadonly() {
  178. return readonly;
  179. }
  180. public void setReadonly(boolean readonly) {
  181. if (this.readonly != readonly) {
  182. this.readonly = readonly;
  183. updateEnabledState();
  184. }
  185. }
  186. @Override
  187. public void setEnabled(boolean enabled) {
  188. if (this.enabled != enabled) {
  189. this.enabled = enabled;
  190. updateEnabledState();
  191. }
  192. }
  193. public Registration addSelectionChangeHandler(
  194. Consumer<JsonObject> selectionChanged) {
  195. selectionChangeListeners.add(selectionChanged);
  196. return (Registration) () -> selectionChangeListeners
  197. .remove(selectionChanged);
  198. }
  199. public void selectItemKey(String selectedItemKey) {
  200. RadioButton radioButton = keyToOptions.get(selectedItemKey);
  201. if (radioButton != null) {// Items might not be loaded yet
  202. radioButton.setValue(true);
  203. }
  204. }
  205. }