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);
129 hildon_time_selector_class_init (HildonTimeSelectorClass * class)
131 GObjectClass *gobject_class;
132 GtkObjectClass *object_class;
133 GtkWidgetClass *widget_class;
134 GtkContainerClass *container_class;
136 gobject_class = (GObjectClass *) class;
137 object_class = (GtkObjectClass *) class;
138 widget_class = (GtkWidgetClass *) class;
139 container_class = (GtkContainerClass *) class;
142 gobject_class->get_property = hildon_time_selector_get_property;
143 gobject_class->set_property = hildon_time_selector_set_property;
144 gobject_class->constructor = hildon_time_selector_constructor;
145 gobject_class->finalize = hildon_time_selector_finalize;
147 g_object_class_install_property (gobject_class,
149 g_param_spec_uint ("minutes-step",
150 "Step between minutes in the model",
151 "Step between the minutes in the list of"
152 " options of the widget ",
154 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
162 g_type_class_add_private (object_class, sizeof (HildonTimeSelectorPrivate));
166 hildon_time_selector_constructor (GType type,
167 guint n_construct_properties,
168 GObjectConstructParam *construct_params)
171 HildonTimeSelector *selector;
172 HildonTouchSelectorColumn *column;
174 object = (* G_OBJECT_CLASS (hildon_time_selector_parent_class)->constructor)
175 (type, n_construct_properties, construct_params);
177 selector = HILDON_TIME_SELECTOR (object);
179 selector->priv->hours_model = _create_hours_model (selector);
181 column = hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
182 selector->priv->hours_model, TRUE);
183 g_object_set (column, "text-column", 0, NULL);
186 /* we need initialization parameters in order to create minute models*/
187 selector->priv->minutes_step = selector->priv->minutes_step ? selector->priv->minutes_step : 1;
189 selector->priv->minutes_model = _create_minutes_model (selector->priv->minutes_step);
191 column = hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
192 selector->priv->minutes_model, TRUE);
193 g_object_set (column, "text-column", 0, NULL);
195 if (selector->priv->ampm_format) {
196 selector->priv->ampm_model = _create_ampm_model (selector);
198 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
199 selector->priv->ampm_model, TRUE);
201 g_signal_connect (G_OBJECT (selector),
202 "changed", G_CALLBACK (_manage_ampm_selection_cb),
207 /* By default we should select the current day */
208 hildon_time_selector_set_time (selector,
209 selector->priv->creation_hours,
210 selector->priv->creation_minutes);
217 hildon_time_selector_init (HildonTimeSelector * selector)
219 selector->priv = HILDON_TIME_SELECTOR_GET_PRIVATE (selector);
221 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (selector), GTK_NO_WINDOW);
222 gtk_widget_set_redraw_on_allocate (GTK_WIDGET (selector), FALSE);
224 hildon_touch_selector_set_print_func (HILDON_TOUCH_SELECTOR (selector),
227 _get_real_time (&selector->priv->creation_hours,
228 &selector->priv->creation_minutes);
230 _check_ampm_format (selector);
235 hildon_time_selector_get_property (GObject *object,
240 HildonTimeSelectorPrivate *priv = HILDON_TIME_SELECTOR_GET_PRIVATE (object);
244 case PROP_MINUTES_STEP:
245 g_value_set_uint (value, priv->minutes_step);
249 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
255 hildon_time_selector_set_property (GObject *object,
260 HildonTimeSelectorPrivate *priv = HILDON_TIME_SELECTOR_GET_PRIVATE (object);
264 case PROP_MINUTES_STEP:
265 priv->minutes_step = g_value_get_uint (value);
269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
275 hildon_time_selector_finalize (GObject * object)
277 /* FIXME: FILL ME !! */
279 (*G_OBJECT_CLASS (hildon_time_selector_parent_class)->finalize) (object);
282 /* ------------------------------ PRIVATE METHODS ---------------------------- */
285 _custom_print_func (HildonTouchSelector * touch_selector)
287 gchar *result = NULL;
288 struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
289 HildonTimeSelector *selector = NULL;
290 static gchar string[255];
294 selector = HILDON_TIME_SELECTOR (touch_selector);
296 hildon_time_selector_get_time (selector, &hours, &minutes);
301 if (selector->priv->ampm_format) {
302 if (selector->priv->pm) {
303 strftime (string, 255, _("wdgt_va_12h_time_pm"), &tm);
305 strftime (string, 255, _("wdgt_va_12h_time_am"), &tm);
308 strftime (string, 255, _("wdgt_va_24h_time"), &tm);
312 result = g_strdup (string);
317 static GtkTreeModel *
318 _create_minutes_model (guint minutes_step)
320 GtkListStore *store_minutes = NULL;
322 static gchar label[255];
323 struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
326 store_minutes = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
327 for (i = 0; i <= 59; i=i+minutes_step) {
329 strftime (label, 255, _("wdgt_va_minutes"), &tm);
331 gtk_list_store_append (store_minutes, &iter);
332 gtk_list_store_set (store_minutes, &iter,
333 COLUMN_STRING, label, COLUMN_INT, i, -1);
336 return GTK_TREE_MODEL (store_minutes);
339 static GtkTreeModel *
340 _create_hours_model (HildonTimeSelector * selector)
342 GtkListStore *store_hours = NULL;
345 struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
346 static gchar label[255];
347 static gint range_12h[12] = {12, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11};
348 static gint range_24h[24] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,
349 12,13,14,15,16,17,18,19,20,21,22,23};
351 gint num_elements = 0;
352 gchar *format_string = NULL;
354 if (selector->priv->ampm_format) {
357 format_string = N_("wdgt_va_12h_hours");
361 format_string = N_("wdgt_va_24h_hours");
364 store_hours = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
365 for (i = 0; i < num_elements; i++) {
366 tm.tm_hour = range[i];
367 strftime (label, 255, _(format_string), &tm);
369 gtk_list_store_append (store_hours, &iter);
370 gtk_list_store_set (store_hours, &iter,
371 COLUMN_STRING, label, COLUMN_INT, range[i], -1);
374 return GTK_TREE_MODEL (store_hours);
377 static GtkTreeModel *
378 _create_ampm_model (HildonTimeSelector * selector)
380 GtkListStore *store_ampm = NULL;
382 static gchar label[255];
384 store_ampm = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
386 snprintf (label, 255, _("wdgt_va_am"));
387 gtk_list_store_append (store_ampm, &iter);
388 gtk_list_store_set (store_ampm, &iter,
389 COLUMN_STRING, label,
392 snprintf (label, 255, _("wdgt_va_pm"));
393 gtk_list_store_append (store_ampm, &iter);
394 gtk_list_store_set (store_ampm, &iter,
395 COLUMN_STRING, label,
398 return GTK_TREE_MODEL (store_ampm);
402 _get_real_time (gint * hours, gint * minutes)
405 struct tm *tm = NULL;
408 tm = localtime (&secs);
411 *hours = tm->tm_hour;
414 if (minutes != NULL) {
415 *minutes = tm->tm_min;
420 _manage_ampm_selection_cb (HildonTouchSelector * touch_selector,
421 gint num_column, gpointer data)
423 HildonTimeSelector *selector = NULL;
427 g_return_if_fail (HILDON_IS_TIME_SELECTOR (touch_selector));
428 selector = HILDON_TIME_SELECTOR (touch_selector);
430 if (num_column == COLUMN_AMPM &&
431 hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
432 COLUMN_AMPM, &iter)) {
433 gtk_tree_model_get (selector->priv->ampm_model, &iter, COLUMN_INT, &pm, -1);
435 selector->priv->pm = pm;
440 _check_ampm_format (HildonTimeSelector * selector)
442 GConfClient *client = NULL;
443 gboolean value = TRUE;
444 GError *error = NULL;
446 client = gconf_client_get_default ();
447 value = gconf_client_get_bool (client, CLOCK_GCONF_IS_24H_FORMAT, &error);
450 ("Error trying to get gconf variable %s, using 24h format by default",
451 CLOCK_GCONF_IS_24H_FORMAT);
452 g_error_free (error);
455 selector->priv->ampm_format = !value;
456 selector->priv->pm = TRUE;
460 _set_pm (HildonTimeSelector * selector, gboolean pm)
464 selector->priv->pm = pm;
466 gtk_tree_model_iter_nth_child (selector->priv->ampm_model, &iter, NULL, pm);
468 hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
469 COLUMN_AMPM, &iter, FALSE);
472 /* ------------------------------ PUBLIC METHODS ---------------------------- */
475 * hildon_time_selector_new:
477 * Creates a new #HildonTimeSelector
479 * Returns: a new #HildonTimeSelector
484 hildon_time_selector_new ()
486 return g_object_new (HILDON_TYPE_TIME_SELECTOR, NULL);
491 * hildon_time_selector_new_step:
493 * Creates a new #HildonTimeSelector
494 * @minutes_step: step between the minutes we are going to show in the
497 * Returns: a new #HildonTimeSelector
502 hildon_time_selector_new_step (guint minutes_step)
504 return g_object_new (HILDON_TYPE_TIME_SELECTOR, "minutes-step",
509 * hildon_time_selector_set_time
510 * @selector: the #HildonTimeSelector
511 * @hours: the current hour (0-23)
512 * @minutes: the current minute (0-59)
514 * Sets the current active hour on the #HildonTimeSelector widget
516 * The format of the hours accepted is always 24h format, with a range
521 * Returns: %TRUE on success, %FALSE otherwise
524 hildon_time_selector_set_time (HildonTimeSelector * selector,
525 guint hours, guint minutes)
530 g_return_val_if_fail (hours <= 23, FALSE);
531 g_return_val_if_fail (minutes <= 59, FALSE);
533 if (selector->priv->ampm_format) {
534 _set_pm (selector, hours >= 12);
536 hours_item = hours - selector->priv->pm * 12;
541 gtk_tree_model_iter_nth_child (selector->priv->hours_model, &iter, NULL,
543 hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
544 COLUMN_HOURS, &iter, FALSE);
546 g_assert (selector->priv->minutes_step>0);
547 minutes = minutes/selector->priv->minutes_step;
548 gtk_tree_model_iter_nth_child (selector->priv->minutes_model, &iter, NULL,
550 hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
551 COLUMN_MINUTES, &iter, FALSE);
557 * hildon_time_selector_get_time
558 * @selector: the #HildonTimeSelector
559 * @hours: to set the current hour (0-23)
560 * @minutes: to set the current minute (0-59)
562 * Gets the current active hour on the #HildonTimeSelector widget. Both @year
563 * and @minutes can be NULL.
565 * This method returns the date always in 24h format, with a range (0-23):(0-59)
570 hildon_time_selector_get_time (HildonTimeSelector * selector,
571 guint * hours, guint * minutes)
576 hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
577 COLUMN_HOURS, &iter);
578 gtk_tree_model_get (selector->priv->hours_model,
579 &iter, COLUMN_INT, hours, -1);
580 if (selector->priv->ampm_format) {
582 *hours += selector->priv->pm * 12;
586 if (minutes != NULL) {
587 hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
588 COLUMN_MINUTES, &iter);
589 gtk_tree_model_get (selector->priv->minutes_model,
590 &iter, COLUMN_INT, minutes, -1);