2 * This file is a part of hildon
4 * Copyright (C) 2005, 2008 Nokia Corporation.
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.
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.
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.
22 * SECTION:hildon-time-selector
23 * @short_description: A widget to select the current time.
25 * #HildonTimeSelector allows users to choose a time by selecting hour
26 * and minute. It also allows choosing between AM or PM format.
28 * The currently selected time can be altered with
29 * hildon_time_selector_set_time(), and retrieved using
30 * hildon_time_selector_get_time().
32 * Use this widget instead of deprecated HildonTimeEditor widget.
35 #define _GNU_SOURCE /* needed for GNU nl_langinfo_l */
36 #define __USE_GNU /* needed for locale */
38 #ifdef HAVE_SYS_TIME_H
48 #include <gconf/gconf-client.h>
50 #include "hildon-time-selector.h"
52 #define HILDON_TIME_SELECTOR_GET_PRIVATE(obj) \
53 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HILDON_TYPE_TIME_SELECTOR, HildonTimeSelectorPrivate))
55 G_DEFINE_TYPE (HildonTimeSelector, hildon_time_selector, HILDON_TYPE_TOUCH_SELECTOR)
58 #define LAST_YEAR 50 /* since current year */
60 #define _(String) dgettext("hildon-libs", String)
61 #define N_(String) String
64 /* FIXME: we should get this two props from the clock ui headers */
65 #define CLOCK_GCONF_PATH "/apps/clock"
66 #define CLOCK_GCONF_IS_24H_FORMAT CLOCK_GCONF_PATH "/time-format"
87 struct _HildonTimeSelectorPrivate
89 GtkTreeModel *hours_model;
90 GtkTreeModel *minutes_model;
91 GtkTreeModel *ampm_model;
94 gboolean ampm_format; /* if using am/pm format or 24 h one */
96 gboolean pm; /* if we are on pm (only useful if ampm_format == TRUE) */
99 gint creation_minutes;
102 static void hildon_time_selector_finalize (GObject * object);
103 static GObject* hildon_time_selector_constructor (GType type,
104 guint n_construct_properties,
105 GObjectConstructParam *construct_params);
106 static void hildon_time_selector_get_property (GObject *object,
110 static void hildon_time_selector_set_property (GObject *object,
115 /* private functions */
116 static GtkTreeModel *_create_hours_model (HildonTimeSelector * selector);
117 static GtkTreeModel *_create_minutes_model (guint minutes_step);
118 static GtkTreeModel *_create_ampm_model (HildonTimeSelector * selector);
120 static void _get_real_time (gint * hours, gint * minutes);
121 static void _manage_ampm_selection_cb (HildonTouchSelector * selector,
122 gint num_column, gpointer data);
123 static void _check_ampm_format (HildonTimeSelector * selector);
124 static void _set_pm (HildonTimeSelector * selector, gboolean pm);
126 static gchar *_custom_print_func (HildonTouchSelector * selector,
130 hildon_time_selector_class_init (HildonTimeSelectorClass * class)
132 GObjectClass *gobject_class;
133 GtkObjectClass *object_class;
134 GtkWidgetClass *widget_class;
135 GtkContainerClass *container_class;
137 gobject_class = (GObjectClass *) class;
138 object_class = (GtkObjectClass *) class;
139 widget_class = (GtkWidgetClass *) class;
140 container_class = (GtkContainerClass *) class;
143 gobject_class->get_property = hildon_time_selector_get_property;
144 gobject_class->set_property = hildon_time_selector_set_property;
145 gobject_class->constructor = hildon_time_selector_constructor;
146 gobject_class->finalize = hildon_time_selector_finalize;
148 g_object_class_install_property (gobject_class,
150 g_param_spec_uint ("minutes-step",
151 "Step between minutes in the model",
152 "Step between the minutes in the list of"
153 " options of the widget ",
155 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
163 g_type_class_add_private (object_class, sizeof (HildonTimeSelectorPrivate));
167 hildon_time_selector_constructor (GType type,
168 guint n_construct_properties,
169 GObjectConstructParam *construct_params)
172 HildonTimeSelector *selector;
173 HildonTouchSelectorColumn *column;
175 object = (* G_OBJECT_CLASS (hildon_time_selector_parent_class)->constructor)
176 (type, n_construct_properties, construct_params);
178 selector = HILDON_TIME_SELECTOR (object);
180 selector->priv->hours_model = _create_hours_model (selector);
182 column = hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
183 selector->priv->hours_model, TRUE);
184 g_object_set (column, "text-column", 0, NULL);
187 /* we need initialization parameters in order to create minute models*/
188 selector->priv->minutes_step = selector->priv->minutes_step ? selector->priv->minutes_step : 1;
190 selector->priv->minutes_model = _create_minutes_model (selector->priv->minutes_step);
192 column = hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
193 selector->priv->minutes_model, TRUE);
194 g_object_set (column, "text-column", 0, NULL);
196 if (selector->priv->ampm_format) {
197 selector->priv->ampm_model = _create_ampm_model (selector);
199 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
200 selector->priv->ampm_model, TRUE);
202 g_signal_connect (G_OBJECT (selector),
203 "changed", G_CALLBACK (_manage_ampm_selection_cb),
208 /* By default we should select the current day */
209 hildon_time_selector_set_time (selector,
210 selector->priv->creation_hours,
211 selector->priv->creation_minutes);
218 hildon_time_selector_init (HildonTimeSelector * selector)
220 selector->priv = HILDON_TIME_SELECTOR_GET_PRIVATE (selector);
222 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (selector), GTK_NO_WINDOW);
223 gtk_widget_set_redraw_on_allocate (GTK_WIDGET (selector), FALSE);
225 hildon_touch_selector_set_print_func (HILDON_TOUCH_SELECTOR (selector),
228 _get_real_time (&selector->priv->creation_hours,
229 &selector->priv->creation_minutes);
231 _check_ampm_format (selector);
236 hildon_time_selector_get_property (GObject *object,
241 HildonTimeSelectorPrivate *priv = HILDON_TIME_SELECTOR_GET_PRIVATE (object);
245 case PROP_MINUTES_STEP:
246 g_value_set_uint (value, priv->minutes_step);
250 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
256 hildon_time_selector_set_property (GObject *object,
261 HildonTimeSelectorPrivate *priv = HILDON_TIME_SELECTOR_GET_PRIVATE (object);
265 case PROP_MINUTES_STEP:
266 priv->minutes_step = g_value_get_uint (value);
270 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
276 hildon_time_selector_finalize (GObject * object)
278 /* FIXME: FILL ME !! */
280 (*G_OBJECT_CLASS (hildon_time_selector_parent_class)->finalize) (object);
283 /* ------------------------------ PRIVATE METHODS ---------------------------- */
286 _custom_print_func (HildonTouchSelector * touch_selector,
289 gchar *result = NULL;
290 struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
291 HildonTimeSelector *selector = NULL;
292 static gchar string[255];
296 selector = HILDON_TIME_SELECTOR (touch_selector);
298 hildon_time_selector_get_time (selector, &hours, &minutes);
303 if (selector->priv->ampm_format) {
304 if (selector->priv->pm) {
305 strftime (string, 255, _("wdgt_va_12h_time_pm"), &tm);
307 strftime (string, 255, _("wdgt_va_12h_time_am"), &tm);
310 strftime (string, 255, _("wdgt_va_24h_time"), &tm);
314 result = g_strdup (string);
319 static GtkTreeModel *
320 _create_minutes_model (guint minutes_step)
322 GtkListStore *store_minutes = NULL;
324 static gchar label[255];
325 struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
328 store_minutes = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
329 for (i = 0; i <= 59; i=i+minutes_step) {
331 strftime (label, 255, _("wdgt_va_minutes"), &tm);
333 gtk_list_store_append (store_minutes, &iter);
334 gtk_list_store_set (store_minutes, &iter,
335 COLUMN_STRING, label, COLUMN_INT, i, -1);
338 return GTK_TREE_MODEL (store_minutes);
341 static GtkTreeModel *
342 _create_hours_model (HildonTimeSelector * selector)
344 GtkListStore *store_hours = NULL;
347 struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
348 static gchar label[255];
349 static gint range_12h[12] = {12, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11};
350 static gint range_24h[24] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,
351 12,13,14,15,16,17,18,19,20,21,22,23};
353 gint num_elements = 0;
354 gchar *format_string = NULL;
356 if (selector->priv->ampm_format) {
359 format_string = N_("wdgt_va_12h_hours");
363 format_string = N_("wdgt_va_24h_hours");
366 store_hours = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
367 for (i = 0; i < num_elements; i++) {
368 tm.tm_hour = range[i];
369 strftime (label, 255, _(format_string), &tm);
371 gtk_list_store_append (store_hours, &iter);
372 gtk_list_store_set (store_hours, &iter,
373 COLUMN_STRING, label, COLUMN_INT, range[i], -1);
376 return GTK_TREE_MODEL (store_hours);
379 static GtkTreeModel *
380 _create_ampm_model (HildonTimeSelector * selector)
382 GtkListStore *store_ampm = NULL;
384 static gchar label[255];
386 store_ampm = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
388 snprintf (label, 255, _("wdgt_va_am"));
389 gtk_list_store_append (store_ampm, &iter);
390 gtk_list_store_set (store_ampm, &iter,
391 COLUMN_STRING, label,
394 snprintf (label, 255, _("wdgt_va_pm"));
395 gtk_list_store_append (store_ampm, &iter);
396 gtk_list_store_set (store_ampm, &iter,
397 COLUMN_STRING, label,
400 return GTK_TREE_MODEL (store_ampm);
404 _get_real_time (gint * hours, gint * minutes)
407 struct tm *tm = NULL;
410 tm = localtime (&secs);
413 *hours = tm->tm_hour;
416 if (minutes != NULL) {
417 *minutes = tm->tm_min;
422 _manage_ampm_selection_cb (HildonTouchSelector * touch_selector,
423 gint num_column, gpointer data)
425 HildonTimeSelector *selector = NULL;
429 g_return_if_fail (HILDON_IS_TIME_SELECTOR (touch_selector));
430 selector = HILDON_TIME_SELECTOR (touch_selector);
432 if (num_column == COLUMN_AMPM &&
433 hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
434 COLUMN_AMPM, &iter)) {
435 gtk_tree_model_get (selector->priv->ampm_model, &iter, COLUMN_INT, &pm, -1);
437 selector->priv->pm = pm;
442 _check_ampm_format (HildonTimeSelector * selector)
444 GConfClient *client = NULL;
445 gboolean value = TRUE;
446 GError *error = NULL;
448 client = gconf_client_get_default ();
449 value = gconf_client_get_bool (client, CLOCK_GCONF_IS_24H_FORMAT, &error);
452 ("Error trying to get gconf variable %s, using 24h format by default",
453 CLOCK_GCONF_IS_24H_FORMAT);
454 g_error_free (error);
457 selector->priv->ampm_format = !value;
458 selector->priv->pm = TRUE;
462 _set_pm (HildonTimeSelector * selector, gboolean pm)
466 selector->priv->pm = pm;
468 gtk_tree_model_iter_nth_child (selector->priv->ampm_model, &iter, NULL, pm);
470 hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
471 COLUMN_AMPM, &iter, FALSE);
474 /* ------------------------------ PUBLIC METHODS ---------------------------- */
477 * hildon_time_selector_new:
479 * Creates a new #HildonTimeSelector
481 * Returns: a new #HildonTimeSelector
486 hildon_time_selector_new ()
488 return g_object_new (HILDON_TYPE_TIME_SELECTOR, NULL);
493 * hildon_time_selector_new_step:
495 * Creates a new #HildonTimeSelector
496 * @minutes_step: step between the minutes we are going to show in the
499 * Returns: a new #HildonTimeSelector
504 hildon_time_selector_new_step (guint minutes_step)
506 return g_object_new (HILDON_TYPE_TIME_SELECTOR, "minutes-step",
511 * hildon_time_selector_set_time
512 * @selector: the #HildonTimeSelector
513 * @hours: the current hour (0-23)
514 * @minutes: the current minute (0-59)
516 * Sets the current active hour on the #HildonTimeSelector widget
518 * The format of the hours accepted is always 24h format, with a range
523 * Returns: %TRUE on success, %FALSE otherwise
526 hildon_time_selector_set_time (HildonTimeSelector * selector,
527 guint hours, guint minutes)
532 g_return_val_if_fail (hours <= 23, FALSE);
533 g_return_val_if_fail (minutes <= 59, FALSE);
535 if (selector->priv->ampm_format) {
536 _set_pm (selector, hours >= 12);
538 hours_item = hours - selector->priv->pm * 12;
543 gtk_tree_model_iter_nth_child (selector->priv->hours_model, &iter, NULL,
545 hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
546 COLUMN_HOURS, &iter, FALSE);
548 g_assert (selector->priv->minutes_step>0);
549 minutes = minutes/selector->priv->minutes_step;
550 gtk_tree_model_iter_nth_child (selector->priv->minutes_model, &iter, NULL,
552 hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
553 COLUMN_MINUTES, &iter, FALSE);
559 * hildon_time_selector_get_time
560 * @selector: the #HildonTimeSelector
561 * @hours: to set the current hour (0-23)
562 * @minutes: to set the current minute (0-59)
564 * Gets the current active hour on the #HildonTimeSelector widget. Both @year
565 * and @minutes can be NULL.
567 * This method returns the date always in 24h format, with a range (0-23):(0-59)
572 hildon_time_selector_get_time (HildonTimeSelector * selector,
573 guint * hours, guint * minutes)
578 hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
579 COLUMN_HOURS, &iter);
580 gtk_tree_model_get (selector->priv->hours_model,
581 &iter, COLUMN_INT, hours, -1);
582 if (selector->priv->ampm_format) {
584 *hours += selector->priv->pm * 12;
588 if (minutes != NULL) {
589 hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
590 COLUMN_MINUTES, &iter);
591 gtk_tree_model_get (selector->priv->minutes_model,
592 &iter, COLUMN_INT, minutes, -1);