2009-03-16 Claudio Saavedra <csaavedra@igalia.com>
[hildon] / src / hildon-date-selector.c
index beb2552..c2e0f96 100644 (file)
  * SECTION:hildon-date-selector
  * @short_description: A widget to select the current date.
  *
- * HildonDateSelector is a date widget, equivalent to hildon-calendar, but with a multi-column
- * approach
+ * #HildonDateSelector is a date widget with multiple columns. Users
+ * can choose a date by selecting values in the day, month and year
+ * columns.
  *
+ * The currently selected month and year can be altered with
+ * hildon_date_selector_select_month(). The day can be selected from
+ * the active month using hildon_date_selector_select_day().
  */
 
 #define _GNU_SOURCE     /* needed for GNU nl_langinfo_l */
@@ -89,8 +93,19 @@ struct _HildonDateSelectorPrivate
   gint creation_year;           /* date at creation time */
 
   gint current_num_days;
+
+  gint min_year;
+  gint max_year;
+};
+
+enum {
+  PROP_MIN_YEAR = 1,
+  PROP_MAX_YEAR,
 };
 
+static GObject * hildon_date_selector_constructor (GType                  type,
+                                                   guint                  n_construct_properties,
+                                                   GObjectConstructParam *construct_properties);
 static void hildon_date_selector_finalize (GObject * object);
 
 /* private functions */
@@ -109,7 +124,8 @@ static GtkTreeModel *_update_day_model (HildonDateSelector * selector);
 static gint _month_days (gint month, gint year);
 static void _init_column_order (HildonDateSelector * selector);
 
-static gchar *_custom_print_func (HildonTouchSelector * selector);
+static gchar *_custom_print_func (HildonTouchSelector * selector,
+                                  gpointer user_data);
 
 /***************************************************************************/
 /* The following date routines are taken from the lib_date package.  Keep
@@ -187,6 +203,48 @@ _calc_days (N_int year, N_int mm, N_int dd)
 }
 
 static void
+hildon_date_selector_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  HildonDateSelectorPrivate *priv = HILDON_DATE_SELECTOR (object)->priv;
+
+  switch (prop_id)
+  {
+  case PROP_MIN_YEAR:
+    priv->min_year = g_value_get_int (value);
+    break;
+  case PROP_MAX_YEAR:
+    priv->max_year = g_value_get_int (value);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+hildon_date_selector_get_property (GObject      *object,
+                                   guint         prop_id,
+                                   GValue       *value,
+                                   GParamSpec   *pspec)
+{
+  HildonDateSelectorPrivate *priv = HILDON_DATE_SELECTOR (object)->priv;
+
+  switch (prop_id)
+  {
+  case PROP_MIN_YEAR:
+    g_value_set_int (value, priv->min_year);
+    break;
+  case PROP_MAX_YEAR:
+    g_value_set_int (value, priv->max_year);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
 hildon_date_selector_class_init (HildonDateSelectorClass * class)
 {
   GObjectClass *gobject_class;
@@ -201,42 +259,55 @@ hildon_date_selector_class_init (HildonDateSelectorClass * class)
 
   /* GObject */
   gobject_class->finalize = hildon_date_selector_finalize;
+  gobject_class->get_property = hildon_date_selector_get_property;
+  gobject_class->set_property = hildon_date_selector_set_property;
+  gobject_class->constructor = hildon_date_selector_constructor;
 
   /* GtkWidget */
 
   /* GtkContainer */
 
+  /* properties */
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_MIN_YEAR,
+    g_param_spec_int (
+      "min-year",
+      "Minimum year",
+      "The minimum available year in the selector",
+      1900,
+      2100,
+      1970,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_MAX_YEAR,
+    g_param_spec_int (
+      "max-year",
+      "Maximum year",
+      "The maximum available year in the selector",
+      1900,
+      2100,
+      2037,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
   /* signals */
 
   g_type_class_add_private (object_class, sizeof (HildonDateSelectorPrivate));
 }
 
 static void
-hildon_date_selector_init (HildonDateSelector * selector)
+hildon_date_selector_construct_ui (HildonDateSelector *selector)
 {
   GSList *iter = NULL;
   gint current_item = 0;
   HildonTouchSelectorColumn *column = NULL;
 
-  selector->priv = HILDON_DATE_SELECTOR_GET_PRIVATE (selector);
-
-  GTK_WIDGET_SET_FLAGS (GTK_WIDGET (selector), GTK_NO_WINDOW);
-  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (selector), FALSE);
-
-  hildon_touch_selector_set_print_func (HILDON_TOUCH_SELECTOR (selector),
-                                        _custom_print_func);
-
-  _locales_init (selector->priv);
-
-  _init_column_order (selector);
-
-  _get_real_date (&selector->priv->creation_year,
-                  &selector->priv->creation_month, &selector->priv->creation_day);
-
   selector->priv->year_model = _create_year_model (selector);
   selector->priv->month_model = _create_month_model (selector);
   selector->priv->day_model = _create_day_model (selector);
-  selector->priv->current_num_days = 31;
 
   /* We add the columns, checking the locale order */
   iter = selector->priv->column_order;
@@ -264,14 +335,51 @@ hildon_date_selector_init (HildonDateSelector * selector)
       break;
     }
   }
+}
+
+static GObject *
+hildon_date_selector_constructor (GType                  type,
+                                  guint                  n_construct_properties,
+                                  GObjectConstructParam *construct_properties)
+{
+  GObject *object;
+  HildonDateSelector *selector;
+
+  object = G_OBJECT_CLASS (hildon_date_selector_parent_class)->constructor
+    (type, n_construct_properties, construct_properties);
+
+  selector = HILDON_DATE_SELECTOR (object);
 
-  g_signal_connect (G_OBJECT (selector),
-                    "changed", G_CALLBACK (_manage_selector_change_cb), NULL);
+  hildon_date_selector_construct_ui (selector);
+
+  g_signal_connect (object, "changed", G_CALLBACK (_manage_selector_change_cb), NULL);
 
   /* By default we should select the current day */
   hildon_date_selector_select_current_date (selector, selector->priv->creation_year,
                                             selector->priv->creation_month,
                                             selector->priv->creation_day);
+
+  return object;
+}
+
+static void
+hildon_date_selector_init (HildonDateSelector * selector)
+{
+  selector->priv = HILDON_DATE_SELECTOR_GET_PRIVATE (selector);
+
+  GTK_WIDGET_SET_FLAGS (GTK_WIDGET (selector), GTK_NO_WINDOW);
+  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (selector), FALSE);
+
+  hildon_touch_selector_set_print_func (HILDON_TOUCH_SELECTOR (selector),
+                                        _custom_print_func);
+
+  _locales_init (selector->priv);
+
+  _init_column_order (selector);
+
+  _get_real_date (&selector->priv->creation_year,
+                  &selector->priv->creation_month, &selector->priv->creation_day);
+  selector->priv->current_num_days = 31;
 }
 
 static void
@@ -289,7 +397,7 @@ hildon_date_selector_finalize (GObject * object)
 
 /* ------------------------------ PRIVATE METHODS ---------------------------- */
 static gchar *
-_custom_print_func (HildonTouchSelector * touch_selector)
+_custom_print_func (HildonTouchSelector * touch_selector, gpointer user_data)
 {
   HildonDateSelector *selector = NULL;
   gchar *result = NULL;
@@ -442,7 +550,7 @@ _create_year_model (HildonDateSelector * selector)
   real_year = selector->priv->creation_year;
 
   store_years = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
-  for (i = real_year - INIT_YEAR; i < real_year + LAST_YEAR; i++) {
+  for (i = selector->priv->min_year; i < selector->priv->max_year + 1; i++) {
     tm.tm_year = i - 1900;
     strftime (label, 255, _("wdgt_va_year"), &tm);
 
@@ -489,7 +597,7 @@ _update_day_model (HildonDateSelector * selector)
   guint current_day = 0;
   guint current_year = 0;
   guint current_month = 0;
-  guint num_days = 31;
+  gint num_days = 31;
 
   hildon_date_selector_get_date (selector, &current_year, &current_month,
                                  &current_day);
@@ -585,7 +693,7 @@ _month_days (gint month, gint year)
     {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
   };
 
-  g_return_val_if_fail (month >= 0 && month <= 12, -1);
+  g_return_val_if_fail (month >= 0 && month < 12, -1);
 
   return month_days[_leap (year)][month];
 }
@@ -608,7 +716,47 @@ hildon_date_selector_new ()
   return g_object_new (HILDON_TYPE_DATE_SELECTOR, NULL);
 }
 
+/**
+ * hildon_date_selector_new_with_year_range:
+ * @min_year: the minimum available year or -1 to ignore
+ * @max_year: the maximum available year or -1 to ignore
+ *
+ * Creates a new #HildonDateSelector with a specific year range.
+ * If @min_year or @max_year are set to -1, then the default
+ * upper or lower bound will be used, respectively.
+ *
+ * Returns: a new #HildonDateSelector
+ *
+ * Since: 2.2
+ **/
+GtkWidget *
+hildon_date_selector_new_with_year_range (gint min_year,
+                                          gint max_year)
+{
+  GtkWidget *selector;
+
+  g_return_val_if_fail (min_year <= max_year, NULL);
+
+  if (min_year == -1 && min_year == -1) {
+    selector = g_object_new (HILDON_TYPE_DATE_SELECTOR,
+                             NULL);
+  } else if (min_year == -1) {
+    selector = g_object_new (HILDON_TYPE_DATE_SELECTOR,
+                             "max-year", max_year,
+                             NULL);
+  } else if (max_year == -1) {
+    selector = g_object_new (HILDON_TYPE_DATE_SELECTOR,
+                             "min-year", min_year,
+                             NULL);
+  } else {
+    selector = g_object_new (HILDON_TYPE_DATE_SELECTOR,
+                             "min-year", min_year,
+                             "max-year", max_year,
+                             NULL);
+  }
 
+  return selector;
+}
 /**
  * hildon_date_selector_select_current_date:
  * @selector: the #HildonDateSelector
@@ -619,6 +767,8 @@ hildon_date_selector_new ()
  * Sets the current active date on the #HildonDateSelector widget
  *
  * Since: 2.2
+ *
+ * Returns: %TRUE on success, %FALSE otherwise
  **/
 gboolean
 hildon_date_selector_select_current_date (HildonDateSelector * selector,
@@ -629,19 +779,18 @@ hildon_date_selector_select_current_date (HildonDateSelector * selector,
   gint max_year = 0;
   gint num_days = 0;
 
-  min_year = selector->priv->creation_year - INIT_YEAR;
-  max_year = selector->priv->creation_year + LAST_YEAR;
+  min_year = selector->priv->min_year;
+  max_year = selector->priv->max_year;
 
-  g_return_val_if_fail (year > min_year && year < max_year, FALSE);
-  g_return_val_if_fail (month >= 0 && month < 12, FALSE);
+  g_return_val_if_fail (min_year <= year && year <= max_year, FALSE);
+  g_return_val_if_fail (month < 12, FALSE);
 
   num_days = _month_days (month, year);
   g_return_val_if_fail (day > 0 && day <= num_days, FALSE);
 
 
   gtk_tree_model_iter_nth_child (selector->priv->year_model, &iter, NULL,
-                                 year - selector->priv->creation_year +
-                                 INIT_YEAR);
+                                 year - min_year);
   hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
                                      selector->priv->year_column, &iter,
                                      FALSE);
@@ -680,20 +829,19 @@ hildon_date_selector_get_date (HildonDateSelector * selector,
   GtkTreeIter iter;
 
   if (year != NULL) {
-    hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
-                                        selector->priv->year_column, &iter);
-    gtk_tree_model_get (selector->priv->year_model,
-                        &iter, COLUMN_INT, year, -1);
+    if (hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
+                                            selector->priv->year_column, &iter))
+      gtk_tree_model_get (selector->priv->year_model,
+                          &iter, COLUMN_INT, year, -1);
   }
 
   if (month != NULL) {
-    hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
-                                        selector->priv->month_column, &iter);
-    gtk_tree_model_get (selector->priv->month_model,
-                        &iter, COLUMN_INT, month, -1);
+    if (hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
+                                            selector->priv->month_column, &iter))
+      gtk_tree_model_get (selector->priv->month_model,
+                          &iter, COLUMN_INT, month, -1);
   }
 
-
   if (day != NULL) {
     if (hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
                                             selector->priv->day_column, &iter))
@@ -715,10 +863,12 @@ hildon_date_selector_get_date (HildonDateSelector * selector,
  *
  * Modify the current month and year on the current active date
  *
- * Utility function, too keep this API more similar to the previously existing
- * hildon-calendar widget.
+ * Utility function to keep this API similar to the previously
+ * existing #HildonCalendar widget.
+ *
+ * Since: 2.2
  *
- * Since: 2.2 
+ * Returns: %TRUE on success, %FALSE otherwise
  **/
 gboolean hildon_date_selector_select_month (HildonDateSelector *selector,
                                             guint month, guint year)
@@ -737,8 +887,8 @@ gboolean hildon_date_selector_select_month (HildonDateSelector *selector,
  *
  * Modify the current day on the current active date
  *
- * Utility function, too keep this API more similar to the previously existing
- * hildon-calendar widget.
+ * Utility function to keep this API similar to the previously
+ * existing #HildonCalendar widget.
  *
  * Since: 2.2
  **/