Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

VListSelect.java 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Copyright 2000-2018 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.HashSet;
  19. import java.util.List;
  20. import java.util.Objects;
  21. import java.util.Set;
  22. import java.util.function.BiConsumer;
  23. import com.google.gwt.user.client.ui.Composite;
  24. import com.google.gwt.user.client.ui.FlowPanel;
  25. import com.google.gwt.user.client.ui.HasEnabled;
  26. import com.google.gwt.user.client.ui.ListBox;
  27. import com.vaadin.client.FastStringSet;
  28. import com.vaadin.client.Focusable;
  29. import com.vaadin.client.connectors.AbstractMultiSelectConnector.MultiSelectWidget;
  30. import com.vaadin.shared.Registration;
  31. import com.vaadin.shared.ui.listselect.ListSelectState;
  32. import elemental.json.JsonObject;
  33. /**
  34. * A simple list select for selecting multiple items.
  35. *
  36. * @author Vaadin Ltd
  37. */
  38. public class VListSelect extends Composite
  39. implements Field, Focusable, HasEnabled, MultiSelectWidget {
  40. private List<BiConsumer<Set<String>, Set<String>>> selectionChangeListeners = new ArrayList<>();
  41. /** Container for select. Kept for DOM backwards compatibility. */
  42. protected final FlowPanel container;
  43. /** The select component. */
  44. protected final ListBox select;
  45. private boolean enabled;
  46. private boolean readOnly;
  47. private FastStringSet selectedItemKeys = FastStringSet.create();
  48. /**
  49. * Constructs a simple ListSelect widget in multiselect mode.
  50. */
  51. public VListSelect() {
  52. container = new FlowPanel();
  53. initWidget(container);
  54. select = new ListBox();
  55. select.setMultipleSelect(true);
  56. // Add event handlers
  57. select.addClickHandler(
  58. clickEvent -> selectionEvent(clickEvent.getSource()));
  59. select.addChangeHandler(
  60. changeEvent -> selectionEvent(changeEvent.getSource()));
  61. container.add(select);
  62. updateEnabledState();
  63. setStylePrimaryName(ListSelectState.PRIMARY_STYLENAME);
  64. }
  65. @Override
  66. public void setStylePrimaryName(String style) {
  67. super.setStylePrimaryName(style);
  68. select.setStyleName(style + "-select");
  69. }
  70. /**
  71. * Sets the number of visible items for the list select.
  72. *
  73. * @param rows
  74. * the number of items to show
  75. * @see ListBox#setVisibleItemCount(int)
  76. */
  77. public void setRows(int rows) {
  78. if (select.getVisibleItemCount() != rows) {
  79. select.setVisibleItemCount(rows);
  80. }
  81. }
  82. /**
  83. * Returns the number of visible items for the list select.
  84. *
  85. * @return the number of items to show
  86. * @see ListBox#setVisibleItemCount(int)
  87. */
  88. public int getRows() {
  89. return select.getVisibleItemCount();
  90. }
  91. @Override
  92. public Registration addSelectionChangeListener(
  93. BiConsumer<Set<String>, Set<String>> listener) {
  94. Objects.nonNull(listener);
  95. selectionChangeListeners.add(listener);
  96. return (Registration) () -> selectionChangeListeners.remove(listener);
  97. }
  98. @Override
  99. public void setItems(List<JsonObject> items) {
  100. selectedItemKeys = FastStringSet.create();
  101. for (int i = 0; i < items.size(); i++) {
  102. final JsonObject item = items.get(i);
  103. // reuse existing option if possible
  104. String key = MultiSelectWidget.getKey(item);
  105. if (i < select.getItemCount()) {
  106. select.setItemText(i, MultiSelectWidget.getCaption(item));
  107. select.setValue(i, key);
  108. } else {
  109. select.addItem(MultiSelectWidget.getCaption(item), key);
  110. }
  111. final boolean selected = MultiSelectWidget.isSelected(item);
  112. // Check that the selection has changed before updating it because
  113. // IE11 causes problems on Windows 7 if we update without needing to
  114. if (selected != select.isItemSelected(i)) {
  115. select.setItemSelected(i, selected);
  116. }
  117. if (selected) {
  118. selectedItemKeys.add(key);
  119. }
  120. }
  121. // remove extra
  122. for (int i = select.getItemCount() - 1; i >= items.size(); i--) {
  123. select.removeItem(i);
  124. }
  125. }
  126. /**
  127. * Gets the currently selected item values.
  128. *
  129. * @return the currently selected item keys
  130. */
  131. protected FastStringSet getSelectedItems() {
  132. final FastStringSet selectedItemKeys = FastStringSet.create();
  133. for (int i = 0; i < select.getItemCount(); i++) {
  134. if (select.isItemSelected(i)) {
  135. String key = select.getValue(i);
  136. selectedItemKeys.add(key);
  137. }
  138. }
  139. return selectedItemKeys;
  140. }
  141. private void selectionEvent(Object source) {
  142. if (source == select) {
  143. // selection can change by adding and at the same time removing
  144. // previous keys, or by just adding (e.g. when modifier keys are
  145. // pressed)
  146. final Set<String> newSelectedItemKeys = new HashSet<>();
  147. final Set<String> removedItemKeys = new HashSet<>();
  148. for (int i = 0; i < select.getItemCount(); i++) {
  149. String key = select.getValue(i);
  150. boolean selected = select.isItemSelected(i);
  151. boolean wasSelected = selectedItemKeys.contains(key);
  152. if (selected && !wasSelected) {
  153. newSelectedItemKeys.add(key);
  154. selectedItemKeys.add(key);
  155. } else if (!selected && wasSelected) {
  156. removedItemKeys.add(key);
  157. selectedItemKeys.remove(key);
  158. }
  159. }
  160. selectionChangeListeners.forEach(
  161. l -> l.accept(newSelectedItemKeys, removedItemKeys));
  162. }
  163. }
  164. @Override
  165. public void setHeight(String height) {
  166. select.setHeight(height);
  167. super.setHeight(height);
  168. }
  169. @Override
  170. public void setWidth(String width) {
  171. select.setWidth(width);
  172. super.setWidth(width);
  173. }
  174. /**
  175. * Sets the tab index.
  176. *
  177. * @param tabIndex
  178. * the tab index to set
  179. */
  180. public void setTabIndex(int tabIndex) {
  181. select.setTabIndex(tabIndex);
  182. }
  183. /**
  184. * Gets the tab index.
  185. *
  186. * @return the tab index
  187. */
  188. public int getTabIndex() {
  189. return select.getTabIndex();
  190. }
  191. /**
  192. * Sets this select as read only, meaning selection cannot be changed.
  193. *
  194. * @param readOnly
  195. * {@code true} for read only, {@code false} for not read only
  196. */
  197. public void setReadOnly(boolean readOnly) {
  198. if (this.readOnly != readOnly) {
  199. this.readOnly = readOnly;
  200. updateEnabledState();
  201. }
  202. }
  203. /**
  204. * Returns {@code true} if this select is in read only mode, {@code false}
  205. * if not.
  206. *
  207. * @return {@code true} for read only, {@code false} for not read only
  208. */
  209. public boolean isReadOnly() {
  210. return readOnly;
  211. }
  212. @Override
  213. public void setEnabled(boolean enabled) {
  214. if (this.enabled != enabled) {
  215. this.enabled = enabled;
  216. updateEnabledState();
  217. }
  218. }
  219. @Override
  220. public boolean isEnabled() {
  221. return enabled;
  222. }
  223. private void updateEnabledState() {
  224. select.setEnabled(isEnabled() && !isReadOnly());
  225. }
  226. @Override
  227. public void focus() {
  228. select.setFocus(true);
  229. }
  230. }