Adding the missing variable setter in the set_property handler. Fixes NB#54182.
[hildon] / src / hildon-date-editor.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-date-editor
27  * @short_description: A widget which queries a date from user or opens
28  * a HildonCalendarPopup.
29  * @see_also: #HildonCalendarPopup, #HildonTimeEditor
30  * 
31  * HildonDateEditor is a widget with three entry fields (day, month,
32  * year) and an icon (button): clicking on the icon opens up a
33  * HildonCalendarPopup.
34  *
35  * <example>
36  * <programlisting>
37  * gint y, m, d;
38  * <!-- -->
39  * date_editor = hildon_date_editor_new ();
40  * <!-- -->
41  * hildon_date_editor_get_date(date_editor, &amp;y, &amp;m, &amp;d);
42  * <!-- -->
43  * </programlisting>
44  * </example>
45  *
46  */
47
48 #ifdef                                          HAVE_CONFIG_H
49 #include                                        <config.h>
50 #endif
51
52 #include                                        "hildon-date-editor.h"
53 #include                                        <glib.h>
54 #include                                        <gtk/gtk.h>
55 #include                                        <gtk/gtkenums.h>
56 #include                                        <gdk/gdkkeysyms.h>
57 #include                                        <time.h>
58 #include                                        <stdlib.h>
59 #include                                        <stdio.h>
60 #include                                        <string.h>
61 #include                                        "hildon-calendar-popup.h"
62 #include                                        "hildon-defines.h"
63 #include                                        "hildon-private.h"
64 #include                                        "hildon-marshalers.h"
65 #include                                        "hildon-enum-types.h"
66 #include                                        "hildon-time-editor.h"
67 #include                                        "hildon-banner.h"
68 #include                                        <libintl.h>
69 #include                                        "hildon-date-editor-private.h"
70
71 #define                                         _(string) dgettext("hildon-libs", string)
72
73 #define                                         c_(string) dgettext("hildon-common-strings", string)
74
75 #define                                         ENTRY_BORDERS 11
76
77 #define                                         DATE_EDITOR_HEIGHT 30
78
79 #define                                         DAY_ENTRY_WIDTH 2
80
81 #define                                         MONTH_ENTRY_WIDTH 2
82
83 #define                                         YEAR_ENTRY_WIDTH 4
84
85 #define                                         DEFAULT_MIN_YEAR 1970
86
87 #define                                         DEFAULT_MAX_YEAR 2037
88
89 static GtkContainerClass*                       parent_class;
90
91 static void
92 hildon_date_editor_class_init                   (HildonDateEditorClass *editor_class);
93
94 static void 
95 hildon_date_editor_init                         (HildonDateEditor *editor);
96
97 static gboolean
98 hildon_date_editor_icon_press                   (GtkWidget *widget, 
99                                                  gpointer data);
100
101 static gboolean
102 hildon_date_editor_released                     (GtkWidget *widget, 
103                                                  gpointer data);
104
105 static gboolean
106 hildon_date_editor_keypress                     (GtkWidget *widget, 
107                                                  GdkEventKey *event,
108                                                  gpointer data);
109
110 static gboolean
111 hildon_date_editor_keyrelease                   (GtkWidget *widget, 
112                                                  GdkEventKey *event,
113                                                  gpointer data);
114 static gboolean
115 hildon_date_editor_clicked                      (GtkWidget *widget, 
116                                                  gpointer data);
117
118 static gint
119 hildon_date_editor_entry_validate               (GtkWidget *widget, 
120                                                  gpointer data);
121
122 static void
123 hildon_date_editor_entry_changed                (GtkEditable *widget, 
124                                                  gpointer data);
125
126 static gboolean
127 hildon_date_editor_entry_focus_out              (GtkWidget *widget, 
128                                                  GdkEventFocus *event,
129                                                  gpointer data);
130
131 static gboolean
132 hildon_date_editor_date_error                   (HildonDateEditor *editor, 
133                                                  HildonDateTimeError type);
134
135 static gboolean 
136 hildon_date_editor_entry_focus_in               (GtkWidget *widget,
137                                                  GdkEventFocus *event,
138                                                  gpointer data);
139
140 static void
141 hildon_date_editor_get_property                 (GObject *object, 
142                                                  guint param_id,
143                                                  GValue *value, 
144                                                  GParamSpec *pspec);
145
146 static void 
147 hildon_date_editor_set_property                 (GObject *object, 
148                                                  guint param_id,
149                                                  const GValue *value, 
150                                                  GParamSpec *pspec);
151 static void
152 hildon_child_forall                             (GtkContainer *container,
153                                                  gboolean include_internals,
154                                                  GtkCallback callback, 
155                                                  gpointer callback_data);
156
157 static void 
158 hildon_date_editor_destroy                      (GtkObject *self);
159
160 static void
161 hildon_date_editor_size_allocate                (GtkWidget *widget,
162                                                  GtkAllocation *allocation);
163
164 static void
165 hildon_date_editor_size_request                 (GtkWidget *widget,
166                                                  GtkRequisition *requisition);
167
168 static gboolean
169 hildon_date_editor_entry_select_all             (GtkWidget *widget);
170
171 /* Property indices */
172 enum
173 {
174     PROP_0, 
175     PROP_DAY,
176     PROP_MONTH,
177     PROP_YEAR,
178     PROP_MIN_YEAR,
179     PROP_MAX_YEAR
180 };
181
182 enum 
183 {
184     DATE_ERROR,
185     LAST_SIGNAL
186 };
187
188 static guint                                    date_editor_signals[LAST_SIGNAL] = { 0 };
189
190 /**
191  * hildon_date_editor_get_type:
192  *
193  * Initializes and returns the type of a hildon date editor.
194  *
195  * @Returns: GType of #HildonDateEditor
196  */
197 GType G_GNUC_CONST
198 hildon_date_editor_get_type                     (void)
199 {
200     static GType editor_type = 0;
201
202     if (! editor_type) {
203         static const GTypeInfo editor_info = {
204             sizeof (HildonDateEditorClass),
205             NULL,       /* base_init */
206             NULL,       /* base_finalize */
207             (GClassInitFunc) hildon_date_editor_class_init,
208             NULL,       /* class_finalize */
209             NULL,       /* class_data */
210             sizeof (HildonDateEditor),
211             0,          /* n_preallocs */
212             (GInstanceInitFunc) hildon_date_editor_init,
213         };
214         editor_type = g_type_register_static (GTK_TYPE_CONTAINER,
215                 "HildonDateEditor",
216                 &editor_info, 0);
217     }
218
219     return editor_type;
220 }
221
222 static void
223 hildon_date_editor_class_init                   (HildonDateEditorClass *editor_class)
224 {
225     GtkContainerClass *container_class = GTK_CONTAINER_CLASS (editor_class);
226     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (editor_class);
227     GObjectClass *gobject_class = G_OBJECT_CLASS (editor_class);
228
229     parent_class = g_type_class_peek_parent (editor_class);
230
231     g_type_class_add_private (editor_class, sizeof (HildonDateEditorPrivate));
232
233     gobject_class->set_property             = hildon_date_editor_set_property;
234     gobject_class->get_property             = hildon_date_editor_get_property;
235     widget_class->size_request              = hildon_date_editor_size_request;
236     widget_class->size_allocate             = hildon_date_editor_size_allocate;
237     widget_class->focus                     = hildon_private_composite_focus;
238
239     container_class->forall                 = hildon_child_forall;
240     GTK_OBJECT_CLASS(editor_class)->destroy = hildon_date_editor_destroy;
241
242     editor_class->date_error                = (gpointer) hildon_date_editor_date_error; 
243
244     date_editor_signals[DATE_ERROR] =
245         g_signal_new ("date-error",
246                 G_OBJECT_CLASS_TYPE (gobject_class),
247                 G_SIGNAL_RUN_LAST,
248                 G_STRUCT_OFFSET (HildonDateEditorClass, date_error),
249                 g_signal_accumulator_true_handled, NULL,
250                 _hildon_marshal_BOOLEAN__ENUM,
251                 G_TYPE_BOOLEAN, 1, HILDON_TYPE_DATE_TIME_ERROR);
252
253     /**
254      * HildonDateEditor:year:
255      *
256      * Current year.
257      */
258     g_object_class_install_property (gobject_class, PROP_YEAR,
259             g_param_spec_uint ("year",
260                 "Current year",
261                 "Current year",
262                 1, 10000,
263                 2007,
264                 G_PARAM_READABLE | G_PARAM_WRITABLE));
265
266     /**
267      * HildonDateEditor:month:
268      *
269      * Current month.
270      */
271     g_object_class_install_property (gobject_class, PROP_MONTH,
272             g_param_spec_uint ("month",
273                 "Current month",
274                 "Current month",
275                 1, 12,
276                 1,
277                 G_PARAM_READABLE | G_PARAM_WRITABLE));
278
279     /**
280      * HildonDateEditor:day:
281      *
282      * Current day.
283      */
284     g_object_class_install_property (gobject_class, PROP_DAY,
285             g_param_spec_uint ("day",
286                 "Current day",
287                 "Current day",
288                 1, 31,
289                 1,
290                 G_PARAM_READABLE | G_PARAM_WRITABLE));
291
292     /**
293      * HildonDateEditor:min-year:
294      *
295      * Minimum valid year.
296      */
297     g_object_class_install_property (gobject_class, PROP_MIN_YEAR,
298             g_param_spec_uint ("min-year",
299                 "Minimum valid year",
300                 "Minimum valid year",
301                 1, 10000,
302                 DEFAULT_MIN_YEAR,
303                 G_PARAM_READWRITE));
304
305     /**
306      * HildonDateEditor:max-year:
307      *
308      * Maximum valid year.
309      */
310     g_object_class_install_property (gobject_class, PROP_MAX_YEAR,
311             g_param_spec_uint ("max-year",
312                 "Maximum valid year",
313                 "Maximum valid year",
314                 1, 10000,
315                 DEFAULT_MAX_YEAR,
316                 G_PARAM_READWRITE));
317 }
318
319 /* Forces setting of the icon to certain state. Used initially
320    and from the actual setter function */
321 static void
322 real_set_calendar_icon_state                    (HildonDateEditorPrivate *priv, 
323                                                  gboolean pressed)
324 {
325     g_assert (priv);
326
327     gtk_image_set_from_icon_name (GTK_IMAGE (priv->calendar_icon),
328             pressed ? "qgn_widg_datedit_pr" : "qgn_widg_datedit", HILDON_ICON_SIZE_SMALL);
329
330     priv->calendar_icon_pressed = pressed;
331 }
332
333 /* Sets the icon to given state (normal/pressed). Returns
334    info if the state actually changed. */
335 static gboolean 
336 hildon_date_editor_set_calendar_icon_state      (HildonDateEditor *editor,
337                                                  gboolean pressed)
338 {
339     HildonDateEditorPrivate *priv;
340
341     g_assert (HILDON_IS_DATE_EDITOR (editor));
342
343     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
344     g_assert (priv);
345
346     if (pressed != priv->calendar_icon_pressed) {
347         real_set_calendar_icon_state (priv, pressed);
348         return TRUE;
349     }
350
351     return FALSE;
352 }
353
354 /* Packing day, month and year entries depend on locale settings
355    We find out the order and all separators by converting a known
356    date to default format and inspecting the result string */
357 static void 
358 apply_locale_field_order                        (HildonDateEditorPrivate *priv)
359 {
360     GDate locale_test_date;
361     GtkWidget *delim;
362     gchar buffer[256];
363     gchar *iter, *delim_text;
364
365     g_date_set_dmy (&locale_test_date, 1, 2, 1970);
366     (void) g_date_strftime (buffer, sizeof (buffer), "%x", &locale_test_date);    
367     iter = buffer;
368
369     while (*iter)
370     {
371         gchar *endp;
372         unsigned long value;
373
374         /* Try to convert the current location into number. */
375         value = strtoul (iter, &endp, 10);
376
377         /* If the conversion didn't progress or the detected value was
378            unknown (we used a fixed date, you remember), we treat 
379            current position as a literal */
380         switch (value)
381         {
382             case 1:
383                 gtk_box_pack_start (GTK_BOX (priv->d_box_date),
384                         priv->d_entry, FALSE, FALSE, 0);
385                 break;
386
387             case 2:
388                 gtk_box_pack_start (GTK_BOX (priv->d_box_date),
389                         priv->m_entry, FALSE, FALSE, 0);
390                 break;
391
392             case 70:   /* %x format uses only 2 numbers for some locales */
393             case 1970:
394                 gtk_box_pack_start (GTK_BOX (priv->d_box_date),
395                         priv->y_entry, FALSE, FALSE, 0);
396                 break;
397
398             default:
399                 /* All non-number characters starting from current position 
400                    form the delimeter */
401                 for (endp = iter; *endp; endp++)
402                     if (g_ascii_isdigit (*endp))
403                         break;
404
405                 /* Now endp points one place past the delimeter text */
406                 delim_text = g_strndup (iter, endp - iter);
407                 delim = gtk_label_new (delim_text);
408                 gtk_box_pack_start (GTK_BOX (priv->d_box_date),
409                         delim, FALSE, FALSE, 0);
410
411                 priv->delims = g_list_append (priv->delims, delim);
412                 g_free(delim_text);
413
414                 break;
415         };
416
417         iter = endp;
418     }
419 }
420
421 static void 
422 hildon_date_editor_init                         (HildonDateEditor *editor)
423 {
424     HildonDateEditorPrivate *priv;
425     GDate cur_date;
426
427     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
428     g_assert (priv);
429
430     GTK_WIDGET_SET_FLAGS (GTK_WIDGET (editor), GTK_NO_WINDOW);
431
432     gtk_widget_push_composite_child ();
433
434     /* initialize values */
435     g_date_clear (&cur_date, 1);
436     g_date_set_time (&cur_date, time (NULL));
437
438     priv->day = g_date_get_day (&cur_date);
439     priv->month = g_date_get_month (&cur_date);
440     priv->year = g_date_get_year (&cur_date);
441     priv->min_year = DEFAULT_MIN_YEAR;
442     priv->max_year = DEFAULT_MAX_YEAR;
443
444     /* make widgets */
445     priv->frame = gtk_frame_new (NULL);
446     gtk_container_set_border_width (GTK_CONTAINER (priv->frame), 0);
447
448     priv->d_entry = gtk_entry_new ();
449     priv->m_entry = gtk_entry_new ();
450     priv->y_entry = gtk_entry_new ();
451
452 #ifdef MAEMO_GTK
453     g_object_set (G_OBJECT(priv->d_entry), "hildon-input-mode", 
454             HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
455     g_object_set (G_OBJECT(priv->m_entry), "hildon-input-mode", 
456             HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
457     g_object_set (G_OBJECT(priv->y_entry), "hildon-input-mode", 
458             HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
459 #endif
460
461     /* set entry look */
462     gtk_entry_set_width_chars (GTK_ENTRY (priv->d_entry), DAY_ENTRY_WIDTH);
463     gtk_entry_set_width_chars (GTK_ENTRY (priv->m_entry), MONTH_ENTRY_WIDTH);
464     gtk_entry_set_width_chars (GTK_ENTRY (priv->y_entry), YEAR_ENTRY_WIDTH);
465
466     gtk_entry_set_max_length (GTK_ENTRY (priv->d_entry), DAY_ENTRY_WIDTH);
467     gtk_entry_set_max_length (GTK_ENTRY (priv->m_entry), MONTH_ENTRY_WIDTH);
468     gtk_entry_set_max_length (GTK_ENTRY (priv->y_entry), YEAR_ENTRY_WIDTH);
469
470     gtk_entry_set_has_frame (GTK_ENTRY (priv->d_entry), FALSE);
471     gtk_entry_set_has_frame (GTK_ENTRY (priv->m_entry), FALSE);
472     gtk_entry_set_has_frame (GTK_ENTRY (priv->y_entry), FALSE);
473
474     gtk_widget_set_composite_name (priv->d_entry, "day_entry");
475     gtk_widget_set_composite_name (priv->m_entry, "month_entry");
476     gtk_widget_set_composite_name (priv->y_entry, "year_entry");
477
478     priv->d_box_date = gtk_hbox_new (FALSE, 0);
479
480     priv->d_button_image = gtk_button_new ();
481     priv->calendar_icon = gtk_image_new ();
482     real_set_calendar_icon_state (priv, FALSE);
483     GTK_WIDGET_UNSET_FLAGS (priv->d_button_image, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
484
485     apply_locale_field_order (priv);
486
487     gtk_container_add (GTK_CONTAINER (priv->frame), priv->d_box_date);
488     gtk_container_add (GTK_CONTAINER (priv->d_button_image), priv->calendar_icon);
489     gtk_button_set_relief (GTK_BUTTON (priv->d_button_image), GTK_RELIEF_NONE);
490     gtk_button_set_focus_on_click (GTK_BUTTON (priv->d_button_image), FALSE);
491
492     gtk_widget_set_parent (priv->frame, GTK_WIDGET (editor));
493     gtk_widget_set_parent (priv->d_button_image, GTK_WIDGET (editor));
494     gtk_widget_show_all (priv->frame);
495     gtk_widget_show_all (priv->d_button_image);
496
497     /* image button signal connects */
498     g_signal_connect (GTK_OBJECT (priv->d_button_image), "pressed",
499             G_CALLBACK (hildon_date_editor_icon_press), editor);
500     g_signal_connect (GTK_OBJECT (priv->d_button_image), "released",
501             G_CALLBACK (hildon_date_editor_released), editor);
502     g_signal_connect (GTK_OBJECT (priv->d_button_image), "clicked",
503             G_CALLBACK (hildon_date_editor_clicked), editor);
504     g_signal_connect (GTK_OBJECT (priv->d_button_image), "key_press_event",
505             G_CALLBACK (hildon_date_editor_keypress), editor);
506
507     /* entry signal connects */    
508     g_signal_connect (GTK_OBJECT (priv->d_entry), "focus-in-event",
509             G_CALLBACK (hildon_date_editor_entry_focus_in), editor);
510
511     g_signal_connect (GTK_OBJECT (priv->m_entry), "focus-in-event",
512             G_CALLBACK (hildon_date_editor_entry_focus_in), editor);
513
514     g_signal_connect (GTK_OBJECT (priv->y_entry), "focus-in-event",
515             G_CALLBACK (hildon_date_editor_entry_focus_in), editor);
516
517     g_signal_connect (GTK_OBJECT (priv->d_entry), "focus-out-event",
518             G_CALLBACK (hildon_date_editor_entry_focus_out), editor);
519
520     g_signal_connect (GTK_OBJECT (priv->m_entry), "focus-out-event",
521             G_CALLBACK (hildon_date_editor_entry_focus_out), editor);
522
523     g_signal_connect (GTK_OBJECT (priv->y_entry), "focus-out-event",
524             G_CALLBACK (hildon_date_editor_entry_focus_out), editor);
525
526     g_signal_connect (GTK_OBJECT (priv->d_entry), "key-press-event",
527             G_CALLBACK (hildon_date_editor_keypress), editor);
528
529     g_signal_connect (GTK_OBJECT (priv->m_entry), "key-press-event",
530             G_CALLBACK (hildon_date_editor_keypress), editor);
531
532     g_signal_connect (GTK_OBJECT (priv->y_entry), "key-press-event",
533             G_CALLBACK (hildon_date_editor_keypress), editor);
534
535     g_signal_connect (GTK_OBJECT (priv->d_entry), "key-release-event",
536             G_CALLBACK (hildon_date_editor_keyrelease), editor);
537
538     g_signal_connect(GTK_OBJECT(priv->m_entry), "key-release-event",
539             G_CALLBACK(hildon_date_editor_keyrelease), editor);
540
541     g_signal_connect (GTK_OBJECT (priv->y_entry), "key-release-event",
542             G_CALLBACK (hildon_date_editor_keyrelease), editor);
543
544     hildon_date_editor_set_date (editor, priv->year, priv->month, priv->day);
545
546     g_signal_connect (GTK_OBJECT (priv->d_entry), "changed",
547             G_CALLBACK (hildon_date_editor_entry_changed), editor);
548
549     g_signal_connect (GTK_OBJECT (priv->m_entry), "changed",
550             G_CALLBACK (hildon_date_editor_entry_changed), editor);
551
552     g_signal_connect (GTK_OBJECT (priv->y_entry), "changed",
553             G_CALLBACK (hildon_date_editor_entry_changed), editor);
554
555     gtk_widget_pop_composite_child ();
556 }
557
558 static void 
559 hildon_date_editor_set_property                 (GObject *object, 
560                                                  guint param_id,
561                                                  const GValue *value, 
562                                                  GParamSpec *pspec)
563 {
564     HildonDateEditor *editor = HILDON_DATE_EDITOR (object);
565     HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
566     gint val;
567
568     g_assert (priv);
569
570     switch (param_id)
571     {
572         case PROP_YEAR:
573             hildon_date_editor_set_year (editor, g_value_get_uint (value));
574             break;
575
576         case PROP_MONTH:
577             hildon_date_editor_set_month (editor, g_value_get_uint (value));
578             break;
579
580         case PROP_DAY:
581             hildon_date_editor_set_day (editor, g_value_get_uint (value));
582             break;
583
584         case PROP_MIN_YEAR:
585             val = g_value_get_uint (value);
586             priv->min_year = val;
587             /* Clamp current year */
588             if (hildon_date_editor_get_year (editor) < priv->min_year)
589                 hildon_date_editor_set_year (editor, priv->min_year);
590             break;
591
592         case PROP_MAX_YEAR:
593             val = g_value_get_uint (value);
594             priv->max_year = val;
595             /* Clamp current year */
596             if (hildon_date_editor_get_year (editor) > priv->max_year)
597                 hildon_date_editor_set_year (editor, priv->max_year);
598             break;
599
600         default:
601             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
602             break;
603     }
604 }
605
606 static void 
607 hildon_date_editor_get_property                 (GObject *object, 
608                                                  guint param_id,
609                                                  GValue *value, 
610                                                  GParamSpec *pspec)
611 {
612     HildonDateEditor *editor = HILDON_DATE_EDITOR (object);
613     HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
614
615     switch (param_id)
616     {
617         case PROP_YEAR:
618             g_value_set_uint (value, hildon_date_editor_get_year (editor));
619             break;
620
621         case PROP_MONTH:
622             g_value_set_uint (value, hildon_date_editor_get_month (editor));
623             break;
624
625         case PROP_DAY:
626             g_value_set_uint (value, hildon_date_editor_get_day (editor));
627             break;
628
629         case PROP_MIN_YEAR:
630             g_value_set_uint (value, priv->min_year);
631             break;
632
633         case PROP_MAX_YEAR:
634             g_value_set_uint (value, priv->max_year);
635             break;
636
637         default:
638             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
639             break;
640     }
641 }
642
643 static void 
644 hildon_child_forall                             (GtkContainer *container,
645                                                  gboolean include_internals,
646                                                  GtkCallback callback,
647                                                  gpointer callback_data)
648 {
649     HildonDateEditor *editor;
650     HildonDateEditorPrivate *priv;
651
652     g_assert (HILDON_IS_DATE_EDITOR (container));
653     g_assert (callback);
654
655     editor = HILDON_DATE_EDITOR (container);
656     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
657     g_assert (priv);
658
659     if (include_internals) {
660         (*callback) (priv->frame, callback_data);
661         (*callback) (priv->d_button_image, callback_data);
662     }
663 }
664
665 static void 
666 hildon_date_editor_destroy                      (GtkObject *self)
667 {
668     HildonDateEditorPrivate *priv;
669
670     priv = HILDON_DATE_EDITOR_GET_PRIVATE (self);
671     g_assert (priv);
672
673     if (priv->frame) {
674         gtk_widget_unparent (priv->frame);
675         priv->frame = NULL;
676     }
677     if (priv->d_button_image) {
678         gtk_widget_unparent (priv->d_button_image);
679         priv->d_button_image = NULL;
680     }
681     if (priv->delims) {
682         g_list_free (priv->delims);
683         priv->delims = NULL;
684     }
685
686     if (GTK_OBJECT_CLASS (parent_class)->destroy)
687         GTK_OBJECT_CLASS (parent_class)->destroy (self);
688 }
689
690 /**
691  * hildon_date_editor_new:
692  *
693  * Creates a new date editor. The current system date
694  * is shown in the editor.
695  *
696  * Returns: pointer to a new @HildonDateEditor widget.
697  */
698 GtkWidget*
699 hildon_date_editor_new                          (void)
700 {
701     return (GtkWidget *) g_object_new (HILDON_TYPE_DATE_EDITOR, NULL);
702 }
703
704 /**
705  * hildon_date_editor_set_date:
706  * @date: the @HildonDateEditor widget
707  * @year: year
708  * @month: month
709  * @day: day
710  *
711  * Sets the date shown in the editor. 
712  */
713 void 
714 hildon_date_editor_set_date                     (HildonDateEditor *editor,
715                                                  guint year, 
716                                                  guint month, 
717                                                  guint day)
718 {
719     HildonDateEditorPrivate *priv;
720
721     g_return_if_fail (HILDON_IS_DATE_EDITOR (editor));
722
723     /* This function cannot be implemented by calling
724        component setters, since applying the individual
725        values one by one can make the date temporarily
726        invalid (depending on what the previous values were), 
727        which in turn causes that the desired date
728        is not set (even though it's valid). We must set all the
729        components at one go and not try to do any validation etc
730        there in between. */
731
732     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
733     g_assert (priv);
734
735     if (g_date_valid_dmy (day, month, year))
736     {
737         GDate date;
738         gchar buffer[256];
739
740         priv->year = year;
741         priv->month = month;
742         priv->day = day;
743
744         g_date_set_dmy (&date, day, month, year);
745
746         /* We apply the new values, but do not want automatic focus move
747            etc to take place */
748         g_snprintf (buffer, sizeof (buffer), "%04d", year);
749         g_signal_handlers_block_by_func (priv->y_entry, 
750                 (gpointer) hildon_date_editor_entry_changed, editor);
751         gtk_entry_set_text (GTK_ENTRY (priv->y_entry), buffer);
752         g_signal_handlers_unblock_by_func (priv->y_entry, 
753                 (gpointer) hildon_date_editor_entry_changed, editor);
754
755         g_date_strftime (buffer, sizeof (buffer), "%m", &date);
756         g_signal_handlers_block_by_func (priv->m_entry, 
757                 (gpointer) hildon_date_editor_entry_changed, editor);
758         gtk_entry_set_text (GTK_ENTRY (priv->m_entry), buffer);
759         g_signal_handlers_unblock_by_func (priv->m_entry, 
760                 (gpointer) hildon_date_editor_entry_changed, editor);
761
762         g_date_strftime (buffer, sizeof (buffer), "%d", &date);
763         g_signal_handlers_block_by_func (priv->d_entry, 
764                 (gpointer) hildon_date_editor_entry_changed, editor);
765         gtk_entry_set_text (GTK_ENTRY (priv->d_entry), buffer);
766         g_signal_handlers_unblock_by_func (priv->d_entry, 
767                 (gpointer) hildon_date_editor_entry_changed, editor);
768
769         g_object_notify (G_OBJECT (editor), "year");
770         g_object_notify (G_OBJECT (editor), "month");
771         g_object_notify (G_OBJECT (editor), "day");
772     }
773 }
774
775 /**
776  * hildon_date_editor_get_date:
777  * @date: the @HildonDateEditor widget
778  * @year: year
779  * @month: month
780  * @day: day
781  *
782  * Gets the date represented by the date editor.
783  * You can pass NULL to any of the pointers if
784  * you're not interested in obtaining it. 
785  *
786  */
787 void 
788 hildon_date_editor_get_date                     (HildonDateEditor *date,
789                                                  guint *year, 
790                                                  guint *month, 
791                                                  guint *day)
792 {
793     HildonDateEditorPrivate *priv;
794
795     g_return_if_fail (HILDON_IS_DATE_EDITOR (date));
796
797     priv = HILDON_DATE_EDITOR_GET_PRIVATE (date);
798
799     /* FIXME: The role of priv->{day,month,year} members vs. entry contents
800        is unclear. They do not neccesarily match and still the texts are
801        used as return values and members for some internal validation!!
802        At least a partly reason is to allow empty text to become
803        0 return value, while members are restricted to valid ranges?!
804        However, if we change the current way, we are likely to break 
805        some applications  if they rely on some specific way how this 
806        widget currently handles empty values and temporarily invalid values.
807
808        The key issue is this: What should the _get methods return while
809        user is editing a field and the result is incomplete. The
810        partial result? The last good result? If we return partial result
811        we also need a way to inform if the date is not valid. Current
812        implementation is some kind of hybrid of these two...
813
814        for example:
815        hildon_date_editor_set_day(editor, hildon_date_editor_get_day(editor));
816
817        easily fails, since set_day tries to force validity while get_day
818        doesn't do that.
819
820        Proposal: Always return the same values that are shown in the
821        fields. We add a separate flag (Or use GDate) to 
822        indicate if the current date is valid. This would allow 
823        setters to make the date invalid as well. */
824
825     if (year != NULL)
826         *year = /*priv->year;*/
827         (guint) atoi (gtk_entry_get_text (GTK_ENTRY (priv->y_entry)));
828     if (month != NULL)
829         *month = /*priv->month;*/
830         (guint) atoi (gtk_entry_get_text (GTK_ENTRY (priv->m_entry)));
831     if (day != NULL)
832         *day = /*priv->day;*/ 
833         (guint) atoi (gtk_entry_get_text (GTK_ENTRY (priv->d_entry)));
834 }
835
836 /* icon button press event */
837 static gboolean 
838 hildon_date_editor_icon_press                   (GtkWidget *widget,
839                                                  gpointer data)
840 {
841     g_assert (GTK_IS_WIDGET (widget));
842     g_assert (HILDON_IS_DATE_EDITOR (data));
843
844     hildon_date_editor_set_calendar_icon_state (HILDON_DATE_EDITOR (data), TRUE);
845
846     return FALSE;
847 }
848
849 static gboolean 
850 hildon_date_editor_entry_focus_in               (GtkWidget *widget,
851                                                  GdkEventFocus *event,
852                                                  gpointer data)
853 {
854     g_idle_add ((GSourceFunc) hildon_date_editor_entry_select_all, GTK_ENTRY (widget));
855
856     return FALSE;
857 }
858
859
860 static void
861 popup_calendar_dialog                           (HildonDateEditor *ed)
862 {
863     guint y = 0, m = 0, d = 0;
864     GtkWidget *popup;
865     GtkWidget *parent;
866     guint result;
867     GValue val = {0, };
868
869     hildon_date_editor_get_date (ed, &y, &m, &d);
870
871     parent = gtk_widget_get_ancestor (GTK_WIDGET (ed), GTK_TYPE_WINDOW);
872     popup = hildon_calendar_popup_new (GTK_WINDOW (parent), y, m, d);
873
874     g_value_init (&val, G_TYPE_INT);
875     /* Set max/min year in calendar popup to date editor values */
876     g_object_get_property (G_OBJECT (ed), "min-year", &val);
877     g_object_set_property (G_OBJECT (popup), "min-year", &val);
878     g_object_get_property (G_OBJECT (ed), "max-year", &val);
879     g_object_set_property (G_OBJECT (popup), "max-year", &val);
880
881     /* Pop up calendar */
882     result = gtk_dialog_run (GTK_DIALOG (popup));
883     switch (result) {
884         case GTK_RESPONSE_OK:
885         case GTK_RESPONSE_ACCEPT:
886             hildon_calendar_popup_get_date (HILDON_CALENDAR_POPUP (popup), &y,
887                     &m, &d);
888             hildon_date_editor_set_date (ed, y, m, d);
889     }
890
891     gtk_widget_destroy (popup);
892 }
893
894 /* button released */
895 static gboolean 
896 hildon_date_editor_released                     (GtkWidget *widget,
897                                                  gpointer data)
898 {
899     HildonDateEditor *ed;
900
901     g_assert (GTK_IS_WIDGET (widget));
902     g_assert (HILDON_IS_DATE_EDITOR (data));
903
904     ed = HILDON_DATE_EDITOR (data);
905
906     /* restores the icon state. The clicked cycle raises the dialog */
907     hildon_date_editor_set_calendar_icon_state (ed, FALSE);
908
909     return FALSE;
910 }
911
912 /* button released */
913 static gboolean 
914 hildon_date_editor_clicked                      (GtkWidget *widget,
915                                                  gpointer data)
916 {
917     HildonDateEditor *ed;
918
919     g_assert (GTK_IS_WIDGET (widget));
920     g_assert (HILDON_IS_DATE_EDITOR (data));
921
922     ed = HILDON_DATE_EDITOR (data);
923
924     /* restores the non-clicked button state and raises the dialog */
925     hildon_date_editor_set_calendar_icon_state (ed, FALSE);
926     popup_calendar_dialog (ed);
927
928     return FALSE;
929 }
930
931 /* This is called whenever some editor filed loses the focus and
932    when the all of the fields are filled. 
933    Earlier this was called whenever an entry changed */
934 /* FIXME: Validation on focus_out is broken by concept */
935 static gint
936 hildon_date_editor_entry_validate               (GtkWidget *widget, 
937                                                  gpointer data)
938 {
939     HildonDateEditor *ed;
940     HildonDateEditorPrivate *priv;
941     gint d, m, y, max_days;
942     gboolean r;  /* temp return values for signals */
943     const gchar *text;        
944     gint error_code = HILDON_DATE_TIME_ERROR_NO_ERROR;
945
946     g_assert (HILDON_IS_DATE_EDITOR (data));
947     g_assert (GTK_IS_ENTRY (widget));
948
949     ed = HILDON_DATE_EDITOR (data);
950     priv = HILDON_DATE_EDITOR_GET_PRIVATE (ed);
951     g_assert (priv);
952
953     if (priv->skip_validation)
954         return error_code;
955
956     /*check if the calling entry is empty*/
957     text = gtk_entry_get_text (GTK_ENTRY (widget));
958     if(text == NULL || text[0] == 0)
959     {
960         if (widget == priv->d_entry)
961             g_signal_emit (ed, date_editor_signals[DATE_ERROR], 0, HILDON_DATE_TIME_ERROR_EMPTY_DAY, &r);
962         else if(widget == priv->m_entry)
963             g_signal_emit (ed, date_editor_signals[DATE_ERROR], 0, HILDON_DATE_TIME_ERROR_EMPTY_MONTH, &r);
964         else
965             g_signal_emit (ed, date_editor_signals[DATE_ERROR], 0, HILDON_DATE_TIME_ERROR_EMPTY_YEAR, &r);
966
967         /* restore empty entry to safe value */
968         hildon_date_editor_set_date (ed, priv->year, priv->month, priv->day);
969         return error_code;
970     }
971
972     /* Ok, we now check validity. Some fields can be empty */
973     text = gtk_entry_get_text (GTK_ENTRY (priv->d_entry));
974     if (text == NULL || text[0] == 0) return error_code;
975     d = atoi (text);
976     text = gtk_entry_get_text (GTK_ENTRY (priv->m_entry));
977     if (text == NULL || text[0] == 0) return error_code;
978     m = atoi (text);
979     text = gtk_entry_get_text (GTK_ENTRY (priv->y_entry));
980     if (text == NULL || text[0] == 0) return error_code;
981     y = atoi (text);
982
983     /* Did it actually change? */
984     if (d != priv->day || m != priv->month || y != priv->year)
985     {
986         /* We could/should use hildon_date_editor_set_year and such functions
987          * to set the date, instead of use gtk_entry_set_text, and then change
988          * the priv member but hildon_date_editor_set_year and such functions
989          * check if the date is valid, we do want to do date validation check
990          * here according to spec */
991
992         /* Validate month */
993         if (widget == priv->m_entry) {
994             if (m < 1) {
995                 error_code = HILDON_DATE_TIME_ERROR_MIN_MONTH;
996                 m = 1;
997             }
998             else if (m > 12) {
999                 error_code = HILDON_DATE_TIME_ERROR_MAX_MONTH;
1000                 m = 12;
1001             }
1002         }
1003
1004         /* Validate year */
1005         if(widget == priv->y_entry) {
1006             if (y < priv->min_year) {
1007                 error_code = HILDON_DATE_TIME_ERROR_MIN_YEAR;
1008                 y = priv->min_year;
1009             }
1010             else if (y > priv->max_year) {
1011                 error_code =   HILDON_DATE_TIME_ERROR_MAX_YEAR;
1012                 y = priv->max_year;
1013             }
1014         }
1015
1016         /* Validate day. We have to do this in every case, since
1017            changing month or year can make the day number to be invalid */
1018         max_days = g_date_get_days_in_month (m,y);
1019         if(d < 1) {
1020             error_code = HILDON_DATE_TIME_ERROR_MIN_DAY;
1021             d = 1;
1022         }
1023         else if (d > max_days) {
1024             if (d > 31) {         
1025                 error_code = HILDON_DATE_TIME_ERROR_MAX_DAY;
1026                 d = max_days;
1027             }
1028             else {                /* the date does not exist (is invalid) */
1029                 error_code = HILDON_DATE_TIME_ERROR_INVALID_DATE;
1030                 /* check what was changed and restore previous value */
1031                 if (widget == priv->y_entry)
1032                     y = priv->year;
1033                 else if (widget == priv->m_entry)
1034                     m = priv->month;
1035                 else
1036                     d = priv->day;
1037             }
1038         }
1039
1040         if (error_code != HILDON_DATE_TIME_ERROR_NO_ERROR)
1041         {
1042             g_signal_emit (ed, date_editor_signals[DATE_ERROR], 0, error_code, &r);
1043
1044             g_idle_add ((GSourceFunc) hildon_date_editor_entry_select_all, widget);
1045         }
1046     }
1047
1048     /* Fix and reformat the date after error signal is processed. 
1049        reformatting can be needed even in a such case that numerical
1050        values of the date components are the same as earlier. */
1051     hildon_date_editor_set_date (ed, y, m, d);
1052     return error_code;
1053 }
1054
1055 /* Idle callback */
1056 static gboolean
1057 hildon_date_editor_entry_select_all             (GtkWidget *widget)
1058 {
1059     GDK_THREADS_ENTER ();
1060
1061     gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1062
1063     GDK_THREADS_LEAVE ();
1064
1065     return FALSE;
1066 }
1067
1068 /* When entry becomes full, we move the focus to the next field.
1069    If we are on the last field, the whole contents are validated. */
1070 static void
1071 hildon_date_editor_entry_changed                (GtkEditable *ed, 
1072                                                  gpointer data)
1073 {
1074     GtkEntry *entry;
1075     gint error_code;
1076     HildonDateEditorPrivate *priv;
1077
1078     g_assert (GTK_IS_ENTRY (ed));
1079     g_assert (HILDON_IS_DATE_EDITOR (data));
1080
1081     entry = GTK_ENTRY (ed);
1082
1083     /* If day entry is full, move to next entry or validate */
1084     if (g_utf8_strlen (gtk_entry_get_text (entry), -1) == gtk_entry_get_max_length (entry))
1085     {
1086         error_code = hildon_date_editor_entry_validate (GTK_WIDGET (entry), data);
1087         if (error_code == HILDON_DATE_TIME_ERROR_NO_ERROR)
1088         {
1089             priv = HILDON_DATE_EDITOR_GET_PRIVATE (HILDON_DATE_EDITOR (data));
1090             g_assert (priv);
1091             priv->skip_validation = TRUE;
1092             gtk_widget_child_focus (GTK_WIDGET (data), GTK_DIR_RIGHT);
1093         }
1094     }
1095 }
1096
1097 static gboolean 
1098 hildon_date_editor_keyrelease                   (GtkWidget *widget,
1099                                                  GdkEventKey *event,
1100                                                  gpointer data)
1101 {
1102     HildonDateEditor *ed;
1103     HildonDateEditorPrivate *priv;
1104
1105     g_return_val_if_fail (data, FALSE);
1106     g_return_val_if_fail (widget, FALSE);
1107
1108     ed = HILDON_DATE_EDITOR (data);
1109     priv = HILDON_DATE_EDITOR_GET_PRIVATE (ed);
1110
1111     if (event->keyval == GDK_KP_Enter || 
1112         event->keyval == GDK_Return ||
1113         event->keyval == GDK_ISO_Enter) {
1114         if (hildon_date_editor_set_calendar_icon_state (ed, FALSE))
1115         {
1116             popup_calendar_dialog (ed);
1117             return TRUE;
1118         }
1119     } else if (event->keyval == GDK_Escape)
1120         priv->skip_validation = FALSE;
1121
1122     return FALSE;
1123 }
1124
1125 /* keyboard handling */
1126 static gboolean 
1127 hildon_date_editor_keypress                     (GtkWidget *widget,
1128                                                  GdkEventKey *event,
1129                                                  gpointer data)
1130 {
1131     HildonDateEditor *ed;
1132     HildonDateEditorPrivate *priv;
1133
1134     g_assert (HILDON_IS_DATE_EDITOR (data));
1135     g_assert (GTK_IS_ENTRY (widget));
1136
1137     ed = HILDON_DATE_EDITOR (data);
1138
1139     switch (event->keyval) {
1140         case GDK_Return:
1141         case GDK_ISO_Enter:
1142             /* Ignore return value, since we want to handle event at all times.
1143                otherwise vkb would popup when the keyrepeat starts. */
1144             hildon_date_editor_set_calendar_icon_state (ed, TRUE);
1145             return TRUE;
1146         case GDK_Escape:
1147             priv = HILDON_DATE_EDITOR_GET_PRIVATE (ed);
1148             priv->skip_validation = TRUE;
1149             break;
1150         default:
1151             break;
1152     }
1153
1154     return FALSE;
1155 }
1156
1157 static gboolean 
1158 hildon_date_editor_entry_focus_out              (GtkWidget *widget,
1159                                                  GdkEventFocus *event,
1160                                                  gpointer data)
1161 {
1162     HildonDateEditor *ed;
1163     HildonDateEditorPrivate *priv;
1164
1165     g_assert (HILDON_IS_DATE_EDITOR (data));
1166
1167     ed = HILDON_DATE_EDITOR (data);
1168     priv = HILDON_DATE_EDITOR_GET_PRIVATE (ed);
1169     g_assert (priv);
1170
1171     hildon_date_editor_entry_validate (widget, data);
1172     priv->skip_validation = FALSE;
1173
1174     return FALSE;
1175 }
1176
1177 static gboolean 
1178 hildon_date_editor_date_error                   (HildonDateEditor *editor,
1179                                                  HildonDateTimeError type)
1180 {
1181     HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
1182     g_assert (priv);
1183     
1184     switch (type)
1185     {
1186         case HILDON_DATE_TIME_ERROR_MAX_DAY:
1187             hildon_banner_show_informationf (GTK_WIDGET (editor), NULL, _("ckct_ib_maximum_value"), 31);
1188             break;
1189
1190         case HILDON_DATE_TIME_ERROR_MAX_MONTH:
1191             hildon_banner_show_informationf (GTK_WIDGET (editor), NULL, _("ckct_ib_maximum_value"), 12);
1192             break;
1193
1194         case HILDON_DATE_TIME_ERROR_MAX_YEAR:
1195             hildon_banner_show_informationf (GTK_WIDGET (editor), NULL, _("ckct_ib_maximum_value"), priv->max_year);
1196             break;
1197
1198         case HILDON_DATE_TIME_ERROR_MIN_DAY:
1199         case HILDON_DATE_TIME_ERROR_MIN_MONTH:
1200             hildon_banner_show_informationf (GTK_WIDGET (editor), NULL, _("ckct_ib_minimum_value"), 1);
1201             break;
1202
1203         case HILDON_DATE_TIME_ERROR_MIN_YEAR:
1204             hildon_banner_show_informationf (GTK_WIDGET (editor), NULL, _("ckct_ib_minimum_value"), priv->min_year);
1205             break;
1206
1207         case HILDON_DATE_TIME_ERROR_EMPTY_DAY:
1208             hildon_banner_show_informationf (GTK_WIDGET (editor), NULL, _("ckct_ib_set_a_value_within_range"), 1, 31);
1209             break;
1210
1211         case HILDON_DATE_TIME_ERROR_EMPTY_MONTH:
1212             hildon_banner_show_informationf (GTK_WIDGET (editor), NULL, _("ckct_ib_set_a_value_within_range"), 1, 12);
1213             break;
1214
1215         case HILDON_DATE_TIME_ERROR_EMPTY_YEAR:
1216             hildon_banner_show_informationf (GTK_WIDGET (editor), NULL, _("ckct_ib_set_a_value_within_range"),
1217                     priv->min_year, priv->max_year);
1218             break;
1219
1220         case HILDON_DATE_TIME_ERROR_INVALID_CHAR:
1221             hildon_banner_show_information (GTK_WIDGET (editor), NULL, c_("ckct_ib_illegal_character"));
1222             break;
1223
1224         case HILDON_DATE_TIME_ERROR_INVALID_DATE:
1225             hildon_banner_show_information (GTK_WIDGET (editor), NULL, _("ckct_ib_date_does_not_exist"));
1226             break;
1227
1228         default:
1229             /*default error message ?*/
1230             break;
1231     }
1232
1233     return TRUE;
1234 }
1235
1236 static void 
1237 hildon_date_editor_size_request                 (GtkWidget *widget,
1238                                                  GtkRequisition *requisition)
1239 {
1240     HildonDateEditor *ed;
1241     HildonDateEditorPrivate *priv;
1242     GtkRequisition f_req, img_req;
1243
1244     g_assert (GTK_IS_WIDGET (widget));
1245     g_assert (requisition != NULL);
1246
1247     ed = HILDON_DATE_EDITOR (widget);
1248     priv = HILDON_DATE_EDITOR_GET_PRIVATE (ed);
1249     g_assert (priv);
1250
1251     /* Our own children affect our size */
1252     gtk_widget_size_request (priv->frame, &f_req);
1253     gtk_widget_size_request (priv->d_button_image, &img_req);
1254
1255     /* calculate our size */
1256     requisition->width = f_req.width + img_req.width + HILDON_MARGIN_DEFAULT;
1257
1258     /* FIXME: Fixed size is bad! We should use the maximum of our children, but
1259        doing so would break current pixel specifications, since
1260        the text entry by itself is already 30px tall + then frame takes
1261        something */
1262     requisition->height = DATE_EDITOR_HEIGHT;
1263 }
1264
1265 static void 
1266 hildon_date_editor_size_allocate                (GtkWidget *widget,
1267                                                  GtkAllocation *allocation)
1268 {
1269     HildonDateEditor *ed;
1270     HildonDateEditorPrivate *priv;
1271     GtkAllocation f_alloc, img_alloc;
1272     GtkRequisition req;
1273     GtkRequisition max_req;
1274     GList *iter;
1275
1276     g_assert (GTK_IS_WIDGET (widget));
1277     g_assert (allocation != NULL);
1278
1279     ed = HILDON_DATE_EDITOR (widget);
1280     priv = HILDON_DATE_EDITOR_GET_PRIVATE (ed);
1281
1282     widget->allocation = *allocation;
1283
1284     gtk_widget_get_child_requisition (widget, &max_req);
1285
1286     /* Center vertically */
1287     f_alloc.y = img_alloc.y = allocation->y +
1288         MAX (allocation->height - max_req.height, 0) / 2;
1289
1290     /* Center horizontally */
1291     f_alloc.x = img_alloc.x = allocation->x +
1292         MAX (allocation->width - max_req.width, 0) / 2;
1293
1294     /* allocate frame */
1295     if (GTK_WIDGET_VISIBLE (priv->frame)) {
1296         gtk_widget_get_child_requisition (priv->frame, &req);
1297
1298         f_alloc.width = req.width;
1299         f_alloc.height = max_req.height;
1300         gtk_widget_size_allocate (priv->frame, &f_alloc);
1301     }
1302
1303     /* allocate icon */
1304     if (GTK_WIDGET_VISIBLE (priv->d_button_image)) {
1305         gtk_widget_get_child_requisition (priv->d_button_image,
1306                 &req);
1307
1308         img_alloc.x += f_alloc.width + HILDON_MARGIN_DEFAULT;
1309         img_alloc.width = req.width;
1310         img_alloc.height = max_req.height;
1311         gtk_widget_size_allocate (priv->d_button_image, &img_alloc);
1312     }
1313
1314     /* FIXME: We really should not alloc delimeters by hand (since they
1315        are not our own children, but we need to force to appear 
1316        higher. This ugly hack is needed to compensate the forced
1317        height in size_request. */
1318     for (iter = priv->delims; iter; iter = iter->next)
1319     {
1320         GtkWidget *delim;
1321         GtkAllocation alloc;
1322
1323         delim = GTK_WIDGET (iter->data);
1324         alloc = delim->allocation;
1325         alloc.height = max_req.height; 
1326         alloc.y = priv->d_entry->allocation.y - 2;
1327
1328         gtk_widget_size_allocate (delim, &alloc);
1329     }
1330 }
1331
1332 /**
1333  * hildon_date_editor_set_year:
1334  * @editor: the @HildonDateEditor widget
1335  * @year: year
1336  *
1337  * Sets the year shown in the editor. 
1338  *
1339  * Returns: TRUE if the year is valid and has been set.
1340  */
1341 gboolean 
1342 hildon_date_editor_set_year                     (HildonDateEditor *editor, 
1343                                                  guint year)
1344 {
1345     HildonDateEditorPrivate *priv;
1346     g_return_val_if_fail (HILDON_IS_DATE_EDITOR (editor), FALSE);
1347
1348     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
1349     g_assert (priv);
1350
1351     if (g_date_valid_dmy (priv->day, priv->month, year))
1352     {
1353         gchar buffer[256];
1354         priv->year = year;
1355
1356         g_snprintf (buffer, sizeof (buffer), "%04d", year);
1357
1358         /* We apply the new day, but do not want automatic focus move
1359            etc to take place */
1360         g_signal_handlers_block_by_func (priv->y_entry, 
1361                 (gpointer) hildon_date_editor_entry_changed, editor);
1362         gtk_entry_set_text (GTK_ENTRY (priv->y_entry), buffer);
1363         g_signal_handlers_unblock_by_func (priv->y_entry, 
1364                 (gpointer) hildon_date_editor_entry_changed, editor);
1365
1366         g_object_notify (G_OBJECT(editor), "year");
1367         return TRUE;
1368     }
1369
1370     return FALSE;
1371 }
1372
1373 /**
1374  * hildon_date_editor_set_month:
1375  * @editor: the @HildonDateEditor widget
1376  * @month: month
1377  *
1378  * Sets the month shown in the editor. 
1379  *
1380  * Returns: TRUE if the month is valid and has been set.
1381  */
1382 gboolean 
1383 hildon_date_editor_set_month                    (HildonDateEditor *editor, 
1384                                                  guint month)
1385 {
1386     HildonDateEditorPrivate *priv;
1387     g_return_val_if_fail (HILDON_IS_DATE_EDITOR (editor), FALSE);
1388     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
1389     g_assert (priv);
1390
1391     if (g_date_valid_dmy (priv->day, month, priv->year))
1392     {
1393         GDate date;
1394         gchar buffer[256];
1395
1396         priv->month = month;
1397         g_date_set_dmy (&date, priv->day, month, priv->year);
1398         g_date_strftime (buffer, sizeof(buffer), "%m", &date);
1399
1400         /* We apply the new day, but do not want automatic focus move
1401            etc to take place */
1402         g_signal_handlers_block_by_func (priv->m_entry, 
1403                 (gpointer) hildon_date_editor_entry_changed, editor);
1404         gtk_entry_set_text (GTK_ENTRY (priv->m_entry), buffer);
1405         g_signal_handlers_unblock_by_func (priv->m_entry, 
1406                 (gpointer) hildon_date_editor_entry_changed, editor);
1407
1408         g_object_notify (G_OBJECT (editor), "month");
1409         return TRUE;
1410     }
1411     return FALSE;
1412 }
1413
1414 /**
1415  * hildon_date_editor_set_day:
1416  * @editor: the @HildonDateEditor widget
1417  * @day: day
1418  *
1419  * Sets the day shown in the editor. 
1420  *
1421  * Returns: TRUE if the day is valid and has been set.
1422  */
1423 gboolean 
1424 hildon_date_editor_set_day                      (HildonDateEditor *editor, 
1425                                                  guint day)
1426 {
1427     HildonDateEditorPrivate *priv;
1428
1429     g_return_val_if_fail (HILDON_IS_DATE_EDITOR (editor), FALSE);
1430     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
1431     g_assert (priv);
1432
1433     if (g_date_valid_dmy (day, priv->month, priv->year))
1434     {
1435         GDate date;
1436         gchar buffer[256];
1437
1438         priv->day = day;
1439         g_date_set_dmy (&date, day, priv->month, priv->year);
1440         g_date_strftime (buffer, sizeof (buffer), "%d", &date);
1441
1442         /* We apply the new day, but do not want automatic focus move
1443            etc to take place */
1444         g_signal_handlers_block_by_func (priv->d_entry, 
1445                 (gpointer) hildon_date_editor_entry_changed, editor);
1446         gtk_entry_set_text (GTK_ENTRY (priv->d_entry), buffer);
1447         g_signal_handlers_unblock_by_func (priv->d_entry, 
1448                 (gpointer) hildon_date_editor_entry_changed, editor);
1449
1450         g_object_notify (G_OBJECT(editor), "day");
1451         return TRUE;
1452     }
1453     return FALSE;
1454 }
1455
1456 /**
1457  * hildon_date_editor_get_year:
1458  * @editor: the @HildonDateEditor widget
1459  *
1460  * Returns: the current year shown in the editor.
1461  */
1462 guint
1463 hildon_date_editor_get_year                     (HildonDateEditor *editor)
1464 {
1465     HildonDateEditorPrivate *priv;
1466     g_return_val_if_fail (HILDON_IS_DATE_EDITOR(editor), 0);
1467
1468     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
1469     g_assert (priv);
1470
1471     return (guint) atoi (gtk_entry_get_text (GTK_ENTRY (priv->y_entry)));
1472 }
1473
1474 /**
1475  * hildon_date_editor_get_month:
1476  * @editor: the @HildonDateEditor widget
1477  *
1478  * Gets the month shown in the editor. 
1479  *
1480  * Returns: the current month shown in the editor.
1481  */
1482 guint 
1483 hildon_date_editor_get_month                    (HildonDateEditor *editor)
1484 {
1485     HildonDateEditorPrivate *priv;
1486     g_return_val_if_fail (HILDON_IS_DATE_EDITOR (editor), 0);
1487
1488     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
1489     g_assert (priv);
1490
1491     return (guint) atoi (gtk_entry_get_text (GTK_ENTRY (priv->m_entry)));
1492 }
1493
1494 /**
1495  * hildon_date_editor_get_day:
1496  * @editor: the @HildonDateEditor widget
1497  *
1498  * Gets the day shown in the editor. 
1499  *
1500  * Returns: the current day shown in the editor
1501  */
1502 guint 
1503 hildon_date_editor_get_day                      (HildonDateEditor *editor)
1504 {
1505     HildonDateEditorPrivate *priv;
1506     g_return_val_if_fail (HILDON_IS_DATE_EDITOR (editor), 0);
1507
1508     priv = HILDON_DATE_EDITOR_GET_PRIVATE (editor);
1509     g_assert (priv);
1510
1511     return (guint) atoi (gtk_entry_get_text (GTK_ENTRY (priv->d_entry)));
1512 }
1513