]> source.dussan.org Git - vaadin-framework.git/commitdiff
Fix for #4311
authorJohn Alhroos <john.ahlroos@itmill.com>
Tue, 25 May 2010 13:15:27 +0000 (13:15 +0000)
committerJohn Alhroos <john.ahlroos@itmill.com>
Tue, 25 May 2010 13:15:27 +0000 (13:15 +0000)
svn changeset:13359/svn branch:6.4

src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
src/com/vaadin/ui/DateField.java
tests/src/com/vaadin/tests/components/datefield/DateFieldUnparsableDate.java
tests/src/com/vaadin/tests/components/datefield/DefaultHandleUnparsableDateField.java [new file with mode: 0644]

index 8d5c21c512be9c071effa86a308a24dee7a821d7..b8a004e6996e075a52678b7a2737b4ebe5447644 100644 (file)
@@ -27,6 +27,7 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
 \r
     private final VOverlay popup;\r
     private boolean open = false;\r
+    private boolean parsable = true;\r
 \r
     public VPopupCalendar() {\r
         super();\r
@@ -51,7 +52,10 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
     @Override\r
     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
         boolean lastReadOnlyState = readonly;\r
+        parsable = uidl.getBooleanAttribute("parsable");\r
+\r
         super.updateFromUIDL(uidl, client);\r
+\r
         popup.setStyleName(VDateField.CLASSNAME + "-popup "\r
                 + VDateField.CLASSNAME + "-"\r
                 + resolutionToString(currentResolution));\r
@@ -174,4 +178,15 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
         return fieldExtraWidth;\r
     }\r
 \r
+    @Override\r
+    protected void buildDate() {\r
+        // Save previous value\r
+        String previousValue = getText();\r
+        super.buildDate();\r
+\r
+        // Restore previous value if the input could not be parsed\r
+        if (!parsable) {\r
+            setText(previousValue);\r
+        }\r
+    }\r
 }\r
index 510676b3a47ec3ee27119ff50418a888450fd32f..209c5cabde3376bc5d363727e81a3cb7aff0473c 100644 (file)
@@ -356,4 +356,12 @@ public class VTextualDate extends VDateField implements Paintable, Field,
         text.setFocus(true);
     }
 
+    protected String getText() {
+        return text.getText();
+    }
+
+    protected void setText(String text) {
+        this.text.setText(text);
+    }
+
 }
index 45fd45716d29c64f9ad1fc91ef7688174d420954..52f6d60a9dc4346d5bdbc784815b257c8316cc76 100644 (file)
@@ -12,6 +12,7 @@ import java.util.Locale;
 import java.util.Map;
 
 import com.vaadin.data.Property;
+import com.vaadin.data.Validator.InvalidValueException;
 import com.vaadin.event.FieldEvents;
 import com.vaadin.event.FieldEvents.BlurEvent;
 import com.vaadin.event.FieldEvents.BlurListener;
@@ -19,6 +20,7 @@ import com.vaadin.event.FieldEvents.FocusEvent;
 import com.vaadin.event.FieldEvents.FocusListener;
 import com.vaadin.terminal.PaintException;
 import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.UserError;
 import com.vaadin.terminal.gwt.client.ui.VDateField;
 import com.vaadin.terminal.gwt.client.ui.VPopupCalendar;
 
@@ -119,6 +121,13 @@ public class DateField extends AbstractField implements
 
     private boolean lenient = false;
 
+    private String dateString = null;
+
+    /**
+     * Was the last entered string parsable?
+     */
+    private boolean parsingSucceeded = true;
+
     /**
      * Determines if week numbers are shown in the date selector.
      */
@@ -130,6 +139,7 @@ public class DateField extends AbstractField implements
      * Constructs an empty <code>DateField</code> with no caption.
      */
     public DateField() {
+        setInvalidAllowed(false);
     }
 
     /**
@@ -140,6 +150,7 @@ public class DateField extends AbstractField implements
      */
     public DateField(String caption) {
         setCaption(caption);
+        setInvalidAllowed(false);
     }
 
     /**
@@ -164,6 +175,7 @@ public class DateField extends AbstractField implements
      *            the Property to be edited with this editor.
      */
     public DateField(Property dataSource) throws IllegalArgumentException {
+        setInvalidAllowed(false);
         if (!Date.class.isAssignableFrom(dataSource.getType())) {
             throw new IllegalArgumentException("Can't use "
                     + dataSource.getType().getName()
@@ -186,6 +198,7 @@ public class DateField extends AbstractField implements
      *            the Date value.
      */
     public DateField(String caption, Date value) {
+        setInvalidAllowed(false);
         setValue(value);
         setCaption(caption);
     }
@@ -216,6 +229,7 @@ public class DateField extends AbstractField implements
 
         target.addAttribute("type", type);
         target.addAttribute(VDateField.WEEK_NUMBERS, isShowISOWeekNumbers());
+        target.addAttribute("parsable", parsingSucceeded);
 
         // Gets the calendar
         final Calendar calendar = getCalendar();
@@ -264,6 +278,7 @@ public class DateField extends AbstractField implements
     @Override
     public void changeVariables(Object source, Map variables) {
         super.changeVariables(source, variables);
+        setComponentError(null);
 
         if (!isReadOnly()
                 && (variables.containsKey("year")
@@ -281,7 +296,7 @@ public class DateField extends AbstractField implements
 
             // this enables analyzing invalid input on the server
             Object o = variables.get("dateString");
-            String dateString = null;
+            dateString = null;
             if (o != null) {
                 dateString = o.toString();
             }
@@ -345,7 +360,10 @@ public class DateField extends AbstractField implements
 
             if (newDate == null && dateString != null && !"".equals(dateString)) {
                 try {
-                    setValue(handleUnparsableDateString(dateString));
+                    Date parsedDate = handleUnparsableDateString(dateString);
+                    parsingSucceeded = true;
+                    setValue(parsedDate, true);
+
                     /*
                      * Ensure the value is sent to the client if the value is
                      * set to the same as the previous (#4304). Does not repaint
@@ -354,13 +372,25 @@ public class DateField extends AbstractField implements
                      */
                     requestRepaint();
                 } catch (ConversionException e) {
-                    // FIXME: Should not throw the exception but set an error
-                    // message for the field. And should retain the entered
-                    // value.
-                    throw e;
+                    /*
+                     * Sets the component error to the Conversion Exceptions
+                     * message. This can be overriden in
+                     * handleUnparsableDateString.
+                     */
+                    setComponentError(new UserError(e.getLocalizedMessage()));
+
+                    /*
+                     * The value of the DateField should be null if an invalid
+                     * value has been given. Not using setValue() since we do
+                     * not want to cause the client side value to change.
+                     */
+                    parsingSucceeded = false;
+                    setInternalValue(null);
+                    fireValueChange(true);
                 }
             } else if (newDate != oldDate
                     && (newDate == null || !newDate.equals(oldDate))) {
+                parsingSucceeded = true;
                 setValue(newDate, true); // Don't require a repaint, client
                 // updates itself
             }
@@ -392,7 +422,7 @@ public class DateField extends AbstractField implements
      */
     protected Date handleUnparsableDateString(String dateString)
             throws Property.ConversionException {
-        throw new Property.ConversionException();
+        throw new Property.ConversionException("Date format not recognized");
     }
 
     /* Property features */
@@ -430,13 +460,25 @@ public class DateField extends AbstractField implements
         setValue(newValue, false);
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.ui.AbstractField#setValue(java.lang.Object, boolean)
+     */
     @Override
     public void setValue(Object newValue, boolean repaintIsNotNeeded)
             throws Property.ReadOnlyException, Property.ConversionException {
 
         // Allows setting dates directly
         if (newValue == null || newValue instanceof Date) {
-            super.setValue(newValue, repaintIsNotNeeded);
+            try {
+                super.setValue(newValue, repaintIsNotNeeded);
+                parsingSucceeded = true;
+            } catch (InvalidValueException ive) {
+                // Thrown if validator fails
+                parsingSucceeded = false;
+                throw ive;
+            }
         } else {
 
             // Try to parse as string
@@ -444,8 +486,11 @@ public class DateField extends AbstractField implements
                 final SimpleDateFormat parser = new SimpleDateFormat();
                 final Date val = parser.parse(newValue.toString());
                 super.setValue(val, repaintIsNotNeeded);
+                parsingSucceeded = true;
             } catch (final ParseException e) {
-                throw new Property.ConversionException(e.getMessage());
+                parsingSucceeded = false;
+                throw new Property.ConversionException(
+                        "Date format not recognized");
             }
         }
     }
@@ -611,4 +656,31 @@ public class DateField extends AbstractField implements
         requestRepaint();
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.ui.AbstractField#isEmpty()
+     */
+    @Override
+    protected boolean isEmpty() {
+        /*
+         * Logically isEmpty() should return false also in the case that the
+         * entered value is invalid.
+         */
+        return dateString == null || dateString.equals("");
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.ui.AbstractField#isValid()
+     */
+    @Override
+    public boolean isValid() {
+        /*
+         * For the DateField to be valid it has to be parsable also
+         */
+        boolean parsable = isEmpty() || (!isEmpty() && getValue() != null);
+        return parsable && super.isValid();
+    }
 }
index b0c06acb7a97f52653d0f47baa62b8056b739841..ef0cbf03e7b2e8cda2f0a91a9091c21f142a846c 100644 (file)
@@ -2,20 +2,28 @@ package com.vaadin.tests.components.datefield;
 \r
 import java.util.Date;\r
 \r
+import com.vaadin.data.Property;\r
 import com.vaadin.tests.components.TestBase;\r
 import com.vaadin.ui.DateField;\r
 \r
 public class DateFieldUnparsableDate extends TestBase {\r
 \r
     public class MyDateField extends DateField {\r
+        Date oldDate = null;\r
         public MyDateField(String caption) {\r
             super(caption);\r
+            addListener(new Property.ValueChangeListener() {\r
+                public void valueChange(\r
+                        com.vaadin.data.Property.ValueChangeEvent event) {\r
+                    oldDate = (Date) getValue();\r
+                }\r
+            });\r
         }\r
 \r
         @Override\r
         protected Date handleUnparsableDateString(String dateString)\r
                 throws ConversionException {\r
-            return (Date) getValue();\r
+            return oldDate;\r
         }\r
     }\r
 \r
diff --git a/tests/src/com/vaadin/tests/components/datefield/DefaultHandleUnparsableDateField.java b/tests/src/com/vaadin/tests/components/datefield/DefaultHandleUnparsableDateField.java
new file mode 100644 (file)
index 0000000..bcdc826
--- /dev/null
@@ -0,0 +1,43 @@
+package com.vaadin.tests.components.datefield;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.validator.NullValidator;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.DateField;
+
+@SuppressWarnings("serial")
+public class DefaultHandleUnparsableDateField extends TestBase {
+
+    @Override
+    protected void setup() {
+        final DateField date = new DateField("Default DateField");
+        date.setImmediate(true);
+        addComponent(date);
+        date.addListener(new Property.ValueChangeListener() {
+            public void valueChange(ValueChangeEvent event) {
+                if (date.isValid()) {
+                    getMainWindow().showNotification(date.toString());
+                }
+
+            }
+        });
+
+        final DateField validated = new DateField("Validated Default DateField");
+        validated.setImmediate(true);
+        validated.addValidator(new NullValidator("Validator: Date is NULL",
+                false));
+        addComponent(validated);
+    }
+
+    @Override
+    protected String getDescription() {
+        return "By default the DateField should handle an unparsable date field without throwing an exception";
+    }
+
+    @Override
+    protected Integer getTicketNumber() {
+        return 4311;
+    }
+
+}