diff options
author | elmot <elmot@vaadin.com> | 2016-09-12 17:58:38 +0300 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2016-09-13 18:06:18 +0000 |
commit | 37e488d86b0bc59bf085a64eda3e258a01c496f0 (patch) | |
tree | a287284353b4d2c7068c0126ef773c56e0d8700e /client | |
parent | d0435d5f02f93e3f5123ae54216d0062054cbe90 (diff) | |
download | vaadin-framework-37e488d86b0bc59bf085a64eda3e258a01c496f0.tar.gz vaadin-framework-37e488d86b0bc59bf085a64eda3e258a01c496f0.zip |
Create a CheckBoxGroup that replaces the multi select case of OptionGroup
Change-Id: I250c60741bc65443b66498a8d0b17541edb77bf1
Diffstat (limited to 'client')
3 files changed, 312 insertions, 0 deletions
diff --git a/client/src/main/java/com/vaadin/client/ui/VCheckBoxGroup.java b/client/src/main/java/com/vaadin/client/ui/VCheckBoxGroup.java new file mode 100644 index 0000000000..3b6c73950c --- /dev/null +++ b/client/src/main/java/com/vaadin/client/ui/VCheckBoxGroup.java @@ -0,0 +1,223 @@ +/* + * 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 com.google.gwt.aria.client.Roles; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +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.FocusWidget; +import com.google.gwt.user.client.ui.Focusable; +import com.google.gwt.user.client.ui.HasEnabled; +import com.google.gwt.user.client.ui.Panel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.WidgetUtil; +import com.vaadin.shared.Registration; +import com.vaadin.shared.ui.optiongroup.CheckBoxGroupConstants; +import elemental.json.JsonObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import static com.vaadin.shared.ui.optiongroup.CheckBoxGroupConstants.JSONKEY_ITEM_DISABLED; + +/** + * The client-side widget for the {@code CheckBoxGroup} component. + * + * @author Vaadin Ltd. + * @since 8.0 + */ +public class VCheckBoxGroup extends Composite + implements Field, ClickHandler, ChangeHandler, + com.vaadin.client.Focusable, HasEnabled { + + public static final String CLASSNAME = "v-select-optiongroup"; + public static final String CLASSNAME_OPTION = "v-select-option"; + + private final Map<VCheckBox, JsonObject> optionsToItems; + + /** + * For internal use only. May be removed or replaced in the future. + */ + public ApplicationConnection client; + /** + * For internal use only. May be removed or replaced in the future. + */ + public JsonObject selected; //TODO replace with SelectionModel + /** + * Widget holding the different options (e.g. ListBox or Panel for radio + * buttons) (optional, fallbacks to container Panel) + * <p> + * For internal use only. May be removed or replaced in the future. + */ + public Panel optionsContainer; + + private boolean htmlContentAllowed = false; + + private boolean enabled; + private boolean readonly; + private List<Consumer<JsonObject>> selectionChangeListeners; + + public VCheckBoxGroup() { + optionsContainer = new FlowPanel(); + initWidget(this.optionsContainer); + optionsContainer.setStyleName(CLASSNAME); + optionsToItems = new HashMap<>(); + selectionChangeListeners = new ArrayList<>(); + } + + /* + * Build all the options + */ + public void buildOptions(List<JsonObject> items) { + /* + * In order to retain focus, we need to update values rather than + * recreate panel from scratch (#10451). However, the panel will be + * rebuilt (losing focus) if number of elements or their order is + * changed. + */ + + Roles.getRadiogroupRole().set(getElement()); + optionsContainer.clear(); + for (JsonObject item : items) { + String itemHtml = + item.getString(CheckBoxGroupConstants.JSONKEY_ITEM_VALUE); + if (!isHtmlContentAllowed()) { + itemHtml = WidgetUtil.escapeHTML(itemHtml); + } + VCheckBox checkBox = new VCheckBox(); + + String iconUrl = + item.getString(CheckBoxGroupConstants.JSONKEY_ITEM_ICON); + if (iconUrl != null && iconUrl.length() != 0) { + checkBox.icon = client.getIcon(iconUrl); + } + + checkBox.addStyleName(CLASSNAME_OPTION); + checkBox.addClickHandler(this); + checkBox.setHTML(itemHtml); + checkBox.setValue(true);//TODO selection model here + boolean optionEnabled = !item.getBoolean(JSONKEY_ITEM_DISABLED); + boolean enabled = optionEnabled && !isReadonly() && isEnabled(); + checkBox.setEnabled(enabled); + + optionsContainer.add(checkBox); + optionsToItems.put(checkBox, item); + } + } + + @Override + public void onClick(ClickEvent event) { + if (event.getSource() instanceof VCheckBox) { + VCheckBox source = (VCheckBox) event.getSource(); + if (!source.isEnabled()) { + // Click events on the text are received even though the + // checkbox is disabled + return; + } + + final boolean selected = source.getValue(); + JsonObject item = optionsToItems.get(source); //TODO SelectionModel + if (selected) { + this.selected = item; + } else { + this.selected = null; + } + } + } + + public void setTabIndex(int tabIndex) { + for (Widget anOptionsContainer : optionsContainer) { + FocusWidget widget = (FocusWidget) anOptionsContainer; + widget.setTabIndex(tabIndex); + } + } + + protected void updateEnabledState() { + boolean optionGroupEnabled = isEnabled() && !isReadonly(); + // sets options enabled according to the widget's enabled, + // readonly and each options own enabled + for (Map.Entry<VCheckBox, JsonObject> entry : optionsToItems + .entrySet()) { + VCheckBox checkBox = entry.getKey(); + JsonObject value = entry.getValue(); + Boolean isOptionEnabled = !value.getBoolean( + CheckBoxGroupConstants.JSONKEY_ITEM_DISABLED); + checkBox.setEnabled(optionGroupEnabled && isOptionEnabled); + } + } + + @Override + public void focus() { + Iterator<Widget> iterator = optionsContainer.iterator(); + if (iterator.hasNext()) { + ((Focusable) iterator.next()).setFocus(true); + } + } + + public boolean isHtmlContentAllowed() { + return htmlContentAllowed; + } + + public void setHtmlContentAllowed(boolean htmlContentAllowed) { + this.htmlContentAllowed = htmlContentAllowed; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + public boolean isReadonly() { + return readonly; + } + + @Override + public void onChange(ChangeEvent event) { + //TODO selectionModel + } + + public void setReadonly(boolean readonly) { + if (this.readonly != readonly) { + this.readonly = readonly; + updateEnabledState(); + } + } + + @Override + public void setEnabled(boolean enabled) { + if (this.enabled != enabled) { + this.enabled = enabled; + updateEnabledState(); + } + } + + public Registration addNotifyHandler( + Consumer<JsonObject> selectionChanged) { + selectionChangeListeners.add(selectionChanged); + return (Registration) () -> selectionChangeListeners + .remove(selectionChanged); + } +} diff --git a/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java b/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java index 598280cf5c..3c36ffd4fe 100644 --- a/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java @@ -36,6 +36,12 @@ import com.vaadin.shared.ui.checkbox.CheckBoxServerRpc; import com.vaadin.shared.ui.checkbox.CheckBoxState; import com.vaadin.ui.CheckBox; +/** + * The client-side connector for the {@code CheckBoxGroup} component. + * + * @author Vaadin Ltd. + * @since 8.0 + */ @Connect(CheckBox.class) public class CheckBoxConnector extends AbstractFieldConnector implements ClickHandler { diff --git a/client/src/main/java/com/vaadin/client/ui/optiongroup/CheckBoxGroupConnector.java b/client/src/main/java/com/vaadin/client/ui/optiongroup/CheckBoxGroupConnector.java new file mode 100644 index 0000000000..dbd531382d --- /dev/null +++ b/client/src/main/java/com/vaadin/client/ui/optiongroup/CheckBoxGroupConnector.java @@ -0,0 +1,83 @@ +/* + * 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.optiongroup; + +import java.util.ArrayList; +import java.util.List; + +import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.connectors.AbstractListingConnector; +import com.vaadin.client.data.DataSource; +import com.vaadin.client.ui.VCheckBoxGroup; +import com.vaadin.shared.Registration; +import com.vaadin.shared.data.selection.SelectionModel; +import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.optiongroup.CheckBoxGroupState; +import com.vaadin.ui.CheckBoxGroup; + +import elemental.json.JsonObject; + +@Connect(CheckBoxGroup.class) +public class CheckBoxGroupConnector + extends AbstractListingConnector<SelectionModel.Multi<JsonObject>> { + + private Registration selectionChangeRegistration; + + @Override + protected void init() { + super.init(); + selectionChangeRegistration = + getWidget().addNotifyHandler(this::selectionChanged); + } + + private void selectionChanged(JsonObject newSelection) { + getSelectionModel().select(newSelection); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + getWidget().setTabIndex(getState().tabIndex); + getWidget().setReadonly(isReadOnly()); + getWidget().client = getConnection(); + } + + @Override + public void setDataSource(DataSource<JsonObject> dataSource) { + dataSource.addDataChangeHandler(range -> updateOptionGroup()); + super.setDataSource(dataSource); + } + + private void updateOptionGroup() { + List<JsonObject> items = new ArrayList<>(getDataSource().size()); + for (int i = 0; i < getDataSource().size(); ++i) { + JsonObject item = getDataSource().getRow(i); + items.add(item); + } + getWidget().buildOptions(items); + } + + @Override + public VCheckBoxGroup getWidget() { + return (VCheckBoxGroup) super.getWidget(); + } + + @Override + public CheckBoxGroupState getState() { + return (CheckBoxGroupState) super.getState(); + } +} |