From d627ad58d2d11a09947a8eac4cd12b72c3d02669 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 19 Jun 2012 16:14:06 +0300 Subject: [PATCH] Converter support and updated data source logic (#8990, #8991) --- .../data/util/converter/ConverterUtil.java | 31 ++++++- src/com/vaadin/ui/AbstractField.java | 4 +- src/com/vaadin/ui/Label.java | 86 ++++++++++++++----- .../com/vaadin/tests/data/bean/Person.java | 10 +++ .../component/label/LabelConverters.java | 59 +++++++++++++ 5 files changed, 164 insertions(+), 26 deletions(-) create mode 100644 tests/server-side/com/vaadin/tests/server/component/label/LabelConverters.java diff --git a/src/com/vaadin/data/util/converter/ConverterUtil.java b/src/com/vaadin/data/util/converter/ConverterUtil.java index 8be8ae799e..5fe3101db2 100644 --- a/src/com/vaadin/data/util/converter/ConverterUtil.java +++ b/src/com/vaadin/data/util/converter/ConverterUtil.java @@ -3,11 +3,12 @@ */ package com.vaadin.data.util.converter; +import java.io.Serializable; import java.util.Locale; import com.vaadin.Application; -public class ConverterUtil { +public class ConverterUtil implements Serializable { public static Converter getConverter( Class uiType, Class modelType) { @@ -110,4 +111,32 @@ public class ConverterUtil { } + /** + * Checks if the given converter can handle conversion between the given + * presentation and model type + * + * @param converter + * The converter to check + * @param presentationType + * The presentation type + * @param modelType + * The model type + * @return true if the converter supports conversion between the given + * presentation and model type, false otherwise + */ + public static boolean canConverterHandle(Converter converter, + Class presentationType, Class modelType) { + if (converter == null) { + return false; + } + + if (!modelType.isAssignableFrom(converter.getModelType())) { + return false; + } + if (!presentationType.isAssignableFrom(converter.getPresentationType())) { + return false; + } + + return true; + } } diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java index 3c78c21b53..b74dba6d65 100644 --- a/src/com/vaadin/ui/AbstractField.java +++ b/src/com/vaadin/ui/AbstractField.java @@ -701,8 +701,8 @@ public abstract class AbstractField extends AbstractComponent implements // Check if the current converter is compatible. if (newDataSource != null - && (getConverter() == null || !newDataSource.getType() - .isAssignableFrom(getConverter().getModelType()))) { + && !ConverterUtil.canConverterHandle(getConverter(), getType(), + newDataSource.getType())) { // Changing from e.g. Number -> Double should set a new converter, // changing from Double -> Number can keep the old one (Property // accepts Number) diff --git a/src/com/vaadin/ui/Label.java b/src/com/vaadin/ui/Label.java index 12b9aeab66..12e1f9590e 100644 --- a/src/com/vaadin/ui/Label.java +++ b/src/com/vaadin/ui/Label.java @@ -7,7 +7,8 @@ package com.vaadin.ui; import java.lang.reflect.Method; import com.vaadin.data.Property; -import com.vaadin.data.util.ObjectProperty; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.ConverterUtil; import com.vaadin.terminal.gwt.client.ui.label.ContentMode; import com.vaadin.terminal.gwt.client.ui.label.LabelState; @@ -76,9 +77,13 @@ public class Label extends AbstractComponent implements Property, @Deprecated public static final ContentMode CONTENT_DEFAULT = ContentMode.TEXT; - private static final String DATASOURCE_MUST_BE_SET = "Datasource must be set"; + /** + * A converter used to convert from the data model type to the field type + * and vice versa. Label type is always String. + */ + private Converter converter = null; - private Property dataSource; + private Property dataSource = null; /** * Creates an empty Label. @@ -113,7 +118,9 @@ public class Label extends AbstractComponent implements Property, * @param contentMode */ public Label(String content, ContentMode contentMode) { - this(new ObjectProperty(content, String.class), contentMode); + setValue(content); + setContentMode(contentMode); + setWidth(100, Unit.PERCENTAGE); } /** @@ -126,15 +133,7 @@ public class Label extends AbstractComponent implements Property, public Label(Property contentSource, ContentMode contentMode) { setPropertyDataSource(contentSource); setContentMode(contentMode); - setWidth(100, UNITS_PERCENTAGE); - } - - @Override - public void updateState() { - super.updateState(); - // We don't know when the text is updated so update it here before - // sending the state to the client - getState().setText(getValue()); + setWidth(100, Unit.PERCENTAGE); } @Override @@ -149,24 +148,34 @@ public class Label extends AbstractComponent implements Property, * @return the Value of the label. */ public String getValue() { - if (dataSource == null) { - throw new IllegalStateException(DATASOURCE_MUST_BE_SET); + if (getPropertyDataSource() == null) { + // Use internal value if we are running without a data source + return getState().getText(); } - return dataSource.getValue(); + return ConverterUtil.convertFromModel(getPropertyDataSource() + .getValue(), String.class, getConverter(), getLocale()); } /** * Set the value of the label. Value of the label is the XML contents of the * label. * - * @param newValue + * @param newStringValue * the New value of the label. */ - public void setValue(Object newValue) { - if (dataSource == null) { - throw new IllegalStateException(DATASOURCE_MUST_BE_SET); + public void setValue(Object newStringValue) { + if (newStringValue != null && newStringValue.getClass() != String.class) { + throw new Converter.ConversionException("Value of type " + + newStringValue.getClass() + " cannot be assigned to " + + String.class.getName()); + } + if (getPropertyDataSource() == null) { + getState().setText((String) newStringValue); + requestRepaint(); + } else { + throw new IllegalStateException( + "Label is only a Property.Viewer and cannot update its data source"); } - dataSource.setValue(newValue); } /** @@ -215,7 +224,13 @@ public class Label extends AbstractComponent implements Property, ((Property.ValueChangeNotifier) dataSource).removeListener(this); } - // Sets the new data source + if (!ConverterUtil.canConverterHandle(getConverter(), String.class, + newDataSource.getType())) { + // Try to find a converter + Converter c = ConverterUtil.getConverter(String.class, + newDataSource.getType()); + setConverter(c); + } dataSource = newDataSource; // Listens the new data source if possible @@ -331,7 +346,6 @@ public class Label extends AbstractComponent implements Property, protected void fireValueChange() { // Set the error message fireEvent(new Label.ValueChangeEvent(this)); - requestRepaint(); } /** @@ -340,6 +354,10 @@ public class Label extends AbstractComponent implements Property, * @see com.vaadin.data.Property.ValueChangeListener#valueChange(Property.ValueChangeEvent) */ public void valueChange(Property.ValueChangeEvent event) { + // Update the internal value from the data source + getState().setText(getValue()); + requestRepaint(); + fireValueChange(); } @@ -418,4 +436,26 @@ public class Label extends AbstractComponent implements Property, return res.toString(); } + /** + * Gets the converter used to convert the property data source value to the + * label value. + * + * @return The converter or null if none is set. + */ + public Converter getConverter() { + return converter; + } + + /** + * Sets the converter used to convert the label value to the property data + * source type. The converter must have a presentation type of String. + * + * @param converter + * The new converter to use. + */ + public void setConverter(Converter converter) { + this.converter = (Converter) converter; + requestRepaint(); + } + } diff --git a/tests/server-side/com/vaadin/tests/data/bean/Person.java b/tests/server-side/com/vaadin/tests/data/bean/Person.java index 2cb3a29368..f7bad31d0e 100644 --- a/tests/server-side/com/vaadin/tests/data/bean/Person.java +++ b/tests/server-side/com/vaadin/tests/data/bean/Person.java @@ -130,4 +130,14 @@ public class Person { this.birthDate = birthDate; } + public static Person createTestPerson1() { + return new Person("Foo", "Bar", "yeah@cool.com", 46, Sex.MALE, + new Address("Street", 1123, "Turku", Country.FINLAND)); + } + + public static Person createTestPerson2() { + return new Person("Maya", "Dinkelstein", "maya@foo.bar", 18, + Sex.FEMALE, new Address("Red street", 12, "Amsterdam", + Country.NETHERLANDS)); + } } diff --git a/tests/server-side/com/vaadin/tests/server/component/label/LabelConverters.java b/tests/server-side/com/vaadin/tests/server/component/label/LabelConverters.java new file mode 100644 index 0000000000..e79bd84741 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/component/label/LabelConverters.java @@ -0,0 +1,59 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.tests.server.component.label; + +import junit.framework.TestCase; + +import com.vaadin.Application; +import com.vaadin.data.Property; +import com.vaadin.data.util.MethodProperty; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.ui.Label; + +public class LabelConverters extends TestCase { + + public void testLabelSetDataSourceLaterOn() { + Person p = Person.createTestPerson1(); + Label l = new Label("My label"); + assertEquals("My label", l.getValue()); + assertNull(l.getConverter()); + l.setPropertyDataSource(new MethodProperty(p, "firstName")); + assertEquals(p.getFirstName(), l.getValue()); + p.setFirstName("123"); + assertEquals("123", l.getValue()); + } + + public void testIntegerDataSource() { + Application.setCurrentApplication(new Application()); + Label l = new Label("Foo"); + Property ds = new MethodProperty(Person.createTestPerson1(), + "age"); + l.setPropertyDataSource(ds); + assertEquals(String.valueOf(Person.createTestPerson1().getAge()), + l.getValue()); + } + + public void testSetValueWithDataSource() { + try { + MethodProperty property = new MethodProperty( + Person.createTestPerson1(), "firstName"); + Label l = new Label(property); + l.setValue("Foo"); + fail("setValue should throw an exception when a data source is set"); + } catch (Exception e) { + } + + } + + public void testLabelWithoutDataSource() { + Label l = new Label("My label"); + assertEquals("My label", l.getValue()); + assertNull(l.getConverter()); + assertNull(l.getPropertyDataSource()); + l.setValue("New value"); + assertEquals("New value", l.getValue()); + assertNull(l.getConverter()); + assertNull(l.getPropertyDataSource()); + } +} -- 2.39.5