From 649dba410d825c8a350aeda9a44a591197ec4bc8 Mon Sep 17 00:00:00 2001 From: Sami Ekblad Date: Fri, 22 Jul 2016 19:31:44 +0300 Subject: [PATCH] BoV: Updated selection components to Vaadin 8. Change-Id: Idb4fff857bcdf9d33ecb8d4fd3062ffea96d5391 --- .../components/components-selection.asciidoc | 430 +++++++----------- 1 file changed, 154 insertions(+), 276 deletions(-) diff --git a/documentation/components/components-selection.asciidoc b/documentation/components/components-selection.asciidoc index 0dc65f4f19..1b62744786 100644 --- a/documentation/components/components-selection.asciidoc +++ b/documentation/components/components-selection.asciidoc @@ -36,181 +36,103 @@ They also inherit [classname]#AbstractSelect#. [[components.selection.databinding]] == Binding Selection Components to Data -The selection components are strongly coupled with the Vaadin Data Model, -described in +The selection components typically bound to list of items obtained from backend system. +You can give the the list of items in the constructor or set it set +[methodname]#setItems()#. Read more in <>. The selectable items in all selection components are -objects that implement the [classname]#Item# interface. The items are contained -in a [classname]#Container#. - -All selection components are containers themselves and simply forward all -container operations to the underlying container data source. You can give the -container in the constructor or set it set -[methodname]#setContainerDataSource()#. This is further described in -<>. - - -[source, java] ----- -// Have a container data source of some kind -IndexedContainer container = new IndexedContainer(); -container.addContainerProperty("name", String.class, null); -... - -// Create a selection component bound to the container -OptionGroup group = new OptionGroup("My Select", container); ----- - -If you do not bind a selection component to a container data source, a default -container is used. It is usually either an [classname]#IndexedContainer# or a -[classname]#HierarchicalContainer#. - -The current selection of a selection component is bound to the -[classname]#Property# interface, so you can get the current selection as the -value of the selection component. Also selection changes are handled as value -change events, as is described later. +Components to Data">>. +You can get the current selection as the +value of the selection component using [methodname]#getSelected# defined in +[interfacename]#Select# interface. Also selection changes are handled as +selection change events, as is described later. [[components.selection.adding]] == Adding New Items -New items are added with the [methodname]#addItem()# method defined in the -[classname]#Container# interface, described in -<>. - - -[source, java] ----- -// Create a selection component -ComboBox select = new ComboBox("My ComboBox"); - -// Add items with given item IDs -select.addItem("Mercury"); -select.addItem("Venus"); -select.addItem("Earth"); ----- - -The [methodname]#addItem()# method creates an empty [classname]#Item#, which is -identified by its __item identifier__ (IID) object, given as the parameter. This -item ID is by default used also as the caption of the item, as described in more -detail later. - -We emphasize that [methodname]#addItem()# is a factory method that __takes an -item ID, not the actual item__ as the parameter - the item is returned by the -method. The item is of a type that is specific to the container and has itself -little relevance for most selection components, as the properties of an item may -not be used in any way (except in [classname]#Table#), only the item ID. - -The item identifier is typically a string, in which case it can be used as the -caption, but can be any object type. We could as well have given integers for -the item identifiers and set the captions explicitly with -[methodname]#setItemCaption()#. You could also add an item with the -parameterless [methodname]#addItem()#, which returns an automatically generated -item ID. - +New items are added with the [methodname]#addItems()# method. [source, java] ---- // Create a selection component -ComboBox select = new ComboBox("My Select"); +ComboBox select = new ComboBox<>("Select a planet"); -// Add an item with a generated ID -Object itemId = select.addItem(); -select.setItemCaption(itemId, "The Sun"); - -// Select the item -select.setValue(itemId); +// Add items to select +select.setItems("Mercury","Venus","Earth"); ---- -Some container types may support passing the actual data object to the add -method. For example, you can add items to a [classname]#BeanItemContainer# with -[methodname]#addBean()#. Such implementations can use a separate item ID object, -or the data object itself as the item ID, as is done in [methodname]#addBean()#. -In the latter case you can not depend on the default way of acquiring the item -caption; see the description of the different caption modes later. - -The next section describes the different options for determining the item -captions. - - [[components.selection.captions]] == Item Captions -The displayed captions of items in a selection component can be set explicitly -with [methodname]#setItemCaption()# or determined from the item IDs or item -properties. The caption determination is defined with the __caption mode__, any -of the modes in the [classname]#AbstractSelect.ItemCaptionMode# enum, which you -can set with [methodname]#setItemCaptionMode()#. The default mode is -[parameter]#EXPLICIT_DEFAULTS_ID#, which uses the item identifiers for the -captions, unless given explicitly. - -In addition to a caption, an item can have an icon. The icon is set with -[methodname]#setItemIcon()#. - -The caption modes defined in [classname]#ItemCaptionMode# are the following: - -EXPLICIT_DEFAULTS_ID:: This is the default caption mode and its flexibility allows using it in most -cases. By default, the item identifier will be used as the caption. The -identifier object does not necessarily have to be a string; the caption is -retrieved with [methodname]#toString()# method. If the caption is specified -explicitly with [methodname]#setItemCaption()#, it overrides the item -identifier. +The items are typically a strings, in which case they can be used as the +caption, but can be any object type. We could as well have given Planet instances +for the items and use captions generated based on them +[methodname]#setItemCaptionProvider()# method. -+ [source, java] ---- +// List of Planet objects +List planets = new ArrayList<>(); +planets.add(new Planet("Mercury")); +planets.add(new Planet("Venus")); +planets.add(new Planet("Earth")); + // Create a selection component -ComboBox select = new ComboBox("Moons of Mars"); -select.setItemCaptionMode( - ItemCaptionMode.EXPLICIT_DEFAULTS_ID); +ComboBox select = new ComboBox<>("My Select"); -// The given item ID is also used as the caption -select.addItem(new Integer(1)); +// Add an items to the ComboBox +select.setItems(planets); -// Set item caption for this item explicitly -select.addItem(2); // same as "new Integer(2)" -select.setItemCaption(2, "Deimos"); +select.setItemCaptionProvider(planet -> planet.getName()); +// or even select.setItemCaptionProvider(Planet::getName); + +// Select the first +select.select(planets.get(0)); ---- -EXPLICIT:: Captions must be explicitly specified with [methodname]#setItemCaption()#. If -they are not, the caption will be empty. Such items with empty captions will -nevertheless be displayed in the selection component as empty items. If they -have an icon, they will be visible. -ICON_ONLY:: Only icons are shown, captions are hidden. +In addition to a caption, an item can have an icon. The icon is set with +[methodname]#setItemIconProvider()#. -ID:: String representation of the item identifier object is used as caption. This is -useful when the identifier is a string, and also when the identifier is an -complex object that has a string representation. For example: +Typical use cases for captions are: + +Using the items as the caption: the caption is +retrieved with [methodname]#toString()# method from the item. This is useful +for simple objects like String or Integers, but also for objects that have +human readable output for [methodname]#toString()# . + [source, java] ---- -ComboBox select = new ComboBox("Inner Planets"); -select.setItemCaptionMode(ItemCaptionMode.ID); +ComboBox select = new ComboBox<>("Inner Planets"); // A class that implements toString() -class PlanetId extends Object - implements Serializable { +class Planet implements Serializable { String planetName; - PlanetId (String name) { + Planet(String name) { planetName = name; } + public String toString () { return "The Planet " + planetName; } } -// Use such objects as item identifiers -String planets[] = {"Mercury", "Venus", - "Earth", "Mars"}; -for (int i=0; i planets = new ArrayList<>(); +planets.add(new Planet("Mercury")); +planets.add(new Planet("Venus")); +planets.add(new Planet("Earth")); + +select.addItems(planets); ---- +Using a field of a item as caption: the caption is retrieved using the +[interfacename]#ItemCaptionProvider# typically given as Java 8 lambda: + + + INDEX:: Index number of item is used as caption. This caption mode is applicable only to data sources that implement the [interfacename]#Container.Indexed# interface. @@ -238,91 +160,81 @@ a property of the bean as the caption. + [source, java] ---- -/** A bean with a "name" property. */ -public class Planet implements Serializable { - int id; - String name; - - public Planet(int id, String name) { - this.id = id; - this.name = name; +// A class that implements toString() +class Planet implements Serializable { + Integer id; + String planetName; + + Planet(Integer id, String name) { + this.id = id + this.planetName = name; + } + + public String toString () { + return "The Planet " + planetName; + } + + public Integer getId () { + return id; + } + + + public String getName () { + return planetName; } - ... setters and getters ... } -public void captionproperty( - VerticalLayout layout) { - // Have a bean container to put the beans in - BeanItemContainer container = - new BeanItemContainer( - Planet.class); - - // Put some example data in it - container.addItem( - new Planet(1, "Mercury")); - container.addItem(new Planet(2, "Venus")); - container.addItem(new Planet(3, "Earth")); - container.addItem(new Planet(4, "Mars")); - - // Create a selection component bound - // to the container - ComboBox select = new ComboBox("Planets", - container); - - // Set the caption mode to read the - // caption directly from the 'name' - // property of the bean - select.setItemCaptionMode( - ItemCaptionMode.PROPERTY); - select.setItemCaptionPropertyId("name"); - - ... +// Put some example data +List planets = new ArrayList<>(); +planets.add(new Planet(1, "Mercury")); +planets.add(new Planet(2, "Venus")); +planets.add(new Planet(3, "Earth")); +planets.add(new Planet(4, "Mars")); + +// Create a selection component +ComboBox select = new ComboBox<>("Planets"); + +// Set the caption provider to read the +// caption directly from the 'name' +// property of the bean +select.setItemCaptionProvider(Planet::getName); ---- [[components.selection.getset]] == Getting and Setting Selection -A selection component provides the current selection as the property of the -component (with the [classname]#Property# interface). The property value is an -item identifier object that identifies the selected item. You can get the -identifier with [methodname]#getValue()# of the [classname]#Property# interface. +You can get the item with [methodname]#getSelected()# of the +[classname]#Select# interface that returns collection of selected items. +You can select an item with the corresponding [methodname]#select()# method. -You can select an item with the corresponding [methodname]#setValue()# method. -In multiselect mode, the property will be an unmodifiable set of item -identifiers. If no item is selected, the property will be [parameter]#null# in -single selection mode or an empty collection in multiselect mode. +In multiselect mode, the [methodname]#getSelected()# returns an unmodifiable +set of items. If no item is selected, the select will be an empty collection. The [classname]#ComboBox# and [classname]#NativeSelect# will show empty -selection when no actual item is selected. This is the __null selection item -identifier__. You can set an alternative ID with -[methodname]#setNullSelectionItemId()#. Setting the alternative null ID is -merely a visual text; the [methodname]#getValue()# will still return -[parameter]#null# value if no item is selected, or an empty set in multiselect -mode. +selection when no actual item is selected. [[components.selection.valuechange]] == Handling Selection Changes -The item identifier of the currently selected item will be set as the property -of the selection component. You can access it with the [methodname]#getValue()# -method of the [classname]#Property# interface of the component. Also, when -handling selection changes with a [classname]#Property.ValueChangeListener#, the -[classname]#ValueChangeEvent# will have the selected item as the property of the -event, accessible with the [methodname]#getProperty()# method. +You can access currently selected item with the [methodname]#getSelected()# or +[methodname]#getFirstSelected()# method of the component. Also, when +handling selection changes with a +[classname]#SelectionChangeListener#, the +[classname]#SelectionChange# will have the selected items of the event. [source, java] ---- // Create a selection component with some items -ComboBox select = new ComboBox("My Select"); -select.addItems("Io", "Europa", "Ganymedes", "Callisto"); +ComboBox select = new ComboBox<>("My Select"); +select.setItems("Io", "Europa", "Ganymedes", "Callisto"); // Handle selection change -select.addValueChangeListener(event -> // Java 8 +select.addSelectionChangeListener(event -> layout.addComponent(new Label("Selected " + - event.getProperty().getValue()))); + event.getSelected()))); ---- The result of user interaction is shown in @@ -336,146 +248,112 @@ image::img/select-selected1.png[width=30%, scaledwidth=40%] [[components.selection.newitems]] == Allowing Adding New Items -Some selection components can allow the user to add new items. Currently, only -[classname]#ComboBox# allows it, when the user types in a value and presses -kbd:[Enter]. You need to enable the mode with [methodname]#setNewItemsAllowed(true)#. -Setting the component also in immediate mode may be necessary, as otherwise the -item would not be added immediately when the user interacts with the component, -but after some other component causes a server -request. -// TODO This could be a bug +[classname]#ComboBox# allows the user to add new items, when the user types +in a value and presses kbd:[Enter]. You need to enable this with +[methodname]#setNewItemHandler()#. -[source, java] ----- -myselect.setNewItemsAllowed(true); -myselect.setImmediate(true); ----- - -The user interface for adding new items depends on the selection component. The -regular [classname]#ComboBox# component allows you to simply type the new item -in the combo box and hit kbd:[Enter] to add it. - -Adding new items is not possible if the selection component is read-only or is -bound to a [classname]#Container# that does not allow adding new items. An +Adding new items is not possible if the selection component is read-only. An attempt to do so may result in an exception. [[components.selection.newitems.handling]] === Handling New Items Adding new items is handled by a [interfacename]#NewItemHandler#, which gets the -item caption string as parameter for the [methodname]#addNewItem()# method. The -default implementation, [classname]#DefaultNewItemHandler#, checks for read-only -state, adds the item using the entered caption as the item ID, and if the -selection component gets the captions from a property, copies the caption to -that property. It also selects the item. The default implementation may not be -suitable for all container types, in which case you need to define a custom -handler. For example, a [classname]#BeanItemContainer# expects the items to have -the bean object itself as the ID, not a string. +item caption string as parameter for the [methodname]#addNewItem()# method. ifdef::web[] [source, java] ---- -// Have a bean container to put the beans in -final BeanItemContainer container = - new BeanItemContainer(Planet.class); +// List of planets +List planets = new ArrayList<>(); +planets.add(new Planet(1, "Mercury")); +planets.add(new Planet(2, "Venus")); +planets.add(new Planet(3, "Earth")); +planets.add(new Planet(4, "Mars")); -// Put some example data in it -container.addItem(new Planet(1, "Mercury")); -container.addItem(new Planet(2, "Venus")); -container.addItem(new Planet(3, "Earth")); -container.addItem(new Planet(4, "Mars")); - -final ComboBox select = - new ComboBox("Select or Add a Planet", container); -select.setNullSelectionAllowed(false); +ComboBox select = + new ComboBox<>("Select or Add a Planet"); +select.setItems(planets); // Use the name property for item captions -select.setItemCaptionPropertyId("name"); +select.setItemCaptionProvider(Planet::getName); -// Allow adding new items -select.setNewItemsAllowed(true); -select.setImmediate(true); +// Allow adding new items and add +// handling for new items +select.setNewItemHandler(inputString -> { -// Custom handling for new items -select.setNewItemHandler(new NewItemHandler() { - @Override - public void addNewItem(String newItemCaption) { - // Create a new bean - can't set all properties - Planet newPlanet = new Planet(0, newItemCaption); - container.addBean(newPlanet); + // Create a new bean - can't set all properties + Planet newPlanet = new Planet(0, inputString); + planets.add(newPlanet); - // Remember to set the selection to the new item - select.select(newPlanet); + // Update combobox content + select.setItems(planets); - Notification.show("Added new planet called " + - newItemCaption); - } + // Remember to set the selection to the new item + select.select(newPlanet); + + Notification.show("Added new planet called " + + inputString); }); ---- See the http://demo.vaadin.com/book-examples-vaadin7/book#component.select.combobox.newitemhandler[on-line example, window="_blank"]. endif::web[] - [[components.selection.multiple]] == Multiple Selection Some selection components, such as [classname]#OptionGroup# and [classname]#ListSelect# support a multiple selection mode, which you can enable -with [methodname]#setMultiSelect()#. For [classname]#TwinColSelect#, which is -especially intended for multiple selection, it is enabled by default. +with [methodname]#setSelectionMode(SelectionMode.MULTI)#. +For [classname]#TwinColSelect#, which is especially intended for +multiple selection, it is enabled by default. [source, java] ---- -myselect.setMultiSelect(true); +myselect.setSelectionMode(SelectionMode.MULTI); ---- -As in single selection mode, the property value of the component indicates the -selection. In multiple selection mode, however, the property value is a -[classname]#Collection# of the item IDs of the currently selected items. You can -get and set the property with the [methodname]#getValue()# and -[methodname]#setValue()# methods as usual. +In multiple selection mode the [interfacename]#Select# value is a +[classname]#Collection# of the items of the currently selected items. +You can get and set the selection with the [methodname]#getSelected()# and +[methodname]#setSelected()# methods as usual. -A change in the selection will trigger a [classname]#ValueChangeEvent#, which -you can handle with a [classname]#Propery.ValueChangeListener#. As usual, you -should use [methodname]#setImmediate(true)# to trigger the event immediately -when the user changes the selection. The following example shows how to handle -selection changes with a listener. +A change in the selection will trigger a [classname]#SelectionChange#, which +you can handle with a [classname]#SelectionChangeListener#. The +following example shows how to handle selection changes with a listener. [source, java] ---- // A selection component with some items -ListSelect select = new ListSelect("My Selection"); -select.addItems("Mercury", "Venus", "Earth", +ListSelect select = new ListSelect<>("My Selection"); +select.setItems("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"); // Multiple selection mode -select.setMultiSelect(true); +select.setSelectionMode(SelectionMode.MULTI); // Feedback on value changes -select.addValueChangeListener( - new Property.ValueChangeListener() { - public void valueChange(ValueChangeEvent event) { +select.addSelectionChangeListener(event -> { // Some feedback layout.addComponent(new Label("Selected: " + - event.getProperty().getValue().toString())); + event.getSelected())); } }); -select.setImmediate(true); + ---- [[components.selection.item-icons]] == Item Icons -You can set an icon for each item with [methodname]#setItemIcon()#, or define an -item property that provides the icon resource with -[methodname]#setItemIconPropertyId()#, in a fashion similar to captions. Notice, -however, that icons are not supported in [classname]#NativeSelect#, -[classname]#TwinColSelect#, and some other selection components and modes. This -is because HTML does not support images inside the native [literal]#++select++# +You can set an icon for each item with [methodname]#setItemIconProvider()#, +in a fashion similar to captions. Notice, however, that icons are not +supported in [classname]#NativeSelect#, [classname]#TwinColSelect#, and +some other selection components and modes. This is because HTML does not +support images inside the native [literal]#++select++# elements. Icons are also not really visually applicable. -- 2.39.5