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 8.0KB

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