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