@@ -12,7 +12,6 @@ ifdef::web[] | |||
image:{live-demo-image}[alt="Live Demo", link="http://demo.vaadin.com/sampler/#ui/interaction/button"] | |||
endif::web[] | |||
The [classname]#Button# component is normally used for initiating some action, | |||
such as finalizing input in forms. When the user clicks a button, a | |||
[classname]#Button.ClickEvent# is fired, which can be handled by adding a __click listener__ | |||
@@ -31,18 +30,9 @@ Button button = new Button("Do not press this button"); | |||
button.addClickListener(clickEvent -> | |||
Notification.show("Do not press this button again")); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.button.basic[on-line example, window="_blank"]. | |||
The listener can also be given in the constructor, which is often perhaps simpler. | |||
//// | |||
If you handle several buttons in the same listener, you can differentiate | |||
between them either by comparing the [classname]#Button# object reference | |||
returned by the [methodname]#getButton()# method of | |||
[classname]#Button.ClickEvent# to a kept reference. For a detailed description | |||
of these patterns together with some examples, please see | |||
<<dummy/../../../framework/architecture/architecture-events#architecture.events,"Events and Listeners">>. | |||
//// | |||
== CSS Style Rules | |||
@@ -34,9 +34,6 @@ checkbox2.setValue(true); | |||
checkbox1.addValueChangeListener(event -> | |||
checkbox2.setValue(! checkbox1.getValue())); | |||
checkbox2.addValueChangeListener(event -> | |||
checkbox1.setValue(! checkbox2.getValue())); | |||
---- | |||
The result is shown in <<figure.components.checkbox.basic>>. |
@@ -7,8 +7,6 @@ layout: page | |||
[[components.combobox]] | |||
= [classname]#ComboBox# | |||
*_This section has not yet been updated for Vaadin Framework 8_* | |||
ifdef::web[] | |||
[.sampler] | |||
image:{live-demo-image}[alt="Live Demo", link="http://demo.vaadin.com/sampler/#ui/data-input/multiple-value/combo-box"] | |||
@@ -28,7 +26,7 @@ image::img/combobox-basic.png[width=35%, scaledwidth=50%] | |||
== Filtered Selection | |||
[classname]#ComboBox# allows filtering the items available for selection in the | |||
drop-down list by the text entered in the input box. | |||
drop-down list by the text entered in the input box. To apply custom filtering, the [methodname]#setItems(CaptionFilter, Collection)# can be used. When using a [classname]#DataProvider#, the filtering is delegated to it. | |||
[[figure.components.combobox.filter]] | |||
.Filtered Selection in [classname]#ComboBox# | |||
@@ -41,32 +39,6 @@ on the keyboard. The shown items are loaded from the server as needed, so the | |||
number of items held in the component can be quite large. The number of matching | |||
items is displayed by the drop-down list. | |||
Filtering is enabled by setting a __filtering mode__ with | |||
[methodname]#setFilteringMode()#. | |||
[source, java] | |||
---- | |||
cb.setFilteringMode(FilteringMode.CONTAINS); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.select.combobox.filtering[on-line example, window="_blank"]. | |||
The modes defined in the [classname]#FilteringMode# enum are as follows: | |||
[parameter]#CONTAINS#:: Matches any item that contains the string given in the text field part of the | |||
component. | |||
[parameter]#STARTSWITH#:: Matches only items that begin with the given string. | |||
[parameter]#OFF# (default):: Filtering is by default off and all items are shown all the time. | |||
The above example uses the containment filter that matches to all items | |||
containing the input string. As shown in <<figure.components.combobox.filter>> | |||
below, when we type some text in the input area, the drop-down list will show | |||
all the matching items. | |||
[[components.combobox.newitems]] | |||
== Allowing Adding New Items | |||
@@ -91,7 +63,6 @@ List<Planet> 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")); | |||
ComboBox<Planet> select = | |||
new ComboBox<>("Select or Add a Planet"); | |||
@@ -104,7 +75,6 @@ select.setItemCaptionGenerator(Planet::getName); | |||
// handling for new items | |||
select.setNewItemHandler(inputString -> { | |||
// Create a new bean - can't set all properties | |||
Planet newPlanet = new Planet(planets.size(), inputString); | |||
planets.add(newPlanet); | |||
@@ -113,9 +83,6 @@ select.setNewItemHandler(inputString -> { | |||
// Remember to set the selection to the new item | |||
select.select(newPlanet); | |||
Notification.show("Added new planet called " + | |||
inputString); | |||
}); | |||
---- | |||
@@ -34,12 +34,10 @@ class MyComposite extends CustomComponent { | |||
// A layout structure used for composition | |||
Panel panel = new Panel("My Custom Component"); | |||
VerticalLayout panelContent = new VerticalLayout(); | |||
panelContent.setMargin(true); // Very useful | |||
panel.setContent(panelContent); | |||
// Compose from multiple components | |||
Label label = new Label(message); | |||
label.setSizeUndefined(); // Shrink | |||
panelContent.addComponent(label); | |||
panelContent.addComponent(new Button("Ok")); | |||
@@ -8,17 +8,12 @@ layout: page | |||
= Composite Fields with [classname]#CustomField# | |||
The [classname]#CustomField# is a way to create composite components as with [classname]#CustomComponent#, except that it implements the [interfacename]#Field# interface and inherits [classname]#AbstractField#, described in <<dummy/../../../framework/components/components-fields#components.fields,"Field Components">>. | |||
A field allows editing a property value in the Vaadin data model, and can be bound to data with field groups, as described in <<dummy/../../../framework/datamodel/datamodel-forms#datamodel.forms, "Binding Data to Forms">>. | |||
The field values are buffered and can be validated with validators. | |||
A field allows editing a property value in the data model, and can be bound to data with [classname]#Binder#, as described in <<dummy/../../../framework/datamodel/datamodel-forms#datamodel.forms, "Binding Data to Forms">>. | |||
A composite field class must implement the [methodname]#getType()# and [methodname]#initContent()# methods. | |||
The latter should return the content composite of the field. | |||
It is typically a layout component, but can be any component. | |||
A composite field class must implement [methodname]#initContent()# method. | |||
It should return the content composite of the field. | |||
It is also possible to override [methodname]#validate()#, | |||
[methodname]#setInternalValue()#, [methodname]#commit()#, | |||
[methodname]#setPropertyDataSource#, [methodname]#isEmpty()# and other methods | |||
to implement different functionalities in the field. Methods overriding | |||
Methods overriding | |||
[methodname]#setInternalValue()# should call the superclass method. | |||
[[components.customfield.basic]] | |||
@@ -38,33 +33,31 @@ We customize the [methodname]#setValue()# method to reflect the state back to th | |||
[source, Java] | |||
---- | |||
public class BooleanField extends CustomField<Boolean> { | |||
Button button = new Button(); | |||
public BooleanField() { | |||
setValue(true); // On by default | |||
} | |||
private final Button button = new Button("Off"); | |||
private boolean value; | |||
@Override | |||
protected Component initContent() { | |||
// Flip the field value on click | |||
button.addClickListener(click -> | |||
setValue(! (Boolean) getValue())); | |||
return new VerticalLayout( | |||
new Label("Click the button"), button); | |||
button.addClickListener(event -> { | |||
setValue(!getValue()); | |||
button.setCaption(getValue() ? "On" : "Off"); | |||
}); | |||
VerticalLayout layout = new VerticalLayout(); | |||
layout.addComponent(new Label("Click the button")); | |||
layout.addComponent(button); | |||
return layout; | |||
} | |||
@Override | |||
public Class<Boolean> getType() { | |||
return Boolean.class; | |||
public Boolean getValue() { | |||
return value; | |||
} | |||
@Override | |||
public void setValue(Boolean newFieldValue) | |||
throws com.vaadin.data.Property.ReadOnlyException, | |||
ConversionException { | |||
button.setCaption(newFieldValue? "On" : "Off"); | |||
super.setValue(newFieldValue); | |||
protected void doSetValue(Boolean value) { | |||
this.value = value; | |||
button.setCaption(value ? "On" : "Off"); | |||
} | |||
} | |||
---- |
@@ -62,6 +62,9 @@ Java. | |||
---- | |||
// Display only year, month, and day in ISO format | |||
date.setDateFormat("yyyy-MM-dd"); | |||
// Display the correct format as placeholder | |||
date.setPlaceholder("yyyy-mm-dd"); | |||
---- | |||
The result is shown in <<figure.components.datefield.popupdatefield.format>>. | |||
@@ -73,8 +76,6 @@ image::img/datefield-formatting.png[width=35%, scaledwidth=60%] | |||
The same format specification is also used for parsing user-input date, | |||
as described later. | |||
ifdef::web[] | |||
[[components.datefield.popupdatefield.malformed]] | |||
=== Handling Malformed User Input | |||
@@ -119,23 +120,14 @@ in the following example. | |||
// custom error message for invalid format | |||
DateField date = new DateField("My Date") { | |||
@Override | |||
protected Result<Date> handleUnparsableDateString(String dateString) { | |||
// Try custom parsing | |||
String fields[] = dateString.split("/"); | |||
if (fields.length >= 3) { | |||
try { | |||
int year = Integer.parseInt(fields[0]); | |||
int month = Integer.parseInt(fields[1])-1; | |||
int day = Integer.parseInt(fields[2]); | |||
return Result.ok(LocalDate.of(year, month, day)); | |||
} catch (NumberFormatException e) { | |||
return Result.error("Not a number"); | |||
} | |||
protected Result<LocalDate> handleUnparsableDateString( | |||
String dateString) { | |||
try { | |||
// try to parse with alternative format | |||
return Result.ok(LocalDate.of(dateString, myFormat)); | |||
} catch (DateTimeParseException e) { | |||
return Result.error("Bad date"); | |||
} | |||
// Bad date | |||
return Result.error("Your date needs two slashes"); | |||
} | |||
}; | |||
@@ -147,68 +139,6 @@ date.setDateFormat("yyyy/MM/dd"); | |||
date.setLenient(true); | |||
---- | |||
The handler method must either return a parsed [classname]#Date# object or throw | |||
a [classname]#ConversionException#. Returning [parameter]#null# will set the | |||
field value to [parameter]#null# and clear the input box. | |||
endif::web[] | |||
ifdef::web[] | |||
[[components.datefield.popupdatefield.error-customization]] | |||
=== Customizing the Error Message | |||
In addition to customized parsing, overriding the handler method for unparseable | |||
input is useful for internationalization and other customization of the error | |||
message. You can also use it for another way for reporting the errors, as is | |||
done in the example below: | |||
[source, java] | |||
---- | |||
// Create a date field with a custom error message for invalid format | |||
DateField date = new DateField("My Date") { | |||
@Override | |||
protected Result<LocalDate> handleUnparsableDateString(String dateString) { | |||
// Have a notification for the error | |||
Notification.show( | |||
"Your date needs two slashes", | |||
Notification.TYPE_WARNING_MESSAGE); | |||
// A failure must always also throw an exception | |||
return Result.error("Bad date"); | |||
} | |||
}; | |||
---- | |||
If the input is invalid, you should always throw the exception; returning a | |||
[parameter]#null# value would make the input field empty, which is probably | |||
undesired. | |||
endif::web[] | |||
[[components.datefield.popupdatefield.prompt]] | |||
=== Placeholder | |||
Like other fields that have a text box, [classname]#DateField# allows an | |||
placeholder that is visible until the user has input a value. You can set that with [methodname]#setPlaceholder#. | |||
[source, java] | |||
---- | |||
DateField date = new DateField(); | |||
// Set the prompt | |||
date.setPlaceholder("Select a date"); | |||
// Set width explicitly to accommodate the prompt | |||
date.setWidth("10em"); | |||
---- | |||
The date field doesn't automatically scale to accommodate the prompt, so you | |||
need to set it explicitly with [methodname]#setWidth()#. | |||
The input prompt is not available in the [classname]#DateField# superclass. | |||
[[components.datefield.popupdatefield.css]] | |||
=== CSS Style Rules | |||
@@ -323,7 +253,7 @@ endings for the weekday bar. | |||
In addition to display a calendar with dates, [classname]#DateField# can also | |||
display just the month or year. The visibility of the input components is | |||
controlled by __date resolution__, which you can set with [methodname]#setResolution()#. | |||
controlled by [methodname]#setDateResolution()#, which you can set with [methodname]#setResolution()#. | |||
The method takes as its parameter the highest resolution date element that should | |||
be visible. Please see the API Reference for the complete list of resolution parameters. | |||
@@ -338,25 +268,8 @@ method of [classname]#AbstractComponent#, as described in | |||
Only Gregorian calendar is supported. | |||
ifdef::web[] | |||
[[components.datefield.weeknumbers]] | |||
== Week Numbers | |||
You can enable week numbers in a date field with | |||
[methodname]#setShowISOWeekNumbers()#. The numbers are shown in a column on the | |||
left side of the field. | |||
[source, java] | |||
---- | |||
df.setShowISOWeekNumbers(true); | |||
---- | |||
The supported numbering is defined in the ISO 8601 standard. Note that the ISO | |||
standard applies only to calendar locales where the week starts on Monday. This | |||
is not the case in many countries, such as Americas (North and South), many | |||
East-Asian countries, and some African countries, where the week starts on | |||
Sunday, nor in some North African and Middle-Eastern countries, where the week | |||
begins on Saturday. In such locales, the week numbers are not displayed. | |||
endif::web[] | |||
[methodname]#setShowISOWeekNumbers()#. The numbers are shown according to the ISO 8601 standard in a column on the left side of the field. |
@@ -109,27 +109,6 @@ imageResource.setFilename(makeImageFilename()); | |||
---- | |||
[[components.embedded.flash]] | |||
== Adobe [classname]#Flash# Graphics | |||
The [classname]#Flash# component allows embedding Adobe Flash animations in | |||
Vaadin UIs. | |||
[source, java] | |||
---- | |||
Flash flash = new Flash(null, | |||
new ThemeResource("img/vaadin_spin.swf")); | |||
layout.addComponent(flash); | |||
---- | |||
You can set Flash parameters with [methodname]#setParameter()#, which takes a | |||
parameter's name and value as strings. You can also set the | |||
[parameter]#codeBase#, [parameter]#archive#, and [parameter]#standBy# attributes | |||
for the Flash object element in HTML. | |||
[[components.embedded.browserframe]] | |||
== [classname]#BrowserFrame# | |||
@@ -158,24 +137,10 @@ Notice that web pages can prevent embedding them in an <iframe>. | |||
The generic [classname]#Embedded# component allows embedding all sorts of | |||
objects, such as SVG graphics, Java applets, and PDF documents, in addition to | |||
the images, Flash graphics, and browser frames which you can embed with the | |||
the images, and browser frames which you can embed with the | |||
specialized components. | |||
For example, to display a Flash animation: | |||
[source, java] | |||
---- | |||
// A resource reference to some object | |||
Resource res = new ThemeResource("img/vaadin_spin.swf"); | |||
// Display the object | |||
Embedded object = new Embedded("My Object", res); | |||
layout.addComponent(object); | |||
---- | |||
Or an SVG image: | |||
Display an SVG image: | |||
[source, java] | |||
---- | |||
@@ -189,7 +154,7 @@ layout.addComponent(object); | |||
---- | |||
The MIME type of the objects is usually detected automatically from the filename | |||
extension with the [classname]#FileTypeResolver# utility in Vaadin. If not, you | |||
extension with the [classname]#FileTypeResolver# utility in Framework. If not, you | |||
can set it explicitly with [methodname]#setMimeType()#, as was done in the | |||
example above (where it was actually unnecessary). | |||
@@ -30,7 +30,6 @@ as follows: | |||
Link link = new Link("Click Me!", | |||
new ExternalResource("http://vaadin.com/")); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.link.basic[on-line example, window="_blank"]. | |||
You can use [methodname]#setIcon()# to make image links as follows: | |||
@@ -47,7 +46,6 @@ Link combo = new Link("To appease both literal and visual", | |||
new ExternalResource("http://vaadin.com/")); | |||
combo.setIcon(new ThemeResource("img/nicubunu_Chain.png")); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.link.basic[on-line example, window="_blank"]. | |||
The resulting links are shown in <<figure.components.link.basic>>. You could add | |||
a " [literal]#++display: block++#" style for the icon element to place the | |||
@@ -82,7 +80,6 @@ link.setTargetName("_blank"); | |||
link.setIcon(new ThemeResource("icons/external-link.png")); | |||
link.addStyleName("icon-after-caption"); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.link.target[on-line example, window="_blank"]. | |||
[[components.link.pop-up]] | |||
== Opening as a Pop-Up Window | |||
@@ -91,27 +88,26 @@ With the [literal]#++_blank++# target, a normal new browser window is opened. If | |||
you wish to open it in a popup window (or tab), you need to give a size for the | |||
window with [methodname]#setTargetWidth()# and [methodname]#setTargetHeight()#. | |||
You can control the window border style with [methodname]#setTargetBorder()#, | |||
which takes any of the defined border styles [parameter]#TARGET_BORDER_DEFAULT#, | |||
[parameter]#TARGET_BORDER_MINIMAL#, and [parameter]#TARGET_BORDER_NONE#. The | |||
which takes any of the defined border styles [parameter]#BorderStyle.DEFAULT#, | |||
[parameter]#BorderStyle.MINIMAL#, and [parameter]#BorderStyle.NONE#. The | |||
exact result depends on the browser. | |||
[source, java] | |||
---- | |||
// Open the URL in a popup | |||
link.setTargetName("_blank"); | |||
link.setTargetBorder(Link.TARGET_BORDER_NONE); | |||
link.setTargetBorder(BorderStyle.NONE); | |||
link.setTargetHeight(300); | |||
link.setTargetWidth(400); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.link.target[on-line example, window="_blank"]. | |||
== Alternatives | |||
In addition to the [classname]#Link# component, Vaadin allows alternative ways to make hyperlinks. | |||
Also, you can make hyperlinks (or any other HTML) in a [classname]#Label# in HTML content mode. | |||
The [classname]#Button# component has a [parameter]#Reindeer.BUTTON_LINK# style name that makes it look like a hyperlink, while handling clicks in a server-side click listener instead of in the browser. | |||
However, browsers do not generally allow opening new windows from with browser code, so for such tasks you need to use the [classname]#BrowserWindowOpener# extension described in <<dummy/../../../framework/advanced/advanced-windows#advanced.windows.popup, "Opening Pop-up Windows">> | |||
The [classname]#Button# component has a [parameter]#ValoTheme.BUTTON_LINK# style name that makes it look like a hyperlink, while handling clicks in a server-side click listener instead of in the browser. | |||
However, browsers do not generally allow opening new windows after server side round trip, so for such tasks you need to use the [classname]#BrowserWindowOpener# extension described in <<dummy/../../../framework/advanced/advanced-windows#advanced.windows.popup, "Opening Pop-up Windows">> | |||
== CSS Style Rules | |||
@@ -132,13 +128,12 @@ text span. | |||
Hyperlink anchors have a number of __pseudo-classes__ that are active at | |||
different times. An unvisited link has [literal]#++a:link++# class and a visited | |||
link [literal]#++a:visited++#. When the mouse pointer hovers over the link, it | |||
will have a:hover, and when the mouse button is being pressed over the link, the | |||
will have [literal]#++a:hover++#, and when the mouse button is being pressed over the link, the | |||
[literal]#++a:active++# class. When combining the pseudo-classes in a selector, | |||
please notice that [literal]#++a:hover++# must come after an | |||
[literal]#++a:link++# and [literal]#++a:visited++#, and [literal]#++a:active++# | |||
after the [literal]#++a:hover++#. | |||
ifdef::web[] | |||
=== Icon Position | |||
Normally, the link icon is before the caption. | |||
@@ -156,7 +151,6 @@ You can have it right of the caption by reversing the text direction in the cont | |||
padding: 0 3px; | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.link.target[on-line example, window="_blank"]. | |||
The resulting link is shown in <<figure.components.link.new-window>>. | |||
@@ -164,4 +158,3 @@ The resulting link is shown in <<figure.components.link.new-window>>. | |||
.Link That Opens a New Window | |||
image::img/link-new.png[width=25%, scaledwidth=50%] | |||
endif::web[] |
@@ -14,9 +14,7 @@ endif::web[] | |||
The [classname]#ListSelect# component is list box that shows the selectable | |||
items in a vertical list. If the number of items exceeds the height of the | |||
component, a scrollbar is shown. The component allows both single and multiple | |||
selection modes, which you can set with [methodname]#setMultiSelect()#. It is | |||
visually identical in both modes. | |||
component, a scrollbar is shown. The component allows selecting multiple values. | |||
[source, java] | |||
@@ -29,6 +27,11 @@ select.setItems("Mercury", "Venus", "Earth", ...); | |||
// Show 5 items and a scrollbar if there are more | |||
select.setRows(5); | |||
select.addValueChangeListener(event -> { | |||
Set<String> selected = event.getNewSelection(); | |||
Notification.show(selected.size() + " items."); | |||
}); | |||
---- | |||
The number of visible items is set with [methodname]#setRows()#. |
@@ -12,9 +12,8 @@ ifdef::web[] | |||
image:{live-demo-image}[alt="Live Demo", link="http://demo.vaadin.com/sampler/#ui/data-input/multiple-value/drop-down-menu"] | |||
endif::web[] | |||
[classname]#NativeSelect# is a drop-down selection component implemented with | |||
the native selection input of web browsers, using the HTML | |||
[literal]#++<select>++# element. | |||
[classname]#NativeSelect# is a selection component allows selecting an item from a | |||
drop-down list. It is implemented with the native selection input of web browsers, using the HTML [literal]#++<select>++# element. | |||
[source, java] |
@@ -13,8 +13,8 @@ image:{live-demo-image}[alt="Live Demo", link="http://demo.vaadin.com/sampler/#u | |||
endif::web[] | |||
[classname]#RadioButtonGroup# is a single selection component that allows | |||
selection from a group of radio buttons. [classname]#CheckBoxGroup# is a multi selection | |||
component where items displayed as check boxes. The common selection component features are | |||
selection from a group of radio buttons. [classname]#CheckBoxGroup# is a multiselection | |||
component where items are displayed as check boxes. The common selection component features are | |||
described in | |||
<<dummy/../../../framework/components/components-selection#components.selection,"Selection Components">>. | |||
@@ -46,8 +46,6 @@ maintains the individual check box objects, you can get an array of the | |||
currently selected items easily, and that you can easily change the appearance | |||
of a single component and use it with a [classname]#Binder#. | |||
ifdef::web[] | |||
[[components.optiongroups.disabling]] | |||
== Disabling Items | |||
@@ -64,7 +62,7 @@ RadioButtonGroup<String> group = new RadioButtonGroup<>("My Disabled Group"); | |||
group.setItems("One", "Two", "Three"); | |||
// Disable one item | |||
group.setItemEnabledProvider( item-> !"Two".equals(item)); | |||
group.setItemEnabledProvider(item-> !"Two".equals(item)); | |||
---- | |||
[[figure.components.optiongroups.disabling]] | |||
@@ -72,7 +70,6 @@ group.setItemEnabledProvider( item-> !"Two".equals(item)); | |||
image::img/optiongroup-disabling.png[width=25%, scaledwidth=50%] | |||
Setting an item as disabled turns on the [literal]#++v-disabled++# style for it. | |||
endif::web[] | |||
[[components.optiongroups.css]] | |||
== CSS Style Rules | |||
@@ -93,43 +90,9 @@ also have the [literal]#++v-select-option++# style that allows styling | |||
regardless of the option type. Disabled items have additionally the | |||
[literal]#++v-disabled++# style. | |||
ifdef::web[] | |||
[[components.optiongroups.css.horizontal]] | |||
=== Horizontal Layout | |||
The options are normally laid out vertically. You can use horizontal layout by | |||
setting [literal]#++display: inline-block++# for the options. The | |||
[literal]#++nowrap++# setting for the overall element prevents wrapping if there | |||
is not enough horizontal space in the layout, or if the horizontal width is | |||
undefined. | |||
[source, css] | |||
---- | |||
/* Lay the options horizontally */ | |||
.v-select-optiongroup-horizontal .v-select-option { | |||
display: inline-block; | |||
} | |||
/* Avoid wrapping if the layout is too tight */ | |||
.v-select-optiongroup-horizontal { | |||
white-space: nowrap; | |||
} | |||
/* Some extra spacing is needed */ | |||
.v-select-optiongroup-horizontal | |||
.v-select-option.v-radiobutton { | |||
padding-right: 10px; | |||
} | |||
---- | |||
The options are normally laid out vertically. You can switch to horizontal layout by using the style name [parameter]#ValoTheme.OPTIONGROUP_HORIZONTAL# with [methodname]#addStyleName()#. | |||
Use of the above rules requires setting a custom [literal]#++horizontal++# style | |||
name for the component. The result is shown in | |||
<<figure.components.optiongroups.horizontal>>. | |||
[[figure.components.optiongroups.horizontal]] | |||
.Horizontal [classname]#RadioButtonGroup# | |||
image::img/optiongroup-horizontal.png[width=35%, scaledwidth=50%] | |||
endif::web[] |
@@ -20,7 +20,6 @@ the typed input from visual inspection. | |||
---- | |||
PasswordField tf = new PasswordField("Keep it secret"); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.passwordfield.basic[on-line example, window="_blank"]. | |||
The result is shown in <<figure.components.passwordfield.basic>>. | |||
@@ -42,11 +42,10 @@ programmatically by calling [methodname]#setPopupVisible(true)#. For example: | |||
[source, java] | |||
---- | |||
// A pop-up view without minimalized representation | |||
PopupView popup = new PopupView(null, | |||
new Table(null, TableExample.generateContent())); | |||
PopupView popup = new PopupView(null, myComponent); | |||
// A component to open the view | |||
Button button = new Button("Show table", click -> | |||
Button button = new Button("Show details", click -> | |||
popup.setPopupVisible(true)); | |||
layout.addComponents(button, popup); |
@@ -62,7 +62,6 @@ bar.setIndeterminate(true); | |||
.Indeterminate progress bar | |||
image::img/progressbar-indeterminate.png[width=15%, scaledwidth=40%] | |||
ifdef::web[] | |||
[[components.progressbar.thread]] | |||
== Doing Heavy Computation | |||
@@ -75,107 +74,6 @@ updating the UI inside a [methodname]#UI.access()# call in a | |||
<<dummy/../../../framework/advanced/advanced-push#advanced.push.running,"Accessing | |||
UI from Another Thread">>. | |||
In the following example, we create a thread in the server to do some "heavy | |||
work" and use polling to update the UI. All the thread needs to do is to set the | |||
value of the progress bar with [methodname]#setValue()# and the current progress | |||
is displayed automatically when the browser polls the server. | |||
[source, java] | |||
---- | |||
HorizontalLayout barbar = new HorizontalLayout(); | |||
layout.addComponent(barbar); | |||
// Create the bar, disabled until progress is started | |||
final ProgressBar progress = new ProgressBar(new Float(0.0)); | |||
progress.setEnabled(false); | |||
barbar.addComponent(progress); | |||
final Label status = new Label("not running"); | |||
barbar.addComponent(status); | |||
// A button to start progress | |||
final Button button = new Button("Click to start"); | |||
layout.addComponent(button); | |||
// A thread to do some work | |||
class WorkThread extends Thread { | |||
// Volatile because read in another thread in access() | |||
volatile double current = 0.0; | |||
@Override | |||
public void run() { | |||
// Count up until 1.0 is reached | |||
while (current < 1.0) { | |||
current += 0.01; | |||
// Do some "heavy work" | |||
try { | |||
sleep(50); // Sleep for 50 milliseconds | |||
} catch (InterruptedException e) {} | |||
// Update the UI thread-safely | |||
UI.getCurrent().access(new Runnable() { | |||
@Override | |||
public void run() { | |||
progress.setValue(new Float(current)); | |||
if (current < 1.0) | |||
status.setValue("" + | |||
((int)(current*100)) + "% done"); | |||
else | |||
status.setValue("all done"); | |||
} | |||
}); | |||
} | |||
// Show the "all done" for a while | |||
try { | |||
sleep(2000); // Sleep for 2 seconds | |||
} catch (InterruptedException e) {} | |||
// Update the UI thread-safely | |||
UI.getCurrent().access(new Runnable() { | |||
@Override | |||
public void run() { | |||
// Restore the state to initial | |||
progress.setValue(new Float(0.0)); | |||
progress.setEnabled(false); | |||
// Stop polling | |||
UI.getCurrent().setPollInterval(-1); | |||
button.setEnabled(true); | |||
status.setValue("not running"); | |||
} | |||
}); | |||
} | |||
} | |||
// Clicking the button creates and runs a work thread | |||
button.addClickListener(new Button.ClickListener() { | |||
public void buttonClick(ClickEvent event) { | |||
final WorkThread thread = new WorkThread(); | |||
thread.start(); | |||
// Enable polling and set frequency to 0.5 seconds | |||
UI.getCurrent().setPollInterval(500); | |||
// Disable the button until the work is done | |||
progress.setEnabled(true); | |||
button.setEnabled(false); | |||
status.setValue("running..."); | |||
} | |||
}); | |||
---- | |||
The example is illustrated in <<figure.components.progressbar.thread>>. | |||
[[figure.components.progressbar.thread]] | |||
.Doing heavy work | |||
image::img/progressbar-thread.png[width=40%, scaledwidth=70%] | |||
endif::web[] | |||
[[components.progressbar.css]] | |||
== CSS Style Rules |
@@ -69,7 +69,6 @@ scripting vulnerabilities and sanitization of user input. | |||
==== | |||
ifdef::web[] | |||
[[components.richtextarea.localization]] | |||
== Localizing RichTextArea Toolbars | |||
@@ -83,21 +82,6 @@ which the individual button icons are picked, so the order of the icons is | |||
different from the rendered. The image file depends on the client-side | |||
implementation of the toolbar. | |||
[source, css] | |||
---- | |||
.v-richtextarea-richtextexample .gwt-ToggleButton | |||
.gwt-Image { | |||
background-image: url(img/richtextarea-toolbar-fi.png) | |||
!important; | |||
} | |||
---- | |||
.Regular English and a Localized Rich Text Area Toolbar | |||
image::img/richtextarea-toolbar-whitebg.png[] | |||
endif::web[] | |||
== CSS Style Rules | |||
@@ -14,11 +14,12 @@ library includes the following selection components, all based on either | |||
[classname]#AbstractSingleSelect# or [classname]#AbstractMultiSelect# class: | |||
[classname]#ComboBox# (<<components-combobox#components.combobox,"ComboBox">>):: | |||
A drop-down list with a text box, where the user can type text to find matching items. | |||
A drop-down list with a text box, where the user can type text to find matching items and | |||
select one item. | |||
The component also provides a placeholder and the user can enter new items. | |||
[classname]#ListSelect# (<<components-listselect#components.listselect,"ListSelect">>):: | |||
A vertical list box for selecting items in either single or multiple selection mode. | |||
A vertical list box for selecting items in multiple selection mode. | |||
[classname]#NativeSelect# (<<components-nativeselect#components.nativeselect, "NativeSelect">>):: | |||
Provides selection using the native selection component of the browser, typically a drop-down list for single selection and a multi-line list in multiselect mode. |
@@ -47,7 +47,6 @@ field is a [classname]#Double# object. | |||
---- | |||
// Shows the value of the vertical slider | |||
final Label vertvalue = new Label(); | |||
vertvalue.setSizeUndefined(); | |||
// Handle changes in slider value. | |||
vertslider.addValueChangeListener(event -> { |
@@ -29,7 +29,6 @@ area.setValue("A row\n"+ | |||
"Another row\n"+ | |||
"Yet another row"); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.textarea.basic[on-line example, window="_blank"]. | |||
The result is shown in <<figure.components.textarea>>. | |||
@@ -62,15 +61,14 @@ shortening a wrapped line will undo the wrapping. | |||
[source, java] | |||
---- | |||
TextArea area1 = new TextArea("Wrapping"); | |||
area1.setWordwrap(true); // The default | |||
area1.setWordWrap(true); // The default | |||
area1.setValue("A quick brown fox jumps over the lazy dog"); | |||
TextArea area2 = new TextArea("Nonwrapping"); | |||
area2.setWordwrap(false); | |||
area2.setWordWrap(false); | |||
area2.setValue("Victor jagt zwölf Boxkämpfer quer "+ | |||
"über den Sylter Deich"); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.textarea.wordwrap[on-line example, window="_blank"]. | |||
The result is shown in <<figure.components.textarea.wordwrap>>. | |||
@@ -15,7 +15,7 @@ endif::web[] | |||
((("[classname]#TextField#", id="term.components.textfield", range="startofrange"))) | |||
[classname]#TextField# is one of the most commonly used user interface components. | |||
It is a [classname]#Field# component that allows entering textual values with keyboard. | |||
It is a field that allows entering textual values with keyboard. | |||
The following example creates a simple text field: | |||
@@ -27,7 +27,6 @@ TextField tf = new TextField("A Field"); | |||
// Put some initial content in it | |||
tf.setValue("Stuff in the field"); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.textfield.basic[on-line example, window="_blank"]. | |||
The result is shown in <<figure.components.textfield.basic>>. | |||
@@ -45,7 +44,6 @@ tf.addValueChangeListener(event -> | |||
// Do something with the value | |||
Notification.show("Value is: " + event.getValue())); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.textfield.inputhandling[on-line example, window="_blank"]. | |||
[classname]#TextField# edits [classname]#String# values, but you can use [classname]#Binder# | |||
to bind it to any property type that has a proper converter, as described in | |||
@@ -89,37 +87,31 @@ to the server and cause a server-side event. Lazier change events allow sending | |||
larger changes in one event if the user is typing fast, thereby reducing server | |||
requests. | |||
((([classname]#TextChangeEventMode#))) | |||
((([classname]#ValueChangeMode#))) | |||
You can set the text change event mode of a [classname]#TextField# with | |||
[methodname]#setTextChangeEventMode()#. The allowed modes are defined in | |||
[classname]#TextChangeEventMode# enum and are as follows: | |||
[methodname]#setValueChangeMode()#. The allowed modes are defined in | |||
[classname]#ValueChangeMode# enum and are as follows: | |||
[parameter]#TextChangeEventMode.LAZY#(default):: An event is triggered when there is a pause in editing the text. The length of | |||
the pause can be modified with [methodname]#setInputEventTimeout()#. As with the | |||
[parameter]#TIMEOUT# mode, a text change event is forced before a possible | |||
[classname]#ValueChangeEvent#, even if the user did not keep a pause while | |||
entering the text. | |||
[parameter]#ValueChangeMode.LAZY#(default):: An event is triggered when there is a pause in editing the text. The length of | |||
the pause can be modified with [methodname]#setValueChangeTimeout()#. | |||
+ | |||
This is the default mode. | |||
[parameter]#TextChangeEventMode.TIMEOUT#:: A text change in the user interface causes the event to be communicated to the | |||
[parameter]#ValueChangeMode.TIMEOUT#:: A text change in the user interface causes the event to be communicated to the | |||
application after a timeout period. If more changes are made during this period, | |||
the event sent to the server-side includes the changes made up to the last | |||
change. The length of the timeout can be set with | |||
[methodname]#setInputEventTimeout()#. | |||
[methodname]#setValueChangeTimeout()#. | |||
+ | |||
If a [classname]#ValueChangeEvent# would occur before the timeout period, a | |||
[classname]#TextChangeEvent# is triggered before it, on the condition that the | |||
text content has changed since the previous [classname]#TextChangeEvent#. | |||
[parameter]#TextChangeEventMode.EAGER#:: An event is triggered immediately for every change in the text content, | |||
[parameter]#ValueChangeMode.EAGER#:: The [classname]#ValueChangeEvent# is triggered immediately for every change in the text content, | |||
typically caused by a key press. The requests are separate and are processed | |||
sequentially one after another. Change events are nevertheless communicated | |||
asynchronously to the server, so further input can be typed while event requests | |||
are being processed. | |||
[parameter]#ValueChangeMode.BLUR#:: The [classname]#ValueChangeEvent# is fired, after the field has lost focus. | |||
[source, java] | |||
---- | |||
// Text field with maximum length | |||
@@ -138,12 +130,10 @@ tf.addValueChangeListener(event -> { | |||
counter.setValue(len + " of " + tf.getMaxLength()); | |||
}); | |||
tf.setValueChangeMode(ValueChangeMode.onKeyPress()); | |||
tf.setValueChangeMode(ValueChangeMode.EAGER); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.textfield.textchangeevents.counter[on-line example, window="_blank"]. | |||
The result is shown in <<figure.components.textfield.textchangeevents>>. | |||
[[figure.components.textfield.textchangeevents]] | |||
@@ -170,10 +160,8 @@ For example, the following custom style uses dashed border: | |||
---- | |||
.v-textfield-dashing { | |||
border: thin dashed; | |||
background: white; /* Has shading image by default */ | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.textfield.css[on-line example, window="_blank"]. | |||
The result is shown in <<figure.components.textfield.css>>. | |||
@@ -15,9 +15,9 @@ endif::web[] | |||
The [classname]#TwinColSelect# field provides a multiple selection component | |||
that shows two lists side by side, with the left column containing unselected | |||
items and the right column the selected items. The user can select items from | |||
the list on the left and click on the ">>" button to move them to the list on | |||
the list on the left and click on the ">" button to move them to the list on | |||
the right. Items can be deselected by selecting them in the right list and | |||
clicking on the "<<" button. | |||
clicking on the "<" button. | |||
[[figure.components.twincolselect.basic]] | |||
.Twin Column Selection |
@@ -12,13 +12,14 @@ ifdef::web[] | |||
image:{live-demo-image}[alt="Live Demo", link="http://demo.vaadin.com/sampler/#ui/data-input/other/upload"] | |||
endif::web[] | |||
*_This section has not yet been updated to Vaadin Framework 8_* | |||
The [classname]#Upload# component allows a user to upload files to the server. | |||
It displays a file name entry box, a file selection button, and an upload submit | |||
button. The user can either write the filename in the text area or click the | |||
[guibutton]#Browse# button to select a file. After the file is selected, the | |||
user sends the file by clicking the upload submit button. | |||
It has two different modes controlled with [methodname]#setImmediateMode(boolean)#, that affect the user workflow. | |||
[parameter]#Immediate# (default):: In the immediate mode, the upload displays a file name entry box and a button for selecting the file. The uploading is started immediately after the file has been selected. | |||
[parameter]#Non-immediate#:: In the non-immediate mode, the upload displays a file name | |||
entry box, a button for selecting the file and a button for starting the upload. | |||
After the file is selected, the user starts the upload by clicking the submit button. | |||
Uploading requires a receiver that implements [interfacename]#Upload.Receiver# | |||
to provide an output stream to which the upload is written by the server. | |||
@@ -26,12 +27,16 @@ to provide an output stream to which the upload is written by the server. | |||
[source, java] | |||
---- | |||
Upload upload = new Upload("Upload it here", receiver); | |||
upload.setImmediateMode(false); | |||
---- | |||
[[figure.ui.upload]] | |||
.The [classname]#Upload# component | |||
.The [classname]#Upload# component in non-immediate mode | |||
image::img/upload.png[width=60%, scaledwidth=80%] | |||
In the image above, the upload is in non-immediate mode. By default in the immediate mode, | |||
only the [guilabel]#Start Upload# button is visible. | |||
You can set the text of the upload button with [methodname]#setButtonCaption()#. | |||
Note that it is difficult to change the caption or look of the | |||
[guibutton]#Browse# button. This is a security feature of web browsers. The | |||
@@ -46,9 +51,7 @@ upload.setButtonCaption("Upload Now"); | |||
You can also hide the upload button with [literal]#++.v-upload .v-button | |||
{display: none}++# in theme, have custom logic for starting the upload, and call | |||
[methodname]#startUpload()# to start it. If the upload component has | |||
[methodname]#setImmediateMode(true)# enabled, uploading starts immediately after | |||
choosing the file. | |||
[methodname]#startUpload()# to start it. | |||
[[components.upload.receiving]] | |||
== Receiving Upload Data | |||
@@ -91,8 +94,7 @@ displays the uploaded image in an [classname]#Image# component. | |||
[source, java] | |||
---- | |||
// Show uploaded file in this placeholder | |||
final Embedded image = new Embedded("Uploaded Image"); | |||
image.setVisible(false); | |||
final Image image = new Image("Uploaded Image"); | |||
// Implement both receiver that saves upload in a file and | |||
// listener for successful upload | |||
@@ -101,25 +103,12 @@ class ImageUploader implements Receiver, SucceededListener { | |||
public OutputStream receiveUpload(String filename, | |||
String mimeType) { | |||
// Create upload stream | |||
FileOutputStream fos = null; // Stream to write to | |||
try { | |||
// Open the file for writing. | |||
file = new File("/tmp/uploads/" + filename); | |||
fos = new FileOutputStream(file); | |||
} catch (final java.io.FileNotFoundException e) { | |||
new Notification("Could not open file<br/>", | |||
e.getMessage(), | |||
Notification.Type.ERROR_MESSAGE) | |||
.show(Page.getCurrent()); | |||
return null; | |||
} | |||
return fos; // Return the output stream to write to | |||
// Create and return a file output stream | |||
... | |||
} | |||
public void uploadSucceeded(SucceededEvent event) { | |||
// Show the uploaded file in the image viewer | |||
image.setVisible(true); | |||
image.setSource(new FileResource(file)); | |||
} | |||
}; | |||
@@ -127,26 +116,9 @@ ImageUploader receiver = new ImageUploader(); | |||
// Create the upload with a caption and set receiver later | |||
Upload upload = new Upload("Upload Image Here", receiver); | |||
upload.setButtonCaption("Start Upload"); | |||
upload.addSucceededListener(receiver); | |||
// Put the components in a panel | |||
Panel panel = new Panel("Cool Image Storage"); | |||
Layout panelContent = new VerticalLayout(); | |||
panelContent.addComponents(upload, image); | |||
panel.setContent(panelContent); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.upload.basic[on-line example, window="_blank"]. | |||
Note that the example does not check the type of the uploaded files in any way, | |||
which will cause an error if the content is anything else but an image. The | |||
program also assumes that the MIME type of the file is resolved correctly based | |||
on the file name extension. After uploading an image, the component will look as | |||
shown in <<figure.ui.upload.example>>. | |||
[[figure.ui.upload.example]] | |||
.Image Upload Example | |||
image::img/upload-example.png[width=60%, scaledwidth=80%] | |||
[[components.upload.css]] | |||
== CSS Style Rules |
@@ -12,24 +12,20 @@ import com.vaadin.ui.VerticalLayout; | |||
* structures. Here, the commit etc. logic is not overridden. | |||
*/ | |||
public class BooleanField extends CustomField<Boolean> { | |||
private final Button button = new Button("Off"); | |||
private boolean value; | |||
@Override | |||
protected Component initContent() { | |||
VerticalLayout layout = new VerticalLayout(); | |||
layout.addComponent(new Label("Please click the button")); | |||
final Button button = new Button("Click me"); | |||
button.addClickListener(event -> { | |||
setValue(!getValue()); | |||
button.setCaption(getValue() ? "On" : "Off"); | |||
}); | |||
layout.addComponent(button); | |||
VerticalLayout layout = new VerticalLayout(); | |||
layout.addComponent(new Label("Please click the button")); | |||
layout.addComponent(button); | |||
return layout; | |||
} | |||
@Override | |||
@@ -40,5 +36,6 @@ public class BooleanField extends CustomField<Boolean> { | |||
@Override | |||
protected void doSetValue(Boolean value) { | |||
this.value = value; | |||
button.setCaption(value ? "On" : "Off"); | |||
} | |||
} |