* doc/tmpl/* * hildon-widgets/* moved widget descriptions to respective source file...
[hildon] / hildon-widgets / hildon-date-editor.c
index 9cec80d..0b2ae20 100644 (file)
  *
  */
 
-/* HILDON DOC
- * @shortdesc: DateEditor is a widget for setting, getting and showing a
- * date.
- * @longdesc: The date editor consists of a GtkLabel that shows the current
- * date in localized form and an icon. Clicking on either the label or the
- * icon opens the #HildonCalendarPopup used for selecting the date.
- * Similarly, if the editor has the focus, and space or enter key is
- * pressed, the #HildonCalendarPopup will open. 
+/**
+ * SECTION:hildon-date-editor
+ * @short_description: A widget which queries a date from user or opens
+ * a HildonCalendarPopup
+ * @see_also: #HildonCalendarPopup, #HildonTimeEditor
  * 
- * @seealso: #HildonTimeEditor, #HildonCalendarPopup
+ * HildonDateEditor is a widget with three entry fields (day, month,
+ * year) and an icon (eventbox): clicking on the icon opens up a
+ * HildonCalendarPopup.
  */
 
 #include <glib.h>
 #include <gtk/gtk.h>
-#include <gtk/gtkmarshal.h>
 #include <gdk/gdkkeysyms.h>
 #include <time.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <langinfo.h>
 
 #include <hildon-widgets/hildon-date-editor.h>
 #include <hildon-widgets/hildon-calendar-popup.h>
@@ -50,6 +47,7 @@
 #include <hildon-widgets/hildon-defines.h>
 #include <hildon-widgets/hildon-input-mode-hint.h>
 #include "hildon-composite-widget.h"
+#include "hildon-marshalers.h"
 
 #ifdef HAVE_CONFIG_H
 #include<config.h>
 #include<libintl.h>
 #define _(string) dgettext(PACKAGE, string)
 
-#define MAX_DATE_LEN 256
 #define ENTRY_BORDERS 11
 #define DATE_EDITOR_HEIGHT 30
-#define BUTTON_SPACING 6
 
 #define DAY_ENTRY_WIDTH 2
 #define MONTH_ENTRY_WIDTH 2
 #define YEAR_ENTRY_WIDTH 4
 
+#define DEFAULT_MIN_YEAR 1970
+#define DEFAULT_MAX_YEAR 2037
+
 #define HILDON_DATE_EDITOR_GET_PRIVATE(obj) \
         (G_TYPE_INSTANCE_GET_PRIVATE((obj),\
         HILDON_DATE_EDITOR_TYPE, HildonDateEditorPrivate));
@@ -75,8 +74,6 @@ static GtkContainerClass *parent_class;
 
 typedef struct _HildonDateEditorPrivate HildonDateEditorPrivate;
 
-static int hildon_date_editor_get_font_width(GtkWidget * widget);
-
 static void
 hildon_date_editor_class_init(HildonDateEditorClass * editor_class);
 
@@ -89,7 +86,6 @@ hildon_date_editor_icon_press(GtkWidget * widget, GdkEventButton * event,
 static gboolean
 hildon_date_editor_entry_released(GtkWidget * widget,
                                   GdkEventButton * event, gpointer data);
-
 static gboolean
 hildon_date_editor_released(GtkWidget * widget, GdkEventButton * event,
                             gpointer data);
@@ -101,12 +97,18 @@ hildon_date_editor_keypress(GtkWidget * widget, GdkEventKey * event,
 static gboolean
 hildon_date_editor_keyrelease(GtkWidget * widget, GdkEventKey * event,
                               gpointer data);
+static void
+hildon_date_editor_entry_validate(GtkWidget *widget, gpointer data);
+
+static void
+hildon_date_editor_entry_changed(GtkEditable *widget, gpointer data);
 
 static gboolean
 hildon_date_editor_entry_focus_out(GtkWidget * widget, GdkEventFocus * event,
                                    gpointer data);
 
-static gboolean hildon_date_editor_validate_date(HildonDateEditor *editor);
+static gboolean hildon_date_editor_date_error(HildonDateEditor *editor, 
+                                             HildonDateEditorErrorType type);
 
 static gboolean hildon_date_editor_entry_focusin(GtkWidget * widget,
                                                  GdkEventFocus * event,
@@ -115,14 +117,13 @@ static void hildon_date_editor_get_property( GObject *object, guint param_id,
                                          GValue *value, GParamSpec *pspec );
 static void hildon_date_editor_set_property (GObject *object, guint param_id,
                                        const GValue *value, GParamSpec *pspec);
-static gboolean
-hildon_date_editor_mnemonic_activate(GtkWidget *widget, gboolean group_cycling);
-
 static void
 hildon_child_forall(GtkContainer * container,
                     gboolean include_internals,
                     GtkCallback callback, gpointer callback_data);
+
 static void hildon_date_editor_destroy(GtkObject * self);
+
 static void
 hildon_date_editor_size_allocate(GtkWidget * widget,
                                  GtkAllocation * allocation);
@@ -131,59 +132,46 @@ static void
 hildon_date_editor_size_request(GtkWidget * widget,
                                 GtkRequisition * requisition);
 
-static guint
-hildon_date_editor_check_locale_settings(HildonDateEditor * editor);
-
-static void hildon_date_editor_finalize(GObject * object);
+static gboolean
+_hildon_date_editor_entry_select_all(GtkWidget *widget);
 
+/* Property indices */
 enum
 {
   PROP_DAY = 1,
   PROP_MONTH,
-  PROP_YEAR
+  PROP_YEAR,
+  PROP_MIN_YEAR,
+  PROP_MAX_YEAR
 };
 
 struct _HildonDateEditorPrivate {
-    guint year; /* current year in the entry */
-    guint month;        /* current month in the entry */
-    guint day;  /* current day in the entry */
-
-    guint y_orig;       /* roll back value for year (if entry has illegal
-                           value) */
-    guint m_orig;       /* roll back value for month */
-    guint d_orig;       /* roll back value for day */
+    /* Cache of values in the entries, used in setting only parts of the date */
+    guint year;   /* current year  in the entry */
+    guint month;  /* current month in the entry */
+    guint day;    /* current day   in the entry */
 
-    gint button_press;  /* wheter to show pressed image */
+    gboolean calendar_icon_pressed;
 
-    gboolean editor_pressed;
-    gboolean valid_value;
-
-    GtkWidget *frame;   /* borders around the date */
-    GtkWidget *d_event_box_image;       /* icon */
-    GtkWidget *d_box_date;      /* hbox for date */
+    GtkWidget *frame;             /* borders around the date */
+    GtkWidget *d_event_box_image; /* icon */
+    GtkWidget *d_box_date;        /* hbox for date */
 
     GtkWidget *d_entry; /* GtkEntry for day */
     GtkWidget *m_entry; /* GtkEntry for month */
     GtkWidget *y_entry; /* GtkEntry for year */
 
-    GtkWidget *dm_delim;  /* Delimeter between day and month entries */
-    GtkWidget *my_delim;  /* Delimeter between month and year entries */
-
-    GtkWidget *d_image; /* normal icon image */
-    GtkWidget *d_image_pressed;
-    guint locale_type;
+    GList *delims;      /* List of delimeters between the fields (and possible at the ends) */
+    GtkWidget *calendar_icon;
 
-    gboolean skip_validation;
-};
+    gboolean skip_validation; /* don't validate date at all */
 
-enum {
-    MONTH_DAY_YEAR,
-    DAY_MONTH_YEAR,
-    YEAR_MONTH_DAY
+    gint min_year; /* minimum year allowed */
+    gint max_year; /* maximum year allowed */
 };
 
 enum {
-    VALIDATE_DATE,
+    DATE_ERROR,
     LAST_SIGNAL
 };
 
@@ -226,26 +214,23 @@ hildon_date_editor_class_init(HildonDateEditorClass * editor_class)
 
     gobject_class->set_property = hildon_date_editor_set_property;
     gobject_class->get_property = hildon_date_editor_get_property;
-    widget_class->mnemonic_activate = hildon_date_editor_mnemonic_activate;
     widget_class->size_request = hildon_date_editor_size_request;
     widget_class->size_allocate = hildon_date_editor_size_allocate;
     widget_class->focus = hildon_composite_widget_focus;
 
     container_class->forall = hildon_child_forall;
     GTK_OBJECT_CLASS(editor_class)->destroy = hildon_date_editor_destroy;
-    gobject_class->finalize = hildon_date_editor_finalize;
-
-    editor_class->validate_date = hildon_date_editor_validate_date; 
 
+    editor_class->date_error = hildon_date_editor_date_error; 
     
-    date_editor_signals[VALIDATE_DATE] =
-        g_signal_new("validate-date",
+    date_editor_signals[DATE_ERROR] =
+        g_signal_new("date-error",
                 G_OBJECT_CLASS_TYPE(gobject_class),
                 G_SIGNAL_RUN_LAST,
-                G_STRUCT_OFFSET(HildonDateEditorClass, validate_date),
-                NULL, NULL,
-                gtk_marshal_BOOLEAN__VOID,
-                G_TYPE_BOOLEAN, 0);
+                G_STRUCT_OFFSET(HildonDateEditorClass, date_error),
+                g_signal_accumulator_true_handled, NULL,
+               _hildon_marshal_BOOLEAN__INT,
+                G_TYPE_BOOLEAN, 1, G_TYPE_INT);
 
   /**
    * HildonDateEditor:year:
@@ -256,12 +241,12 @@ hildon_date_editor_class_init(HildonDateEditorClass * editor_class)
                                    g_param_spec_uint("year",
                                    "Current year",
                                    "Current year",
-                                   1, G_MAXUINT,
+                                   1, 2100,
                                    2005,
                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
 
   /**
-   * HildonControlbar:month:
+   * HildonDateEditor:month:
    *
    * Current month.
    */
@@ -274,7 +259,7 @@ hildon_date_editor_class_init(HildonDateEditorClass * editor_class)
                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
 
   /**
-   * HildonControlbar:day:
+   * HildonDateEditor:day:
    *
    * Current day.
    */
@@ -285,13 +270,132 @@ hildon_date_editor_class_init(HildonDateEditorClass * editor_class)
                                    1, 31,
                                    1,
                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
+
+  /**
+   * HildonDateEditor:min-year:
+   *
+   * Minimum valid year.
+   */
+  g_object_class_install_property( gobject_class, PROP_MIN_YEAR,
+                                   g_param_spec_uint("min-year",
+                                   "Minimum valid year",
+                                   "Minimum valid year",
+                                   1, 2100,
+                                   DEFAULT_MIN_YEAR,
+                                   G_PARAM_READWRITE) );
+
+  /**
+   * HildonDateEditor:max-year:
+   *
+   * Maximum valid year.
+   */
+  g_object_class_install_property( gobject_class, PROP_MAX_YEAR,
+                                   g_param_spec_uint("max-year",
+                                   "Maximum valid year",
+                                   "Maximum valid year",
+                                   1, 2100,
+                                   DEFAULT_MAX_YEAR,
+                                   G_PARAM_READWRITE) );
+}
+
+/* Forces setting of the icon to certain state. Used initially
+   and from the actual setter function */
+static void
+real_set_calendar_icon_state(HildonDateEditorPrivate *priv, 
+    gboolean pressed)
+{
+    gtk_image_set_from_icon_name(GTK_IMAGE(priv->calendar_icon),
+        pressed ? "qgn_widg_datedit_pr" : "qgn_widg_datedit",
+        HILDON_ICON_SIZE_WIDG);
+
+    priv->calendar_icon_pressed = pressed;
+}
+
+/* Sets the icon to given state (normal/pressed). Returns
+   info if the state actually changed. */
+static gboolean 
+hildon_date_editor_set_calendar_icon_state(HildonDateEditor *editor,
+    gboolean pressed)
+{
+    HildonDateEditorPrivate *priv;
+
+    g_assert(HILDON_IS_DATE_EDITOR(editor));
+
+    priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
+    if (pressed != priv->calendar_icon_pressed) {
+        real_set_calendar_icon_state(priv, pressed);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* Packing day, month and year entries depend on locale settings
+   We find out the order and all separators by converting a known
+   date to default format and inspecting the result string */
+static void apply_locale_field_order(HildonDateEditorPrivate *priv)
+{
+    GDate locale_test_date;
+    GtkWidget *delim;
+    gchar buffer[256];
+    gchar *iter, *delim_text;
+
+    g_date_set_dmy(&locale_test_date, 1, 2, 1970);
+    (void) g_date_strftime(buffer, sizeof(buffer), "%x", &locale_test_date);    
+    iter = buffer;
+
+    while (*iter)
+    {
+       gchar *endp;
+       unsigned long value;
+
+       /* Try to convert the current location into number. */
+       value = strtoul(iter, &endp, 10);
+
+       /* If the conversion didn't progress or the detected value was
+          unknown (we used a fixed date, you remember), we treat 
+          current position as a literal */
+       switch (value)
+       {
+         case 1:
+            gtk_box_pack_start(GTK_BOX(priv->d_box_date),
+                priv->d_entry, FALSE, FALSE, 0);
+            break;
+         case 2:
+            gtk_box_pack_start(GTK_BOX(priv->d_box_date),
+                priv->m_entry, FALSE, FALSE, 0);
+            break;
+         case 70:   /* %x format uses only 2 numbers for some locales */
+         case 1970:
+            gtk_box_pack_start(GTK_BOX(priv->d_box_date),
+                priv->y_entry, FALSE, FALSE, 0);
+            break;
+         default:
+            /* All non-number characters starting from current position 
+               form the delimeter */
+            for (endp = iter; *endp; endp++)
+                if (g_ascii_isdigit(*endp))
+                    break;
+
+            /* Now endp points one place past the delimeter text */
+            delim_text = g_strndup(iter, endp - iter);
+            delim = gtk_label_new(delim_text);
+            gtk_box_pack_start(GTK_BOX(priv->d_box_date),
+                           delim, FALSE, FALSE, 0);
+            priv->delims = g_list_append(priv->delims, delim);
+            g_free(delim_text);
+
+            break;
+       };
+
+       iter = endp;
+    }
 }
 
 static void hildon_date_editor_init(HildonDateEditor * editor)
 {
     HildonDateEditorPrivate *priv;
     GDate cur_date;
-    guint locale_type;
 
     priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
 
@@ -306,12 +410,8 @@ static void hildon_date_editor_init(HildonDateEditor * editor)
     priv->day = g_date_get_day(&cur_date);
     priv->month = g_date_get_month(&cur_date);
     priv->year = g_date_get_year(&cur_date);
-
-    priv->y_orig = 0;
-    priv->m_orig = 0;
-    priv->d_orig = 0;
-    priv->button_press = FALSE;
-    priv->valid_value = TRUE;
+    priv->min_year = DEFAULT_MIN_YEAR;
+    priv->max_year = DEFAULT_MAX_YEAR;
 
     /* make widgets */
     priv->frame = gtk_frame_new(NULL);
@@ -320,7 +420,6 @@ static void hildon_date_editor_init(HildonDateEditor * editor)
     priv->d_entry = gtk_entry_new();
     priv->m_entry = gtk_entry_new();
     priv->y_entry = gtk_entry_new();
-    priv->editor_pressed = FALSE;
 
     g_object_set (G_OBJECT(priv->d_entry), "input-mode", 
                   HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
@@ -342,80 +441,35 @@ static void hildon_date_editor_init(HildonDateEditor * editor)
     gtk_entry_set_has_frame(GTK_ENTRY(priv->m_entry), FALSE);
     gtk_entry_set_has_frame(GTK_ENTRY(priv->y_entry), FALSE);
 
-    priv->dm_delim = gtk_label_new(_("Ecdg_ti_date_editor_separator"));
-    priv->my_delim = gtk_label_new(_("Ecdg_ti_date_editor_separator"));
+    gtk_widget_set_composite_name(priv->d_entry, "day_entry");
+    gtk_widget_set_composite_name(priv->m_entry, "month_entry");
+    gtk_widget_set_composite_name(priv->y_entry, "year_entry");
 
     priv->d_box_date = gtk_hbox_new(FALSE, 0);
 
     priv->d_event_box_image = gtk_event_box_new();
+    priv->calendar_icon = gtk_image_new();
+    real_set_calendar_icon_state(priv, FALSE);
 
-    priv->d_image = gtk_image_new_from_icon_name("qgn_widg_datedit",
-                                                 HILDON_ICON_SIZE_WIDG);
-    priv->d_image_pressed = gtk_image_new_from_icon_name("qgn_widg_datedit_pr",
-                                                         HILDON_ICON_SIZE_WIDG);
-    g_object_ref(G_OBJECT(priv->d_image));
-    g_object_ref(G_OBJECT(priv->d_image_pressed));
-    gtk_object_sink(GTK_OBJECT(priv->d_image));
-    gtk_object_sink(GTK_OBJECT(priv->d_image_pressed));
-    /* packing */
-    /* Packing day, month and year entries depend on locale settings */
-    priv->locale_type = locale_type =
-        hildon_date_editor_check_locale_settings(editor);
-
-    if (locale_type == DAY_MONTH_YEAR)
-        gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                           priv->d_entry, FALSE, FALSE, 0);
-    else if (locale_type == MONTH_DAY_YEAR)
-        gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                           priv->m_entry, FALSE, FALSE, 0);
-    else
-        gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                           priv->y_entry, FALSE, FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                       priv->dm_delim, FALSE, FALSE, 0);
-    if (locale_type == DAY_MONTH_YEAR)
-        gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                           priv->m_entry, FALSE, FALSE, 0);
-    else if (locale_type == MONTH_DAY_YEAR)
-        gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                           priv->d_entry, FALSE, FALSE, 0);
-    else
-        gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                           priv->m_entry, FALSE, FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                       priv->my_delim, FALSE, FALSE, 0);
-    if (locale_type == DAY_MONTH_YEAR)
-        gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                           priv->y_entry, FALSE, FALSE, 0);
-    else if (locale_type == MONTH_DAY_YEAR)
-        gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                           priv->y_entry, FALSE, FALSE, 0);
-    else
-        gtk_box_pack_start(GTK_BOX(priv->d_box_date),
-                           priv->d_entry, FALSE, FALSE, 0);
+    apply_locale_field_order(priv);
 
     gtk_container_add(GTK_CONTAINER(priv->frame), priv->d_box_date);
-    gtk_container_add(GTK_CONTAINER(priv->d_event_box_image), priv->d_image);
+    gtk_container_add(GTK_CONTAINER(priv->d_event_box_image), priv->calendar_icon);
 
     gtk_widget_set_parent(priv->frame, GTK_WIDGET(editor));
     gtk_widget_set_parent(priv->d_event_box_image, GTK_WIDGET(editor));
     gtk_widget_show_all(priv->frame);
     gtk_widget_show_all(priv->d_event_box_image);
-
-
     
     /* image signal connects */
     g_signal_connect(GTK_OBJECT(priv->d_event_box_image), "button_press_event",
                      G_CALLBACK(hildon_date_editor_icon_press), editor);
-
     g_signal_connect(GTK_OBJECT(priv->d_event_box_image),
                      "button_release_event",
                      G_CALLBACK(hildon_date_editor_released), editor);
-
     g_signal_connect(GTK_OBJECT(priv->d_event_box_image), "key-press-event",
                      G_CALLBACK(hildon_date_editor_keypress), editor);
-
-    g_signal_connect(GTK_OBJECT(priv->d_image), "key-press-event",
+    g_signal_connect(GTK_OBJECT(priv->calendar_icon), "key-press-event",
                      G_CALLBACK(hildon_date_editor_keypress), editor);
 
 
@@ -467,6 +521,15 @@ static void hildon_date_editor_init(HildonDateEditor * editor)
 
     hildon_date_editor_set_date(editor, priv->year, priv->month, priv->day);
 
+    g_signal_connect(GTK_OBJECT(priv->d_entry), "changed",
+                     G_CALLBACK(hildon_date_editor_entry_changed), editor);
+
+    g_signal_connect(GTK_OBJECT(priv->m_entry), "changed",
+                     G_CALLBACK(hildon_date_editor_entry_changed), editor);
+
+    g_signal_connect(GTK_OBJECT(priv->y_entry), "changed",
+                     G_CALLBACK(hildon_date_editor_entry_changed), editor);
+
     gtk_widget_pop_composite_child();
 }
 
@@ -474,6 +537,9 @@ static void hildon_date_editor_set_property (GObject *object, guint param_id,
                                        const GValue *value, GParamSpec *pspec)
 {
   HildonDateEditor *editor = HILDON_DATE_EDITOR(object);
+  HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
+  gint val;
+
   switch (param_id)
   {
     case PROP_YEAR:
@@ -488,6 +554,32 @@ static void hildon_date_editor_set_property (GObject *object, guint param_id,
       hildon_date_editor_set_day (editor, g_value_get_uint(value));
       break;
 
+    case PROP_MIN_YEAR:
+      val = g_value_get_uint(value);
+      if (val <= priv->max_year)
+        {
+          priv->min_year = val;
+          /* Clamp current year */
+          if (hildon_date_editor_get_year (editor) < priv->min_year)
+            hildon_date_editor_set_year (editor, priv->min_year);
+        }
+      else
+        g_warning("min-year cannot be greater than max-year");
+      break;
+
+    case PROP_MAX_YEAR:
+      val = g_value_get_uint(value);
+      if (val >= priv->min_year)
+        {
+          priv->max_year = val;
+          /* Clamp current year */
+          if (hildon_date_editor_get_year (editor) > priv->max_year)
+            hildon_date_editor_set_year (editor, priv->max_year);
+        }
+      else
+        g_warning("max-year cannot be less than min-year");
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
       break;
@@ -498,6 +590,8 @@ static void hildon_date_editor_get_property( GObject *object, guint param_id,
                                          GValue *value, GParamSpec *pspec )
 {
   HildonDateEditor *editor = HILDON_DATE_EDITOR(object);
+  HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
+
   switch (param_id)
   {
     case PROP_YEAR:
@@ -512,54 +606,20 @@ static void hildon_date_editor_get_property( GObject *object, guint param_id,
       g_value_set_uint (value, hildon_date_editor_get_day (editor));
       break;
 
+    case PROP_MIN_YEAR:
+      g_value_set_uint (value, priv->min_year);
+      break;
+
+    case PROP_MAX_YEAR:
+      g_value_set_uint (value, priv->max_year);
+      break;
+    
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
       break;
   }
 }
 
-static gboolean
-hildon_date_editor_mnemonic_activate(GtkWidget *widget, gboolean group_cycling)
-
-{
-  GtkWidget *entry;
-  HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(widget);
-
-  if( priv->locale_type == MONTH_DAY_YEAR )
-    entry = priv->m_entry;
-  else
-    entry = priv->d_entry;
-
-  gtk_widget_grab_focus( entry );
-  gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
-  return TRUE;
-}
-
-static void hildon_date_editor_finalize(GObject * object)
-{
-    HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(object);
-
-    g_object_unref(G_OBJECT(priv->d_image));
-    g_object_unref(G_OBJECT(priv->d_image_pressed));
-    if( G_OBJECT_CLASS(parent_class)->finalize )
-      G_OBJECT_CLASS(parent_class)->finalize(object);
-}
-
-static guint
-hildon_date_editor_check_locale_settings(HildonDateEditor * editor)
-{
-    gchar *dfmt;
-
-    dfmt = nl_langinfo(D_FMT);
-
-    if (!strncmp(dfmt, "%d", 2))
-        return DAY_MONTH_YEAR;
-    else if (!strncmp(dfmt, "%m", 2))
-        return MONTH_DAY_YEAR;
-    else
-        return YEAR_MONTH_DAY;
-}
-
 static void hildon_child_forall(GtkContainer * container,
                                 gboolean include_internals,
                                 GtkCallback callback,
@@ -568,8 +628,8 @@ static void hildon_child_forall(GtkContainer * container,
     HildonDateEditor *editor;
     HildonDateEditorPrivate *priv;
 
-    g_return_if_fail(container);
-    g_return_if_fail(callback);
+    g_assert(HILDON_IS_DATE_EDITOR(container));
+    g_assert(callback);
 
     editor = HILDON_DATE_EDITOR(container);
     priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
@@ -594,6 +654,10 @@ static void hildon_date_editor_destroy(GtkObject * self)
         gtk_widget_unparent(priv->d_event_box_image);
         priv->d_event_box_image = NULL;
     }
+    if (priv->delims) {
+        g_list_free(priv->delims);
+        priv->delims = NULL;
+    }
 
     if (GTK_OBJECT_CLASS(parent_class)->destroy)
         GTK_OBJECT_CLASS(parent_class)->destroy(self);
@@ -602,11 +666,11 @@ static void hildon_date_editor_destroy(GtkObject * self)
 /**
  * hildon_date_editor_new:
  *
- * This function creates a new time editor. The current system date
+ * Creates a new date editor. The current system date
  * is shown in the editor.
  *
- * Return value: Pointer to a new @HildonDateEditor widget.
- **/
+ * Returns: pointer to a new @HildonDateEditor widget.
+ */
 GtkWidget *hildon_date_editor_new(void)
 {
     return GTK_WIDGET(g_object_new(HILDON_DATE_EDITOR_TYPE, NULL));
@@ -619,19 +683,65 @@ GtkWidget *hildon_date_editor_new(void)
  * @month: month
  * @day: day
  *
- * This function sets the date shown in the editor. The function returns 
- * if the date specified by the arguments is not valid, the
- * function returns.
- **/
-void hildon_date_editor_set_date(HildonDateEditor * date,
+ * Sets the date shown in the editor. 
+ */
+void hildon_date_editor_set_date(HildonDateEditor * editor,
                                  guint year, guint month, guint day)
 {
-    g_return_if_fail(date);
-    g_return_if_fail(HILDON_IS_DATE_EDITOR(date));
+    HildonDateEditorPrivate *priv;
+
+    g_return_if_fail(HILDON_IS_DATE_EDITOR(editor));
+
+    /* This function cannot be implemented by calling
+       component setters, since applying the individual
+       values one by one can make the date temporarily
+       invalid (depending on what the previous values were), 
+       which in turn causes that the desired date
+       is not set (even though it's valid). We must set all the
+       components at one go and not try to do any validation etc
+       there in between. */
+
+    g_return_if_fail(HILDON_IS_DATE_EDITOR(editor));
+    priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
 
-    hildon_date_editor_set_year(date, year);
-    hildon_date_editor_set_month(date, month);
-    hildon_date_editor_set_day(date, day);
+    if (g_date_valid_dmy(day, month, year))
+    {
+        GDate date;
+        gchar buffer[256];
+        
+        priv->year = year;
+        priv->month = month;
+        priv->day = day;
+        
+        g_date_set_dmy(&date, day, month, year);
+
+        /* We apply the new values, but do not want automatic focus move
+           etc to take place */
+        g_snprintf(buffer, sizeof(buffer), "%04d", year);
+        g_signal_handlers_block_by_func(priv->y_entry, 
+            (gpointer) hildon_date_editor_entry_changed, editor);
+        gtk_entry_set_text(GTK_ENTRY(priv->y_entry), buffer);
+        g_signal_handlers_unblock_by_func(priv->y_entry, 
+            (gpointer) hildon_date_editor_entry_changed, editor);
+
+        g_date_strftime(buffer, sizeof(buffer), "%m", &date);
+        g_signal_handlers_block_by_func(priv->m_entry, 
+            (gpointer) hildon_date_editor_entry_changed, editor);
+        gtk_entry_set_text(GTK_ENTRY(priv->m_entry), buffer);
+        g_signal_handlers_unblock_by_func(priv->m_entry, 
+            (gpointer) hildon_date_editor_entry_changed, editor);
+
+        g_date_strftime(buffer, sizeof(buffer), "%d", &date);
+        g_signal_handlers_block_by_func(priv->d_entry, 
+            (gpointer) hildon_date_editor_entry_changed, editor);
+        gtk_entry_set_text(GTK_ENTRY(priv->d_entry), buffer);
+        g_signal_handlers_unblock_by_func(priv->d_entry, 
+            (gpointer) hildon_date_editor_entry_changed, editor);
+  
+        g_object_notify(G_OBJECT(editor), "year");
+        g_object_notify(G_OBJECT(editor), "month");
+        g_object_notify(G_OBJECT(editor), "day");
+    }
 }
 
 /**
@@ -641,15 +751,14 @@ void hildon_date_editor_set_date(HildonDateEditor * date,
  * @month: month
  * @day: day
  *
- * This function returns the year, month, and day currently on the
+ * Returns: the year, month, and day currently on the
  * date editor.
- **/
+ */
 void hildon_date_editor_get_date(HildonDateEditor * date,
                                  guint * year, guint * month, guint * day)
 {
     HildonDateEditorPrivate *priv;
 
-    g_return_if_fail(date);
     g_return_if_fail(HILDON_IS_DATE_EDITOR(date));
     g_return_if_fail(year);
     g_return_if_fail(month);
@@ -657,33 +766,51 @@ void hildon_date_editor_get_date(HildonDateEditor * date,
 
     priv = HILDON_DATE_EDITOR_GET_PRIVATE(date);
 
-    *year = priv->year;
-    *month = priv->month;
-    *day = priv->day;
+    /* FIXME: The role of priv->{day,month,year} members vs. entry contents
+              is unclear. They do not neccesarily match and still the texts are
+              used as return values and members for some internal validation!!
+              At least a partly reason is to allow empty text to become
+              0 return value, while members are restricted to valid ranges?!
+              However, if we change the current way, we are likely to break 
+              some applications  if they rely on some specific way how this 
+              widget currently handles empty values and temporarily invalid values.
+
+              The key issue is this: What should the _get methods return while
+              user is editing a field and the result is incomplete. The
+              partial result? The last good result? If we return partial result
+              we also need a way to inform if the date is not valid. Current
+              implementation is some kind of hybrid of these two...
+
+              for example:
+                 hildon_date_editor_set_day(editor, hildon_date_editor_get_day(editor));
+
+              easily fails, since set_day tries to force validity while get_day
+              doesn't do that.
+
+              Proposal: Always return the same values that are shown in the
+                        fields. We add a separate flag (Or use GDate) to 
+                        indicate if the current date is valid. This would allow 
+                        setters to make the date invalid as well.
+    */
+    *year = /*priv->year;*/
+      (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)));
+    *month = /*priv->month;*/
+      (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)));
+    *day = /*priv->day;*/ 
+      (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)));
 }
 
 static gboolean hildon_date_editor_icon_press(GtkWidget * widget,
                                               GdkEventButton * event,
                                               gpointer data)
 {
-    HildonDateEditor *ed;
-    HildonDateEditorPrivate *priv;
+    g_assert(GTK_IS_WIDGET(widget));
+    g_assert(event != NULL);
+    g_assert(HILDON_IS_DATE_EDITOR(data));
 
-    g_return_val_if_fail(widget, FALSE);
-    g_return_val_if_fail(event, FALSE);
-    g_return_val_if_fail(data, FALSE);
+    if (event->button == 1)
+       hildon_date_editor_set_calendar_icon_state(HILDON_DATE_EDITOR(data), TRUE);
 
-    ed = HILDON_DATE_EDITOR(data);
-    priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
-
-    if (event->button == 1 && !priv->button_press) {
-        gtk_container_remove(GTK_CONTAINER(priv->d_event_box_image),
-                             priv->d_image);
-        gtk_container_add(GTK_CONTAINER(priv->d_event_box_image),
-                          priv->d_image_pressed);
-        gtk_widget_show_all(priv->d_event_box_image);
-        priv->button_press = TRUE;
-    }
     return FALSE;
 }
 
@@ -697,15 +824,13 @@ static gboolean hildon_date_editor_entry_released(GtkWidget * widget,
     ed = HILDON_DATE_EDITOR(data);
     priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
 
-    if (priv->valid_value && event->button == 1) {
-        GtkEntry *e = GTK_ENTRY(widget);
-        gint start = 0, end = gtk_entry_get_max_length(e);
-
-        /* We might not get focus because unvalid values in entries */
+    if (event->button == 1) {
+        /* We might not get focus because of invalid values in entries */
         if (GTK_WIDGET_HAS_FOCUS(widget))
-            gtk_editable_select_region(GTK_EDITABLE(e), start, end);
-    } else
-        priv->valid_value = TRUE;
+                       g_idle_add((GSourceFunc)
+                                       _hildon_date_editor_entry_select_all, GTK_ENTRY(widget));
+    }
+
     return FALSE;
 }
 
@@ -715,32 +840,35 @@ static gboolean hildon_date_editor_entry_focusin(GtkWidget * widget,
 {
     if (!GTK_ENTRY(widget)->button)
     {
-        GtkEntry *e = GTK_ENTRY(widget);
-        gint end = gtk_entry_get_max_length(e);
-        gtk_editable_select_region(GTK_EDITABLE(widget), 0, end);
+               g_idle_add((GSourceFunc)
+                               _hildon_date_editor_entry_select_all, GTK_ENTRY(widget));
     }
 
     return FALSE;
 }
 
 
-/* This handler is called from mainloop
-   after button exposes are processed */
-static gboolean idle_popup(gpointer data)
+static void popup_calendar_dialog(HildonDateEditor *ed)
 {
     guint y = 0, m = 0, d = 0;
-    HildonDateEditor *ed;
     GtkWidget *popup;
     GtkWidget *parent;
     guint result;
-
-    ed = HILDON_DATE_EDITOR(data);
+    GValue val = {0, };
 
     hildon_date_editor_get_date(ed, &y, &m, &d);
 
     parent = gtk_widget_get_ancestor(GTK_WIDGET(ed), GTK_TYPE_WINDOW);
     popup = hildon_calendar_popup_new(GTK_WINDOW(parent), y, m, d);
 
+    g_value_init(&val, G_TYPE_INT);
+    /* Set max/min year in calendar popup to date editor values */
+    g_object_get_property(G_OBJECT(ed), "min-year", &val);
+    g_object_set_property(G_OBJECT(popup), "min-year", &val);
+    g_object_get_property(G_OBJECT(ed), "max-year", &val);
+    g_object_set_property(G_OBJECT(popup), "max-year", &val);
+
+    /* Pop up calendar */
     result = gtk_dialog_run(GTK_DIALOG(popup));
     switch (result) {
     case GTK_RESPONSE_OK:
@@ -751,8 +879,6 @@ static gboolean idle_popup(gpointer data)
     }
 
     gtk_widget_destroy(popup);
-
-    return FALSE;
 }
 
 /* button released */
@@ -761,31 +887,161 @@ static gboolean hildon_date_editor_released(GtkWidget * widget,
                                             gpointer data)
 {
     HildonDateEditor *ed;
+
+    g_assert(GTK_IS_WIDGET(widget));
+    g_assert(event != NULL);
+    g_assert(HILDON_IS_DATE_EDITOR(data));
+
+    ed = HILDON_DATE_EDITOR(data);
+
+    if (hildon_date_editor_set_calendar_icon_state(ed, FALSE))
+        popup_calendar_dialog(ed);
+
+    return FALSE;
+}
+
+/* This is called whenever some editor filed loses the focus and
+   when the all of the fields are filled. 
+   Earlier this was called whenever an entry changed */
+/* FIXME: Validation on focus_out is broken by concept */
+static void
+hildon_date_editor_entry_validate(GtkWidget *widget, gpointer data)
+{
+    HildonDateEditor *ed;
     HildonDateEditorPrivate *priv;
+    gint d, m, y, max_days;
+    gboolean r;  /* temp return values for signals */
+    const gchar *text;        
+    gint error_code = NO_ERROR;
 
-    g_return_val_if_fail(widget, FALSE);
-    g_return_val_if_fail(event, FALSE);
-    g_return_val_if_fail(data, FALSE);
+    g_assert(HILDON_IS_DATE_EDITOR(data));
+    g_assert(GTK_IS_ENTRY(widget));
 
     ed = HILDON_DATE_EDITOR(data);
     priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
 
-    if (!priv->button_press)
-        return FALSE;
+    if (priv->skip_validation)
+       return;
 
-    /* change the icon image back to normal */
-    gtk_container_remove(GTK_CONTAINER(priv->d_event_box_image),
-                         priv->d_image_pressed);
-    gtk_container_add(GTK_CONTAINER(priv->d_event_box_image),
-                      priv->d_image);
-    gtk_widget_show_all(priv->d_event_box_image);
+    /*check if the calling entry is empty*/
+    text = gtk_entry_get_text(GTK_ENTRY(widget));
+    if(text == NULL || text[0] == 0)
+    {
+      if (widget == priv->d_entry)
+         g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0, EMPTY_DAY, &r);
+      else if(widget == priv->m_entry)
+         g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0, EMPTY_MONTH, &r);
+      else
+         g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0, EMPTY_YEAR, &r);
+
+      return;
+    }
 
-    /* Wait until exposes are ready */
-    g_idle_add(idle_popup, ed);
+    /* Ok, we now check validity. Some fields can be empty */
+    text = gtk_entry_get_text(GTK_ENTRY(priv->d_entry));
+    if (text == NULL || text[0] == 0) return;
+    d = atoi(text);
+    text = gtk_entry_get_text(GTK_ENTRY(priv->m_entry));
+    if (text == NULL || text[0] == 0) return;
+    m = atoi(text);
+    text = gtk_entry_get_text(GTK_ENTRY(priv->y_entry));
+    if (text == NULL || text[0] == 0) return;
+    y = atoi(text);
+
+    /* Did it actually change? */
+    if (d != priv->day || m != priv->month || y != priv->year)
+    {
+        /* We could/should use hildon_date_editor_set_year and such functions
+         * to set the date, instead of use gtk_entry_set_text, and then change
+        * the priv member but hildon_date_editor_set_year and such functions
+        * check if the date is valid, we do want to do date validation check
+        * here according to spec */
+
+       /* Validate month */
+        if(widget == priv->m_entry) {
+            if(m < 1) {
+                error_code = MIN_MONTH;
+                m = 1;
+            }
+            else if (m > 12) {
+                error_code = MAX_MONTH;
+                m = 12;
+            }
+        }
 
-    priv->button_press = FALSE;
+       /* Validate year */
+        if(widget == priv->y_entry) {
+            if (y < priv->min_year) {
+                error_code = MIN_YEAR;
+                y = priv->min_year;
+            }
+            else if (y > priv->max_year) {
+                error_code = MAX_YEAR;
+                y = priv->max_year;
+            }
+        }
 
-    return FALSE;
+       /* Validate day. We have to do this in every case, since
+           changing month or year can make the day number to be invalid */
+        max_days = g_date_get_days_in_month(m,y);
+        if(d < 1) {
+           error_code = MIN_DAY;
+           d = 1;
+        }
+        else if (d > max_days) {
+           if (d > 31) {         
+               error_code = MAX_DAY;
+               d = max_days;
+           }
+           else {                /* the date does not exist (is invalid) */
+               error_code = INVALID_DATE;
+               /* check what was changed and restore previous value */
+               if ( widget == priv->y_entry )
+                   y = priv->year;
+               else if ( widget == priv->m_entry )
+                   m = priv->month;
+               else
+                   d = priv->day;
+           }
+        }
+
+        if (error_code != NO_ERROR)
+        {
+            g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0, error_code, &r);
+
+            g_idle_add ((GSourceFunc) 
+                    _hildon_date_editor_entry_select_all, 
+                    widget);
+
+           /* Set focus back to invalid entry */
+            gtk_widget_grab_focus(widget);
+        }
+    }
+
+    /* Fix and reformat the date after error signal is processed. 
+       reformatting can be needed even in a such case that numerical
+       values of the date components are the same as earlier. */
+    hildon_date_editor_set_date(ed, y, m, d);
+}
+
+/* When entry becomes full, we move the focus to the next field.
+   If we are on the last field, the whole contents are validated. */
+static void
+hildon_date_editor_entry_changed(GtkEditable *ed, gpointer data)
+{
+  GtkEntry *entry;
+
+  g_assert(GTK_IS_ENTRY(ed));
+  g_assert(HILDON_IS_DATE_EDITOR(data));
+
+  entry = GTK_ENTRY(ed);
+
+  /* If day entry is full, move to next entry or validate */
+  if (g_utf8_strlen(gtk_entry_get_text(entry), -1) == gtk_entry_get_max_length(entry))
+    {
+      if (!gtk_widget_child_focus(GTK_WIDGET(data), GTK_DIR_RIGHT))
+        hildon_date_editor_entry_validate(GTK_WIDGET(entry), data);
+    }
 }
 
 static gboolean hildon_date_editor_keyrelease(GtkWidget * widget,
@@ -803,19 +1059,13 @@ static gboolean hildon_date_editor_keyrelease(GtkWidget * widget,
 
     if (event->keyval == GDK_KP_Enter || event->keyval == GDK_Return ||
         event->keyval == GDK_ISO_Enter) {
-        if (priv->editor_pressed) {
-            gtk_container_remove(GTK_CONTAINER(priv->d_event_box_image),
-                                 priv->d_image_pressed);
-            gtk_container_add(GTK_CONTAINER(priv->d_event_box_image),
-                              priv->d_image);
-            gtk_widget_show_all(priv->d_event_box_image);
-            g_idle_add(idle_popup, ed);
-            priv->editor_pressed = FALSE;
+        if (hildon_date_editor_set_calendar_icon_state(ed, FALSE))
+        {
+            popup_calendar_dialog(ed);
             return TRUE;
         }
-    }
-    else if (event->keyval == GDK_Escape)
-       priv->skip_validation = FALSE;
+    } else if (event->keyval == GDK_Escape)
+               priv->skip_validation = FALSE;
     
     return FALSE;
 }
@@ -825,465 +1075,93 @@ static gboolean hildon_date_editor_keypress(GtkWidget * widget,
                                             GdkEventKey * event,
                                             gpointer data)
 {
-
     HildonDateEditor *ed;
     HildonDateEditorPrivate *priv;
     gint pos;
 
-    g_return_val_if_fail(data, FALSE);
-    g_return_val_if_fail(widget, FALSE);
+    g_assert(HILDON_IS_DATE_EDITOR(data));
+    g_assert(GTK_IS_ENTRY(widget));
 
     ed = HILDON_DATE_EDITOR(data);
     priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
     pos = gtk_editable_get_position(GTK_EDITABLE(widget));
-
-    if (event->keyval == GDK_Return || event->keyval == GDK_ISO_Enter) {
-        if (!priv->editor_pressed) {
-            gtk_container_remove(GTK_CONTAINER(priv->d_event_box_image),
-                                 priv->d_image);
-            gtk_container_add(GTK_CONTAINER(priv->d_event_box_image),
-                              priv->d_image_pressed);
-            gtk_widget_show_all(priv->d_event_box_image);
-            priv->editor_pressed = TRUE;
-            return TRUE;
-        }
-        return FALSE;
-    }
-
-    if  (event->keyval == GDK_KP_Enter)
-           return FALSE;
        
-
-    
-    /* We don't want wrap */
-    if (event->keyval == GDK_KP_Left || event->keyval == GDK_Left)
-        if (pos == 0) {
-            if (priv->locale_type == DAY_MONTH_YEAR) {
-                if (widget == priv->d_entry)
-                    return TRUE;
-            } else {
-                if (widget == priv->m_entry)
-                    return TRUE;
-            }
-        }
-
-    if (event->keyval == GDK_KP_Right || event->keyval == GDK_Right)
-        if (widget == priv->y_entry
-            && pos >= strlen(GTK_ENTRY(widget)->text))
-            return TRUE;
-
     switch (event->keyval) {
     case GDK_Left:
-        /* left on day entry */
-        if (widget == priv->d_entry) {
-            gint pos =
-                gtk_editable_get_position(GTK_EDITABLE(priv->d_entry));
-            if (pos == 0) {
-                gtk_editable_select_region(GTK_EDITABLE(priv->d_entry), 0,
-                                           0);
-                if (priv->locale_type == DAY_MONTH_YEAR) {
-                    gtk_widget_grab_focus(priv->y_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->y_entry),
-                                              -1);
-                } else {
-                    gtk_widget_grab_focus(priv->m_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->m_entry),
-                                              -1);
-                }
-                return TRUE;
-            }
-        }
-        /* left on month entry */
-        else if (widget == priv->m_entry) {
-            gint pos =
-                gtk_editable_get_position(GTK_EDITABLE(priv->m_entry));
-
-            /* switch to day entry */
-            if (pos == 0) {
-                gtk_editable_select_region(GTK_EDITABLE(priv->m_entry), 0,
-                                           0);
-                if (priv->locale_type == DAY_MONTH_YEAR) {
-                    gtk_widget_grab_focus(priv->d_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->d_entry),
-                                              -1);
-                } else {
-                    gtk_widget_grab_focus(priv->y_entry);
-                }
-                gtk_editable_set_position(GTK_EDITABLE(priv->y_entry), -1);
-                return TRUE;
-            }
-        }
-        /* left on year entry */
-        else if (widget == priv->y_entry) {
-            gint pos =
-                gtk_editable_get_position(GTK_EDITABLE(priv->y_entry));
-
-            /* switch to month entry */
-            if (pos == 0) {
-                gtk_editable_select_region(GTK_EDITABLE(priv->y_entry), 0,
-                                           0);
-                if (priv->locale_type == DAY_MONTH_YEAR) {
-                    gtk_widget_grab_focus(priv->m_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->m_entry),
-                                              -1);
-                } else {
-                    gtk_widget_grab_focus(priv->d_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->d_entry),
-                                              -1);
-                }
-                return TRUE;
-            }
-        }
-        return FALSE;
-
+        (void) gtk_widget_child_focus(GTK_WIDGET(data), GTK_DIR_LEFT);
+        return TRUE;
+        break;
     case GDK_Right:
-        /* right on day entry */
-        if (widget == priv->d_entry) {
-            gint pos =
-                gtk_editable_get_position(GTK_EDITABLE(priv->d_entry));
-            gint len = gtk_entry_get_max_length(GTK_ENTRY(priv->d_entry));
-            gint chars =
-                g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)),
-                              len);
-
-            /* switch to month entry */
-            if ((pos == len) || (pos > chars)) {
-                gtk_editable_select_region(GTK_EDITABLE(priv->d_entry), 0,
-                                           0);
-                if (priv->locale_type == DAY_MONTH_YEAR) {
-                    gtk_widget_grab_focus(priv->m_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->m_entry),
-                                              0);
-                } else {
-                    gtk_widget_grab_focus(priv->y_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->y_entry),
-                                              0);
-                }
-                return TRUE;
-            }
-        }
-        /* right on month entry */
-        else if (widget == priv->m_entry) {
-            gint pos =
-                gtk_editable_get_position(GTK_EDITABLE(priv->m_entry));
-            gint len = gtk_entry_get_max_length(GTK_ENTRY(priv->m_entry));
-            gint chars =
-                g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)),
-                              len);
-
-            /* switch to year entry */
-            if ((pos == len) || (pos > chars)) {
-                gtk_editable_select_region(GTK_EDITABLE(priv->m_entry), 0,
-                                           0);
-                if (priv->locale_type == DAY_MONTH_YEAR) {
-                    gtk_widget_grab_focus(priv->y_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->y_entry),
-                                              0);
-                } else {
-                    gtk_widget_grab_focus(priv->d_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->d_entry),
-                                              0);
-                }
-                return TRUE;
-            }
-        }
-        /* right on year entry */
-        else if (widget == priv->y_entry) {
-            gint pos =
-                gtk_editable_get_position(GTK_EDITABLE(priv->y_entry));
-            gint len = gtk_entry_get_max_length(GTK_ENTRY(priv->y_entry));
-            gint chars =
-                g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)),
-                              len);
-
-            /* switch to day entry */
-            if ((pos == len) || (pos > chars)) {
-                gtk_editable_select_region(GTK_EDITABLE(priv->y_entry), 0,
-                                           0);
-                if (priv->locale_type == DAY_MONTH_YEAR) {
-                    gtk_widget_grab_focus(priv->d_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->d_entry),
-                                              0);
-                } else {
-                    gtk_widget_grab_focus(priv->y_entry);
-                    gtk_editable_set_position(GTK_EDITABLE(priv->y_entry),
-                                              0);
-                }
-                return TRUE;
-            }
-        }
-        return FALSE;
-
-        /* all digit keys */
-    case GDK_0:
-    case GDK_1:
-    case GDK_2:
-    case GDK_3:
-    case GDK_4:
-    case GDK_5:
-    case GDK_6:
-    case GDK_7:
-    case GDK_8:
-    case GDK_9:
-      {
-        if ((widget == priv->d_entry) || (widget == priv->m_entry) ||
-            (widget == priv->y_entry)) {
-            GtkWidgetClass *cl = GTK_WIDGET_GET_CLASS(widget);
-
-            cl->key_press_event(widget, event);
-        } else
-            return TRUE;
-      }
-      return TRUE;
-
-        /* accepts these as is */
-    case GDK_Tab:
-    case GDK_Shift_L:
-    case GDK_Shift_R:
-    case GDK_BackSpace:
-    case GDK_Delete:
-    case GDK_Up:
-    case GDK_Down:
-        return FALSE;
+        (void) gtk_widget_child_focus(GTK_WIDGET(data), GTK_DIR_RIGHT);
+        return TRUE;
+        break;
+    case GDK_Return:
+    case GDK_ISO_Enter:
+        /* Ignore return value, since we want to handle event at all times.
+           otherwise vkb would popup when the keyrepeat starts. */
+        (void) hildon_date_editor_set_calendar_icon_state(ed, TRUE);
+        return TRUE;
 
     case GDK_Escape:
         priv->skip_validation = TRUE;
-        return FALSE;
-
-        /* select date */
+        break;
     default:
-        return TRUE;
+        break;
     }
+
+    return FALSE;
 }
 
 static gboolean hildon_date_editor_entry_focus_out(GtkWidget * widget,
                                              GdkEventFocus * event,
                                              gpointer data)
 {
-    HildonDateEditor *ed;
-    HildonDateEditorPrivate *priv;
-    gint d, m, y;
-    gboolean return_value = FALSE;
-    GDate gd;
-    gchar new_val[5];
-
-    ed = HILDON_DATE_EDITOR(data);
-    priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
-    
-    /* deselect the entry */
-    gtk_editable_select_region(GTK_EDITABLE(widget), 0, 0);
-
-    if (priv->skip_validation)
-        return FALSE;
-    
-    g_signal_emit_by_name (G_OBJECT(ed), "validate_date", &return_value);
-
-    d = atoi(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)));
-    m = atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)));
-    y = atoi(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)));
-
-    /* If date is invalid we'll try to fix it */
-    if(!return_value) {
-        
-        g_date_clear(&gd, 1);
-        g_date_set_time(&gd, time(NULL));
-            
-        /* Year is illegal, year 0 is not allowed by this code */
-        if ((g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)),
-                           -1) == 0) || (y == 0)) {
-            gint end = gtk_entry_get_max_length(GTK_ENTRY(priv->y_entry));
-
-            gtk_infoprint(NULL, _("Ckct_ib_date_does_not_exist"));
-
-            /* set year to current year or to orignal value, if one exists 
-             */
-            if (priv->y_orig == 0)
-                y = g_date_get_year(&gd);
-            else
-                y = priv->y_orig;
-
-            sprintf(new_val, "%02d", y);
-            gtk_entry_set_text(GTK_ENTRY(priv->y_entry), new_val);
-            gtk_widget_grab_focus(priv->y_entry);
-
-            gtk_editable_select_region(GTK_EDITABLE(priv->y_entry),
-                                       0, end);
-            priv->valid_value = FALSE;
-        }
-
-        /* month is illegal */
-        else if ((g_utf8_strlen
-             (gtk_entry_get_text(GTK_ENTRY(priv->m_entry)), -1) == 0)
-            || (m == 0)) {
-            gint end = gtk_entry_get_max_length(GTK_ENTRY(priv->m_entry));
-
-            gtk_infoprintf(NULL, _("Ckct_ib_set_a_value_within_range"), 1, 12);
-
-            /* set month to current month or to orignal value, if one
-               exists */
-            if (priv->m_orig == 0)
-                m = g_date_get_month(&gd);
-            else
-                m = priv->m_orig;
-
-            sprintf(new_val, "%02d", m);
-            gtk_entry_set_text(GTK_ENTRY(priv->m_entry), new_val);
-            gtk_widget_grab_focus(priv->m_entry);
-
-            gtk_editable_select_region(GTK_EDITABLE(priv->m_entry), 0,
-                                       end);
-            priv-> valid_value = FALSE;
-        }
-
-        /* day is illegal */
-        else if ((g_utf8_strlen
-             (gtk_entry_get_text(GTK_ENTRY(priv->d_entry)), -1) == 0)
-            || (d == 0)) {
-            gint end = gtk_entry_get_max_length(GTK_ENTRY(priv->d_entry));
-
-            gtk_infoprintf(NULL, _("Ckct_ib_set_a_value_within_range"), 1,  31);
-
-            /* set day to current day or to orginal value, if one exists */
-            if (priv->d_orig == 0)
-                d = g_date_get_day(&gd);
-            else
-                d = priv->d_orig;
-
-            sprintf(new_val, "%02d", d);
-            gtk_entry_set_text(GTK_ENTRY(priv->d_entry), new_val);
-            gtk_widget_grab_focus(priv->d_entry);
-
-            gtk_editable_select_region(GTK_EDITABLE(priv->d_entry), 0,
-                                       end);
-            priv->valid_value = FALSE;
-        }
-
-        else {
-           /* date is not valid. Check what's wrong and correct it */
-           /* day entry was edited */
-           if (widget == priv->d_entry) {
-              gint l =
-                  gtk_entry_get_max_length(GTK_ENTRY(priv->d_entry));
-              gint c;
-
-              /* set day to 1 */
-              if (d < 1) {
-                  d = 1;
-                  gtk_infoprintf(NULL, _("Ckct_ib_minimum_value"), 1);
-
-                  sprintf(new_val, "%02d", d);
-                  gtk_entry_set_text(GTK_ENTRY(priv->d_entry),
-                                     new_val);
-                  c = g_utf8_strlen(gtk_entry_get_text
-                                    (GTK_ENTRY(priv->d_entry)), l);
-                  gtk_widget_grab_focus (priv->d_entry);
-                  gtk_editable_select_region(GTK_EDITABLE
-                                             (priv->d_entry), 0, c);
-                  priv->valid_value = FALSE;
-              }
-              /* set day to max number of days in this month */
-              else if (d > g_date_get_days_in_month(m,y)) {
-                  d = g_date_get_days_in_month(m, y);
-                  gtk_infoprintf(NULL, _("Ckct_ib_maximum_value"), d);
-
-                  sprintf(new_val, "%02d", d);
-                  gtk_entry_set_text(GTK_ENTRY(priv->d_entry),
-                                     new_val);
-                  c = g_utf8_strlen(gtk_entry_get_text
-                                    (GTK_ENTRY(priv->d_entry)), l);
-                  gtk_widget_grab_focus (priv->d_entry);
-                  gtk_editable_select_region(GTK_EDITABLE
-                                             (priv->d_entry), 0, c);
-                  priv->valid_value = FALSE;
-              }
-          }
-
-          /* month entry was edited */
-          else if (widget == priv->m_entry) {
-              gint l =
-                  gtk_entry_get_max_length(GTK_ENTRY(priv->m_entry));
-              gint c;
-
-              /* set month to 1 */
-              if (m < 1) {
-                  m = 1;
-                  gtk_infoprintf(NULL, _("Ckct_ib_minimum_value"), 1);
-
-                  sprintf(new_val, "%02d", m);
-                  gtk_entry_set_text(GTK_ENTRY(priv->m_entry),
-                                     new_val);
-                  c = g_utf8_strlen(gtk_entry_get_text
-                                    (GTK_ENTRY(priv->m_entry)), l);
-                  gtk_widget_grab_focus (priv->m_entry);
-                  gtk_editable_select_region(GTK_EDITABLE
-                                            (priv->m_entry), 0, c);
-                  priv->valid_value = FALSE;
-              }
-              /* set month to 12 */
-              else if (m > 12) {
-                  m = 12;
-                  gtk_infoprintf(NULL, _("Ckct_ib_maximum_value"), m);
-                  sprintf(new_val, "%02d", m);
-                  gtk_entry_set_text(GTK_ENTRY(priv->m_entry),
-                                      new_val);
-                  c = g_utf8_strlen(gtk_entry_get_text
-                                    (GTK_ENTRY(priv->m_entry)), l);
-                  gtk_widget_grab_focus (priv->m_entry);
-                  gtk_editable_select_region(GTK_EDITABLE
-                                             (priv->m_entry), 0, c);
-                  priv->valid_value = FALSE;
-              }
-              else if (d > g_date_get_days_in_month(m,y)) {
-                  d = g_date_get_days_in_month(m, y);
-                  gtk_infoprintf(NULL, _("Ckct_ib_maximum_value"), d);
-
-                  sprintf(new_val, "%02d", d);
-                  gtk_entry_set_text(GTK_ENTRY(priv->d_entry),
-                          new_val);
-                  c = g_utf8_strlen(gtk_entry_get_text
-                          (GTK_ENTRY(priv->d_entry)), l);
-                  gtk_widget_grab_focus (priv->d_entry);
-                  gtk_editable_select_region(GTK_EDITABLE
-                          (priv->d_entry), 0, c);
-                  priv->valid_value = FALSE;
-              }
-          }
-        }
-    }
-
-    hildon_date_editor_set_date(ed, y, m, d);
-
-    priv->d_orig = d;
-    priv->m_orig = m;
-    priv->y_orig = y;
-
-    /* if month entry has only one character, prepend it with 0 */
-    if (g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)), -1) ==
-            1) {
-        sprintf(new_val, "%02d", m);
-        gtk_entry_set_text(GTK_ENTRY(priv->m_entry), new_val);
-    }
-
-    /* if day entry has only one character, prepend it with 0 */
-    if (g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)), -1) ==
-            1) {
-        sprintf(new_val, "%02d", d);
-        gtk_entry_set_text(GTK_ENTRY(priv->d_entry), new_val);
-    }
-    return FALSE;
+  hildon_date_editor_entry_validate(widget, data);
+  return FALSE;
 }
 
-static gboolean hildon_date_editor_validate_date(HildonDateEditor *editor)
+static gboolean 
+hildon_date_editor_date_error(HildonDateEditor *editor,
+                             HildonDateEditorErrorType type)
 {
-    gint d, m, y;
-    HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
-    
-    /* get texts */
-    d = atoi(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)));
-    m = atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)));
-    y = atoi(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)));
+  HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
 
-    return g_date_valid_dmy(d, m, y);
+  switch(type)
+    {
+    case MAX_DAY:
+      gtk_infoprintf(NULL, _("Ckct_ib_maximum_value"), 31);
+      break;
+    case MAX_MONTH:
+      gtk_infoprintf(NULL, _("Ckct_ib_maximum_value"), 12);
+      break;
+    case MAX_YEAR:
+      gtk_infoprintf(NULL, _("Ckct_ib_maximum_value"), priv->max_year);
+      break;
+    case MIN_DAY:
+    case MIN_MONTH:
+      gtk_infoprintf(NULL, _("Ckct_ib_minimum_value"), 1);
+      break;
+    case MIN_YEAR:
+      gtk_infoprintf(NULL, _("Ckct_ib_minimum_value"), priv->min_year);
+      break;
+    case EMPTY_DAY:
+      gtk_infoprintf(NULL, _("Ckct_ib_set_a_value_within_range"), 1, 31);
+      break;
+    case EMPTY_MONTH:
+      gtk_infoprintf(NULL, _("Ckct_ib_set_a_value_within_range"), 1, 12);
+      break;
+    case EMPTY_YEAR:
+      gtk_infoprintf(NULL, _("Ckct_ib_set_a_value_within_range"),
+                     priv->min_year, priv->max_year);
+      break;
+    case INVALID_DATE:
+      gtk_infoprint(NULL, _("Ckct_ib_date_does_not_exist"));
+      break;
+   default:
+      /*default error message ?*/
+      break;
+    }
+  return TRUE;
 }
 
 static void hildon_date_editor_size_request(GtkWidget * widget,
@@ -1291,37 +1169,25 @@ static void hildon_date_editor_size_request(GtkWidget * widget,
 {
     HildonDateEditor *ed;
     HildonDateEditorPrivate *priv;
-    GtkRequisition d_req, m_req, y_req, f_req, img_req;
+    GtkRequisition f_req, img_req;
 
-    g_return_if_fail(widget);
-    g_return_if_fail(requisition);
+    g_assert(GTK_IS_WIDGET(widget));
+    g_assert(requisition != NULL);
 
     ed = HILDON_DATE_EDITOR(widget);
     priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
 
-    /* call size request for entries */
-    gtk_widget_size_request(priv->d_entry, &d_req);
-    gtk_widget_size_request(priv->m_entry, &m_req);
-    gtk_widget_size_request(priv->y_entry, &y_req);
-
-    /* set entry widths to width_of_digit * 2 + border */
-    d_req.width = (hildon_date_editor_get_font_width(priv->d_entry) << 1)
-        + ENTRY_BORDERS;
-    m_req.width = (hildon_date_editor_get_font_width(priv->m_entry) << 1)
-        + ENTRY_BORDERS;
-    y_req.width = (hildon_date_editor_get_font_width(priv->y_entry) << 2)
-        + ENTRY_BORDERS;
-
-    gtk_widget_set_size_request(priv->d_entry, d_req.width, d_req.height);
-    gtk_widget_set_size_request(priv->m_entry, m_req.width, m_req.height);
-    gtk_widget_set_size_request(priv->y_entry, y_req.width, y_req.height);
-
-
+    /* Our own children affect our size */
     gtk_widget_size_request(priv->frame, &f_req);
     gtk_widget_size_request(priv->d_event_box_image, &img_req);
 
     /* calculate our size */
-    requisition->width = f_req.width + img_req.width + BUTTON_SPACING;
+    requisition->width = f_req.width + img_req.width + HILDON_MARGIN_DEFAULT;
+
+    /* FIXME: Fixed size is bad! We should use the maximum of our children, but
+              doing so would break current pixel specifications, since
+              the text entry by itself is already 30px tall + then frame takes
+              something */
     requisition->height = DATE_EDITOR_HEIGHT;
 }
 
@@ -1333,9 +1199,10 @@ static void hildon_date_editor_size_allocate(GtkWidget * widget,
     GtkAllocation f_alloc, img_alloc;
     GtkRequisition req;
     GtkRequisition max_req;
+    GList *iter;
 
-    g_return_if_fail(widget);
-    g_return_if_fail(allocation);
+    g_assert(GTK_IS_WIDGET(widget));
+    g_assert(allocation != NULL);
 
     ed = HILDON_DATE_EDITOR(widget);
     priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
@@ -1344,14 +1211,15 @@ static void hildon_date_editor_size_allocate(GtkWidget * widget,
 
     gtk_widget_get_child_requisition(widget, &max_req);
 
+    /* Center vertically */
     f_alloc.y = img_alloc.y = allocation->y +
             MAX(allocation->height - max_req.height, 0) / 2;
 
+    /* Center horizontally */
     f_alloc.x = img_alloc.x = allocation->x +
             MAX(allocation->width - max_req.width, 0) / 2;
 
     /* allocate frame */
-    if (priv->frame)
         if (GTK_WIDGET_VISIBLE(priv->frame)) {
             gtk_widget_get_child_requisition(priv->frame, &req);
 
@@ -1360,44 +1228,33 @@ static void hildon_date_editor_size_allocate(GtkWidget * widget,
             gtk_widget_size_allocate(priv->frame, &f_alloc);
         }
 
-    /* allocate entry box */
-    if (priv->d_event_box_image)
+    /* allocate icon */
         if (GTK_WIDGET_VISIBLE(priv->d_event_box_image)) {
             gtk_widget_get_child_requisition(priv->d_event_box_image,
                                              &req);
 
-            img_alloc.x += f_alloc.width + BUTTON_SPACING;
+            img_alloc.x += f_alloc.width + HILDON_MARGIN_DEFAULT;
             img_alloc.width = req.width;
             img_alloc.height = max_req.height;
             gtk_widget_size_allocate(priv->d_event_box_image, &img_alloc);
         }
 
-    priv->dm_delim->allocation.height = max_req.height; 
-    priv->my_delim->allocation.height = max_req.height; 
-    priv->my_delim->allocation.y = priv->d_entry->allocation.y-5;
-    priv->dm_delim->allocation.y = priv->d_entry->allocation.y-5;
-    gtk_widget_size_allocate(priv->dm_delim, &priv->dm_delim->allocation);
-    gtk_widget_size_allocate(priv->my_delim, &priv->my_delim->allocation);
-}
-
-/* calculate approximate width of a digit */
-static int hildon_date_editor_get_font_width(GtkWidget * widget)
-{
-    PangoContext *context;
-    PangoFontMetrics *metrics;
-    gint digit_width;
-
-    context = gtk_widget_get_pango_context(widget);
-    metrics = pango_context_get_metrics(context, widget->style->font_desc,
-                                        pango_context_get_language
-                                        (context));
-
-    digit_width = pango_font_metrics_get_approximate_digit_width(metrics);
-    digit_width = PANGO_PIXELS(digit_width);
+    /* FIXME: We really should not alloc delimeters by hand (since they
+              are not our own children, but we need to force to appear 
+              higher. This ugly hack is needed to compensate the forced
+              height in size_request. */
+    for (iter = priv->delims; iter; iter = iter->next)
+    {
+        GtkWidget *delim;
+        GtkAllocation alloc;
 
-    pango_font_metrics_unref(metrics);
+        delim = GTK_WIDGET(iter->data);
+        alloc = delim->allocation;
+        alloc.height = max_req.height; 
+        alloc.y = priv->d_entry->allocation.y - 2;
 
-    return digit_width;
+        gtk_widget_size_allocate(delim, &alloc);
+    }
 }
 
 /**
@@ -1405,10 +1262,10 @@ static int hildon_date_editor_get_font_width(GtkWidget * widget)
  * @editor: the @HildonDateEditor widget
  * @year: year
  *
- * This function sets the year shown in the editor. 
+ * Sets the year shown in the editor. 
  *
- * Return: Returns TRUE if the year is valid.
- **/
+ * Returns: TRUE if the year is valid
+ */
 gboolean hildon_date_editor_set_year(HildonDateEditor *editor, guint year)
 {
   HildonDateEditorPrivate *priv;
@@ -1417,13 +1274,18 @@ gboolean hildon_date_editor_set_year(HildonDateEditor *editor, guint year)
 
   if (g_date_valid_dmy(priv->day, priv->month, year))
   {
-    GDate date;
-    gchar str[MAX_DATE_LEN + 1];
+    gchar buffer[256];
     priv->year = year;
-    g_date_set_dmy(&date, priv->day, priv->month, year);
 
-    g_date_strftime(str, MAX_DATE_LEN, "%EY", &date);
-    gtk_entry_set_text(GTK_ENTRY(priv->y_entry), str);
+    g_snprintf(buffer, sizeof(buffer), "%04d", year);
+
+    /* We apply the new day, but do not want automatic focus move
+       etc to take place */
+    g_signal_handlers_block_by_func(priv->y_entry, 
+        (gpointer) hildon_date_editor_entry_changed, editor);
+    gtk_entry_set_text(GTK_ENTRY(priv->y_entry), buffer);
+    g_signal_handlers_unblock_by_func(priv->y_entry, 
+        (gpointer) hildon_date_editor_entry_changed, editor);
 
     g_object_notify(G_OBJECT(editor), "year");
     return TRUE;
@@ -1437,10 +1299,10 @@ gboolean hildon_date_editor_set_year(HildonDateEditor *editor, guint year)
  * @editor: the @HildonDateEditor widget
  * @month: month
  *
- * This function sets the month shown in the editor. 
+ * Sets the month shown in the editor. 
  *
- * Return: Returns TRUE if the month is valid.
- **/
+ * Returns: TRUE if the month is valid
+ */
 gboolean hildon_date_editor_set_month(HildonDateEditor *editor, guint month)
 {
   HildonDateEditorPrivate *priv;
@@ -1450,12 +1312,19 @@ gboolean hildon_date_editor_set_month(HildonDateEditor *editor, guint month)
   if (g_date_valid_dmy(priv->day, month, priv->year))
   {
     GDate date;
-    gchar str[MAX_DATE_LEN + 1];
+    gchar buffer[256];
+
     priv->month = month;
     g_date_set_dmy(&date, priv->day, month, priv->year);
+    g_date_strftime(buffer, sizeof(buffer), "%m", &date);
 
-    g_date_strftime(str, MAX_DATE_LEN, "%m", &date);
-    gtk_entry_set_text(GTK_ENTRY(priv->m_entry), str);
+    /* We apply the new day, but do not want automatic focus move
+       etc to take place */
+    g_signal_handlers_block_by_func(priv->m_entry, 
+        (gpointer) hildon_date_editor_entry_changed, editor);
+    gtk_entry_set_text(GTK_ENTRY(priv->m_entry), buffer);
+    g_signal_handlers_unblock_by_func(priv->m_entry, 
+        (gpointer) hildon_date_editor_entry_changed, editor);
 
     g_object_notify(G_OBJECT(editor), "month");
     return TRUE;
@@ -1468,10 +1337,10 @@ gboolean hildon_date_editor_set_month(HildonDateEditor *editor, guint month)
  * @editor: the @HildonDateEditor widget
  * @day: day
  *
- * This function sets the day shown in the editor. 
+ * Sets the day shown in the editor. 
  *
- * Return: Returns TRUE if the day is valid.
- **/
+ * Returns: TRUE if the day is valid
+ */
 gboolean hildon_date_editor_set_day(HildonDateEditor *editor, guint day)
 {
   HildonDateEditorPrivate *priv;
@@ -1482,12 +1351,19 @@ gboolean hildon_date_editor_set_day(HildonDateEditor *editor, guint day)
   if (g_date_valid_dmy(day, priv->month, priv->year))
   {
     GDate date;
-    gchar str[MAX_DATE_LEN + 1];
+    gchar buffer[256];
+
     priv->day = day;
     g_date_set_dmy(&date, day, priv->month, priv->year);
+    g_date_strftime(buffer, sizeof(buffer), "%d", &date);
 
-    g_date_strftime(str, MAX_DATE_LEN, "%d", &date);
-    gtk_entry_set_text(GTK_ENTRY(priv->d_entry), str);
+    /* We apply the new day, but do not want automatic focus move
+       etc to take place */
+    g_signal_handlers_block_by_func(priv->d_entry, 
+        (gpointer) hildon_date_editor_entry_changed, editor);
+    gtk_entry_set_text(GTK_ENTRY(priv->d_entry), buffer);
+    g_signal_handlers_unblock_by_func(priv->d_entry, 
+        (gpointer) hildon_date_editor_entry_changed, editor);
 
     g_object_notify(G_OBJECT(editor), "day");
     return TRUE;
@@ -1499,48 +1375,54 @@ gboolean hildon_date_editor_set_day(HildonDateEditor *editor, guint day)
  * hildon_date_editor_get_year:
  * @editor: the @HildonDateEditor widget
  *
- * This function gets the year shown in the editor. 
- *
- * Return: Returns the current year shown in the editor.
- **/
+ * Returns: the current year shown in the editor.
+ */
 guint hildon_date_editor_get_year(HildonDateEditor *editor)
 {
   HildonDateEditorPrivate *priv;
   g_return_val_if_fail( HILDON_IS_DATE_EDITOR(editor), 0 );
   priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
-  return priv->year;
+  return (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)));
 }
 
 /**
  * hildon_date_editor_get_month:
  * @editor: the @HildonDateEditor widget
  *
- * This function gets the month shown in the editor. 
+ * Gets the month shown in the editor. 
  *
- * Return: Returns the current month shown in the editor.
- **/
+ * Returns: the current month shown in the editor.
+ */
 
 guint hildon_date_editor_get_month(HildonDateEditor *editor)
 {
   HildonDateEditorPrivate *priv;
   g_return_val_if_fail( HILDON_IS_DATE_EDITOR(editor), 0 );
   priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
-  return priv->month;
+  return (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)));
 }
 
 /**
  * hildon_date_editor_get_day:
  * @editor: the @HildonDateEditor widget
  *
- * This function gets the day shown in the editor. 
+ * Gets the day shown in the editor. 
  *
- * Return: Returns the current day shown in the editor.
- **/
+ * Returns: the current day shown in the editor
+ */
 
 guint hildon_date_editor_get_day(HildonDateEditor *editor)
 {
   HildonDateEditorPrivate *priv;
   g_return_val_if_fail( HILDON_IS_DATE_EDITOR(editor), 0 );
   priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
-  return priv->day;
+  return (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)));
+}
+
+/* Idle callback */
+static gboolean
+_hildon_date_editor_entry_select_all (GtkWidget *widget)
+{
+       gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
+       return FALSE;
 }