Skip to content

Commit

Permalink
ListSelect with new data binding API
Browse files Browse the repository at this point in the history
No single select mode for list select.
Based on AbstractMultiSelect.
Removes feature for adding new items.

Change-Id: I9a92aaf1f3d338a3b05c3aa4048f9db496dacd1d
  • Loading branch information
pleku authored and Denis Anisimov committed Sep 28, 2016
1 parent 96119ab commit c4b17ca
Show file tree
Hide file tree
Showing 15 changed files with 963 additions and 322 deletions.
263 changes: 263 additions & 0 deletions client/src/main/java/com/vaadin/client/ui/VListSelect.java
Original file line number Diff line number Diff line change
@@ -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<BiConsumer<Set<String>, Set<String>>> 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<String>, Set<String>> 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<JsonObject> 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<String> newSelectedItemKeys = new HashSet<>();
final Set<String> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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());
}

}
Loading

0 comments on commit c4b17ca

Please sign in to comment.