2006-08-30 Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
[hildon] / hildon-widgets / hildon-time-editor.c
index b2ab5cb..e2af240 100644 (file)
@@ -1,14 +1,14 @@
 /*
  * This file is part of hildon-libs
  *
- * Copyright (C) 2005 Nokia Corporation.
+ * Copyright (C) 2005, 2006 Nokia Corporation.
  *
- * Contact: Luc Pionchon <luc.pionchon@nokia.com>
+ * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License.
  *
  * This library is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  *
  */
 
-/* HILDON DOC
- * @shortdesc: TimeEditor is a widget for setting, getting and showing a
- * time.
- * @longdesc: The Time Editor widget is used to enter the system time
- * (hours and minutes) in the Date/Time system plugin. It is a composite
- * widget consisting of two GtkEntry widgets that are placed next to each
- * other. The leftmost GtkEntry is used to enter the hours, and it accepts
- * the values 0--23, while the rightmost GtkEntry accepts values 0--59
- * and is used to set the minutes. Between the two GtkEntries there
- * is a label displaying a colon.
- * </para><para>
- * From the usability point of view, the GtkSpinbutton widget would
- * have been a better choice than the GtkEntry widgets, but it uses
- * floating point operations and is thus not acceptable in this
- * project.
- *
- * @seealso: #HildonDateEditor
+/**
+ * SECTION:hildon-time-editor
+ * @short_description: A widget used to enter time or duration in hours, minutes,
+ * and optional seconds
+ * @see_also: #HildonTimePicker
+ * 
+ * HildonTimeEditor is used to edit time or duration. Time mode is
+ * restricted to normal 24 hour cycle, but Duration mode can select any
+ * amount of time up to 99 hours.  It consists of entries for hours,
+ * minutes and seconds, and pm/am indicator as well as a button which
+ * popups a #HildonTimePicker dialog.
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include <pango/pango.h>
-#include <gtk/gtkbox.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkeventbox.h>
 #include <gtk/gtkentry.h>
-#include <gtk/gtk.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkframe.h>
 #include <gdk/gdkkeysyms.h>
-#include <gtk/gtkwidget.h>
 
 #include <string.h>
 #include <time.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <ctype.h>
 #include <langinfo.h>
 #include <libintl.h>
 
 #include <hildon-widgets/hildon-defines.h>
 #include <hildon-widgets/hildon-time-editor.h>
 #include <hildon-widgets/hildon-time-picker.h>
-#include <hildon-widgets/gtk-infoprint.h>
+#include <hildon-widgets/hildon-banner.h>
 #include <hildon-widgets/hildon-input-mode-hint.h>
+#include <hildon-widgets/hildon-private.h>
 #include "hildon-composite-widget.h"
-#include "hildon-date-editor.h"
+#include "hildon-marshalers.h"
+#include "hildon-libs-enum-types.h"
 
 #define _(String) dgettext(PACKAGE, String)
 
-/* empty space on left and right side of a GtkEntry. Space needed
-is 12, we add 4 extra pixels so that the arabic locale works
-correctly. (With 12 only one digit would be shown in the entries).
-*/
-#define TIME_EDITOR_LBORDER         2
-#define TIME_EDITOR_RBORDER         1
-#define TIME_EDITOR_HEIGHT         28
-#define TIME_EDITOR_CLOCK_BORDER    6
-#define ENTRY_BORDER               2
-#define ICON_WIDTH                 26
-#define ICON_HEIGHT                26
-#define ICON_PRESSED                4
-#define ICON_NAME                  "qgn_widg_timedit"
-#define ICON_SIZE                  "timepicker-size"
 #define HILDON_TIME_EDITOR_GET_PRIVATE(obj) \
     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
      HILDON_TYPE_TIME_EDITOR, HildonTimeEditorPrivate));
+
+#define TICKS(h,m,s) ((h) * 3600 + (m) * 60 + (s))
+
+#define TIME_EDITOR_HEIGHT         30
+#define ICON_PRESSED                4
+#define ICON_NAME                  "qgn_widg_timedit"
+#define ICON_SIZE                  "timepicker-size"
 #define MIN_DURATION 0
-#define MAX_DURATION (3600 * 99) + (60 * 59) + 59
+#define MAX_DURATION TICKS(99, 59, 59)
 
+/* Default values for properties */
 #define HILDON_TIME_EDITOR_TICKS_VALUE           0
-#define HILDON_TIME_EDITOR_SHOW_SECONDS          TRUE
 #define HILDON_TIME_EDITOR_DURATION_MODE         FALSE
 #define HILDON_TIME_EDITOR_DURATION_LOWER_VALUE  0
-#define HILDON_TIME_EDITOR_TIME_LOWER_VALUE      0
-#define HILDON_TIME_EDITOR_TIME_UPPER_VALUE      (3600 * 23) + (60 * 59) + 59
-#define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE  (3600 * 99) + (60 * 59) + 59
+#define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE  TICKS(99, 59, 59)
 
 #define HOURS_MAX_24   23
 #define HOURS_MAX_12   12
-#define HOURS_MIN_24   0
-#define HOURS_MIN_12   1
+#define HOURS_MIN_24    0
+#define HOURS_MIN_12    1
 #define MINUTES_MAX 59
 #define SECONDS_MAX 59
 #define MINUTES_MIN 0
@@ -117,90 +103,131 @@ enum
        PROP_DURATION_MODE,
        PROP_DURATION_MIN,
        PROP_DURATION_MAX,
-       PROP_SHOW_SECONDS
+       PROP_SHOW_SECONDS,
+       PROP_SHOW_HOURS
 };
 
-typedef enum
-{
-  VALIDATION_ERROR, /* should never be returned, translates as system error */
-  VALIDATION_OK,
-  VALIDATION_DURATION_MAX,
-  VALIDATION_DURATION_MIN,
-  VALIDATION_TIME_HOURS,
-  VALIDATION_TIME_MINUTES,
-  VALIDATION_TIME_SECONDS,
-  VALIDATION_LAST
-} HildonValidation;
+/* Indices for h/m/s entries in priv->entries */
+enum {
+  ENTRY_HOURS,
+  ENTRY_MINS,
+  ENTRY_SECS,
+
+  ENTRY_COUNT
+};
+
+/* Signals */
+enum {
+  TIME_ERROR,
+  LAST_SIGNAL
+};
+
+/* Error codes categories */
+enum {
+  MAX_VALUE,
+  MIN_VALUE,
+  WITHIN_RANGE,
+  NUM_ERROR_CODES
+};
+
+static guint time_editor_signals[LAST_SIGNAL] = { 0 };
+static guint hour_errors[NUM_ERROR_CODES] = { MAX_HOURS, MIN_HOURS, EMPTY_HOURS  };
+static guint  min_errors[NUM_ERROR_CODES] = { MAX_MINS,  MIN_MINS,  EMPTY_MINS   };
+static guint  sec_errors[NUM_ERROR_CODES] = { MAX_SECS,  MIN_SECS,  EMPTY_SECS   };
+
+struct _HildonTimeEditorPrivate {
+    guint      ticks;                /* Current duration in seconds  */
+
+    gchar     *am_symbol;
+    gchar     *pm_symbol;
+
+    GtkWidget *eventbox;             /* hold entries                 */
+    GtkWidget *iconbutton;           /* button for icon              */
+
+    GtkWidget *frame;                /* frame around the entries     */
+    GtkWidget *entries[ENTRY_COUNT]; /* h, m, s entries              */
+    GtkWidget *hm_label;             /* between hour and minute      */
+    GtkWidget *sec_label;            /* between minute and second    */
+    GtkWidget *ampm_label;           /* label for showing am or pm   */
+
+    GtkWidget *error_widget;         /* field to highlight in idle   */
+
+
+    gboolean   duration_mode;        /* In HildonDurationEditor mode */
+    gboolean   show_seconds;         /* show seconds                 */
+    gboolean   show_hours;           /* show hours                   */
+
+    gboolean   ampm_pos_after;       /* is am/pm shown after others  */
+    gboolean   clock_24h;            /* whether to show a 24h clock  */
+    gboolean   am;                   /* TRUE == am, FALSE == pm      */
+
+    guint      duration_min;         /* duration editor ranges       */
+    guint      duration_max;         /* duration editor ranges       */
+
+    guint      highlight_idle;
+};
 
 /***
  * Widget functions
  */
 
-static void
-hildon_time_editor_class_init(HildonTimeEditorClass * editor_class);
+static void hildon_time_editor_class_init  (HildonTimeEditorClass *editor_class);
+static void hildon_time_editor_init        (HildonTimeEditor      *editor);
 
-static void hildon_time_editor_init(HildonTimeEditor * editor);
+static void hildon_time_editor_finalize    (GObject      *obj_self);
 
-static void hildon_time_editor_finalize(GObject * obj_self);
+static void hildon_time_editor_set_property(GObject      *object,
+                                            guint         param_id,
+                                            const GValue *value,
+                                            GParamSpec   *pspec);
 
-static void hildon_time_editor_set_property( GObject *object, guint param_id,
-                                       const GValue *value, GParamSpec *pspec );
-static void hildon_time_editor_get_property( GObject *object, guint param_id,
-                                         GValue *value, GParamSpec *pspec );
+static void hildon_time_editor_get_property(GObject      *object,
+                                            guint         param_id,
+                                            GValue       *value,
+                                            GParamSpec   *pspec);
 
-static void
-hildon_time_editor_forall(GtkContainer * container,
-                          gboolean include_internals, GtkCallback callback,
-                          gpointer callback_data);
+static void hildon_time_editor_forall(GtkContainer *container,
+                                      gboolean      include_internals,
+                                      GtkCallback   callback,
+                                      gpointer      callback_data);
                           
 static void hildon_time_editor_destroy(GtkObject * self);
 
-static void hildon_time_editor_add_style(void);
-
-static void
-set_widget_allocation(GtkWidget * widget, GtkAllocation * alloc,
-                      GtkAllocation * allocation);
-
 /***
  * Signal handlers
  */
 
-static gboolean
-hildon_time_editor_entry_focusout(GtkWidget * widget,
-                                  GdkEventFocus * event, gpointer data);
+static gboolean hildon_time_editor_entry_focusout(GtkWidget     *widget,
+                                                  GdkEventFocus *event,
+                                                  gpointer       data);
 
-static gboolean hildon_time_editor_entry_focusin(GtkWidget * widget,
-                                                 GdkEventFocus * event, 
-                                                 gpointer data);
-static gboolean
-hildon_time_editor_mnemonic_activate(GtkWidget * widget,
-                                     gboolean group_cycling);
+static gboolean hildon_time_editor_entry_focusin(GtkWidget      *widget,
+                                                 GdkEventFocus  *event, 
+                                                 gpointer        data);
 
-static gboolean
-hildon_time_editor_ampm_clicked(GtkWidget * widget, GdkEventButton * event,
-                                gpointer data);
-static gboolean
-hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data);
+static gboolean hildon_time_editor_time_error(HildonTimeEditor *editor,
+                                             HildonTimeEditorErrorType type);
 
-static gboolean
-hildon_time_editor_entry_clicked(GtkWidget * widget,
-                                 GdkEventButton * event, gpointer data);
+static gboolean hildon_time_editor_ampm_clicked(GtkWidget       *widget,
+                                                GdkEventButton  *event,
+                                                gpointer         data);
 
-static void
-hildon_time_editor_entry_changed(GtkWidget * widget, gpointer user_data);
+static gboolean hildon_time_editor_icon_clicked(GtkWidget       *widget,
+                                                gpointer         data);
 
+static gboolean hildon_time_editor_entry_clicked(GtkWidget      *widget,
+                                                 GdkEventButton *event,
+                                                 gpointer        data);
 
-static void
-hildon_time_editor_size_request(GtkWidget * widget,
-                                GtkRequisition * requisition);
+static void     hildon_time_editor_size_request(GtkWidget       *widget,
+                                                GtkRequisition  *requisition);
 
-static void
-hildon_time_editor_size_allocate(GtkWidget * widget,
-                                 GtkAllocation * allocation);
+static void     hildon_time_editor_size_allocate(GtkWidget      *widget,
+                                                 GtkAllocation  *allocation);
 
-static gboolean
-hildon_time_editor_entry_keypress(GtkWidget * widget, GdkEventKey * event,
-                                  gpointer data);
+static gboolean hildon_time_editor_entry_keypress(GtkWidget     *widget,
+                                                  GdkEventKey   *event,
+                                                  gpointer       data);
 
 /***
  * Internal functions
@@ -213,71 +240,29 @@ void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
                                            GtkWidget * menu,
                                            GtkCallback func,
                                            GtkWidgetTapAndHoldFlags flags);
-
 static void
-hildon_time_editor_get_max_values(HildonTimeEditor *editor,
-        guint * max_hours, guint * min_hours,
-        guint * max_minutes, guint * min_minutes,
-        guint * max_seconds, guint * min_seconds);
-        
-static void
-hildon_time_editor_validate (HildonTimeEditor *editor);
+hildon_time_editor_validate (HildonTimeEditor *editor, gboolean allow_intermediate);
 
-static HildonValidation
-hildon_time_editor_validate_duration (HildonTimeEditor * editor, guint ticks);
-
-static HildonValidation
-hildon_time_editor_validate_time (HildonTimeEditor * editor,
-                                  guint hours,
-                                  guint minutes,
-                                  guint seconds,
-                                  gboolean mode_24h);
+static void hildon_time_editor_set_to_current_time (HildonTimeEditor * editor);
 
 /***
  * Utility functions
  */
  
-static void
-convert_to_12h (guint *h, guint *m, guint *s, gboolean *am);
-static void
-convert_to_24h (guint *h, guint *m, guint *s, gboolean am);
+static void convert_to_12h (guint *h, gboolean *am);
+static void convert_to_24h (guint *h, gboolean  am);
 
-static void ticks_to_time (guint ticks,
+static void ticks_to_time (guint  ticks,
                            guint *hours,
                            guint *minutes,
-                    guint *seconds);
-
-
-struct _HildonTimeEditorPrivate {
-    guint ticks;        /* Current duration in seconds */
-    gchar *am_symbol;
-    gchar *pm_symbol;
-
-    GtkWidget *eventbox;        /* hold entries */
-    GtkWidget *iconbutton;      /* button for icon */
-
-    GtkWidget *h_entry;
-    GtkWidget *m_entry;
-    GtkWidget *s_entry;
-    GtkWidget *label;   /* between h and m */
-    GtkWidget *label2;  /* between m and s */
-    GtkWidget *ampm;    /* label for showing am or pm */
-    GtkWidget *icon;    /* label for showing am or pm */
-    GtkWidget *frame;   /* frame around the entries */
-
-    gboolean duration_mode;     /* In HildonDurationEditor mode */
-    gboolean show_s;    /* show seconds */
-    gboolean ampm_pos_after;    /* is the am/pm shown after others */
-    gboolean clock_24h; /* whether to show a 24h clock */
-    gboolean am;        /* TRUE == showing am, FALSE == pm */
-    gboolean valid_value; /* If entry has an valid value */
-    
-    gboolean validated; /* If the current value has been validated */
+                           guint *seconds);
 
-    /* Duration editor ranges */
-    guint duration_min;
-    guint duration_max;
-};
+static void
+hildon_time_editor_inserted_text  (GtkEditable * editable,
+                                   gchar * new_text,
+                                   gint new_text_length,
+                                   gint * position,
+                                   gpointer user_data);
 
 GType hildon_time_editor_get_type(void)
 {
@@ -286,13 +271,13 @@ GType hildon_time_editor_get_type(void)
     if (!editor_type) {
         static const GTypeInfo editor_info = {
             sizeof(HildonTimeEditorClass),
-            NULL,       /* base_init */
-            NULL,       /* base_finalize */
+            NULL,       /* base_init      */
+            NULL,       /* base_finalize  */
             (GClassInitFunc) hildon_time_editor_class_init,
             NULL,       /* class_finalize */
-            NULL,       /* class_data */
+            NULL,       /* class_data     */
             sizeof(HildonTimeEditor),
-            0,  /* n_preallocs */
+            0,          /* n_preallocs    */
             (GInstanceInitFunc) hildon_time_editor_init,
         };
         editor_type = g_type_register_static(GTK_TYPE_CONTAINER,
@@ -310,25 +295,18 @@ static void hildon_time_editor_forall(GtkContainer * container,
     HildonTimeEditor *editor;
     HildonTimeEditorPrivate *priv;
 
+    g_assert(HILDON_IS_TIME_EDITOR(container));
+    g_assert(callback != NULL);
+
     editor = HILDON_TIME_EDITOR(container);
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
-    g_return_if_fail(container);
-    g_return_if_fail(callback);
-
     if (!include_internals)
         return;
 
-
     /* widget that are always shown */
-    (*callback) (priv->h_entry, callback_data);
-    (*callback) (priv->m_entry, callback_data);
     (*callback) (priv->iconbutton, callback_data);
     (*callback) (priv->frame, callback_data);
-    (*callback) (priv->label, callback_data);
-    (*callback) (priv->label2, callback_data);
-    (*callback) (priv->s_entry, callback_data);
-    (*callback) (priv->eventbox, callback_data);
 }
 
 static void hildon_time_editor_destroy(GtkObject * self)
@@ -337,18 +315,6 @@ static void hildon_time_editor_destroy(GtkObject * self)
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(self);
 
-    if (priv->h_entry) {
-        gtk_widget_unparent(priv->h_entry);
-        priv->h_entry = NULL;
-    }
-    if (priv->m_entry) {
-        gtk_widget_unparent(priv->m_entry);
-        priv->m_entry = NULL;
-    }
-    if (priv->label) {
-        gtk_widget_unparent(priv->label);
-        priv->label = NULL;
-    }
     if (priv->iconbutton) {
         gtk_widget_unparent(priv->iconbutton);
         priv->iconbutton = NULL;
@@ -357,19 +323,6 @@ static void hildon_time_editor_destroy(GtkObject * self)
         gtk_widget_unparent(priv->frame);
         priv->frame = NULL;
     }
-    if (priv->eventbox) {
-        gtk_widget_unparent(priv->eventbox);
-        priv->eventbox = NULL;
-        priv->ampm = NULL;
-    }
-    if (priv->label2) {
-        gtk_widget_unparent(priv->label2);
-        priv->label2 = NULL;
-    }
-    if (priv->s_entry) {
-        gtk_widget_unparent(priv->s_entry);
-        priv->s_entry = NULL;
-    }
   
     if (GTK_OBJECT_CLASS(parent_class)->destroy)
         GTK_OBJECT_CLASS(parent_class)->destroy(self);
@@ -390,9 +343,6 @@ hildon_time_editor_class_init(HildonTimeEditorClass * editor_class)
 
     object_class->get_property = hildon_time_editor_get_property;
     object_class->set_property = hildon_time_editor_set_property;
-
-
-    widget_class->mnemonic_activate = hildon_time_editor_mnemonic_activate;
     widget_class->size_request = hildon_time_editor_size_request;
     widget_class->size_allocate = hildon_time_editor_size_allocate;
     widget_class->tap_and_hold_setup =
@@ -404,10 +354,22 @@ hildon_time_editor_class_init(HildonTimeEditorClass * editor_class)
 
     object_class->finalize = hildon_time_editor_finalize;
 
+    editor_class->time_error = hildon_time_editor_time_error; 
+    
+    time_editor_signals[TIME_ERROR] =
+        g_signal_new("time-error",
+                    G_OBJECT_CLASS_TYPE(object_class),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET(HildonTimeEditorClass, time_error),
+                    g_signal_accumulator_true_handled, NULL,
+                    _hildon_marshal_BOOLEAN__ENUM,
+                    G_TYPE_BOOLEAN, 1, HILDON_TYPE_TIME_EDITOR_ERROR_TYPE);
+
   /**
    * HildonTimeEditor:ticks:
    *
-   * TimeEditor current duration (or time since midnight) value.
+   * If editor is in duration mode, contains the duration seconds.
+   * If not, contains seconds since midnight.
    */
   g_object_class_install_property( object_class, PROP_TICKS,
                                    g_param_spec_uint("ticks",
@@ -420,19 +382,31 @@ hildon_time_editor_class_init(HildonTimeEditorClass * editor_class)
   /**
    * HildonTimeEditor:show_seconds:
    *
-   * TimeEditor show_seconds property.
+   * Controls whether seconds are shown in the editor
    */
   g_object_class_install_property( object_class, PROP_SHOW_SECONDS,
                                    g_param_spec_boolean("show_seconds",
                                    "Show seconds property",
                                    "Controls whether the seconds are shown in the editor",
-                                   HILDON_TIME_EDITOR_SHOW_SECONDS,
+                                   FALSE,
+                                   G_PARAM_READABLE | G_PARAM_WRITABLE) );
+
+  /**
+   * HildonTimeEditor:show_hours:
+   *
+   * Controls whether hours are shown in the editor
+   */
+  g_object_class_install_property( object_class, PROP_SHOW_HOURS,
+                                   g_param_spec_boolean("show_hours",
+                                   "Show hours field",
+                                   "Controls whether the hours field is shown in the editor",
+                                   TRUE,
                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
 
   /**
    * HildonTimeEditor:duration_mode:
    *
-   * TimeEditor duration mode indicator.
+   * Controls whether the TimeEditor is in duration mode
    */
   g_object_class_install_property( object_class, PROP_DURATION_MODE,
                                    g_param_spec_boolean("duration_mode",
@@ -444,20 +418,20 @@ hildon_time_editor_class_init(HildonTimeEditorClass * editor_class)
   /**
    * HildonTimeEditor:duration_min:
    *
-   * TimeEditor minimum duration value.
+   * Minimum allowed duration value.
    */
   g_object_class_install_property( object_class, PROP_DURATION_MIN,
                                    g_param_spec_uint("duration_min",
                                    "Minumum duration value",
                                    "Smallest possible duration value",
-                                   0, G_MAXUINT,
+                                   MIN_DURATION, MAX_DURATION,
                                    HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
 
   /**
    * HildonTimeEditor:duration_max:
    *
-   * TimeEditor maximum duration value.
+   * Maximum allowed duration value.
    */
   g_object_class_install_property( object_class, PROP_DURATION_MAX,
                                    g_param_spec_uint("duration_max",
@@ -466,7 +440,6 @@ hildon_time_editor_class_init(HildonTimeEditorClass * editor_class)
                                    0, G_MAXUINT,
                                    HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
-
 }
 
 static
@@ -476,67 +449,96 @@ void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
                                            GtkWidgetTapAndHoldFlags flags)
 {
     HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
+    gint i;
 
-    gtk_widget_tap_and_hold_setup(priv->h_entry, menu, func,
-                                  GTK_TAP_AND_HOLD_NO_SIGNALS);
-    gtk_widget_tap_and_hold_setup(priv->m_entry, menu, func,
-                                  GTK_TAP_AND_HOLD_NO_SIGNALS);
-    gtk_widget_tap_and_hold_setup(priv->s_entry, menu, func,
-                                  GTK_TAP_AND_HOLD_NO_SIGNALS);
+    /* Forward this tap_and_hold_setup signal to all our child widgets */
+    for (i = 0; i < ENTRY_COUNT; i++)
+    {
+      gtk_widget_tap_and_hold_setup(priv->entries[i], menu, func,
+                                    GTK_TAP_AND_HOLD_NO_SIGNALS);
+    }
     gtk_widget_tap_and_hold_setup(priv->eventbox, menu, func,
                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
     gtk_widget_tap_and_hold_setup(priv->iconbutton, menu, func,
                                   GTK_TAP_AND_HOLD_NONE);
 }
 
+static void hildon_time_editor_entry_changed(GtkWidget *widget, gpointer data)
+{
+    g_assert(HILDON_IS_TIME_EDITOR(data));
+    hildon_time_editor_validate(HILDON_TIME_EDITOR(data), TRUE);
+}
+
 static void hildon_time_editor_init(HildonTimeEditor * editor)
 {
     HildonTimeEditorPrivate *priv;
-    guint ticks = 0;
+    GtkWidget *hbox, *icon;
+    gint i;
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
     gtk_widget_push_composite_child();
     
-    priv->ticks = 0;
-    priv->show_s = FALSE;
+    /* Setup defaults and create widgets */
+    priv->ticks          = 0;
+    priv->show_seconds   = FALSE;
+    priv->show_hours     = TRUE;
     priv->ampm_pos_after = TRUE;
-    priv->clock_24h = TRUE;
-    priv->duration_mode = FALSE;
-    priv->iconbutton = gtk_button_new();
-    priv->h_entry = gtk_entry_new();
-    priv->m_entry = gtk_entry_new();
-    priv->s_entry = gtk_entry_new();
-    priv->ampm = gtk_label_new(NULL);
-    priv->label = gtk_label_new(_("Ecdg_ti_time_editor_separator"));
-    priv->label2 = gtk_label_new(_("Ecdg_ti_time_editor_separator"));
-    priv->icon = gtk_image_new_from_icon_name(ICON_NAME, HILDON_ICON_SIZE_26);
-    priv->frame = gtk_frame_new(NULL);
-    priv->eventbox = gtk_event_box_new();
-    priv->valid_value = TRUE;
-    priv->validated = FALSE;
-    
+    priv->clock_24h      = TRUE;
+    priv->duration_mode  = FALSE;
+    priv->iconbutton     = gtk_button_new();
+    priv->ampm_label     = gtk_label_new(NULL);
+    priv->hm_label       = gtk_label_new(NULL);
+    priv->sec_label      = gtk_label_new(NULL);
+    priv->frame          = gtk_frame_new(NULL);
+    priv->eventbox       = gtk_event_box_new();
+
+    icon = gtk_image_new_from_icon_name(ICON_NAME, HILDON_ICON_SIZE_WIDG);
+    hbox = gtk_hbox_new(FALSE, 0);
+
     GTK_WIDGET_SET_FLAGS(editor, GTK_NO_WINDOW);
-    GTK_WIDGET_UNSET_FLAGS(priv->iconbutton, GTK_CAN_FOCUS);
+    GTK_WIDGET_UNSET_FLAGS(priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
     
     gtk_event_box_set_visible_window(GTK_EVENT_BOX(priv->eventbox), FALSE);
 
     gtk_container_set_border_width(GTK_CONTAINER(priv->frame), 0);
 
-    gtk_container_add(GTK_CONTAINER(priv->iconbutton), priv->icon);
-    gtk_container_add(GTK_CONTAINER(priv->eventbox), priv->ampm);
+    gtk_container_add(GTK_CONTAINER(priv->iconbutton), icon);
+    gtk_container_add(GTK_CONTAINER(priv->eventbox), priv->ampm_label);
 
-    gtk_entry_set_has_frame(GTK_ENTRY(priv->h_entry), FALSE);
-    gtk_entry_set_has_frame(GTK_ENTRY(priv->m_entry), FALSE);
-    gtk_entry_set_has_frame(GTK_ENTRY(priv->s_entry), FALSE);
+    /* Create hour, minute and second entries */
+    for (i = 0; i < ENTRY_COUNT; i++)
+    {
+      priv->entries[i] = gtk_entry_new();
+
+      /* No frames for entries, so that they all appear to be inside one long entry */
+      gtk_entry_set_has_frame(GTK_ENTRY(priv->entries[i]), FALSE);
+
+      /* Set the entries to accept only numeric characters */
+      g_object_set (priv->entries[i], "input-mode",
+                    HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
+
+      /* The entry fields all take exactly two characters */
+      gtk_entry_set_max_length  (GTK_ENTRY(priv->entries[i]), 2);
+      gtk_entry_set_width_chars (GTK_ENTRY(priv->entries[i]), 2);
+
+      /* Connect signals */
+      g_signal_connect(priv->entries[i], "button-release-event",
+                       G_CALLBACK(hildon_time_editor_entry_clicked), editor);
+      g_signal_connect(priv->entries[i], "focus-in-event",
+                       G_CALLBACK(hildon_time_editor_entry_focusin), editor);
+      g_signal_connect(priv->entries[i], "focus-out-event",
+                       G_CALLBACK(hildon_time_editor_entry_focusout), editor);
+      g_signal_connect(priv->entries[i], "key-press-event",
+                       G_CALLBACK(hildon_time_editor_entry_keypress), editor);
+      g_signal_connect(priv->entries[i], "changed",
+                       G_CALLBACK(hildon_time_editor_entry_changed), editor);
     
-    g_object_set (G_OBJECT(priv->h_entry), "input-mode",
-                  HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
-    g_object_set (G_OBJECT(priv->m_entry), "input-mode", 
-                  HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
-    g_object_set (G_OBJECT(priv->s_entry), "input-mode",
-                  HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
-
+      /* inserted signal sets time */
+      g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
+                             G_CALLBACK (hildon_time_editor_inserted_text), 
+                             editor);
+    }
     
     /* clicked signal for am/pm label */
     g_signal_connect(G_OBJECT(priv->eventbox), "button_press_event",
@@ -546,112 +548,45 @@ static void hildon_time_editor_init(HildonTimeEditor * editor)
     g_signal_connect(G_OBJECT(priv->iconbutton), "clicked",
                      G_CALLBACK(hildon_time_editor_icon_clicked), editor);
 
-    /* clicked signal for hour entry */
-    g_signal_connect(G_OBJECT(priv->h_entry), "button-release-event",
-                     G_CALLBACK(hildon_time_editor_entry_clicked), editor);
-    g_signal_connect(G_OBJECT(priv->h_entry), "focus-in-event",
-                     G_CALLBACK(hildon_time_editor_entry_focusin), editor);
-
-    /* clicked signal for minute entry */
-    g_signal_connect(G_OBJECT(priv->m_entry), "button-release-event",
-                     G_CALLBACK(hildon_time_editor_entry_clicked), editor);
-    g_signal_connect(G_OBJECT(priv->m_entry), "focus-in-event",
-                     G_CALLBACK(hildon_time_editor_entry_focusin), editor);
-
-    /* clicked signal for second entry */
-    g_signal_connect(G_OBJECT(priv->s_entry), "button-release-event",
-                     G_CALLBACK(hildon_time_editor_entry_clicked), editor);
-    g_signal_connect(G_OBJECT(priv->s_entry), "focus-in-event",
-                     G_CALLBACK(hildon_time_editor_entry_focusin), editor);
-
-    /* focus out events */
-    g_signal_connect(G_OBJECT(priv->h_entry), "focus-out-event",
-                     G_CALLBACK(hildon_time_editor_entry_focusout),
-                     editor);
-    g_signal_connect(G_OBJECT(priv->m_entry), "focus-out-event",
-                     G_CALLBACK(hildon_time_editor_entry_focusout),
-                     editor);
-    g_signal_connect(G_OBJECT(priv->s_entry), "focus-out-event",
-                     G_CALLBACK(hildon_time_editor_entry_focusout),
-                     editor);
-
-    /* key press events */
-    g_signal_connect(G_OBJECT(priv->h_entry), "key-press-event",
-                     G_CALLBACK(hildon_time_editor_entry_keypress),
-                     editor);
-    g_signal_connect(G_OBJECT(priv->m_entry), "key-press-event",
-                     G_CALLBACK(hildon_time_editor_entry_keypress),
-                     editor);
-    g_signal_connect(G_OBJECT(priv->s_entry), "key-press-event",
-                     G_CALLBACK(hildon_time_editor_entry_keypress),
-                     editor);
-
-    /* changed signal sets time */
-    g_signal_connect_after (G_OBJECT(priv->h_entry), "changed",
-                      G_CALLBACK (hildon_time_editor_entry_changed), 
-                      editor);
-    g_signal_connect_after (G_OBJECT(priv->m_entry), "changed",
-                      G_CALLBACK (hildon_time_editor_entry_changed), 
-                      editor);
-    g_signal_connect_after (G_OBJECT(priv->s_entry), "changed",
-                      G_CALLBACK (hildon_time_editor_entry_changed), 
-                      editor);
-                      
+    /* Set ourself as the parent of all the widgets we created */
     gtk_widget_set_parent(priv->iconbutton, GTK_WIDGET(editor));
-    gtk_widget_set_parent(priv->label, GTK_WIDGET(editor));
-
-    gtk_widget_set_parent(priv->label2, GTK_WIDGET(editor));
-    gtk_widget_set_parent(priv->s_entry, GTK_WIDGET(editor));
-    gtk_widget_set_parent(priv->eventbox, GTK_WIDGET(editor));
-    gtk_widget_set_parent(priv->m_entry, GTK_WIDGET(editor));
-    gtk_widget_set_parent(priv->h_entry, GTK_WIDGET(editor));
+    gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), priv->hm_label,             FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_MINS],  FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), priv->sec_label,            FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_SECS],  FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), priv->eventbox,             FALSE, FALSE, 0);
 
-    gtk_widget_show(priv->h_entry);
-    gtk_widget_show(priv->m_entry);
-    gtk_widget_show_all(priv->iconbutton);
-    gtk_widget_show(priv->label);
+    gtk_container_add(GTK_CONTAINER(priv->frame), hbox);
 
+    /* Show created widgets */
     gtk_widget_set_parent(priv->frame, GTK_WIDGET(editor));
     gtk_widget_show_all(priv->frame);
+    gtk_widget_show_all(priv->iconbutton);
 
-    /* Check if we are in am/pm time locale */
+    /* Update AM/PM and time separators settings from locale */
     if (!hildon_time_editor_check_locale(editor)) {
+        /* Using 12h clock */
         priv->clock_24h = FALSE;
-        gtk_widget_show_all(priv->eventbox);
+    } else {
+        gtk_widget_hide(priv->eventbox);
     }
-
-    {   /* get current time */
-        time_t tm;
-        struct tm *stm;
-
-        tm = time(NULL);
-        stm = localtime(&tm);
-
-        if (stm) {
-            ticks = stm->tm_hour * 3600;
-            ticks = ticks + stm->tm_min * 60;
-            ticks = ticks + stm->tm_sec;
-        }
+    if (!priv->show_seconds) {
+        gtk_widget_hide(priv->sec_label);
+        gtk_widget_hide(priv->entries[ENTRY_SECS]);
     }
 
-    hildon_time_editor_set_ticks (editor, ticks);
-    
-    gtk_entry_set_max_length(GTK_ENTRY(priv->h_entry), 2);
-    gtk_entry_set_width_chars(GTK_ENTRY(priv->h_entry), 2);
-    gtk_entry_set_max_length(GTK_ENTRY(priv->m_entry), 2);
-    gtk_entry_set_width_chars(GTK_ENTRY(priv->m_entry), 2);
-    gtk_entry_set_max_length(GTK_ENTRY(priv->s_entry), 2);
-    gtk_entry_set_width_chars(GTK_ENTRY(priv->s_entry), 2);
-
-    hildon_time_editor_add_style();
-    gtk_widget_set_name(GTK_WIDGET(priv->iconbutton),
-                        "hildon-time-editor-icon");
-    
+    /* set the default time to current time. */
+    hildon_time_editor_set_to_current_time (editor);
+
     gtk_widget_pop_composite_child();
 }
 
-static void hildon_time_editor_set_property (GObject *object, guint param_id,
-                                      const GValue *value, GParamSpec *pspec)
+static void hildon_time_editor_set_property (GObject      *object,
+                                             guint         param_id,
+                                             const GValue *value,
+                                             GParamSpec   *pspec)
 {
   HildonTimeEditor *time_editor = HILDON_TIME_EDITOR(object);
   switch (param_id)
@@ -664,6 +599,10 @@ static void hildon_time_editor_set_property (GObject *object, guint param_id,
       hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
       break;
 
+    case PROP_SHOW_HOURS:
+      hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
+      break;
+
     case PROP_DURATION_MODE:
       hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
       break;
@@ -682,8 +621,10 @@ static void hildon_time_editor_set_property (GObject *object, guint param_id,
   }
 }
 
-static void hildon_time_editor_get_property (GObject *object, guint param_id,
-                                            GValue *value, GParamSpec *pspec)
+static void hildon_time_editor_get_property (GObject    *object,
+                                             guint       param_id,
+                                             GValue     *value,
+                                             GParamSpec *pspec)
 {
   HildonTimeEditor *time_editor = HILDON_TIME_EDITOR(object);
   switch (param_id)
@@ -697,6 +638,10 @@ static void hildon_time_editor_get_property (GObject *object, guint param_id,
       g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
       break;
 
+    case PROP_SHOW_HOURS:
+      g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
+      break;
+
     case PROP_DURATION_MODE:
       g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
       break;
@@ -715,24 +660,13 @@ static void hildon_time_editor_get_property (GObject *object, guint param_id,
   }
 }
 
-
-static gboolean
-hildon_time_editor_mnemonic_activate( GtkWidget *widget,
-                                      gboolean group_cycling)
-{
-  HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
-  gtk_widget_grab_focus( priv->h_entry );
-  gtk_editable_select_region(GTK_EDITABLE(priv->h_entry), 0, 2);
-  return TRUE;
-}
-
 /**
  * hildon_time_editor_new:
  *
  * This function creates a new time editor. 
  *
- * Return value: pointer to a new #HildonTimeEditor widget.
- **/
+ * Returns: pointer to a new #HildonTimeEditor widget
+ */
 
 GtkWidget *hildon_time_editor_new(void)
 {
@@ -743,170 +677,195 @@ static void hildon_time_editor_finalize(GObject * obj_self)
 {
     HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(obj_self);
 
-    if (priv->am_symbol)
-        g_free(priv->am_symbol);
-    if (priv->pm_symbol)
-        g_free(priv->pm_symbol);
+    g_free(priv->am_symbol);
+    g_free(priv->pm_symbol);
+
+    if (priv->highlight_idle)
+        g_source_remove(priv->highlight_idle);
 
     if (G_OBJECT_CLASS(parent_class)->finalize)
         G_OBJECT_CLASS(parent_class)->finalize(obj_self);
 }
 
-static void hildon_time_editor_add_style(void)
+/**
+ * _hildon_time_editor_get_time_separators:
+ * @editor: the #HildonTimeEditor
+ * @hm_sep_label: the label that will show the hour:minutes separator
+ * @ms_sep_label: the label that will show the minutes:seconds separator
+ *
+ * Gets hour-minute separator and minute-second separator from current
+ * locale and sets then to the labels we set as parameters. Both
+ * parameters can be NULL if you just want to assing one separator.
+ *
+ */
+void 
+_hildon_time_editor_get_time_separators(GtkLabel *hm_sep_label,
+                                        GtkLabel *ms_sep_label)
 {
-    gtk_rc_parse_string("  style \"hildon-time-editor-icon\" {"
-                        "    GtkButton::default_border = { 0, 0, 0, 0 }"
-                        "    xthickness = 0"
-                        "    ythickness = 0"
-                        "    engine \"pixmap\" {"
-                        "      image {"
-                        "        function = BOX"
-                        "      }"
-                        "    }"
-                        "  }"
-                        "  widget \"*.hildon-time-editor-icon\""
-                        "    style \"hildon-time-editor-icon\"");
+    gchar buffer[256];
+    gchar *separator;
+    GDate locale_test_date;
+    gchar *iter, *endp;
+
+    /* Get localized time string */
+    g_date_set_dmy(&locale_test_date, 1, 2, 1970);
+    (void) g_date_strftime(buffer, sizeof(buffer), "%X", &locale_test_date);
+
+    if (hm_sep_label != NULL)
+      {
+        /* Find h-m separator */
+        iter = buffer;
+        while (*iter && g_ascii_isdigit(*iter)) iter++;
+    
+        /* Extract h-m separator*/
+        endp = iter;
+        while (*endp && !g_ascii_isdigit(*endp)) endp++;
+        separator = g_strndup(iter, endp - iter);
+        gtk_label_set_label(hm_sep_label, separator);
+        g_free(separator);
+      }
+
+    if (ms_sep_label != NULL)
+      {      
+        /* Find m-s separator */
+        iter = endp;
+        while (*iter && g_ascii_isdigit(*iter)) iter++;
+    
+        /* Extract m-s separator*/
+        endp = iter;
+        while (*endp && !g_ascii_isdigit(*endp)) endp++;
+        separator = g_strndup(iter, endp - iter);
+        gtk_label_set_label(ms_sep_label, separator);
+        g_free(separator);
+      }
+
 }
 
+/* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
 static void ticks_to_time (guint ticks,
                            guint *hours,
                            guint *minutes,
                            guint *seconds)
 {
-  guint h,m,s;
-
-  h = ticks / 3600;
-  m = (ticks - h*3600) / 60;
-  s = ticks - h*3600 - m*60;
-
-  *hours = h;
-  *minutes = m;
-  *seconds = s;
+  guint left;
 
+  *hours = ticks / 3600;
+  left   = ticks % 3600;
+  *minutes = left / 60;
+  *seconds = left % 60;
 }
 
 /**
  * hildon_time_editor_set_ticks:
- * @self: the @HildonTimeEditor widget.
- * @ticks: The duration to set, in seconds.
+ * @editor: the #HildonTimeEditor widget
+ * @ticks: the duration to set, in seconds
  *
  * Sets the current duration in seconds. This means seconds from
  * midnight, if not in duration mode. In case of any errors, it tries
  * to fix it.
- * 
- **/
+ */
 
 void hildon_time_editor_set_ticks (HildonTimeEditor * editor,
                                    guint ticks)
 {
     HildonTimeEditorPrivate *priv;
-    HildonValidation validation;
-    guint h = 1;
-    guint m = 0;
-    guint s = 0;
-    gchar hours[3]   = "01";
-    gchar minutes[3] = "00";
-    gchar seconds[3] = "00";
-
-    g_return_if_fail(editor);
-    g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
+    guint i, h, m, s;
+    gchar str[3];
+
+    g_assert(HILDON_IS_TIME_EDITOR(editor));
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
-    /* Validate the value if it is not already validated */
-    if (!priv->validated) {
-        if (priv->duration_mode) {
-            validation = hildon_time_editor_validate_duration (editor, ticks);
-            switch(validation) {
-                case VALIDATION_DURATION_MIN:
-                    priv->ticks = priv->duration_min;
-                    break;
-                case VALIDATION_DURATION_MAX:
-                    priv->ticks = priv->duration_max;
-                    break;
-                default:
-                    priv->ticks = ticks;
-                    break;
-            }
-        } else {
-            ticks_to_time (ticks, &h, &m, &s);
-            validation = hildon_time_editor_validate_time (editor, h, m, s, TRUE);
-            switch (validation) {
-                case VALIDATION_TIME_HOURS:
-                    if (priv->clock_24h) {
-                        if (h > HOURS_MAX_24) {
-                            h = HOURS_MAX_24;
-                        } else if (h < HOURS_MIN_24) {
-                            h = HOURS_MIN_24;
-                        }
-                    } else {
-                        if (h > HOURS_MAX_12) {
-                            h = HOURS_MAX_12;
-                        } else if (h < HOURS_MIN_12) {
-                            h = HOURS_MIN_12;
-                        }
-                    }
-                    priv->ticks = (3600 * h) + (60 * m) + s;
-                    break;
-                case VALIDATION_TIME_MINUTES:
-                    if (m > MINUTES_MAX) {
-                        m = MINUTES_MAX;
-                    } else if (m < MINUTES_MIN) {
-                        m = MINUTES_MIN;
-                    }
-                    break;
-                case VALIDATION_TIME_SECONDS:
-                    if (s > SECONDS_MAX) {
-                        s = SECONDS_MAX;
-                    } else if (s < SECONDS_MIN) {
-                        s = SECONDS_MIN;
-                    }
-                    priv->ticks = (3600 * h) + (60 * m) + s;
-                    break;
-                default:
-                    priv->ticks = ticks;
-                    break;
-            }
-        }
-    } else {
-      priv->ticks = ticks;
+    /* Validate ticks. If it's too low or too high, set it to
+       min/max value for the current mode. */
+    if (priv->duration_mode)
+        priv->ticks = CLAMP(ticks, priv->duration_min, priv->duration_max);
+    else {
+        /* Check that ticks value is valid. We only need to check that hours
+           don't exceed 23. */
+        ticks_to_time (ticks, &h, &m, &s);
+        if (h > HOURS_MAX_24)
+            ticks = TICKS(HOURS_MAX_24, m, s);
+
+        priv->ticks = ticks;
     }
     
-    ticks_to_time (priv->ticks, &h, &m, &s);
-    
+    /* Get the time in H:M:S. */
     ticks_to_time (priv->ticks, &h, &m, &s);
     
     if (!priv->clock_24h && !priv->duration_mode)
       {
-        convert_to_12h (&h, &m, &s, &priv->am);
+        /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
+        convert_to_12h (&h, &priv->am);
       }
 
-    g_snprintf(hours,   3, "%02u", h);
-    g_snprintf(minutes, 3, "%02u", m);
-    g_snprintf(seconds, 3, "%02u", s);
-    gtk_entry_set_text(GTK_ENTRY(priv->h_entry), hours);
-    gtk_entry_set_text(GTK_ENTRY(priv->m_entry), minutes);
-    gtk_entry_set_text(GTK_ENTRY(priv->s_entry), seconds);
-       
-    priv->valid_value = TRUE;
-    priv->validated = FALSE;
-
-    /* set current time (am/pm) */
-    gtk_label_set_label(GTK_LABEL(priv->ampm), priv->am ? priv->am_symbol :
-                        priv->pm_symbol);
+    /* Set H:M:S values to entries. We  do not want to invoke validation
+       callbacks (since they can cause new call to this function), so we 
+       block signals while setting values. */
+    for (i = 0; i < ENTRY_COUNT; i++)
+    {
+      g_signal_handlers_block_by_func(priv->entries[i],
+        (gpointer) hildon_time_editor_entry_changed, editor);
+
+      g_signal_handlers_block_by_func(priv->entries[i],
+        (gpointer) hildon_time_editor_inserted_text, editor);
+      
+      g_signal_handlers_block_by_func(priv->entries[i],
+       (gpointer) hildon_time_editor_entry_focusout, editor);
+
+    }
+
+    g_snprintf(str, sizeof(str), "%02u", h);
+    gtk_entry_set_text(GTK_ENTRY(priv->entries[ENTRY_HOURS]), str);
+
+    g_snprintf(str, sizeof(str), "%02u", m);
+    gtk_entry_set_text(GTK_ENTRY(priv->entries[ENTRY_MINS]), str);
+
+    g_snprintf(str, sizeof(str), "%02u", s);
+    gtk_entry_set_text(GTK_ENTRY(priv->entries[ENTRY_SECS]), str);
+
+    for (i = 0; i < ENTRY_COUNT; i++)
+    {
+      g_signal_handlers_unblock_by_func(priv->entries[i],
+        (gpointer) hildon_time_editor_entry_changed, editor);
+
+      g_signal_handlers_unblock_by_func(priv->entries[i],
+        (gpointer) hildon_time_editor_inserted_text, editor);
+
+      g_signal_handlers_unblock_by_func(priv->entries[i],
+       (gpointer) hildon_time_editor_entry_focusout, editor);
+
+   }
+
+    /* Update AM/PM label in case we're in 12h mode */
+    gtk_label_set_label(GTK_LABEL(priv->ampm_label),
+                       priv->am ? priv->am_symbol : priv->pm_symbol);
     
     g_object_notify (G_OBJECT (editor), "ticks");
 }
 
+static void
+hildon_time_editor_set_to_current_time (HildonTimeEditor * editor)
+{
+    time_t now;
+    const struct tm *tm;
+
+    now = time(NULL);
+    tm = localtime(&now);
+
+    if (tm != NULL)
+        hildon_time_editor_set_time(editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
 /**
  * hildon_time_editor_get_ticks:
- * @self: the @HildonTimeEditor widget.
+ * @editor: the #HildonTimeEditor widget
  *
  * This function returns the current duration, in seconds.
  * This means seconds from midnight, if not in duration mode.
  * 
- * Return value: Current duration in seconds. 
- **/
+ * Returns: current duration in seconds 
+ */
  
 guint hildon_time_editor_get_ticks (HildonTimeEditor * editor)
 {
@@ -922,51 +881,46 @@ guint hildon_time_editor_get_ticks (HildonTimeEditor * editor)
 
 /**
  * hildon_time_editor_set_show_seconds:
- * @editor: The #HildonTimeEditor.
- * @enable: Enable or disable showing of seconds.
+ * @editor: the #HildonTimeEditor
+ * @show_seconds: enable or disable showing of seconds
  *
  * This function shows or hides the seconds field.
- *
- **/
+ */
 
 void hildon_time_editor_set_show_seconds (HildonTimeEditor * editor,
                                         gboolean show_seconds)
 {
     HildonTimeEditorPrivate *priv;
 
-    g_return_if_fail(editor);
+    g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
-    if (!priv->show_s && show_seconds) {
-        priv->show_s = TRUE;
-
-        gtk_widget_show(priv->s_entry);
-        gtk_widget_show(priv->label2);
-        
-    } else if (priv->show_s && !show_seconds) {
-
-        gtk_widget_hide(priv->s_entry);
-        gtk_widget_hide(priv->label2);
+    if (show_seconds != priv->show_seconds) {
+        priv->show_seconds = show_seconds;
 
-        priv->show_s = FALSE;
-    } else
-        return;
-
-    gtk_widget_queue_resize(GTK_WIDGET(editor));
+        /* show/hide seconds field and its ':' label if the value changed. */
+        if (show_seconds) {
+            gtk_widget_show(priv->entries[ENTRY_SECS]);
+            gtk_widget_show(priv->sec_label);        
+        } else {    
+            gtk_widget_hide(priv->entries[ENTRY_SECS]);
+            gtk_widget_hide(priv->sec_label);
+        }
     
-    g_object_notify (G_OBJECT (editor), "show_seconds");
+        g_object_notify (G_OBJECT (editor), "show_seconds");
+    }
 }
 
 /**
  * hildon_time_editor_get_show_seconds:
- * @self: the @HildonTimeEditor widget.
+ * @editor: the #HildonTimeEditor widget
  *
  * This function returns a boolean indicating the visibility of
- * seconds in the @HildonTimeEditor
+ * seconds in the #HildonTimeEditor
  *
- * Return value: TRUE if the seconds are visible. 
- **/
+ * Returns: TRUE if the seconds are visible 
+ */
 
 gboolean hildon_time_editor_get_show_seconds (HildonTimeEditor * editor)
 {
@@ -975,90 +929,69 @@ gboolean hildon_time_editor_get_show_seconds (HildonTimeEditor * editor)
     g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
-    return (priv->show_s);
+    return (priv->show_seconds);
 }
 
 /**
  * hildon_time_editor_set_duration_mode:
- * @editor: The #HildonTimeEditor.
- * @enable: Enable or disable duration editor mode
+ * @editor: the #HildonTimeEditor
+ * @duration_mode: enable or disable duration editor mode
  *
  * This function sets the duration editor mode in which the maximum hours
- * is 99 and the #HildonTimePicker is disabled.
- *
- **/
+ * is 99.
+ */
  
 void hildon_time_editor_set_duration_mode (HildonTimeEditor * editor,
                                          gboolean duration_mode)
 {
     HildonTimeEditorPrivate *priv;
 
-    g_return_if_fail(editor);
+    g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
-    /* switch to duration editor mode */
-    if (duration_mode && !priv->duration_mode) {
+    if (duration_mode != priv->duration_mode) {
         priv->duration_mode = duration_mode;
-        hildon_time_editor_set_duration_range(editor, MIN_DURATION,
-                                              MAX_DURATION);
 
-        if (!priv->clock_24h)
-            gtk_widget_hide(GTK_WIDGET(priv->ampm));
-
-        gtk_widget_hide(GTK_WIDGET(priv->eventbox));
-        gtk_widget_hide(GTK_WIDGET(priv->icon));
-
-        /* Show seconds for duration editor */
-        hildon_time_editor_set_show_seconds(editor, TRUE);
-    }
-    /* switch to time editor mode */
-    else if (!duration_mode && priv->duration_mode) {
-        guint ticks;
-        time_t tm;
-        struct tm *stm;
-            
-        priv->duration_mode = duration_mode;
-
-        if (!priv->clock_24h)
-            gtk_widget_show(GTK_WIDGET(priv->ampm));
-
-        gtk_widget_show(GTK_WIDGET(priv->eventbox));
-        gtk_widget_show(GTK_WIDGET(priv->icon));
-        
+        if (duration_mode) {
+            /* FIXME: Why do we reset the duration range here?
+               Would change API, so won't touch this for now. */
+            hildon_time_editor_set_duration_range(editor, MIN_DURATION,
+                                                      MAX_DURATION);
+            /* There's no AM/PM label or time picker icon in duration mode.
+               Make sure they're hidden. */
+            gtk_widget_hide(GTK_WIDGET(priv->ampm_label));
+            gtk_widget_hide(GTK_WIDGET(priv->eventbox));
+            gtk_widget_hide(GTK_WIDGET(priv->iconbutton));
+            /* Duration mode has seconds by default. */
+            hildon_time_editor_set_show_seconds(editor, TRUE);
+        } else {
+            /* Make sure AM/PM label and time picker icons are visible if needed */
+            if (!priv->clock_24h)
+                gtk_widget_show(GTK_WIDGET(priv->ampm_label));
 
-        /* Put the ticks to match current time, anything set in the 
-         * duration mode is bound to be invalid or useless in time mode
-         */
-        
-        tm = time(NULL);
-        stm = localtime(&tm);
+            gtk_widget_show(GTK_WIDGET(priv->eventbox));
+            gtk_widget_show(GTK_WIDGET(priv->iconbutton));        
 
-        ticks = HILDON_TIME_EDITOR_TIME_LOWER_VALUE;
-        
-        if (stm) {
-            ticks = stm->tm_hour * 3600;
-            ticks = ticks + stm->tm_min * 60;
-            ticks = ticks + stm->tm_sec;
+               /* Reset the ticks to current time. Anything set in duration mode
+             * is bound to be invalid or useless in time mode.
+             */
+            hildon_time_editor_set_to_current_time (editor);
         }
-        
-        hildon_time_editor_set_ticks (editor, ticks);
-        
+
+        g_object_notify (G_OBJECT (editor), "duration_mode");
     }
-    gtk_widget_queue_resize(GTK_WIDGET(editor));
-    
-    g_object_notify (G_OBJECT (editor), "duration_mode");
 }
 
 /**
  * hildon_time_editor_get_duration_mode:
- * @self: the @HildonTimeEditor widget.
+ * @editor: the #HildonTimeEditor widget
  *
- * This function returns a boolean indicating whether the @HildonTimeEditor
+ * This function returns a boolean indicating whether the #HildonTimeEditor
  * is in the duration mode.
  * 
- * Return value: TRUE if the @HildonTimeEditor is in duration mode. 
- **/
+ * Returns: TRUE if the #HildonTimeEditor is in duration mode 
+ */
 
 gboolean hildon_time_editor_get_duration_mode (HildonTimeEditor * editor)
 {
@@ -1072,21 +1005,19 @@ gboolean hildon_time_editor_get_duration_mode (HildonTimeEditor * editor)
 
 /**
  * hildon_time_editor_set_duration_min:
- * @self: the @HildonTimeEditor widget.
- * @duration_min: Mimimum allowed duration.
+ * @editor: the #HildonTimeEditor widget
+ * @duration_min: mimimum allowed duration
  *
  * Sets the minimum allowed duration for the duration mode.
  * Note: Has no effect in time mode
- **/
+ */
 
 void hildon_time_editor_set_duration_min (HildonTimeEditor * editor,
                                           guint duration_min)
 {
     HildonTimeEditorPrivate *priv;
 
-    g_return_if_fail(editor);
     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
-
     g_return_if_fail(duration_min >= MIN_DURATION);
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
@@ -1107,19 +1038,18 @@ void hildon_time_editor_set_duration_min (HildonTimeEditor * editor,
 
 /**
  * hildon_time_editor_get_duration_min:
- * @self: the @HildonTimeEditor widget.
+ * @editor: the #HildonTimeEditor widget
  *
- * This function returns the smallest duration the @HildonTimeEditor
+ * This function returns the smallest duration the #HildonTimeEditor
  * allows in the duration mode.
  * 
- * Return value: Mimimum allowed duration in seconds. 
- **/
+ * Returns: minimum allowed duration in seconds 
+ */
  
 guint hildon_time_editor_get_duration_min (HildonTimeEditor * editor)
 {
     HildonTimeEditorPrivate *priv;
 
-    g_return_val_if_fail(editor, 0);
     g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
@@ -1132,22 +1062,19 @@ guint hildon_time_editor_get_duration_min (HildonTimeEditor * editor)
 
 /**
  * hildon_time_editor_set_duration_max:
- * @self: the @HildonTimeEditor widget.
- * @duration_min: Maximum allowed duration in seconds.
+ * @editor: the #HildonTimeEditor widget
+ * @duration_max: maximum allowed duration in seconds
  *
  * Sets the maximum allowed duration in seconds for the duration mode.
  * Note: Has no effect in time mode
- * 
- **/
+ */
  
 void hildon_time_editor_set_duration_max (HildonTimeEditor * editor,
                                           guint duration_max)
 {
     HildonTimeEditorPrivate *priv;
 
-    g_return_if_fail(editor);
     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
-
     g_return_if_fail(duration_max <= MAX_DURATION);
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
@@ -1168,19 +1095,18 @@ void hildon_time_editor_set_duration_max (HildonTimeEditor * editor,
 
 /**
  * hildon_time_editor_get_duration_max:
- * @self: the @HildonTimeEditor widget.
+ * @editor: the #HildonTimeEditor widget
  *
- * This function returns the longest duration the @HildonTimeEditor
+ * This function returns the longest duration the #HildonTimeEditor
  * allows in the duration mode.
  * 
- * Return value: Maximum allowed duration in seconds. 
- **/
+ * Returns: maximum allowed duration in seconds 
+ */
  
 guint hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
 {
     HildonTimeEditorPrivate *priv;
 
-    g_return_val_if_fail(editor, 0);
     g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
@@ -1194,36 +1120,34 @@ guint hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
 
 /**
  * hildon_time_editor_set_time:
- * @editor: the @HildonTimeEditor widget.
+ * @editor: the #HildonTimeEditor widget
  * @hours: hours
  * @minutes: minutes
  * @seconds: seconds
  *
  * This function sets the time on an existing time editor. If the
- * time specified by the arguments is invalid, the function returns
- * without doing anything else. The time is assumed to be in 24h format.
- *  
- **/
+ * time specified by the arguments is invalid, it's fixed.
+ * The time is assumed to be in 24h format.
+ */
 
 void hildon_time_editor_set_time(HildonTimeEditor * editor, guint hours,
                                  guint minutes, guint seconds)
 {
     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
 
-    hildon_time_editor_set_ticks (editor, hours * 3600 + minutes * 60 + seconds);
-
+    hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
 }
 
 /**
  * hildon_time_editor_get_time:
- * @editor: the @HildonTimeEditor widget.
+ * @editor: the #HildonTimeEditor widget
  * @hours: hours
  * @minutes: minutes
  * @seconds: seconds
  *
- * Gets the time of the @HildonTimeEditor widget. The time returned is
+ * Gets the time of the #HildonTimeEditor widget. The time returned is
  * always in 24h format.
- **/
+ */
 
 void hildon_time_editor_get_time(HildonTimeEditor * editor,
                                  guint * hours,
@@ -1231,24 +1155,22 @@ void hildon_time_editor_get_time(HildonTimeEditor * editor,
 {
     HildonTimeEditorPrivate *priv;
     
-    g_return_if_fail(editor);
     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
     ticks_to_time (hildon_time_editor_get_ticks (editor),
                    hours, minutes, seconds);
-
 }
 
 /**
  * hildon_time_editor_set_duration_range:
- * @editor: the @HildonTimeEditor widget.
+ * @editor: the #HildonTimeEditor widget
  * @min_seconds: minimum allowed time in seconds
  * @max_seconds: maximum allowed time in seconds
  *
- * Sets the duration editor time range of the @HildonTimeEditor widget.
- **/
+ * Sets the duration editor time range of the #HildonTimeEditor widget.
+ */
 
 void hildon_time_editor_set_duration_range(HildonTimeEditor * editor,
                                            guint min_seconds,
@@ -1257,7 +1179,6 @@ void hildon_time_editor_set_duration_range(HildonTimeEditor * editor,
     HildonTimeEditorPrivate *priv;
     guint tmp;
     
-    g_return_if_fail(editor);
     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
@@ -1273,19 +1194,21 @@ void hildon_time_editor_set_duration_range(HildonTimeEditor * editor,
     hildon_time_editor_set_duration_min (editor, min_seconds);
 
     if (priv->duration_mode) {
-        /* Set minimum allowed value for duration editor */
+        /* Set minimum allowed value for duration editor.
+           FIXME: Shouldn't it be changed only if it's not in range?
+           Would change API, so won't touch this for now. */
         hildon_time_editor_set_ticks(editor, min_seconds);
     }
 }
 
 /**
  * hildon_time_editor_get_duration_range:
- * @editor: the @HildonTimeEditor widget.
+ * @editor: the #HildonTimeEditor widget
  * @min_seconds: pointer to guint
  * @max_seconds: pointer to guint
  *
- * Gets the duration editor time range of the @HildonTimeEditor widget.
- **/
+ * Gets the duration editor time range of the #HildonTimeEditor widget.
+ */
 
 void hildon_time_editor_get_duration_range(HildonTimeEditor * editor,
                                            guint * min_seconds,
@@ -1293,7 +1216,6 @@ void hildon_time_editor_get_duration_range(HildonTimeEditor * editor,
 {
     HildonTimeEditorPrivate *priv;
 
-    g_return_if_fail(editor);
     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
@@ -1305,25 +1227,25 @@ void hildon_time_editor_get_duration_range(HildonTimeEditor * editor,
 static gboolean hildon_time_editor_check_locale(HildonTimeEditor * editor)
 {
     HildonTimeEditorPrivate *priv;
-    gchar *t_fm;
 
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
+    /* Update time separator symbols */
+    _hildon_time_editor_get_time_separators(GTK_LABEL(priv->hm_label), GTK_LABEL(priv->sec_label));
+    /* Get AM/PM symbols. */
     priv->am_symbol = g_strdup(nl_langinfo(AM_STR));
     priv->pm_symbol = g_strdup(nl_langinfo(PM_STR));
 
-    if (!strcmp(priv->am_symbol, ""))
+    if (priv->am_symbol[0] == '\0')
         return TRUE;
     else {
-        t_fm = g_strdup(nl_langinfo(T_FMT_AMPM));
-        /* Check what format am/pm time should be */
-        if (!strncmp(t_fm, "%p", 2))
+        /* 12h clock mode. Check if AM/PM should be before or after time.
+           %p is the AM/PM string, so we assume that if the format string
+           begins with %p it's in the beginning, and in any other case it's
+           in the end (although that's not necessarily the case). */
+        if (strncmp(nl_langinfo(T_FMT_AMPM), "%p", 2) == 0)
             priv->ampm_pos_after = FALSE;
-        priv->am_symbol =
-            g_ascii_strdown((const gchar *) priv->am_symbol, -1);
-        priv->pm_symbol =
-            g_ascii_strdown((const gchar *) priv->pm_symbol, -1);
-        g_free(t_fm);
         return FALSE;
     }
 }
@@ -1332,242 +1254,314 @@ static gboolean hildon_time_editor_entry_focusin(GtkWidget * widget,
                                                  GdkEventFocus * event, 
                                                  gpointer data)
 {
+    /* If we were trying to move away from a field with invalid value,
+       we get moved back to it. Here we want to select the text in the field.
+       The !button check checks that the entry wasn't focused with a mouse
+       click.
+
+       The selection happens temporarily if we got here with left/right
+       keys, but it gets immediately unselected within same call due to some
+       inner entry/clipboard magic. */
     if (!GTK_ENTRY(widget)->button)
         gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
 
     return FALSE;
 }
 
-
-void
-hildon_time_editor_validate (HildonTimeEditor *editor)
+static gboolean 
+hildon_time_editor_time_error(HildonTimeEditor *editor,
+                             HildonTimeEditorErrorType type)
 {
-    guint max_hours = 0;
-    guint min_hours = 0;
-    guint max_minutes = 0;
-    guint min_minutes = 0;
-    guint max_seconds = 0;
-    guint min_seconds = 0;
-
-    HildonTimeEditorPrivate *priv;
-    HildonValidation validation;
+  return TRUE;
+}
 
-    GtkWindow *window;
-    guint h,m,s;
+/* Returns negative if we didn't get value,
+ * and should stop further validation 
+ */
+static gint validated_conversion(HildonTimeEditorPrivate *priv,
+                                 GtkWidget               *field,
+                                 gint                     min,
+                                 gint                     max,
+                                 gboolean                 allow_intermediate,
+                                 guint                   *error_code,
+                                 GString                 *error_string)
+{
+    const gchar *text;
+    gchar *tail;
+    long value;
 
-    priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
+    text = gtk_entry_get_text(GTK_ENTRY(field));
 
-    window = GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (editor),
-                                                  GTK_TYPE_WINDOW));
+    if (text && text[0])
+    {
+        /* Try to convert entry text to number */
+        value = strtol(text, &tail, 10);
+
+        /* Check if conversion succeeded */
+        if (tail[0] == 0)
+        {    
+            if (value > max) {
+                g_string_printf(error_string, _("ckct_ib_maximum_value"), max);
+                priv->error_widget = field;
+                *error_code = MAX_VALUE;
+                return max;
+                   }
+            if (value < min && !allow_intermediate) {
+                g_string_printf(error_string, _("ckct_ib_minimum_value"), min);
+                priv->error_widget = field;
+                *error_code = MIN_VALUE;
+                return min;
+            }
 
-    hildon_time_editor_get_max_values(editor, 
-            &max_hours, &min_hours, 
-            &max_minutes, &min_minutes, 
-            &max_seconds, &min_seconds);
-            
-    /* No empty values thank you */
-    if (strlen(GTK_ENTRY(priv->h_entry)->text) == 0)
+            return value;
+        }
+        /* We'll handle failed conversions soon */
+    }
+    else if (allow_intermediate) 
+        return -1;  /* Empty field while user is still editing. No error, but
+                       cannot validate either... */
+    else /* Empty field: show error and set value to minimum allowed */
       {
-        if (!priv->duration_mode)
-          {
-            if (priv->clock_24h)
-              {
-                gtk_infoprintf(window,
-                               _("Ckct_ib_set_a_value_within_range"),
-                               HOURS_MIN_24, HOURS_MAX_24);
-              }
-            else
-              {
-                gtk_infoprintf(window,
-                               _("Ckct_ib_set_a_value_within_range"),
-                               HOURS_MIN_12, HOURS_MAX_12);
-              }
-          }
-        else
-          {
-            gtk_infoprintf(window,
-                           _("Ckct_ib_set_a_value_within_range"),
-                           min_hours, max_hours);
-          }
-        hildon_time_editor_set_ticks (editor, priv->ticks);
-        gtk_widget_grab_focus (priv->h_entry);
+        g_string_printf(error_string, _("ckct_ib_set_a_value_within_range"), min, max);
+        priv->error_widget = field;
+        *error_code = WITHIN_RANGE;
+        return min;
       }
-    else if (strlen(GTK_ENTRY(priv->m_entry)->text) == 0)
-      {
-        if (!priv->duration_mode)
-          {
-            gtk_infoprintf(window,
-                           _("Ckct_ib_set_a_value_within_range"),
-                           MINUTES_MIN, MINUTES_MAX);
-          }
-        else
-          {
-            gtk_infoprintf(window,
-                           _("Ckct_ib_set_a_value_within_range"),
-                           min_minutes, max_minutes);
-          }
-        hildon_time_editor_set_ticks (editor, priv->ticks);
-        gtk_widget_grab_focus (priv->m_entry);
-      }
-    else if (strlen(GTK_ENTRY(priv->s_entry)->text) == 0)
+
+    /* Empty field and not allowed intermediated OR failed conversion */
+    g_string_printf(error_string, _("ckct_ib_set_a_value_within_range"), min, max);
+    priv->error_widget = field;
+    *error_code = WITHIN_RANGE;
+    return -1;
+}
+
+static void
+hildon_time_editor_real_validate(HildonTimeEditor *editor, 
+    gboolean allow_intermediate, GString *error_string)
+{
+    HildonTimeEditorPrivate *priv;
+    guint h, m, s, ticks;
+    guint error_code;
+    guint max_hours, min_hours, max_minutes, min_minutes, max_seconds, min_seconds;
+    gboolean r;
+
+    g_assert(HILDON_IS_TIME_EDITOR(editor));
+
+    priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
+    
+    /* Find limits for field based validation. */
+    if (priv->duration_mode)
+    {
+        ticks_to_time(priv->duration_min, &min_hours, &min_minutes, &min_seconds);
+        ticks_to_time(priv->duration_max, &max_hours, &max_minutes, &max_seconds);
+    } else {
+        if (priv->clock_24h) {
+            max_hours = HOURS_MAX_24;
+            min_hours = HOURS_MIN_24;
+        } else {
+            max_hours = HOURS_MAX_12;
+            min_hours = HOURS_MIN_12;
+        }
+    }
+
+    /* Get time components from fields and validate them... */
+    if (priv->show_hours) {
+        h = validated_conversion(priv, priv->entries[ENTRY_HOURS], min_hours, max_hours, 
+            allow_intermediate, &error_code, error_string);
+       if (priv->error_widget == priv->entries[ENTRY_HOURS])
+         g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, hour_errors[error_code], &r);
+        if ((gint) h < 0) return;
+    }
+    else h = 0;
+    m = validated_conversion(priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX, 
+        allow_intermediate, &error_code, error_string);
+    if (priv->error_widget == priv->entries[ENTRY_MINS])
+         g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, min_errors[error_code], &r);
+    if ((gint) m < 0) return;
+    if (priv->show_seconds) {
+        s = validated_conversion(priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX, 
+            allow_intermediate, &error_code, error_string);
+       if (priv->error_widget == priv->entries[ENTRY_SECS])
+             g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, sec_errors[error_code], &r);
+        if ((gint) s < 0) return;
+    } 
+    else s = 0;
+
+    /* Ok, we now do separate check that tick count is valid for duration mode */      
+    if (priv->duration_mode)
+    {          
+        ticks = TICKS(h, m, s);
+
+        if (ticks < priv->duration_min && !allow_intermediate)
+        {
+            g_string_printf(error_string,
+                _("ckct_ib_min_allowed_duration_hts"), 
+                min_hours, min_minutes, min_seconds);
+            hildon_time_editor_set_ticks (editor, priv->duration_min);
+            priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
+           g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, MIN_DUR, &r);
+            return;
+        }
+        else if (ticks > priv->duration_max)
+        {
+            g_string_printf(error_string,
+                _("ckct_ib_max_allowed_duration_hts"), 
+                max_hours, max_minutes, max_seconds);
+            hildon_time_editor_set_ticks (editor, priv->duration_max);
+            priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
+           g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, MAX_DUR, &r);
+            return;
+        }
+    }
+    else if (!priv->clock_24h)
+        convert_to_24h (&h, priv->am);
+
+    /* The only case when we do not want to refresh the
+       time display, is when the user is editing a value 
+       (unless the value was out of bounds and we have to fix it) */
+    if (!allow_intermediate || priv->error_widget)
+        hildon_time_editor_set_time (editor, h, m, s);
+}
+
+/* Setting text to entries causes entry to recompute itself
+   in idle callback, which remove selection. Because of this
+   we need to do selection in idle as well. */
+static gboolean highlight_callback(gpointer data)
+{
+    HildonTimeEditorPrivate *priv;
+    GtkWidget *widget;
+    gint i;
+
+    GDK_THREADS_ENTER ();
+    
+    g_assert(HILDON_IS_TIME_EDITOR(data));
+
+    priv = HILDON_TIME_EDITOR_GET_PRIVATE(data);
+    widget = priv->error_widget;
+    priv->error_widget = NULL;
+    priv->highlight_idle = 0;
+
+    g_assert(GTK_IS_ENTRY(widget));
+
+    /* Avoid revalidation because it will issue the date_error signal
+       twice when there is an empty field. We must block the signal
+       for all the entries because we do not know where the focus
+       comes from */
+    for (i = 0; i < ENTRY_COUNT; i++)
+      g_signal_handlers_block_by_func(priv->entries[i],
+                                     (gpointer) hildon_time_editor_entry_focusout, data);
+    gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
+    gtk_widget_grab_focus(widget);
+    for (i = 0; i < ENTRY_COUNT; i++)
+      g_signal_handlers_unblock_by_func(priv->entries[i],
+                                       (gpointer) hildon_time_editor_entry_focusout, data);
+
+    GDK_THREADS_LEAVE ();
+
+    return FALSE;
+}
+
+/* Update ticks from current H:M:S entries. If they're invalid, show an
+   infoprint and update the fields unless they're empty. */
+static void
+hildon_time_editor_validate (HildonTimeEditor *editor, gboolean allow_intermediate)
+{
+    HildonTimeEditorPrivate *priv;
+    GString *error_message;
+
+    g_assert(HILDON_IS_TIME_EDITOR(editor));
+
+    priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
+
+    /* if there is already an error we do nothing until it will be managed by the idle */
+    if (priv->highlight_idle == 0)
       {
-        if (!priv->duration_mode)
-          {
-            gtk_infoprintf(window,
-                           _("Ckct_ib_set_a_value_within_range"),
-                           SECONDS_MIN, SECONDS_MAX);
-          }
-        else
+        error_message = g_string_new(NULL);
+        hildon_time_editor_real_validate(editor, 
+                                         allow_intermediate, error_message);
+        
+        if (priv->error_widget) 
           {
-            gtk_infoprintf(window,
-                           _("Ckct_ib_set_a_value_within_range"),
-                           min_seconds, max_seconds);
+            hildon_banner_show_information(priv->error_widget, NULL,
+                                           error_message->str);
+            
+            priv->highlight_idle = g_idle_add(highlight_callback, editor);
           }
-        hildon_time_editor_set_ticks (editor, priv->ticks);
-        gtk_widget_grab_focus (priv->s_entry);
+
+        g_string_free(error_message, TRUE);
       }
-    /* Do the validation dance! */
-    else 
-      {
+}
+
+/* on inserted text, if entry has two digits, jumps to the next field. */
+static void
+hildon_time_editor_inserted_text  (GtkEditable * editable,
+                                   gchar * new_text,
+                                   gint new_text_length,
+                                   gint * position,
+                                   gpointer user_data) 
+{
+  HildonTimeEditor *editor;
+  GtkEntry *entry;
+  gchar *value;
+  HildonTimeEditorPrivate *priv;
+
+  entry = GTK_ENTRY(editable);
+  editor = HILDON_TIME_EDITOR(user_data);
+
+  priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
-        h = (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->h_entry)));
-        m = (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)));
-        s = (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->s_entry)));
+  /* if there is already an error we don't have to do anything */ 
+  if (!priv->error_widget)
+    {
+      value = (gchar *) gtk_entry_get_text(entry);
+  
+      if (strlen(value) == 2)
+        {
+          HildonTimeEditorPrivate *priv;
       
-        if (priv->duration_mode)
-          {
-            validation = hildon_time_editor_validate_duration (editor,
-                                                               h*3600 + m*60 + s);
-          
-            switch (validation)
-              {
-                case VALIDATION_DURATION_MIN:
-                  gtk_infoprintf(window,
-                                 _("Ckct_ib_min_allowed_duration_hts"),
-                                 min_hours, min_minutes, min_seconds);
-                  hildon_time_editor_set_ticks (editor, priv->duration_min);
-                  break;
-                case VALIDATION_DURATION_MAX:
-                  gtk_infoprintf(window,
-                                 _("Ckct_ib_max_allowed_duration_hts"),
-                                 max_hours, max_minutes, max_seconds);
-                  hildon_time_editor_set_ticks (editor, priv->duration_max);
-                  break;
-                default:
-                  hildon_time_editor_set_ticks (editor, h*3600 + m*60 + s);
-                  break;
-              }
-          }
-        else
-          {
-            validation = hildon_time_editor_validate_time (editor, h, m, s, priv->clock_24h);
-            switch (validation)
-              {
-                case VALIDATION_TIME_HOURS:
-                  if (priv->clock_24h)
-                    {
-                      if (h > HOURS_MAX_24)
-                        {
-                          gtk_infoprintf(window,
-                                         _("Ckct_ib_maximum_value"),
-                                         HOURS_MAX_24);
-                          h = HOURS_MAX_24;
-                        }
-                      else
-                        {
-                          gtk_infoprintf(window,
-                                         _("Ckct_ib_minimum_value"),
-                                         HOURS_MIN_24);
-                          h = HOURS_MIN_24;
-                        }
-                    }
-                  else
-                    {
-                      if (h > HOURS_MAX_12)
-                        {
-                          gtk_infoprintf(window,
-                                         _("Ckct_ib_maximum_value"),
-                                         HOURS_MAX_12);
-                          h = HOURS_MAX_12;
-                        }
-                      else
-                        {
-                          gtk_infoprintf(window,
-                                         _("Ckct_ib_minimum_value"),
-                                         HOURS_MIN_12);
-                          h = HOURS_MIN_12;
-                        }
-                    }
-                  if (!priv->clock_24h)
-                    convert_to_24h (&h, &m, &s, priv->am);
-                  hildon_time_editor_set_time (editor, h, m, s);
-                  gtk_widget_grab_focus (priv->h_entry);
-                  gtk_editable_select_region(GTK_EDITABLE(priv->h_entry), 0, 2);
-                  break;
-                case VALIDATION_TIME_MINUTES:
-                  if (m > MINUTES_MAX)
-                    {
-                      gtk_infoprintf(window,
-                                     _("Ckct_ib_maximum_value"),
-                                     MINUTES_MAX);
-                      m = MINUTES_MAX;
-                    }
-                  else
-                    {
-                      gtk_infoprintf(window,
-                                     _("Ckct_ib_minimum_value"),
-                                     MINUTES_MIN);
-                      m = MINUTES_MIN;
-                    }
-                  if (!priv->clock_24h)
-                    convert_to_24h (&h, &m, &s, priv->am);
-                  hildon_time_editor_set_time (editor, h, m, s);
-                  gtk_widget_grab_focus (priv->m_entry);
-                  gtk_editable_select_region(GTK_EDITABLE(priv->m_entry), 0, 2);
-                  break;
-                case VALIDATION_TIME_SECONDS:
-                  if (s > SECONDS_MAX)
-                    {
-                      gtk_infoprintf(window,
-                                     _("Ckct_ib_maximum_value"),
-                                     SECONDS_MAX);
-                      s = SECONDS_MAX;
-                    }
-                  else
-                    {
-                      gtk_infoprintf(window,
-                                     _("Ckct_ib_minimum_value"),
-                                     SECONDS_MIN);
-                      s = SECONDS_MIN;
-                    }
-                  if (!priv->clock_24h)
-                    convert_to_24h (&h, &m, &s, priv->am);
-                  hildon_time_editor_set_time (editor, h, m, s);
-                  gtk_widget_grab_focus (priv->s_entry);
-                  gtk_editable_select_region(GTK_EDITABLE(priv->s_entry), 0, 2);
-                  break;
-                default:
-                  if (!priv->clock_24h)
-                    {
-                      convert_to_24h (&h, &m, &s, priv->am);
-                    }
-                  hildon_time_editor_set_time (editor, h, m, s);
-                  break;
-              }
-          }
-        
-      }
+          priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
+      
+          if (GTK_WIDGET(editable) == priv->entries[ENTRY_HOURS]) 
+            { 
+              /* we don't want a focusout signal with this grab_focus
+                 because the validation was already done during the
+                 changed signal */
+              g_signal_handlers_block_by_func(priv->entries[ENTRY_HOURS],
+                                              (gpointer) hildon_time_editor_entry_focusout, editor);
+              
+              gtk_widget_grab_focus(priv->entries[ENTRY_MINS]);
+              *position = -1;
+
+              g_signal_handlers_unblock_by_func(priv->entries[ENTRY_HOURS],
+                                                (gpointer) hildon_time_editor_entry_focusout, editor);
+              
+            }
+          else if (GTK_WIDGET(editable) == priv->entries[ENTRY_MINS] &&
+                   GTK_WIDGET_VISIBLE (priv->entries[ENTRY_SECS])) 
+            {
+              g_signal_handlers_block_by_func(priv->entries[ENTRY_MINS],
+                                              (gpointer) hildon_time_editor_entry_focusout, editor);
+
+              gtk_widget_grab_focus(priv->entries[ENTRY_SECS]);
+              *position = -1;
+
+              g_signal_handlers_unblock_by_func(priv->entries[ENTRY_MINS],
+                                                (gpointer) hildon_time_editor_entry_focusout, editor);
+              
+            }
+        }
+    }   
 }
 
 static gboolean hildon_time_editor_entry_focusout(GtkWidget * widget,
                                                   GdkEventFocus * event,
                                                   gpointer data)
 {
-  HildonTimeEditor *editor;
+  g_assert(HILDON_IS_TIME_EDITOR(data));
 
-  editor = HILDON_TIME_EDITOR(data);
-
-  hildon_time_editor_validate (editor);
+  /* Validate the given time and update ticks. */
+  hildon_time_editor_validate(HILDON_TIME_EDITOR(data), FALSE);
 
   return FALSE;
 }
@@ -1577,28 +1571,23 @@ hildon_time_editor_ampm_clicked(GtkWidget * widget,
                                 GdkEventButton * event, gpointer data)
 {
     HildonTimeEditor *editor;
-    HildonTimeEditorPrivate *priv = NULL;
-
-    g_return_val_if_fail(widget, FALSE);
-    g_return_val_if_fail(data, FALSE);
+    HildonTimeEditorPrivate *priv;
 
+    g_assert(GTK_IS_WIDGET(widget));
+    g_assert(HILDON_IS_TIME_EDITOR(data));
 
     editor = HILDON_TIME_EDITOR(data);
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
-    /* validate to set the time and get infoprints
-     * if the user was editing the value
-     */
-    hildon_time_editor_validate (editor);
+    /* First validate the given time and update ticks. */
+    hildon_time_editor_validate (editor, FALSE);
+
+    /* Apply the AM/PM change by moving the current time by 12 hours */
     if (priv->am) {
-      if (priv->ticks >= (12*3600))
-        {
-          hildon_time_editor_set_ticks (editor, priv->ticks - 12*3600);
-        } else 
-        {
-          hildon_time_editor_set_ticks (editor, priv->ticks + 12*3600);
-        }
+        /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
+        hildon_time_editor_set_ticks (editor, priv->ticks + 12*3600);
     } else {
+        /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
         hildon_time_editor_set_ticks (editor, priv->ticks - 12*3600);
     }
     return FALSE;
@@ -1608,21 +1597,19 @@ static gboolean
 hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data)
 {
     HildonTimeEditor *editor;
-    HildonTimeEditorPrivate *priv;
     GtkWidget *picker;
     GtkWidget *parent;
     guint h, m, s, result;
 
-    g_return_val_if_fail(widget, FALSE);
-    g_return_val_if_fail(data, FALSE);
+    g_assert(HILDON_IS_TIME_EDITOR(data));
 
     editor = HILDON_TIME_EDITOR(data);
-    priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
     /* icon is passive in duration editor mode */
-    if (priv->duration_mode)
+    if (hildon_time_editor_get_duration_mode(editor))
         return FALSE;
 
+    /* Launch HildonTimePicker dialog */
     parent = gtk_widget_get_ancestor(GTK_WIDGET(editor), GTK_TYPE_WINDOW);
     picker = hildon_time_picker_new(GTK_WINDOW(parent));
 
@@ -1633,6 +1620,7 @@ hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data)
     switch (result) {
     case GTK_RESPONSE_OK:
     case GTK_RESPONSE_ACCEPT:
+        /* Use the selected time */
         hildon_time_picker_get_time(HILDON_TIME_PICKER(picker), &h, &m);
         hildon_time_editor_set_time(editor, h, m, 0);
         break;
@@ -1655,7 +1643,10 @@ static gboolean hildon_time_editor_entry_clicked(GtkWidget * widget,
     priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
 
     /* If the focus has been grabbed back before the "clicked"
-     * signal gets processed, don't highlight the text
+     * signal gets processed, don't highlight the text.
+     * This happens when input in one H:M:S field is invalid and we're
+     * trying to move to another field. The focus moves back to the invalid
+     * field.
      */
     if (gtk_widget_is_focus (widget))
         gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
@@ -1673,210 +1664,71 @@ static void hildon_time_editor_size_request(GtkWidget * widget,
     editor = HILDON_TIME_EDITOR(widget);
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
-    gtk_widget_size_request(priv->frame, &req);
-    *requisition = req;
-
-    requisition->width = TIME_EDITOR_LBORDER + TIME_EDITOR_RBORDER;
-
-    gtk_widget_size_request(priv->h_entry, &req);
-    requisition->width += req.width;
-
-    gtk_widget_size_request(priv->m_entry, &req);
-    requisition->width += req.width;
+    /* Get frame's size */
+    gtk_widget_size_request(priv->frame, requisition);
 
-    gtk_widget_size_request(priv->label, &req);
-    requisition->width += req.width;
-
-    if (priv->iconbutton && GTK_WIDGET_VISIBLE(priv->iconbutton))
+    if (GTK_WIDGET_VISIBLE(priv->iconbutton))
     {
         gtk_widget_size_request(priv->iconbutton, &req);
-        requisition->width += ICON_WIDTH + ICON_PRESSED + 
-                              TIME_EDITOR_CLOCK_BORDER;
-    }
-
-    if (priv->show_s) {
-        gtk_widget_size_request(priv->s_entry, &req);
-        requisition->width += req.width;
-
-        gtk_widget_size_request(priv->label2, &req);
-        requisition->width += req.width;
-    }
-
-    if (!priv->clock_24h && !priv->duration_mode) {
-        gtk_widget_size_request(priv->eventbox, &req);
-        requisition->width += req.width + 4;
+        /* Reserve space for icon */
+        requisition->width += req.width + ICON_PRESSED +
+          HILDON_MARGIN_DEFAULT;
     }
 
-    requisition->height = TIME_EDITOR_HEIGHT + widget->style->ythickness * 2;
-}
-
-static void set_widget_allocation(GtkWidget * widget,
-                                  GtkAllocation * alloc,
-                                  GtkAllocation * allocation)
-{
-    GtkRequisition child_requisition;
-
-    gtk_widget_get_child_requisition(widget, &child_requisition);
-
-    if (allocation->width + allocation->x >
-        alloc->x + child_requisition.width)
-        alloc->width = child_requisition.width;
-    else {
-        alloc->width = allocation->width - (alloc->x - allocation->x);
-        if (alloc->width < 0)
-            alloc->width = 0;
-    }
-    gtk_widget_size_allocate(widget, alloc);
-    alloc->x += alloc->width;
+    /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
+       want to force this since themes might have varying thickness values
+       which cause the height to change. */
+    requisition->height = TIME_EDITOR_HEIGHT;
 }
 
 static void hildon_time_editor_size_allocate(GtkWidget * widget,
                                              GtkAllocation * allocation)
 {
-    HildonTimeEditor *editor;
-    HildonTimeEditorPrivate *priv;
+    HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
     GtkAllocation alloc;
-    GtkAllocation child_alloc;
-    GtkRequisition child_requisition;
-    gint mod_w = 0;
-
-    editor = HILDON_TIME_EDITOR(widget);
-    priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
+    GtkRequisition req, max_req;
 
     widget->allocation = *allocation;
+    gtk_widget_get_child_requisition(widget, &max_req);
 
-    /*Init start values*/
-    alloc.y = widget->allocation.y + widget->style->ythickness;
-
-    if (widget->allocation.height > (TIME_EDITOR_HEIGHT +
-                                     widget->style->ythickness * 2)) {
-        alloc.height = TIME_EDITOR_HEIGHT;
-        alloc.y +=
-            (widget->allocation.height - TIME_EDITOR_HEIGHT) / 2;
-    } else
-        alloc.height =
-            widget->allocation.height - widget->style->ythickness * 2;
-
-    if (alloc.height < 0)
-        alloc.height = 0;
-
-    gtk_widget_get_child_requisition(widget, &child_requisition);
-    if (allocation->width > child_requisition.width) {
-        mod_w = (allocation->width - child_requisition.width) / 2;
-        alloc.x = allocation->x + mod_w;
-    } else
-        alloc.x = allocation->x;
-
-
-    /** frame **/
-    if (priv->frame && GTK_WIDGET_VISIBLE(priv->frame))
-    {
-        alloc.width = child_requisition.width -
-            TIME_EDITOR_CLOCK_BORDER - ICON_WIDTH - ICON_PRESSED;
-        gtk_widget_size_allocate(priv->frame, &alloc);
-    }
-
-    /** icon **/
-    if (priv->iconbutton && GTK_WIDGET_VISIBLE(priv->iconbutton)) {
-        gtk_widget_get_child_requisition(priv->iconbutton, 
-                &child_requisition);
-
-        child_alloc.x = alloc.x + alloc.width + TIME_EDITOR_CLOCK_BORDER;
-
-        if(alloc.height > ICON_HEIGHT)
-            child_alloc.y = alloc.y + (alloc.height - ICON_HEIGHT) / 2 -1;
-        else
-            child_alloc.y = alloc.y;
-        child_alloc.height = ICON_HEIGHT + ICON_PRESSED / 2;
-        child_alloc.width = ICON_WIDTH + ICON_PRESSED;
-        gtk_widget_size_allocate(priv->iconbutton, &child_alloc);
-    }
-
-    /* allocation of child widgets */
-    child_alloc.x = alloc.x + TIME_EDITOR_LBORDER;
-    child_alloc.y = alloc.y;
-    child_alloc.height = TIME_EDITOR_HEIGHT;
-    child_alloc.width = -1;
-
-    /* am/pm label (when first) */
-    if (!priv->duration_mode) {
-        if (!priv->clock_24h && !priv->ampm_pos_after)
-          {
-            set_widget_allocation(priv->eventbox, &child_alloc,
-                    &widget->allocation);
-          }
-    }
+    /* Center horizontally */
+    alloc.x = allocation->x + MAX(allocation->width - max_req.width, 0) / 2;
+    /* Center vertically */
+    alloc.y = allocation->y + MAX(allocation->height - max_req.height, 0) / 2;
+    
+    /* allocate frame */
+    gtk_widget_get_child_requisition(priv->frame, &req);
 
-    /* hours */
-    if (priv->h_entry && GTK_WIDGET_VISIBLE(priv->h_entry))
-      {
-        child_alloc.y += ENTRY_BORDER;
-        child_alloc.height -= ENTRY_BORDER * 2;
-        set_widget_allocation(priv->h_entry, &child_alloc,
-                &widget->allocation);
-        child_alloc.y -= ENTRY_BORDER;
-        child_alloc.height += ENTRY_BORDER * 2;
-      }
+    alloc.width = req.width;
+    alloc.height = max_req.height;
+    gtk_widget_size_allocate(priv->frame, &alloc);
 
-    /* first separator label */
-    if (priv->label && GTK_WIDGET_VISIBLE(priv->label))
-      {
-        /* We'll have to subtract the ythickness from the labels
-         * allocation or it'll be there twice
-         */
-        child_alloc.y -= widget->style->ythickness;
-        set_widget_allocation(priv->label, &child_alloc,
-                &widget->allocation);
-        child_alloc.y += widget->style->ythickness;
-      }
-    /* minutes */
-    if (priv->m_entry && GTK_WIDGET_VISIBLE(priv->m_entry))
-      {
-        /* Entries have a little different allocation requirements
-         * so we'll have to accommodate. This is done per entry
-         * so that the "running" width value of the allocation isn't lost
-         * FIXME: Rearrange this code so it could be done just once
-         */
-        child_alloc.y += ENTRY_BORDER;
-        child_alloc.height -= ENTRY_BORDER * 2;
-        set_widget_allocation(priv->m_entry, &child_alloc,
-                &widget->allocation);
-        child_alloc.y -= ENTRY_BORDER;
-        child_alloc.height += ENTRY_BORDER * 2;
-      }
-    
-    if (priv->show_s) {
-        /* second separator label */
-        if (priv->label2)
-          {
-            child_alloc.y -= widget->style->ythickness;
-            set_widget_allocation(priv->label2, &child_alloc,
-                    &widget->allocation);
-            child_alloc.y += widget->style->ythickness;
-          }
+    /* allocate icon */
+    if (GTK_WIDGET_VISIBLE(priv->iconbutton)) {
+        gtk_widget_get_child_requisition(priv->iconbutton, &req);
 
-        /* seconds */
-        if (priv->s_entry)
-          {
-            child_alloc.y += ENTRY_BORDER;
-            child_alloc.height -= ENTRY_BORDER * 2;
-            set_widget_allocation(priv->s_entry, &child_alloc,
-                    &widget->allocation);
-            child_alloc.y -= ENTRY_BORDER;
-            child_alloc.height += ENTRY_BORDER * 2;
-          }
+        alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
+        alloc.width = req.width;
+        gtk_widget_size_allocate(priv->iconbutton, &alloc);
     }
 
-    /* am/pm label (when last) */
-    if (!priv->duration_mode) {
-        if (!priv->clock_24h && priv->ampm_pos_after)
-          {
-            child_alloc.y -= widget->style->ythickness;
-            set_widget_allocation(priv->eventbox, &child_alloc,
-                    &widget->allocation);
-            child_alloc.y += widget->style->ythickness;
-          }
-    }
+    /* FIXME: ugly way to move labels up. They just don't seem move up
+       otherwise. This is likely because we force the editor to be
+       smaller than it otherwise would be. */
+    alloc = priv->ampm_label->allocation;
+    alloc.y = allocation->y - 2;
+    alloc.height = max_req.height + 2;
+    gtk_widget_size_allocate(priv->ampm_label, &alloc);
+
+    alloc = priv->hm_label->allocation;
+    alloc.y = allocation->y - 2;
+    alloc.height = max_req.height + 2;
+    gtk_widget_size_allocate(priv->hm_label, &alloc);
+
+    alloc = priv->sec_label->allocation;
+    alloc.y = allocation->y - 2;
+    alloc.height = max_req.height + 2;
+    gtk_widget_size_allocate(priv->sec_label, &alloc);
 }
 
 static gboolean hildon_time_editor_entry_keypress(GtkWidget * widget,
@@ -1885,390 +1737,153 @@ static gboolean hildon_time_editor_entry_keypress(GtkWidget * widget,
 {
     HildonTimeEditor *editor;
     HildonTimeEditorPrivate *priv;
-    gint pos;
+    gint cursor_pos;
 
-    g_return_val_if_fail(widget, FALSE);
-    g_return_val_if_fail(event, FALSE);
-    g_return_val_if_fail(data, FALSE);
+    g_assert(GTK_IS_ENTRY(widget));
+    g_assert(event != NULL);
+    g_assert(HILDON_IS_TIME_EDITOR(data));
 
     editor = HILDON_TIME_EDITOR(data);
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
+    cursor_pos = gtk_editable_get_position(GTK_EDITABLE(widget));
 
-    pos = gtk_editable_get_position(GTK_EDITABLE(widget));
-
-    if (event->keyval == GDK_Return) {
-        /* Check that we have correct values in entries */
-        hildon_time_editor_validate (editor);
-        _gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), TRUE);
-        hildon_time_editor_icon_clicked(widget, data);
-        _gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), FALSE);
-        return TRUE;
-    }
-    
-    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 && widget == priv->h_entry) {
+    switch (event->keyval)
+    {
+        case GDK_Return:
+            /* Return key popups up time picker dialog. Visually it looks as if
+               the time picker icon was clicked. Before opening the time picker
+               the fields are first validated and fixed. */
+            hildon_time_editor_validate (editor, FALSE);
+            hildon_gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), TRUE);
+            hildon_time_editor_icon_clicked(widget, data);
+            hildon_gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), FALSE);
             return TRUE;
-        }
-    }
 
-    if (event->keyval == GDK_KP_Right || event->keyval == GDK_Right) {
-        if (pos >= strlen(GTK_ENTRY(widget)->text)) {
-            if ((widget == priv->m_entry
-                 && !GTK_WIDGET_REALIZED(priv->s_entry))
-                || (widget == priv->s_entry
-                    && GTK_WIDGET_REALIZED(priv->s_entry))) {
+        case GDK_Left:
+            /* left arrow pressed in the entry. If we are on first position, try to
+               move to the previous field. */
+            if (cursor_pos == 0) {
+                (void) gtk_widget_child_focus(GTK_WIDGET(editor), GTK_DIR_LEFT);
                 return TRUE;
             }
-        }
-    }
-
-    /* numeric key pressed */
-    if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
-        GtkWidgetClass *c = GTK_WIDGET_GET_CLASS(widget);
-
-        c->key_press_event(widget, event);
-
-        if (GTK_IS_ENTRY (widget))
-          {
-            if (strlen (gtk_entry_get_text (GTK_ENTRY (widget))) == 2)
-              {
-                hildon_time_editor_validate (editor);
-              }
-          }
-
-        return TRUE;
-    }
-    /* tab pressed in hour entry */
-    else if (widget == priv->h_entry && (event->keyval == GDK_Tab ||
-                   event->keyval == GDK_KP_Tab)) {
-        gtk_widget_grab_focus(priv->m_entry);
-        return TRUE;
-    }
-    /* tab pressed in minute entry */
-    else if (widget == priv->m_entry && (event->keyval == GDK_Tab ||
-                   event->keyval == GDK_KP_Tab)) {
-        if (priv->show_s)
-            gtk_widget_grab_focus(priv->s_entry);
-        else
-            gtk_widget_grab_focus(priv->h_entry);
-        return TRUE;
-    }
-    /* tab pressed in second entry */
-    else if (widget == priv->s_entry && (event->keyval == GDK_Tab ||
-                   event->keyval == GDK_KP_Tab)) {
-        gtk_widget_grab_focus(priv->h_entry);
-        return TRUE;
-    }
-    /* left tab pressed in second entry */
-    else if (widget == priv->s_entry &&
-             event->keyval == GDK_ISO_Left_Tab) {
-        gtk_widget_grab_focus(priv->m_entry);
-        return TRUE;
-    }
-    /* left tab pressed in minute entry */
-    else if (widget == priv->m_entry &&
-             event->keyval == GDK_ISO_Left_Tab) {
-        gtk_widget_grab_focus(priv->h_entry);
-        return TRUE;
-    }
-    /* left tab pressed in hour entry */
-    else if (widget == priv->h_entry &&
-             event->keyval == GDK_ISO_Left_Tab) {
-        if (priv->show_s)
-            gtk_widget_grab_focus(priv->s_entry);
-        else
-            gtk_widget_grab_focus(priv->m_entry);
-        return TRUE;
-    }
-    /* right arrow pressed in hour entry */
-    else if (widget == priv->h_entry &&
-             (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)
-             && pos >= GTK_ENTRY(priv->h_entry)->text_length) {
-        gtk_widget_grab_focus(priv->m_entry);
-        gtk_editable_set_position(GTK_EDITABLE(priv->m_entry), 0);
-        return TRUE;
-    }
-    /* right arrow pressed in minute entry */
-    else if (widget == priv->m_entry &&
-             (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)
-             && pos >= GTK_ENTRY(priv->m_entry)->text_length) {
-        if (priv->show_s) {
-            gtk_widget_grab_focus(priv->s_entry);
-            gtk_editable_set_position(GTK_EDITABLE(priv->s_entry), 0);
-        } else {
-            gtk_widget_grab_focus(priv->h_entry);
-            gtk_editable_set_position(GTK_EDITABLE(priv->h_entry), 0);
-        }
-        return TRUE;
-    }
-    /* right arrow pressed in second entry */
-    else if (widget == priv->s_entry &&
-             (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)
-             && pos >= GTK_ENTRY(priv->s_entry)->text_length) {
-        gtk_widget_grab_focus(priv->h_entry);
-        gtk_editable_set_position(GTK_EDITABLE(priv->h_entry), 0);
-        return TRUE;
-    }
-    /* left arrow key pressed in hour entry */
-    else if (widget == priv->h_entry &&
-             (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) &&
-             pos <= 0) {
-        if (priv->show_s) {
-            gtk_widget_grab_focus(priv->s_entry);
-            gtk_editable_set_position(GTK_EDITABLE(priv->s_entry), -1);
-        } else {
-            gtk_widget_grab_focus(priv->m_entry);
-            gtk_editable_set_position(GTK_EDITABLE(priv->m_entry), -1);
-        }
-        return TRUE;
-    }
-    /* left arrow key pressed in minute entry */
-    else if (widget == priv->m_entry &&
-             (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) &&
-             pos <= 0) {
-        gtk_widget_grab_focus(priv->h_entry);
-        gtk_editable_set_position(GTK_EDITABLE(priv->h_entry), -1);
-        return TRUE;
-    }
-    /* left arrow key pressed in seconds entry */
-    else if (widget == priv->s_entry &&
-             (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) &&
-             pos <= 0) {
-        gtk_widget_grab_focus(priv->m_entry);
-        gtk_editable_set_position(GTK_EDITABLE(priv->m_entry), -1);
-        return TRUE;
-    }
-    /* pass other arrow key presses and backspace and del onwards */
-    else if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left ||
-             event->keyval == GDK_Right || event->keyval == GDK_KP_Right ||
-             event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
-             event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
-             event->keyval == GDK_BackSpace || event->keyval == GDK_Delete
-             || event->keyval == GDK_KP_Delete)
-        return FALSE;   /* pass the keypress on */
-
-    /* ingore other keys */
-    return TRUE;
-}
-
-static HildonValidation
-hildon_time_editor_validate_duration (HildonTimeEditor * editor, guint ticks)
-{
-  HildonTimeEditorPrivate *priv;
-
-  g_return_val_if_fail (editor, VALIDATION_ERROR);
+            break;
 
-  priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
-
-  if (ticks > priv->duration_max)
-    return VALIDATION_DURATION_MAX;
+        case GDK_Right:
+            /* right arrow pressed in the entry. If we are on last position, try to
+               move to the next field. */
+            if (cursor_pos >= g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(widget)), -1)) {
+                (void) gtk_widget_child_focus(GTK_WIDGET(editor), GTK_DIR_RIGHT);    
+                return TRUE;
+            }
+            break;
 
-  if (ticks < priv->duration_min)
-    return VALIDATION_DURATION_MIN;
+        default:
+            break;
+    };
 
-  return (VALIDATION_OK);
+    return FALSE;
 }
 
+/*** 
+ * Utility functions
+ */
 
-static HildonValidation
-hildon_time_editor_validate_time (HildonTimeEditor * editor,
-                                  guint hours,
-                                  guint minutes,
-                                  guint seconds,
-                                  gboolean mode_24h)
+static void
+convert_to_12h (guint *h, gboolean *am)
 {
-  HildonTimeEditorPrivate *priv;
-
-  g_return_val_if_fail (editor, VALIDATION_ERROR);
-
-  priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
-
-  priv->validated = FALSE;
+  g_assert(0 <= *h && *h < 24);
 
-  if (mode_24h) {
-    if (hours < HOURS_MIN_24 || hours > HOURS_MAX_24)
-        return VALIDATION_TIME_HOURS;
-  } else {
-    if (hours < HOURS_MIN_12 || hours > HOURS_MAX_12)
-        return VALIDATION_TIME_HOURS;
-  }
-
-  if (minutes < MINUTES_MIN || minutes > MINUTES_MAX)
-    return VALIDATION_TIME_MINUTES;
-  
-  if (seconds < SECONDS_MIN || seconds > SECONDS_MAX)
-    return VALIDATION_TIME_SECONDS;
+  /* 00:00 to 00:59  add 12 hours      */
+  /* 01:00 to 11:59  straight to am    */
+  /* 12:00 to 12:59  straight to pm    */
+  /* 13:00 to 23:59  subtract 12 hours */
 
-  priv->validated = TRUE;
-  return (VALIDATION_OK);
+  if      (       *h == 0       ) { *am = TRUE;  *h += 12;}
+  else if (  1 <= *h && *h < 12 ) { *am = TRUE;           }
+  else if ( 12 <= *h && *h < 13 ) { *am = FALSE;          }
+  else                            { *am = FALSE; *h -= 12;}
 }
 
 static void
-hildon_time_editor_entry_changed(GtkWidget * widget, gpointer user_data)
+convert_to_24h (guint *h, gboolean am)
 {
-  HildonTimeEditor *editor;
-
-  editor = HILDON_TIME_EDITOR(user_data);
-
-/*  hildon_time_editor_validate (editor);*/
+  if (*h == 12 && am) /* 12 midnight - 12:59 AM  subtract 12 hours  */
+    {
+      *h -= 12;
+    }
+  else if (!am && 1 <= *h && *h < 12)    /* 1:00 PM - 11:59 AM   add 12 hours */
+    {
+      *h += 12;
+    }
 }
 
-/* NOTE: This function is mostly broken for the duration mode */
-static void
-hildon_time_editor_get_max_values(HildonTimeEditor *editor, 
-        guint * pmax_hours, guint * pmin_hours,
-        guint * pmax_minutes, guint * pmin_minutes,
-        guint * pmax_seconds, guint * pmin_seconds)
+/**
+ * hildon_time_editor_set_show_hours:
+ * @editor: The #HildonTimeEditor.
+ * @enable: Enable or disable showing of hours.
+ *
+ * This function shows or hides the hours field.
+ *
+ * Since: 0.12.4
+ **/
+void hildon_time_editor_set_show_hours(HildonTimeEditor * editor,
+                                       gboolean show_hours)
 {
-    guint max_hours;
-    guint max_minutes;
-    guint max_seconds;
-    guint min_hours;
-    guint min_minutes;
-    guint min_seconds;
-
     HildonTimeEditorPrivate *priv;
 
+    g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
+
     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
-    max_hours   = priv->duration_max / 3600;
-    max_minutes = (priv->duration_max - (max_hours * 3600)) / 60;
-    max_seconds = priv->duration_max - (max_hours * 3600) - (max_minutes * 60);
-    min_hours   = priv->duration_min / 3600;
-    min_minutes = (priv->duration_min - (min_hours * 3600)) / 60;
-    min_seconds = priv->duration_min - (min_hours * 3600) - (min_minutes * 60);
+    if (show_hours != priv->show_hours) {
+        priv->show_hours = show_hours;
 
-    /* Determine max and min values for duration mode */
-    if (priv->duration_mode)
-    {
-      /* if the widget has focus, the value could be out of range, so
-         use the calculated values then
-       */
-      if (!gtk_widget_is_focus (priv->h_entry))
-        {
-          if ((guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->h_entry))) < max_hours)
-            {
-              max_minutes = 59;
-              max_seconds = 59;
-            }
-          if ((guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->h_entry))) > min_hours)
-            {
-              min_minutes = 0;
-              min_seconds = 0;
-            }
+        /* show/hide hours field and its ':' label if the value changed. */
+        if (show_hours) {
+            gtk_widget_show(priv->entries[ENTRY_HOURS]);
+            gtk_widget_show(priv->hm_label);        
+        } else {    
+            gtk_widget_hide(priv->entries[ENTRY_HOURS]);
+            gtk_widget_hide(priv->hm_label);
         }
-      if (!gtk_widget_is_focus (priv->m_entry))
-        {
-          if ((guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry))) < max_minutes)
-            {
-              max_seconds = 59;
-            }
-          if ((guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry))) > min_minutes)
-            {
-              min_seconds = 0;
-            }
-        }
-    }
-    /* 24h clock mode */
-    else if (priv->clock_24h) {
-        max_hours = 23;
-        max_seconds = max_minutes = 59;
-        min_seconds = min_minutes = min_hours = 0;
-    }
-    /* 12h clock mode */
-    else {
-        max_hours = 12;
-        min_hours = 1;
-        max_seconds = max_minutes = 59;
-        min_seconds = min_minutes = 0;
+    
+        g_object_notify (G_OBJECT (editor), "show_hours");
     }
-
-    *pmax_hours   = max_hours;
-    *pmax_minutes = max_minutes;
-    *pmax_seconds = max_seconds;
-    *pmin_hours   = min_hours;
-    *pmin_minutes = min_minutes;
-    *pmin_seconds = min_seconds;
-  
 }
 
-/*** 
- * Utility functions
- */
-
-static void
-convert_to_12h (guint *h, guint *m, guint *s, gboolean *am)
+/**
+ * hildon_time_editor_get_show_hours:
+ * @self: the @HildonTimeEditor widget.
+ *
+ * This function returns a boolean indicating the visibility of
+ * hours in the @HildonTimeEditor
+ *
+ * Return value: TRUE if hours are visible. 
+ *
+ * Since: 0.12.4-1
+ **/
+gboolean hildon_time_editor_get_show_hours(HildonTimeEditor *editor)
 {
-  /* 0000 to 0059
-   * add 12 hours
-   */
-  if (*h == 0)
-    {
-      *h += 12;
-      *am = TRUE;
-    }
-  /* 0100 to 1159
-   * straight to am
-   */
-  else if (*h >= 1 && *h < 12)
-    {
-      *am = TRUE;
-    }
-  /* 1200 to 1259
-   * straight to pm
-   */
-  else if (*h >= 12 && *h < 13)
-    {
-      *am = FALSE;
-    }
-  /* 1300 to 23:59
-   * subtract 12 hours
-   */
-  else if (*h >= 13 && *h < 24 )
-    {
-      *h -= 12;
-      *am = FALSE;
-    }
-}
+    HildonTimeEditorPrivate *priv;
 
-static void
-convert_to_24h (guint *h, guint *m, guint *s, gboolean am)
-{
-  /* 12 midnight - 12:59 AM
-   * subtract 12 hours
-   */
-  if (*h == 12 && am)
-    {
-      *h -= 12;
-    }
-  /* 1:00 PM - 11:59 AM
-   * add 12 hours
-   */
-  else if (!am && *h >= 1 && *h < 12)
-    {
-      *h += 12;
-    }
+    g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
+    priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
+
+    return priv->show_hours;
 }
 
 /***
  * Deprecated functions
  */
 
-
-#ifndef HILDON_DISABLE_DEPRECATED
-
 /**
  * hildon_time_editor_show_seconds:
- * @editor: The #HildonTimeEditor.
- * @enable: Enable or disable showing of seconds.
- *
- * This function is deprecated, use @hildon_time_editor_set_show_seconds instead.
+ * @editor: the #HildonTimeEditor
+ * @enable: enable or disable showing of seconds
  *
- **/
+ * This function is deprecated, 
+ * use #hildon_time_editor_set_show_seconds instead.
+ */
 void hildon_time_editor_show_seconds(HildonTimeEditor * editor,
                                      gboolean enable)
 {
@@ -2276,16 +1891,14 @@ void hildon_time_editor_show_seconds(HildonTimeEditor * editor,
 }
 /**
  * hildon_time_editor_enable_duration_mode:
- * @editor: The #HildonTimeEditor.
- * @enable: Enable or disable duration editor mode
+ * @editor: the #HildonTimeEditor
+ * @enable: enable or disable duration editor mode
  *
- * This function is deprecated, use @hildon_time_editor_set_duration_mode instead.
- *
- **/
+ * This function is deprecated, 
+ * use #hildon_time_editor_set_duration_mode instead.
+ */
 void hildon_time_editor_enable_duration_mode(HildonTimeEditor * editor,
                                              gboolean enable)
 {
     hildon_time_editor_set_duration_mode (editor, enable);
 }
-
-#endif /* HILDON_DISABLE_DEPRECATED */