* src/hildon-*.c * src/hildon-*.h: Ensure a consistent include order, include <gtk...
[hildon] / src / hildon-calendar-popup.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-calendar-popup
27  * @short_description: CalendarPopup allows choosing a date from a popup calendar.
28  * @see_also: #HildonDateEditor, #HildonTimeEditor
29  *
30  * HildonCalendarPopup is a dialog which contains a HildonCalendar.  It
31  * also contains arrow buttons for changing the month/year. If an
32  * entered date is invalid, an information message will be shown.
33  *
34  * <example>
35  * <title>HildonCalendarPopup example</title>
36  * <programlisting>
37  * ...
38  * gint y, m, d;
39  * GtkWidget *parent, *popup;
40  * <!-- -->
41  * // get current date into &amp;y, &amp;m, &amp;d...
42  * <!-- -->
43  * gtk_widget_get_ancestor (GTK_WIDGET (data), GTK_TYPE_WINDOW);
44  * popup = hildon_calendar_popup_new (GTK_WINDOW (parent), y, m, d);
45  * <!-- -->
46  * result = gtk_dialog_run (GTK_DIALOG (popup));
47  * switch (result)
48  * {
49  *      case GTK_RESPONSE_OK:
50  *      case GTK_RESPONSE_ACCEPT:
51  * <!-- -->
52  * hildon_calendar_popup_get_date (HILDON_CALENDAR_POPUP (popup), &amp;y, &amp;m, &amp;d);
53  * <!-- -->
54  * // here set the new date
55  * }
56  * gtk_widget_destroy(popup);
57  * ...
58  * </programlisting>
59  * </example>
60  *
61  */
62
63 #ifdef                                          HAVE_CONFIG_H
64 #include                                        <config.h>
65 #endif
66
67 #include                                        <langinfo.h>
68 #include                                        <time.h>
69 #include                                        <libintl.h>
70
71 #include                                        <gtk/gtk.h>
72 #include                                        <gdk/gdkkeysyms.h>
73
74 #include                                        "hildon-calendar-popup.h"
75 #include                                        "hildon-calendar-popup-private.h"
76 #include                                        "hildon-calendar.h"
77
78 #define                                         _(String)\
79                                                 dgettext("hildon-libs", String)
80
81 static void 
82 init_dmy                                        (guint year, 
83                                                  guint month, 
84                                                  guint day, 
85                                                  guint *d,
86                                                  guint *m, 
87                                                  guint * y);
88
89 static void
90 hildon_calendar_popup_class_init                (HildonCalendarPopupClass *cal_class);
91
92 static void
93 hildon_calendar_popup_init                      (HildonCalendarPopup *cal);
94
95 static void
96 hildon_calendar_selected_date                   (GtkWidget *self, 
97                                                  gpointer cal_popup);
98
99 static gboolean
100 hildon_key_pressed                              (GtkWidget *widget, 
101                                                  GdkEventKey *event,
102                                                  gpointer cal_popup);
103
104 static void
105 hildon_calendar_popup_set_property              (GObject *object,
106                                                  guint property_id,
107                                                  const GValue * value, 
108                                                  GParamSpec * pspec);
109 static void
110 hildon_calendar_popup_get_property              (GObject *object, 
111                                                  guint property_id,
112                                                  GValue *value,
113                                                  GParamSpec *pspec);
114
115 static GtkDialog*                               parent_class;
116
117 enum 
118 {
119     PROP_0,
120     PROP_DAY,
121     PROP_MONTH,
122     PROP_YEAR,
123     PROP_MIN_YEAR,
124     PROP_MAX_YEAR
125 };
126
127 GType G_GNUC_CONST
128 hildon_calendar_popup_get_type                  (void)
129 {
130     static GType popup_type = 0;
131
132     if (!popup_type) {
133         static const GTypeInfo popup_info = {
134             sizeof (HildonCalendarPopupClass),
135             NULL,       /* base_init */
136             NULL,       /* base_finalize */
137             (GClassInitFunc) hildon_calendar_popup_class_init,
138             NULL,       /* class_finalize */
139             NULL,       /* class_data */
140             sizeof (HildonCalendarPopup),
141             0,  /* n_preallocs */
142             (GInstanceInitFunc) hildon_calendar_popup_init,
143         };
144         popup_type = g_type_register_static (GTK_TYPE_DIALOG,
145                 "HildonCalendarPopup",
146                 &popup_info, 0);
147     }
148
149     return popup_type;
150 }
151
152 /**
153  * hildon_calendar_popup_new:
154  * @parent: parent window for dialog
155  * @year: initial year
156  * @month: initial month
157  * @day: initial day
158  *
159  * This function returns a new HildonCalendarPopup. The initially
160  * selected date is specified by the parameters (year, month, day).
161  * If the specified date is invalid, the current date is used. 
162  *
163  * Returns: new @HildonCalendarPopup widget
164  */
165 GtkWidget*
166 hildon_calendar_popup_new                       (GtkWindow *parent, 
167                                                  guint year,
168                                                  guint month,
169                                                  guint day)
170 {
171     HildonCalendarPopup *cal = NULL;
172
173     /* Create new HildonCalendarPopup */
174     cal = HILDON_CALENDAR_POPUP (g_object_new (HILDON_TYPE_CALENDAR_POPUP,
175                 "year", year, "month", month, "day", day,
176                 NULL));
177
178     if (parent) {
179         gtk_window_set_transient_for (GTK_WINDOW(cal), parent);
180     }
181
182     return GTK_WIDGET (cal);
183 }
184
185 /**
186  * hildon_calendar_popup_set_date:
187  * @cal: the @HildonCalendarPopup widget
188  * @year: year
189  * @month: month
190  * @day: day
191  *
192  * Activates a new date on the calendar popup.
193  **/
194 void
195 hildon_calendar_popup_set_date                  (HildonCalendarPopup *cal,
196                                                  guint year, 
197                                                  guint month, 
198                                                  guint day)
199 {
200     guint dtmp, mtmp, ytmp = 0;
201     HildonCalendarPopupPrivate *priv;
202
203     g_return_if_fail (HILDON_IS_CALENDAR_POPUP (cal));
204
205     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE (cal);
206     g_assert (priv);
207
208     /* Choose current date if the date is invalid:  */
209     init_dmy (year, month, day, &dtmp, &mtmp, &ytmp);
210
211     /* Remove all visual markers */
212     hildon_calendar_clear_marks (HILDON_CALENDAR (priv->cal));
213
214     /* Set a new date */
215     hildon_calendar_select_month (HILDON_CALENDAR (priv->cal), mtmp - 1, ytmp);
216     hildon_calendar_select_day (HILDON_CALENDAR (priv->cal), dtmp);
217 }
218
219 /**
220  * hildon_calendar_popup_get_date:
221  * @cal: the @HildonCalendarPopup widget
222  * @year: year
223  * @month: month
224  * @day: day
225  *
226  * Gets the currently selected year, month, and day. 
227  * It's possible to pass NULL to any of the pointers if you don't need that data.
228  */
229 void
230 hildon_calendar_popup_get_date                  (HildonCalendarPopup *cal,
231                                                  guint *year, 
232                                                  guint *month, 
233                                                  guint *day)
234 {
235     HildonCalendarPopupPrivate *priv;
236
237     g_return_if_fail (HILDON_IS_CALENDAR_POPUP (cal));
238
239     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE (cal);
240     g_assert (priv);
241
242     hildon_calendar_get_date (HILDON_CALENDAR (priv->cal), year, month, day);
243     if (month != NULL)
244         *month = *month + 1;
245
246     if (day != NULL && 
247         month != NULL &&
248         year != NULL &&
249         ! g_date_valid_dmy (*day, *month, *year)) 
250         *day = g_date_get_days_in_month (*month, *year);
251 }
252
253 static void
254 hildon_calendar_popup_class_init                (HildonCalendarPopupClass *cal_class)
255 {
256     GObjectClass *object_class = G_OBJECT_CLASS (cal_class);
257     parent_class = g_type_class_peek_parent (cal_class);
258
259     object_class->set_property = hildon_calendar_popup_set_property;
260     object_class->get_property = hildon_calendar_popup_get_property;
261
262     g_type_class_add_private(cal_class, sizeof (HildonCalendarPopupPrivate));
263
264     /* Install new properties for the GObject_class */
265
266     g_object_class_install_property (object_class, PROP_MIN_YEAR,
267             g_param_spec_uint ("min-year",
268                 "Minimum valid year",
269                 "Minimum valid year",
270                 1, 10000,
271                 1970,
272                 G_PARAM_WRITABLE));
273
274     g_object_class_install_property (object_class, PROP_MAX_YEAR,
275             g_param_spec_uint ("max-year",
276                 "Maximum valid year",
277                 "Maximum valid year",
278                 1, 10000,
279                 2037,
280                 G_PARAM_WRITABLE));
281
282     g_object_class_install_property (object_class, PROP_DAY,
283             g_param_spec_int ("day",
284                 "Day",
285                 "currently selected day",
286                 G_MININT,
287                 G_MAXINT,
288                 0,
289                 G_PARAM_READWRITE));
290
291     g_object_class_install_property (object_class, PROP_MONTH,
292             g_param_spec_int ("month",
293                 "Month",
294                 "currently selected month",
295                 G_MININT,
296                 G_MAXINT,
297                 0,
298                 G_PARAM_READWRITE));
299
300     g_object_class_install_property (object_class, PROP_YEAR,
301             g_param_spec_int ("year",
302                 "Year",
303                 "the currently selected year",
304                 G_MININT,
305                 G_MAXINT,
306                 0,
307                 G_PARAM_READWRITE));
308
309 }
310
311 static void
312 hildon_calendar_popup_init                      (HildonCalendarPopup *cal)
313 {
314     HildonCalendarPopupPrivate *priv;
315     static int set_domain = 1;
316
317     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
318     g_assert (priv);
319
320     /* set the domain directory for different language */
321     /* FIXME I can't exactly figure out why is this here... */
322     if (set_domain) {
323         (void) bindtextdomain ("hildon-libs", LOCALEDIR);
324         set_domain = 0;
325     }
326
327     priv->cal = hildon_calendar_new ();
328
329     /* dialog options and packing */
330     hildon_calendar_set_display_options (HILDON_CALENDAR (priv->cal),
331             HILDON_CALENDAR_SHOW_HEADING |
332             HILDON_CALENDAR_SHOW_DAY_NAMES |
333             HILDON_CALENDAR_SHOW_WEEK_NUMBERS);
334
335     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (cal)->vbox), priv->cal,
336             TRUE, TRUE, 0);
337     gtk_dialog_set_has_separator (GTK_DIALOG (cal), FALSE);
338     gtk_dialog_add_button (GTK_DIALOG (cal), _("ecdg_bd_font_dialog_ok"), GTK_RESPONSE_OK);
339     gtk_dialog_add_button (GTK_DIALOG (cal), _("ecdg_bd_wizard_cancel"), GTK_RESPONSE_CANCEL);
340     gtk_widget_show(priv->cal);
341
342     /* Connect signals */
343     g_signal_connect (G_OBJECT (priv->cal), "key-press-event",
344             G_CALLBACK (hildon_key_pressed), cal);
345
346     g_signal_connect (G_OBJECT (priv->cal), "selected_date",
347             G_CALLBACK (hildon_calendar_selected_date), cal);
348
349     /* set decorations, needs realizing first */
350     /* FIXME That should be moved to on_realize */
351     gtk_widget_realize (GTK_WIDGET (cal));
352     gdk_window_set_decorations (GTK_WIDGET (cal)->window, GDK_DECOR_BORDER);
353 }
354
355 /*
356  * Signal handler for key-press-event. Closes the dialog for some
357  * special keys.
358  */
359 static gboolean
360 hildon_key_pressed                              (GtkWidget *widget, 
361                                                  GdkEventKey *event, 
362                                                  gpointer cal_popup)
363 {
364     g_assert (HILDON_IS_CALENDAR_POPUP (cal_popup));
365
366     /* Handle Return key press as OK response */
367     if (event->keyval == GDK_Return)
368     {
369         gtk_dialog_response (GTK_DIALOG (cal_popup), GTK_RESPONSE_OK);
370         return TRUE;
371     }
372
373     /* Handle Esc key press as CANCEL response */
374     if ((event->keyval == GDK_Escape))
375     {
376         gtk_dialog_response (GTK_DIALOG (cal_popup), GTK_RESPONSE_CANCEL);
377         return TRUE;
378     }
379
380     return FALSE;
381 }
382
383 /*
384  * Validates the given date or initializes it with the current date
385  */
386 static void
387 init_dmy                                        (guint year, 
388                                                  guint month, 
389                                                  guint day, 
390                                                  guint *d, 
391                                                  guint *m, 
392                                                  guint *y)
393 {
394     g_assert (d != NULL);
395     g_assert (m != NULL);
396     g_assert (y != NULL);
397
398     GDate date;
399
400     /* Initialize the date with a valid selected date */ 
401     if (g_date_valid_dmy (day, month, year)) {
402         *d = day;
403         *m = month;
404         *y = year;
405     } else { 
406
407         /* If selected date is invalid initialize the date with current date */ 
408         g_date_clear (&date, 1);
409         g_date_set_time (&date, time (NULL));
410
411         *d = g_date_get_day (&date);
412         *m = g_date_get_month (&date);
413         *y = g_date_get_year (&date);
414     }
415 }
416
417 /*
418  * Exits the dialog when "selected_date" signal is emmited. */
419 static void
420 hildon_calendar_selected_date                   (GtkWidget *self, 
421                                                  gpointer cal_popup)
422 {
423     g_assert (GTK_IS_WIDGET (self));
424     g_assert (HILDON_IS_CALENDAR_POPUP (cal_popup));
425
426     gtk_dialog_response (GTK_DIALOG (cal_popup), GTK_RESPONSE_OK);
427 }
428
429
430 static void 
431 hildon_calendar_popup_set_property              (GObject *object, 
432                                                  guint property_id,
433                                                  const GValue *value, 
434                                                  GParamSpec *pspec)
435 {
436     HildonCalendarPopup *popup = HILDON_CALENDAR_POPUP (object);
437
438     HildonCalendarPopupPrivate *priv = 
439         HILDON_CALENDAR_POPUP_GET_PRIVATE(HILDON_CALENDAR_POPUP (object));
440     g_assert (priv);
441
442     switch (property_id) {
443
444         case PROP_DAY: 
445         {
446             guint year, month, day = 0;
447             hildon_calendar_popup_get_date (popup, &year, &month, &day);
448
449             /*Verifies that the date is valid: */
450             hildon_calendar_popup_set_date (popup, year, month, g_value_get_int (value));
451             break;
452         }
453
454         case PROP_MONTH:
455         {
456             guint year, month, day = 0;
457             hildon_calendar_popup_get_date (popup, &year, &month, &day);
458
459             /*Verifies that the date is valid: */
460             hildon_calendar_popup_set_date (popup, year, g_value_get_int (value), day);
461             break;
462         }
463
464         case PROP_YEAR:
465         {
466             guint year, month, day = 0;
467             hildon_calendar_popup_get_date (popup, &year, &month, &day);
468
469             /*Verifies that the date is valid: */
470             hildon_calendar_popup_set_date (popup, g_value_get_int (value), month, day);
471             break;
472         }
473
474         case PROP_MIN_YEAR:
475             g_object_set_property (G_OBJECT (priv->cal), "min-year", value);
476             break;
477
478         case PROP_MAX_YEAR:
479             g_object_set_property (G_OBJECT (priv->cal), "max-year", value);
480             break;
481
482         default:
483             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
484             break;
485     }
486 }
487
488 static void 
489 hildon_calendar_popup_get_property              (GObject *object, 
490                                                 guint property_id,
491                                                 GValue *value,
492                                                 GParamSpec *pspec)
493 {
494     HildonCalendarPopupPrivate *priv = 
495         HILDON_CALENDAR_POPUP_GET_PRIVATE (HILDON_CALENDAR_POPUP (object));
496     g_assert (priv);
497
498     switch (property_id) {
499
500         case PROP_DAY:
501             g_object_get_property (G_OBJECT (priv->cal), pspec->name, value);
502             break;
503
504         case PROP_MONTH:
505             g_object_get_property (G_OBJECT (priv->cal), pspec->name, value);
506             break;
507
508         case PROP_YEAR:
509             g_object_get_property (G_OBJECT (priv->cal), pspec->name, value);
510             break;
511
512         default:
513             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
514             break;
515     }
516 }
517