diff options
Diffstat (limited to 'documentation/datamodel/datamodel-properties.asciidoc')
-rw-r--r-- | documentation/datamodel/datamodel-properties.asciidoc | 399 |
1 files changed, 0 insertions, 399 deletions
diff --git a/documentation/datamodel/datamodel-properties.asciidoc b/documentation/datamodel/datamodel-properties.asciidoc deleted file mode 100644 index d5d0d3e39d..0000000000 --- a/documentation/datamodel/datamodel-properties.asciidoc +++ /dev/null @@ -1,399 +0,0 @@ ---- -title: Properties -order: 2 -layout: page ---- - -[[datamodel.properties]] -= Properties - -The [interfacename]#Property# interface is the base of the Vaadin Data Model. It -provides a standardized API for a single data value object that can be read -(get) and written (set). A property is always typed, but can optionally support -data type conversions. The type of a property can be any Java class. Optionally, -properties can provide value change events for following their changes. - -You can set the value of a property with [methodname]#setValue()# and read with -[methodname]#getValue()#. - -In the following, we set and read the property value from a -[classname]#TextField# component, which implements the [interfacename]#Property# -interface to allow accessing the field value. - - ----- -final TextField tf = new TextField("Name"); - -// Set the value -tf.setValue("The text field value"); - -// When the field value is edited by the user -tf.addValueChangeListener( - new Property.ValueChangeListener() { - public void valueChange(ValueChangeEvent event) { - // Do something with the new value - layout.addComponent(new Label(tf.getValue())); - } -}); ----- -See the http://demo.vaadin.com/book-examples-vaadin7/book#datamodel.properties.basic[on-line example, window="_blank"]. - -Changes in the property value usually fire a [classname]#ValueChangeEvent#, -which can be handled with a [classname]#ValueChangeListener#. The event object -provides reference to the property with [methodname]#getProperty()#. Note that -its [methodname]#getValue()# method returns the value with [classname]#Object# -type, so you need to cast it to the proper type. - -Properties are in themselves unnamed. They are collected in __items__, which -associate the properties with names: the __Property Identifiers__ or __PID__s. -Items can be further contained in containers and are identified with __Item -Identifiers__ or __IID__s. In the spreadsheet analogy, __Property Identifiers__ -would correspond to column names and __Item Identifiers__ to row names. The -identifiers can be arbitrary objects, but must implement the -[methodname]#equals(Object)# and [methodname]#hashCode()# methods so that they -can be used in any standard Java [classname]#Collection#. - -The [classname]#Property# interface can be utilized either by implementing the -interface or by using some of the built-in property implementations. Vaadin -includes a [classname]#Property# interface implementation for arbitrary function -pairs and bean properties, with the [classname]#MethodProperty# class, and for -simple object properties, with the [classname]#ObjectProperty# class, as -described later. - -In addition to the simple components, selection components provide their current -selection as the property value. In single selection mode, the property is a -single item identifier, while in multiple selection mode it is a set of item -identifiers. See the documentation of the selection components for further -details. - -Components that can be bound to a property have an internal default data source -object, typically a [classname]#ObjectProperty#, which is described later. As -all such components are viewers or editors, also described later, so you can -rebind a component to any data source with -[methodname]#setPropertyDataSource()#. - -[[datamodel.properties.viewers]] -== Property Viewers and Editors - -The most important function of the [classname]#Property# as well as of the other -data model interfaces is to connect classes implementing the interface directly -to editor and viewer classes. This means connecting a data source (model) to a -user interface component (views) to allow editing or viewing the data model. - -A property can be bound to a component implementing the [classname]#Viewer# -interface with [methodname]#setPropertyDataSource()#. - - ----- -// Have a data model -ObjectProperty property = - new ObjectProperty("Hello", String.class); - -// Have a component that implements Viewer -Label viewer = new Label(); - -// Bind it to the data -viewer.setPropertyDataSource(property); ----- - -You can use the same method in the [classname]#Editor# interface to bind a -component that allows editing a particular property type to a property. - - ----- -// Have a data model -ObjectProperty property = - new ObjectProperty("Hello", String.class); - -// Have a component that implements Viewer -TextField editor = new TextField("Edit Greeting"); - -// Bind it to the data -editor.setPropertyDataSource(property); - ----- - -As all field components implement the [classname]#Property# interface, you can -bind any component implementing the [classname]#Viewer# interface to any field, -assuming that the viewer is able the view the object type of the field. -Continuing from the above example, we can bind a [classname]#Label# to the -[classname]#TextField# value: - - ----- -Label viewer = new Label(); -viewer.setPropertyDataSource(editor); - -// The value shown in the viewer is updated immediately -// after editing the value in the editor (once it -// loses the focus) -editor.setImmediate(true); ----- - -If a field has validators, as described in -<<dummy/../../../framework/components/components-fields#components.fields.validation,"Field -Validation">>, the validators are executed before writing the value to the -property data source, or by calling the [methodname]#validate()# or -[methodname]#commit()# for the field. - - -[[datamodel.properties.objectproperty]] -== [classname]#ObjectProperty# Implementation - -The [classname]#ObjectProperty# class is a simple implementation of the -[classname]#Property# interface that allows storing an arbitrary Java object. - - ----- -// Have a component that implements Viewer interface -final TextField tf = new TextField("Name"); - -// Have a data model with some data -String myObject = "Hello"; - -// Wrap it in an ObjectProperty -ObjectProperty property = - new ObjectProperty(myObject, String.class); - -// Bind the property to the component -tf.setPropertyDataSource(property); ----- - - -[[datamodel.properties.converter]] -== Converting Between Property Type and Representation - -Fields allow editing a certain type, such as a [classname]#String# or -[classname]#Date#. The bound property, on the other hand, could have some -entirely different type. Conversion between a representation edited by the field -and the model defined in the property is handler with a converter that -implements the [interfacename]#Converter# interface. - -Most common type conversions, such as between string and integer, are handled by -the default converters. They are created in a converter factory global in the -application. - -[[datamodel.properties.converter.basic]] -=== Basic Use of Converters - -The [methodname]#setConverter([interfacename]#Converter#)# method sets the -converter for a field. The method is defined in [classname]#AbstractField#. - - ----- -// Have an integer property -final ObjectProperty<Integer> property = - new ObjectProperty<Integer>(42); - -// Create a TextField, which edits Strings -final TextField tf = new TextField("Name"); - -// Use a converter between String and Integer -tf.setConverter(new StringToIntegerConverter()); - -// And bind the field -tf.setPropertyDataSource(property); ----- - -The built-in converters are the following: - -[[datamodel.properties.converter.basic.built-in]] -.Built-in Converters -[options="header"] -|=============== -|Converter|Representation|Model -|[classname]#StringToIntegerConverter#|[classname]#String#|[classname]#Integer# -|[classname]#StringToDoubleConverter#|[classname]#String#|[classname]#Double# -|[classname]#StringToNumberConverter#|[classname]#String#|[classname]#Number# -|[classname]#StringToBooleanConverter#|[classname]#String#|[classname]#Boolean# -|[classname]#StringToDateConverter#|[classname]#String#|[classname]#Date# -|[classname]#DateToLongConverter#|[classname]#Date#|[classname]#Long# - -|=============== - - - -In addition, there is a [classname]#ReverseConverter# that takes a converter as -a parameter and reverses the conversion direction. - -If a converter already exists for a type, the -[methodname]#setConverter([interfacename]#Class#)# retrieves the converter for -the given type from the converter factory, and then sets it for the field. This -method is used implicitly when binding field to a property data source. - - -[[datamodel.properties.converter.custom]] -=== Implementing a Converter - -A conversion always occurs between a __representation type__, edited by the -field component, and a __model type__, that is, the type of the property data -source. Converters implement the [interfacename]#Converter# interface defined in -the [package]#com.vaadin.data.util.converter# package. - -For example, let us assume that we have a simple [classname]#Complex# type for -storing complex values. - - ----- -public class ComplexConverter - implements Converter<String, Complex> { - @Override - public Complex convertToModel(String value, Locale locale) - throws ConversionException { - String parts[] = - value.replaceAll("[\\(\\)]", "").split(","); - if (parts.length != 2) - throw new ConversionException( - "Unable to parse String to Complex"); - return new Complex(Double.parseDouble(parts[0]), - Double.parseDouble(parts[1])); - } - - @Override - public String convertToPresentation(Complex value, - Locale locale) - throws ConversionException { - return "("+value.getReal()+","+value.getImag()+")"; - } - - @Override - public Class<Complex> getModelType() { - return Complex.class; - } - - @Override - public Class<String> getPresentationType() { - return String.class; - } -} ----- - -The conversion methods get the locale for the conversion as a parameter. - - -[[datamodel.properties.converter.converterfactory]] -=== Converter Factory - -If a field does not directly allow editing a property type, a default converter -is attempted to create using an application-global converter factory. If you -define your own converters that you wish to include in the converter factory, -you need to implement one yourself. While you could implement the -[interfacename]#ConverterFactory# interface, it is usually easier to just extend -[classname]#DefaultConverterFactory#. - - ----- -class MyConverterFactory extends DefaultConverterFactory { - @Override - public <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> - createConverter(Class<PRESENTATION> presentationType, - Class<MODEL> modelType) { - // Handle one particular type conversion - if (String.class == presentationType && - Complex.class == modelType) - return (Converter<PRESENTATION, MODEL>) - new ComplexConverter(); - - // Default to the supertype - return super.createConverter(presentationType, - modelType); - } -} - -// Use the factory globally in the application -Application.getCurrentApplication().setConverterFactory( - new MyConverterFactory()); ----- - - - -ifdef::web[] -[[datamodel.properties.implementing]] -== Implementing the [classname]#Property# Interface - -Implementation of the [classname]#Property# interface requires defining setters -and getters for the value and the __read-only__ mode. Only a getter is needed -for the property type, as the type is often fixed in property implementations. - -The following example shows a simple implementation of the [classname]#Property# -interface: - - ----- -class MyProperty implements Property { - Integer data = 0; - boolean readOnly = false; - - // Return the data type of the model - public Class<?> getType() { - return Integer.class; - } - - public Object getValue() { - return data; - } - - // Override the default implementation in Object - @Override - public String toString() { - return Integer.toHexString(data); - } - - public boolean isReadOnly() { - return readOnly; - } - - public void setReadOnly(boolean newStatus) { - readOnly = newStatus; - } - - public void setValue(Object newValue) - throws ReadOnlyException, ConversionException { - if (readOnly) - throw new ReadOnlyException(); - - // Already the same type as the internal representation - if (newValue instanceof Integer) - data = (Integer) newValue; - - // Conversion from a string is required - else if (newValue instanceof String) - try { - data = Integer.parseInt((String) newValue, 16); - } catch (NumberFormatException e) { - throw new ConversionException(); - } - else - // Don't know how to convert any other types - throw new ConversionException(); - - // Reverse decode the hexadecimal value - } -} - -// Instantiate the property and set its data -MyProperty property = new MyProperty(); -property.setValue(42); - -// Bind it to a component -final TextField tf = new TextField("Name", property); ----- - -The components get the displayed value by the [methodname]#toString()# method, -so it is necessary to override it. To allow editing the value, value returned in -the [methodname]#toString()# must be in a format that is accepted by the -[methodname]#setValue()# method, unless the property is read-only. The -[methodname]#toString()# can perform any type conversion necessary to make the -internal type a string, and the [methodname]#setValue()# must be able to make a -reverse conversion. - -The implementation example does not notify about changes in the property value -or in the read-only mode. You should normally also implement at least the -[classname]#Property.ValueChangeNotifier# and -[classname]#Property.ReadOnlyStatusChangeNotifier#. See the -[classname]#ObjectProperty# class for an example of the implementation. - -endif::web[] - - - |