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