Add HildonAppMenu::changed signal
[hildon] / hildon / hildon-date-selector.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2008 Nokia Corporation.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version. or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 /**
22  * SECTION:hildon-date-selector
23  * @short_description: A widget to select the current date.
24  *
25  * #HildonDateSelector is a date widget with multiple columns. Users
26  * can choose a date by selecting values in the day, month and year
27  * columns.
28  *
29  * The currently selected month and year can be altered with
30  * hildon_date_selector_select_month(). The day can be selected from
31  * the active month using hildon_date_selector_select_day().
32  */
33
34 #define _GNU_SOURCE     /* needed for GNU nl_langinfo_l */
35 #define __USE_GNU       /* needed for locale */
36
37 #include <locale.h>
38
39 #ifdef HAVE_SYS_TIME_H
40 #include <sys/time.h>
41 #endif
42
43 #include <string.h>
44 #include <stdlib.h>
45
46 #include <libintl.h>
47 #include <time.h>
48 #include <langinfo.h>
49
50 #include "hildon-date-selector.h"
51
52 #define HILDON_DATE_SELECTOR_GET_PRIVATE(obj)                           \
53   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HILDON_TYPE_DATE_SELECTOR, HildonDateSelectorPrivate))
54
55 G_DEFINE_TYPE (HildonDateSelector, hildon_date_selector, HILDON_TYPE_TOUCH_SELECTOR)
56
57 #define INIT_YEAR 100
58 #define LAST_YEAR 50    /* since current year */
59
60 #define _(String) dgettext("hildon-libs", String)
61
62 /* #define _(String) "%A %e. %B %Y"  debug purposes */
63
64 enum
65 {
66   COLUMN_STRING,
67   COLUMN_INT,
68   N_COLUMNS
69 };
70
71 enum
72 {
73   DAY,
74   MONTH,
75   YEAR
76 };
77
78 struct _HildonDateSelectorPrivate
79 {
80   GtkTreeModel *year_model;
81   GtkTreeModel *month_model;
82   GtkTreeModel *day_model;
83
84   GSList *column_order;
85   gint day_column;
86   gint month_column;
87   gint year_column;             /* it depends on the locale */
88
89   gchar *format;                /* day/month/year format, depends on locale */
90
91   gint creation_day;
92   gint creation_month;
93   gint creation_year;           /* date at creation time */
94
95   gint current_num_days;
96
97   gint min_year;
98   gint max_year;
99 };
100
101 enum {
102   PROP_MIN_YEAR = 1,
103   PROP_MAX_YEAR,
104 };
105
106 static GObject * hildon_date_selector_constructor (GType                  type,
107                                                    guint                  n_construct_properties,
108                                                    GObjectConstructParam *construct_properties);
109 static void hildon_date_selector_finalize (GObject * object);
110
111 /* private functions */
112 static GtkTreeModel *_create_day_model (HildonDateSelector * selector);
113 static GtkTreeModel *_create_year_model (HildonDateSelector * selector);
114 static GtkTreeModel *_create_month_model (HildonDateSelector * selector);
115
116 static void _get_real_date (gint * year, gint * month, gint * day);
117 static void _locales_init (HildonDateSelectorPrivate * priv);
118
119 static void _manage_selector_change_cb (HildonTouchSelector * selector,
120                                         gint num_column, gpointer data);
121
122 static GtkTreeModel *_update_day_model (HildonDateSelector * selector);
123
124 static gint _month_days (gint month, gint year);
125 static void _init_column_order (HildonDateSelector * selector);
126
127 static gchar *_custom_print_func (HildonTouchSelector * selector,
128                                   gpointer user_data);
129
130 /***************************************************************************/
131 /* The following date routines are taken from the lib_date package.  Keep
132  * them separate in case we want to update them if a newer lib_date comes
133  * out with fixes.  */
134
135 typedef unsigned int N_int;
136
137 typedef unsigned long N_long;
138
139 typedef signed long Z_long;
140
141 typedef enum
142 { false = FALSE, true = TRUE } boolean;
143
144 #define                                         and &&  /* logical (boolean) operators: lower case */
145
146 #define                                         or ||
147
148 static const N_int month_length[2][13] = {
149   {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
150   {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
151 };
152
153 static const N_int days_in_months[2][14] = {
154   {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
155   {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
156 };
157
158 static Z_long _calc_days (N_int year, N_int mm, N_int dd);
159
160 static N_int _day_of_week (N_int year, N_int mm, N_int dd);
161
162 static boolean _leap (N_int year);
163
164
165 static boolean
166 _leap (N_int year)
167 {
168   return ((((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0));
169 }
170
171 static N_int
172 _day_of_week (N_int year, N_int mm, N_int dd)
173 {
174   Z_long days;
175
176   days = _calc_days (year, mm, dd);
177   if (days > 0L) {
178     days--;
179     days %= 7L;
180     days++;
181   }
182   return ((N_int) days);
183 }
184
185 static Z_long
186 _year_to_days (N_int year)
187 {
188   return (year * 365L + (year / 4) - (year / 100) + (year / 400));
189 }
190
191 static Z_long
192 _calc_days (N_int year, N_int mm, N_int dd)
193 {
194   boolean lp;
195
196   if (year < 1)
197     return (0L);
198   if ((mm < 1) or (mm > 12))
199     return (0L);
200   if ((dd < 1) or (dd > month_length[(lp = _leap (year))][mm]))
201     return (0L);
202   return (_year_to_days (--year) + days_in_months[lp][mm] + dd);
203 }
204
205 static void
206 hildon_date_selector_set_property (GObject      *object,
207                                    guint         prop_id,
208                                    const GValue *value,
209                                    GParamSpec   *pspec)
210 {
211   HildonDateSelectorPrivate *priv = HILDON_DATE_SELECTOR (object)->priv;
212
213   switch (prop_id)
214   {
215   case PROP_MIN_YEAR:
216     priv->min_year = g_value_get_int (value);
217     break;
218   case PROP_MAX_YEAR:
219     priv->max_year = g_value_get_int (value);
220     break;
221   default:
222     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
223   }
224 }
225
226 static void
227 hildon_date_selector_get_property (GObject      *object,
228                                    guint         prop_id,
229                                    GValue       *value,
230                                    GParamSpec   *pspec)
231 {
232   HildonDateSelectorPrivate *priv = HILDON_DATE_SELECTOR (object)->priv;
233
234   switch (prop_id)
235   {
236   case PROP_MIN_YEAR:
237     g_value_set_int (value, priv->min_year);
238     break;
239   case PROP_MAX_YEAR:
240     g_value_set_int (value, priv->max_year);
241     break;
242   default:
243     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
244   }
245 }
246
247 static void
248 hildon_date_selector_class_init (HildonDateSelectorClass * class)
249 {
250   GObjectClass *gobject_class;
251   GtkObjectClass *object_class;
252   GtkWidgetClass *widget_class;
253   GtkContainerClass *container_class;
254
255   gobject_class = (GObjectClass *) class;
256   object_class = (GtkObjectClass *) class;
257   widget_class = (GtkWidgetClass *) class;
258   container_class = (GtkContainerClass *) class;
259
260   /* GObject */
261   gobject_class->finalize = hildon_date_selector_finalize;
262   gobject_class->get_property = hildon_date_selector_get_property;
263   gobject_class->set_property = hildon_date_selector_set_property;
264   gobject_class->constructor = hildon_date_selector_constructor;
265
266   /* GtkWidget */
267
268   /* GtkContainer */
269
270   /* properties */
271
272   g_object_class_install_property (
273     gobject_class,
274     PROP_MIN_YEAR,
275     g_param_spec_int (
276       "min-year",
277       "Minimum year",
278       "The minimum available year in the selector",
279       1900,
280       2100,
281       1970,
282       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
283
284   g_object_class_install_property (
285     gobject_class,
286     PROP_MAX_YEAR,
287     g_param_spec_int (
288       "max-year",
289       "Maximum year",
290       "The maximum available year in the selector",
291       1900,
292       2100,
293       2037,
294       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
295
296   /* signals */
297
298   g_type_class_add_private (object_class, sizeof (HildonDateSelectorPrivate));
299 }
300
301 static void
302 hildon_date_selector_construct_ui (HildonDateSelector *selector)
303 {
304   GSList *iter = NULL;
305   gint current_item = 0;
306   HildonTouchSelectorColumn *column = NULL;
307
308   selector->priv->year_model = _create_year_model (selector);
309   selector->priv->month_model = _create_month_model (selector);
310   selector->priv->day_model = _create_day_model (selector);
311
312   /* We add the columns, checking the locale order */
313   iter = selector->priv->column_order;
314   for (iter = selector->priv->column_order; iter; iter = g_slist_next (iter)) {
315     current_item = GPOINTER_TO_INT (iter->data);
316
317     switch (current_item) {
318     case DAY:
319       column = hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
320                                                          selector->priv->day_model, TRUE);
321       hildon_touch_selector_column_set_text_column (column, 0);
322       break;
323     case MONTH:
324       column = hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
325                                                          selector->priv->month_model, TRUE);
326       hildon_touch_selector_column_set_text_column (column, 0);
327       break;
328     case YEAR:
329       column = hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
330                                                          selector->priv->year_model, TRUE);
331       hildon_touch_selector_column_set_text_column (column, 0);
332       break;
333     default:
334       g_error ("Current column order incorrect");
335       break;
336     }
337   }
338 }
339
340 static GObject *
341 hildon_date_selector_constructor (GType                  type,
342                                   guint                  n_construct_properties,
343                                   GObjectConstructParam *construct_properties)
344 {
345   GObject *object;
346   HildonDateSelector *selector;
347
348   object = G_OBJECT_CLASS (hildon_date_selector_parent_class)->constructor
349     (type, n_construct_properties, construct_properties);
350
351   selector = HILDON_DATE_SELECTOR (object);
352
353   hildon_date_selector_construct_ui (selector);
354
355   g_signal_connect (object, "changed", G_CALLBACK (_manage_selector_change_cb), NULL);
356
357   /* By default we should select the current day */
358   hildon_date_selector_select_current_date (selector, selector->priv->creation_year,
359                                             selector->priv->creation_month,
360                                             selector->priv->creation_day);
361
362   return object;
363 }
364
365 static void
366 hildon_date_selector_init (HildonDateSelector * selector)
367 {
368   selector->priv = HILDON_DATE_SELECTOR_GET_PRIVATE (selector);
369
370   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (selector), GTK_NO_WINDOW);
371   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (selector), FALSE);
372
373   hildon_touch_selector_set_print_func (HILDON_TOUCH_SELECTOR (selector),
374                                         _custom_print_func);
375
376   _locales_init (selector->priv);
377
378   _init_column_order (selector);
379
380   _get_real_date (&selector->priv->creation_year,
381                   &selector->priv->creation_month, &selector->priv->creation_day);
382   selector->priv->current_num_days = 31;
383 }
384
385 static void
386 hildon_date_selector_finalize (GObject * object)
387 {
388   HildonDateSelector *selector = NULL;
389
390   selector = HILDON_DATE_SELECTOR (object);
391
392   g_slist_free (selector->priv->column_order);
393   g_free (selector->priv->format);
394
395   (*G_OBJECT_CLASS (hildon_date_selector_parent_class)->finalize) (object);
396 }
397
398 /* ------------------------------ PRIVATE METHODS ---------------------------- */
399 static gchar *
400 _custom_print_func (HildonTouchSelector * touch_selector, gpointer user_data)
401 {
402   HildonDateSelector *selector = NULL;
403   gchar *result = NULL;
404   guint year, month, day;
405   gint day_of_week = 0;
406   static gchar string[255];
407   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
408
409   selector = HILDON_DATE_SELECTOR (touch_selector);
410
411   hildon_date_selector_get_date (selector, &year, &month, &day);
412   day_of_week = _day_of_week (year, month + 1, day) % 7;
413
414   tm.tm_mday = day;
415   tm.tm_mon = month;
416   tm.tm_year = year - 1900;
417   tm.tm_wday = day_of_week;
418
419   strftime (string, 255, _("wdgt_va_date_long"), &tm);
420
421   result = g_strdup (string);
422
423   return result;
424 }
425
426 /* This was copied from hildon-calendar */
427 static void
428 _locales_init (HildonDateSelectorPrivate * priv)
429 {
430   /* Hildon: This is not exactly portable, see
431    * http://bugzilla.gnome.org/show_bug.cgi?id=343415
432    * The labels need to be instance variables as the startup wizard changes
433    * locale on runtime.
434    */
435   locale_t l;
436
437   l = newlocale (LC_TIME_MASK, setlocale (LC_MESSAGES, NULL), NULL);
438
439   priv->format = g_locale_to_utf8 (nl_langinfo_l (D_FMT, l),
440                                    -1, NULL, NULL, NULL);
441
442   freelocale (l);
443 }
444
445 static void
446 _init_column_order (HildonDateSelector * selector)
447 {
448   gchar *current_order[3] = { NULL, NULL, NULL };
449   gchar *day_pos = NULL;
450   gchar *month_pos = NULL;
451   gchar *year_pos = NULL;
452   gint i, c;
453   gchar *aux = NULL;
454
455   g_debug ("Current format: %s", selector->priv->format);
456
457   /* search each token on the format */
458   day_pos = g_strrstr (selector->priv->format, "%d");
459
460   month_pos = g_strrstr (selector->priv->format, "%m");
461   year_pos = g_strrstr (selector->priv->format, "%y");
462   if (year_pos == NULL) {
463     year_pos = g_strrstr (selector->priv->format, "%Y");
464   }
465
466
467   if ((day_pos == NULL) || (month_pos == NULL) || (year_pos == NULL)) {
468     g_error ("Wrong date format");      /* so default values */
469
470     selector->priv->day_column = 0;
471     selector->priv->month_column = 1;
472     selector->priv->year_column = 2;
473     selector->priv->column_order = g_slist_append (NULL, GINT_TO_POINTER (DAY));
474     selector->priv->column_order =
475       g_slist_append (selector->priv->column_order, GINT_TO_POINTER (MONTH));
476     selector->priv->column_order =
477       g_slist_append (selector->priv->column_order, GINT_TO_POINTER (YEAR));
478   }
479
480   /* sort current_order with this values (bubble sort) */
481   current_order[0] = day_pos;
482   current_order[1] = month_pos;
483   current_order[2] = year_pos;
484
485   for (c = 1; c <= 2; c++) {
486     for (i = 0; i < 3 - c; i++) {
487       if (current_order[i] > current_order[i + 1]) {
488         aux = current_order[i];
489         current_order[i] = current_order[i + 1];
490         current_order[i + 1] = aux;
491       }
492     }
493   }
494
495   /* fill the column positions */
496   selector->priv->column_order = NULL;
497   c = 0;
498   for (i = 0; i < 3; i++) {
499     if (current_order[i] == day_pos) {
500       selector->priv->column_order =
501         g_slist_append (selector->priv->column_order, GINT_TO_POINTER (DAY));
502       selector->priv->day_column = c++;
503     }
504     if (current_order[i] == month_pos) {
505       selector->priv->column_order =
506         g_slist_append (selector->priv->column_order, GINT_TO_POINTER (MONTH));
507       selector->priv->month_column = c++;
508     }
509     if (current_order[i] == year_pos) {
510       selector->priv->column_order =
511         g_slist_append (selector->priv->column_order, GINT_TO_POINTER (YEAR));
512       selector->priv->year_column = c++;
513     }
514   }
515 }
516
517
518 static GtkTreeModel *
519 _create_day_model (HildonDateSelector * selector)
520 {
521   GtkListStore *store_days = NULL;
522   gint i = 0;
523   gchar label[255];
524   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
525   GtkTreeIter iter;
526
527   store_days = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
528   for (i = 1; i < 32; i++) {
529     tm.tm_mday = i;
530     strftime (label, 255, _("wdgt_va_day_numeric"), &tm);
531
532     gtk_list_store_append (store_days, &iter);
533     gtk_list_store_set (store_days, &iter,
534                         COLUMN_STRING, label, COLUMN_INT, i, -1);
535   }
536
537   return GTK_TREE_MODEL (store_days);
538 }
539
540 static GtkTreeModel *
541 _create_year_model (HildonDateSelector * selector)
542 {
543   GtkListStore *store_years = NULL;
544   gint real_year = 0;
545   gint i = 0;
546   static gchar label[255];
547   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
548   GtkTreeIter iter;
549
550   real_year = selector->priv->creation_year;
551
552   store_years = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
553   for (i = selector->priv->min_year; i < selector->priv->max_year + 1; i++) {
554     tm.tm_year = i - 1900;
555     strftime (label, 255, _("wdgt_va_year"), &tm);
556
557     gtk_list_store_append (store_years, &iter);
558     gtk_list_store_set (store_years, &iter,
559                         COLUMN_STRING, label, COLUMN_INT, i, -1);
560   }
561
562   return GTK_TREE_MODEL (store_years);
563 }
564
565 static GtkTreeModel *
566 _create_month_model (HildonDateSelector * selector)
567 {
568   GtkTreeIter iter;
569   gint i = 0;
570   GtkListStore *store_months = NULL;
571   static gchar label[255];
572   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
573
574   store_months = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
575   for (i = 0; i < 12; i++) {
576     tm.tm_mon = i;
577     strftime (label, 255, _("wdgt_va_month"), &tm);
578
579     gtk_list_store_append (store_months, &iter);
580     gtk_list_store_set (store_months, &iter, COLUMN_STRING, label,
581                         COLUMN_INT, i,
582                         -1);
583   }
584
585   return GTK_TREE_MODEL (store_months);
586 }
587
588 static GtkTreeModel *
589 _update_day_model (HildonDateSelector * selector)
590 {
591   GtkListStore *store_days = NULL;
592   GtkTreePath *path = NULL;
593   gint i = 0;
594   GtkTreeIter iter;
595   static gchar label[255];
596   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
597   guint current_day = 0;
598   guint current_year = 0;
599   guint current_month = 0;
600   gint num_days = 31;
601
602   hildon_date_selector_get_date (selector, &current_year, &current_month,
603                                  &current_day);
604
605   num_days = _month_days (current_month, current_year);
606   store_days = GTK_LIST_STORE (selector->priv->day_model);
607
608   if (num_days == selector->priv->current_num_days) {
609     return GTK_TREE_MODEL (store_days);
610   }
611
612   if (num_days > selector->priv->current_num_days) {
613     for (i = selector->priv->current_num_days + 1; i <= num_days; i++) {
614       tm.tm_mday = i;
615       strftime (label, 255, _("wdgt_va_day_numeric"), &tm);
616
617       gtk_list_store_append (store_days, &iter);
618       gtk_list_store_set (store_days, &iter,
619                           COLUMN_STRING, label, COLUMN_INT, i, -1);
620     }
621   } else {
622     path = gtk_tree_path_new_from_indices (num_days,
623                                            -1);
624     gtk_tree_model_get_iter (GTK_TREE_MODEL (store_days), &iter, path);
625     do {
626     }while (gtk_list_store_remove (store_days, &iter));
627
628     gtk_tree_path_free (path);
629   }
630
631
632   selector->priv->current_num_days = num_days;
633
634   /* now we select a day */
635   if (current_day >= num_days) {
636     current_day = num_days;
637   }
638
639   hildon_date_selector_select_day (selector, current_day);
640
641   return GTK_TREE_MODEL (store_days);
642 }
643
644
645 static void
646 _get_real_date (gint * year, gint * month, gint * day)
647 {
648   time_t secs;
649   struct tm *tm = NULL;
650
651   secs = time (NULL);
652   tm = localtime (&secs);
653
654   if (year != NULL) {
655     *year = 1900 + tm->tm_year;
656   }
657
658   if (month != NULL) {
659     *month = tm->tm_mon;
660   }
661
662   if (day != NULL) {
663     *day = tm->tm_mday;
664   }
665 }
666
667
668 static void
669 _manage_selector_change_cb (HildonTouchSelector * touch_selector,
670                             gint num_column, gpointer data)
671 {
672   HildonDateSelector *selector = NULL;
673
674   g_return_if_fail (HILDON_IS_DATE_SELECTOR (touch_selector));
675   selector = HILDON_DATE_SELECTOR (touch_selector);
676
677   if ((num_column == selector->priv->month_column) ||
678       (num_column == selector->priv->year_column)) /* it is required to check that with
679                                                     * the years too,remember: leap years
680                                                     * update_day_model will check if
681                                                     * the number of days is different
682                                                     */
683   {
684     _update_day_model (selector);
685   }
686 }
687
688 static gint
689 _month_days (gint month, gint year)
690 {
691   gint month_days[2][12] = {
692     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
693     {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
694   };
695
696   g_return_val_if_fail (month >= 0 && month < 12, -1);
697
698   return month_days[_leap (year)][month];
699 }
700
701
702 /* ------------------------------ PUBLIC METHODS ---------------------------- */
703
704 /**
705  * hildon_date_selector_new:
706  *
707  * Creates a new #HildonDateSelector
708  *
709  * Returns: a new #HildonDateSelector
710  *
711  * Since: 2.2
712  **/
713 GtkWidget *
714 hildon_date_selector_new ()
715 {
716   return g_object_new (HILDON_TYPE_DATE_SELECTOR, NULL);
717 }
718
719 /**
720  * hildon_date_selector_new_with_year_range:
721  * @min_year: the minimum available year or -1 to ignore
722  * @max_year: the maximum available year or -1 to ignore
723  *
724  * Creates a new #HildonDateSelector with a specific year range.
725  * If @min_year or @max_year are set to -1, then the default
726  * upper or lower bound will be used, respectively.
727  *
728  * Returns: a new #HildonDateSelector
729  *
730  * Since: 2.2
731  **/
732 GtkWidget *
733 hildon_date_selector_new_with_year_range (gint min_year,
734                                           gint max_year)
735 {
736   GtkWidget *selector;
737
738   g_return_val_if_fail (min_year <= max_year, NULL);
739
740   if (min_year == -1 && min_year == -1) {
741     selector = g_object_new (HILDON_TYPE_DATE_SELECTOR,
742                              NULL);
743   } else if (min_year == -1) {
744     selector = g_object_new (HILDON_TYPE_DATE_SELECTOR,
745                              "max-year", max_year,
746                              NULL);
747   } else if (max_year == -1) {
748     selector = g_object_new (HILDON_TYPE_DATE_SELECTOR,
749                              "min-year", min_year,
750                              NULL);
751   } else {
752     selector = g_object_new (HILDON_TYPE_DATE_SELECTOR,
753                              "min-year", min_year,
754                              "max-year", max_year,
755                              NULL);
756   }
757
758   return selector;
759 }
760 /**
761  * hildon_date_selector_select_current_date:
762  * @selector: the #HildonDateSelector
763  * @year:  the current year
764  * @month: the current month (between 0 and 11)
765  * @day:   the current day (between 1 and 31)
766  *
767  * Sets the current active date on the #HildonDateSelector widget
768  *
769  * Since: 2.2
770  *
771  * Returns: %TRUE on success, %FALSE otherwise
772  **/
773 gboolean
774 hildon_date_selector_select_current_date (HildonDateSelector * selector,
775                                           guint year, guint month, guint day)
776 {
777   GtkTreeIter iter;
778   gint min_year = 0;
779   gint max_year = 0;
780   gint num_days = 0;
781
782   min_year = selector->priv->min_year;
783   max_year = selector->priv->max_year;
784
785   g_return_val_if_fail (min_year <= year && year <= max_year, FALSE);
786   g_return_val_if_fail (month < 12, FALSE);
787
788   num_days = _month_days (month, year);
789   g_return_val_if_fail (day > 0 && day <= num_days, FALSE);
790
791
792   gtk_tree_model_iter_nth_child (selector->priv->year_model, &iter, NULL,
793                                  year - min_year);
794   hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
795                                      selector->priv->year_column, &iter,
796                                      FALSE);
797
798   gtk_tree_model_iter_nth_child (selector->priv->month_model, &iter, NULL,
799                                  month);
800   hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
801                                      selector->priv->month_column, &iter,
802                                      FALSE);
803
804   gtk_tree_model_iter_nth_child (selector->priv->day_model, &iter, NULL,
805                                  day - 1);
806   hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
807                                      selector->priv->day_column, &iter,
808                                      FALSE);
809
810   return TRUE;
811 }
812
813
814 /**
815  * hildon_date_selector_get_date:
816  * @selector: the #HildonDateSelector
817  * @year:  location of the current year, or NULL
818  * @month: location of the current month (between 0 and 11), or NULL
819  * @day:   location of the current day (between 1 and 31), or NULL
820  *
821  * Gets the current active date on the #HildonDateSelector widget
822  *
823  * Since: 2.2
824  **/
825 void
826 hildon_date_selector_get_date (HildonDateSelector * selector,
827                                guint * year, guint * month, guint * day)
828 {
829   GtkTreeIter iter;
830
831   if (year != NULL) {
832     if (hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
833                                             selector->priv->year_column, &iter))
834       gtk_tree_model_get (selector->priv->year_model,
835                           &iter, COLUMN_INT, year, -1);
836   }
837
838   if (month != NULL) {
839     if (hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
840                                             selector->priv->month_column, &iter))
841       gtk_tree_model_get (selector->priv->month_model,
842                           &iter, COLUMN_INT, month, -1);
843   }
844
845   if (day != NULL) {
846     if (hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
847                                             selector->priv->day_column, &iter))
848     {
849       gtk_tree_model_get (selector->priv->day_model,
850                           &iter, COLUMN_INT, day, -1);
851     }
852 /*       *day = *day - 1;  */
853   }
854
855 }
856
857
858 /**
859  * hildon_date_selector_select_month:
860  * @selector: the #HildonDateSelector
861  * @month: the current month (0-11)
862  * @year:  the current year
863  *
864  * Modify the current month and year on the current active date
865  *
866  * Utility function to keep this API similar to the previously
867  * existing #HildonCalendar widget.
868  *
869  * Since: 2.2
870  *
871  * Returns: %TRUE on success, %FALSE otherwise
872  **/
873 gboolean hildon_date_selector_select_month (HildonDateSelector *selector,
874                                             guint month, guint year)
875 {
876   guint day = 0;
877
878   hildon_date_selector_get_date (selector, NULL, NULL, &day);
879
880   return hildon_date_selector_select_current_date (selector, year, month, day);
881 }
882
883 /**
884  * hildon_date_selector_select_day:
885  * @selector: the #HildonDateSelector
886  * @day:   the current day (between 1 and 31)
887  *
888  * Modify the current day on the current active date
889  *
890  * Utility function to keep this API similar to the previously
891  * existing #HildonCalendar widget.
892  *
893  * Since: 2.2
894  **/
895 void
896 hildon_date_selector_select_day (HildonDateSelector *selector, guint day)
897 {
898   guint month = 0;
899   guint year = 0;
900
901   hildon_date_selector_get_date (selector, &year, &month, NULL);
902
903   hildon_date_selector_select_current_date (selector, year, month, day);
904 }