]> source.dussan.org Git - vaadin-framework.git/commitdiff
Converter support and updated data source logic (#8990, #8991)
authorArtur Signell <artur@vaadin.com>
Tue, 19 Jun 2012 13:14:06 +0000 (16:14 +0300)
committerArtur Signell <artur@vaadin.com>
Thu, 21 Jun 2012 14:11:26 +0000 (17:11 +0300)
src/com/vaadin/data/util/converter/ConverterUtil.java
src/com/vaadin/ui/AbstractField.java
src/com/vaadin/ui/Label.java
tests/server-side/com/vaadin/tests/data/bean/Person.java
tests/server-side/com/vaadin/tests/server/component/label/LabelConverters.java [new file with mode: 0644]

index 8be8ae799eb2c6a85aac1543278ad663a7aa55aa..5fe3101db235a28c7ba854e2c205226aa97f6e3b 100644 (file)
@@ -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 <UITYPE, MODELTYPE> Converter<UITYPE, MODELTYPE> getConverter(
             Class<UITYPE> uiType, Class<MODELTYPE> 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;
+    }
 }
index 3c78c21b53fb7ac55917eb7294061842727b3fb5..b74dba6d65233a1cf292cc9f5ada2df918feef41 100644 (file)
@@ -701,8 +701,8 @@ public abstract class AbstractField<T> 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)
index 12b9aeab664f3bb8a2885746fa1cda1c42b94687..12e1f9590ee48e1897ac27cd7224e6edafd45c96 100644 (file)
@@ -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<String>,
     @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<String, Object> converter = null;
 
-    private Property<String> dataSource;
+    private Property<String> dataSource = null;
 
     /**
      * Creates an empty Label.
@@ -113,7 +118,9 @@ public class Label extends AbstractComponent implements Property<String>,
      * @param contentMode
      */
     public Label(String content, ContentMode contentMode) {
-        this(new ObjectProperty<String>(content, String.class), contentMode);
+        setValue(content);
+        setContentMode(contentMode);
+        setWidth(100, Unit.PERCENTAGE);
     }
 
     /**
@@ -126,15 +133,7 @@ public class Label extends AbstractComponent implements Property<String>,
     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<String>,
      * @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<String>,
             ((Property.ValueChangeNotifier) dataSource).removeListener(this);
         }
 
-        // Sets the new data source
+        if (!ConverterUtil.canConverterHandle(getConverter(), String.class,
+                newDataSource.getType())) {
+            // Try to find a converter
+            Converter<String, ?> 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<String>,
     protected void fireValueChange() {
         // Set the error message
         fireEvent(new Label.ValueChangeEvent(this));
-        requestRepaint();
     }
 
     /**
@@ -340,6 +354,10 @@ public class Label extends AbstractComponent implements Property<String>,
      * @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<String>,
         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<String, Object> 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<String, ?> converter) {
+        this.converter = (Converter<String, Object>) converter;
+        requestRepaint();
+    }
+
 }
index 2cb3a29368c3ad3e6894d8e6f38bc1af57d15b43..f7bad31d0ed7476d78f9b5d5109fcd8c3b9acb74 100644 (file)
@@ -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 (file)
index 0000000..e79bd84
--- /dev/null
@@ -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<String>(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<Integer>(Person.createTestPerson1(),
+                "age");
+        l.setPropertyDataSource(ds);
+        assertEquals(String.valueOf(Person.createTestPerson1().getAge()),
+                l.getValue());
+    }
+
+    public void testSetValueWithDataSource() {
+        try {
+            MethodProperty<String> property = new MethodProperty<String>(
+                    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());
+    }
+}