From c4b17ca879c0bb51c7da390fcbd25c96b73486fb Mon Sep 17 00:00:00 2001 From: Pekka Hyvönen Date: Tue, 27 Sep 2016 12:26:15 +0300 Subject: ListSelect with new data binding API No single select mode for list select. Based on AbstractMultiSelect. Removes feature for adding new items. Change-Id: I9a92aaf1f3d338a3b05c3aa4048f9db496dacd1d --- .../java/com/vaadin/client/ui/VListSelect.java | 263 +++++++++++++++++++++ .../client/ui/listselect/ListSelectConnector.java | 54 +++++ 2 files changed, 317 insertions(+) create mode 100644 client/src/main/java/com/vaadin/client/ui/VListSelect.java create mode 100644 client/src/main/java/com/vaadin/client/ui/listselect/ListSelectConnector.java (limited to 'client/src') diff --git a/client/src/main/java/com/vaadin/client/ui/VListSelect.java b/client/src/main/java/com/vaadin/client/ui/VListSelect.java new file mode 100644 index 0000000000..185c593b83 --- /dev/null +++ b/client/src/main/java/com/vaadin/client/ui/VListSelect.java @@ -0,0 +1,263 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiConsumer; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.HasEnabled; +import com.google.gwt.user.client.ui.ListBox; +import com.vaadin.client.FastStringSet; +import com.vaadin.client.Focusable; +import com.vaadin.client.connectors.AbstractMultiSelectConnector.MultiSelectWidget; +import com.vaadin.shared.Registration; + +import elemental.json.JsonObject; + +/** + * A simple list select for selecting multiple items. + * + * @author Vaadin Ltd + */ +public class VListSelect extends Composite implements ClickHandler, Field, + Focusable, HasEnabled, MultiSelectWidget { + + private List, Set>> selectionChangeListeners = new ArrayList<>(); + + /** Container for select. Kept for DOM backwards compatibility. */ + protected final FlowPanel container; + /** The select component. */ + protected final ListBox select; + + private boolean enabled; + private boolean readOnly; + private FastStringSet selectedItemKeys = FastStringSet.create(); + + /** + * Constructs a simple ListSelect widget in multiselect mode. + */ + public VListSelect() { + container = new FlowPanel(); + initWidget(container); + + select = new ListBox(); + select.setMultipleSelect(true); + select.addClickHandler(this); + + container.add(select); + + updateEnabledState(); + } + + /** + * Sets the number of visible items for the list select. + * + * @param rows + * the number of items to show + * @see ListBox#setVisibleItemCount(int) + */ + public void setRows(int rows) { + if (select.getVisibleItemCount() != rows) { + select.setVisibleItemCount(rows); + } + } + + /** + * Returns the number of visible items for the list select. + * + * @return the number of items to show + * @see ListBox#setVisibleItemCount(int) + */ + public int getRows() { + return select.getVisibleItemCount(); + } + + @Override + public Registration addSelectionChangeListener( + BiConsumer, Set> listener) { + Objects.nonNull(listener); + selectionChangeListeners.add(listener); + return (Registration) () -> selectionChangeListeners.remove(listener); + } + + @Override + public void setStyleName(String style) { + super.setStyleName(style); + updateStyleNames(); + } + + @Override + public void setStylePrimaryName(String style) { + super.setStylePrimaryName(style); + updateStyleNames(); + } + + /** Update the style names for container & select. */ + protected void updateStyleNames() { + container.setStyleName(getStylePrimaryName()); + select.setStyleName(getStylePrimaryName() + "-select"); + } + + @Override + public void setItems(List items) { + selectedItemKeys = FastStringSet.create(); + for (int i = 0; i < items.size(); i++) { + final JsonObject item = items.get(i); + // reuse existing option if possible + final String key = MultiSelectWidget.getKey(item); + if (i < select.getItemCount()) { + select.setItemText(i, MultiSelectWidget.getCaption(item)); + select.setValue(i, key); + } else { + select.addItem(MultiSelectWidget.getCaption(item), key); + } + final boolean selected = MultiSelectWidget.isSelected(item); + select.setItemSelected(i, selected); + if (selected) { + selectedItemKeys.add(key); + } + } + + // remove extra + for (int i = select.getItemCount() - 1; i >= items.size(); i--) { + select.removeItem(i); + } + } + + /** + * Gets the currently selected item values. + * + * @return the currently selected item keys + */ + protected FastStringSet getSelectedItems() { + final FastStringSet selectedItemKeys = FastStringSet.create(); + for (int i = 0; i < select.getItemCount(); i++) { + if (select.isItemSelected(i)) { + selectedItemKeys.add(select.getValue(i)); + } + } + return selectedItemKeys; + } + + @Override + public void onClick(ClickEvent event) { + if (event.getSource() == select) { + // selection can change by adding and at the same time removing + // previous keys, or by just adding (e.g. when modifier keys are + // pressed) + final Set newSelectedItemKeys = new HashSet<>(); + final Set removedItemKeys = new HashSet<>(); + for (int i = 0; i < select.getItemCount(); i++) { + String key = select.getValue(i); + boolean selected = select.isItemSelected(i); + boolean wasSelected = selectedItemKeys.contains(key); + if (selected && !wasSelected) { + newSelectedItemKeys.add(key); + selectedItemKeys.add(key); + } else if (!selected && wasSelected) { + removedItemKeys.add(key); + selectedItemKeys.remove(key); + } + } + selectionChangeListeners.forEach( + l -> l.accept(newSelectedItemKeys, removedItemKeys)); + } + } + + @Override + public void setHeight(String height) { + select.setHeight(height); + super.setHeight(height); + } + + @Override + public void setWidth(String width) { + select.setWidth(width); + super.setWidth(width); + } + + /** + * Sets the tab index. + * + * @param tabIndex + * the tab index to set + */ + public void setTabIndex(int tabIndex) { + select.setTabIndex(tabIndex); + } + + /** + * Gets the tab index. + * + * @return the tab index + */ + public int getTabIndex() { + return select.getTabIndex(); + } + + /** + * Sets this select as read only, meaning selection cannot be changed. + * + * @param readOnly + * {@code true} for read only, {@code false} for not read only + */ + public void setReadOnly(boolean readOnly) { + if (this.readOnly != readOnly) { + this.readOnly = readOnly; + updateEnabledState(); + } + } + + /** + * Returns {@code true} if this select is in read only mode, {@code false} + * if not. + * + * @return {@code true} for read only, {@code false} for not read only + */ + public boolean isReadOnly() { + return readOnly; + } + + @Override + public void setEnabled(boolean enabled) { + if (this.enabled != enabled) { + this.enabled = enabled; + updateEnabledState(); + } + } + + @Override + public boolean isEnabled() { + return enabled; + } + + private void updateEnabledState() { + select.setEnabled(isEnabled() && !isReadOnly()); + } + + @Override + public void focus() { + select.setFocus(true); + } +} diff --git a/client/src/main/java/com/vaadin/client/ui/listselect/ListSelectConnector.java b/client/src/main/java/com/vaadin/client/ui/listselect/ListSelectConnector.java new file mode 100644 index 0000000000..3e20b115e0 --- /dev/null +++ b/client/src/main/java/com/vaadin/client/ui/listselect/ListSelectConnector.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.listselect; + +import com.vaadin.client.annotations.OnStateChange; +import com.vaadin.client.connectors.AbstractMultiSelectConnector; +import com.vaadin.client.ui.VListSelect; +import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.listselect.ListSelectState; +import com.vaadin.ui.ListSelect; + +/** + * Client side connector for {@link ListSelect} component. + * + * @author Vaadin Ltd + * + */ +@Connect(ListSelect.class) +public class ListSelectConnector extends AbstractMultiSelectConnector { + + @Override + public VListSelect getWidget() { + return (VListSelect) super.getWidget(); + } + + @Override + public MultiSelectWidget getMultiSelectWidget() { + return getWidget(); + } + + @Override + public ListSelectState getState() { + return (ListSelectState) super.getState(); + } + + @OnStateChange("readOnly") + void updateReadOnly() { + getWidget().setReadOnly(isReadOnly()); + } + +} -- cgit v1.2.3