add1dfa62a1d7c2ddf7ba672f921c74a573a4a81
[hildon] / hildon-widgets / hildon-calendar-popup.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Luc Pionchon <luc.pionchon@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; either 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 /* HILDON DOC
26  * @shortdesc: CalendarPopup allows choosing a date from a popup calendar.
27  * @longdesc: The Calendar popup is a dialog that contains a GtkCalendar 
28  * widget. The pop-up is cancelled by pressing the ESC key.
29  * </para><para>
30  * 
31  * @seealso: #HildonDateEditor, #HildonTimeEditor
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include <gtk/gtk.h>
39 #include <gtk/gtkcalendar.h>
40 #include <gdk/gdk.h>
41 #include <gdk/gdkkeysyms.h>
42 #include <langinfo.h>
43 #include <time.h>
44 #include <libintl.h>
45 #include <hildon-widgets/hildon-calendar-popup.h>
46
47 #define _(String) dgettext(PACKAGE, String)
48
49 #define HILDON_CALENDAR_POPUP_GET_PRIVATE(obj) \
50         (G_TYPE_INSTANCE_GET_PRIVATE\
51         ((obj), HILDON_CALENDAR_POPUP_TYPE, HildonCalendarPopupPrivate));
52
53 static GtkDialog *parent_class;
54
55 typedef struct _HildonCalendarPopupPrivate HildonCalendarPopupPrivate;
56
57 static void init_dmy(guint year, guint month, guint day, guint * d,
58                      guint * m, guint * y);
59
60 static void
61 hildon_calendar_popup_class_init(HildonCalendarPopupClass * cal_class);
62
63 static void hildon_calendar_popup_init(HildonCalendarPopup * cal);
64
65 static void hildon_calendar_selected_date(GtkWidget * self, gpointer cal_popup);
66
67 static gboolean hildon_key_pressed(GtkWidget * widget, GdkEventKey * event,
68                                    gpointer cal_popup);
69
70 static void hildon_calendar_popup_set_property(GObject * object, guint property_id,
71                                     const GValue * value, GParamSpec * pspec);
72 static void hildon_calendar_popup_get_property(GObject * object, guint property_id,
73                                     GValue * value, GParamSpec * pspec);
74
75 enum {
76   PROP_0,
77   PROP_DAY,
78   PROP_MONTH,
79   PROP_YEAR,
80   PROP_MIN_YEAR,
81   PROP_MAX_YEAR
82 };
83
84 struct _HildonCalendarPopupPrivate {
85     GtkWidget *cal;
86 };
87
88 GType hildon_calendar_popup_get_type(void)
89 {
90     static GType popup_type = 0;
91
92     if (!popup_type) {
93         static const GTypeInfo popup_info = {
94             sizeof(HildonCalendarPopupClass),
95             NULL,       /* base_init */
96             NULL,       /* base_finalize */
97             (GClassInitFunc) hildon_calendar_popup_class_init,
98             NULL,       /* class_finalize */
99             NULL,       /* class_data */
100             sizeof(HildonCalendarPopup),
101             0,  /* n_preallocs */
102             (GInstanceInitFunc) hildon_calendar_popup_init,
103         };
104         popup_type = g_type_register_static(GTK_TYPE_DIALOG,
105                                             "HildonCalendarPopup",
106                                             &popup_info, 0);
107     }
108
109     return popup_type;
110 }
111
112 /**
113  * hildon_calendar_popup_new:
114  * @parent: parent window for dialog
115  * @year: initial year
116  * @month: initial month
117  * @day: initial day
118  *
119  * This function returns a new HildonCalendarPopup. The initially
120  * selected date is specified by the parameters (year, month, day).
121  * If the specified date is invalid, the current date is used. 
122  *
123  * Return value: Pointer to a new @HildonCalendarPopup widget.
124  **/
125 GtkWidget *hildon_calendar_popup_new(GtkWindow * parent, guint year,
126                                      guint month, guint day)
127 {
128     HildonCalendarPopup *cal = NULL;
129     HildonCalendarPopupPrivate *priv;
130     guint dtmp, mtmp, ytmp;
131
132     init_dmy(year, month, day, &dtmp, &mtmp, &ytmp);
133
134     /* Create new HildonCalendarPopup */
135     cal = HILDON_CALENDAR_POPUP(g_object_new(HILDON_CALENDAR_POPUP_TYPE,
136                                              NULL));
137     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
138
139     if (parent) {
140         gtk_window_set_transient_for(GTK_WINDOW(cal), parent);
141     }
142
143     /* Select day, month, year */
144     gtk_calendar_select_month(GTK_CALENDAR(priv->cal), mtmp - 1, ytmp);
145     gtk_calendar_select_day(GTK_CALENDAR(priv->cal), dtmp);
146
147     return GTK_WIDGET(cal);
148 }
149
150 /**
151  * hildon_calendar_popup_set_date:
152  * @cal: the @HildonCalendarPopup widget
153  * @year: year
154  * @month: month
155  * @day: day
156  *
157  * This function activates a new date on the calendar popup.
158  **/
159 void
160 hildon_calendar_popup_set_date(HildonCalendarPopup * cal,
161                                guint year, guint month, guint day)
162 {
163     HildonCalendarPopupPrivate *priv;
164
165     g_return_if_fail(HILDON_IS_CALENDAR_POPUP(cal));
166
167     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
168
169     /* Remove all visual markers */
170     gtk_calendar_clear_marks(GTK_CALENDAR(priv->cal));
171
172     /* Set a new date */
173     gtk_calendar_select_month(GTK_CALENDAR(priv->cal), month - 1, year);
174     gtk_calendar_select_day(GTK_CALENDAR(priv->cal), day);
175 }
176
177 /**
178  * hildon_calendar_popup_get_date:
179  * @cal: the @HildonCalendarPopup widget
180  * @year: year
181  * @month: month
182  * @day: day
183  *
184  * This function is used to get the currently selected year, month,
185  * and day. 
186  **/
187 void
188 hildon_calendar_popup_get_date(HildonCalendarPopup * cal,
189                                guint * year, guint * month, guint * day)
190 {
191     HildonCalendarPopupPrivate *priv;
192
193     g_return_if_fail(HILDON_IS_CALENDAR_POPUP(cal));
194
195     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
196     gtk_calendar_get_date(GTK_CALENDAR(priv->cal), year, month, day);
197     *month = *month + 1;
198
199     if (!g_date_valid_dmy(*day, *month, *year)) {
200         *day = g_date_get_days_in_month(*month, *year);
201     }
202 }
203
204 static void
205 hildon_calendar_popup_class_init(HildonCalendarPopupClass * cal_class)
206 {
207     GObjectClass *object_class = G_OBJECT_CLASS(cal_class);
208     parent_class = g_type_class_peek_parent(cal_class);
209     
210     object_class->set_property = hildon_calendar_popup_set_property;
211     object_class->get_property = hildon_calendar_popup_get_property;
212
213     g_type_class_add_private(cal_class,
214                              sizeof(HildonCalendarPopupPrivate));
215
216     /* Install new properties for the GObject_class */
217     g_object_class_install_property(object_class, PROP_MIN_YEAR,
218                                     g_param_spec_uint("min-year",
219                                                       "Minimum valid year",
220                                                       "Minimum valid year",
221                                                       1, 2100,
222                                                       1970,
223                                                       G_PARAM_WRITABLE));
224
225     g_object_class_install_property(object_class, PROP_MAX_YEAR,
226                                     g_param_spec_uint("max-year",
227                                                       "Maximum valid year",
228                                                       "Maximum valid year",
229                                                       1, 2100,
230                                                       2037,
231                                                       G_PARAM_WRITABLE));
232
233     g_object_class_install_property(object_class, PROP_DAY,
234                                     g_param_spec_int ("day",
235                                                       "Day",
236                                                       "currently selected day",
237                                                       G_MININT,
238                                                       G_MAXINT,
239                                                       0,
240                                                       G_PARAM_READWRITE));
241
242     g_object_class_install_property(object_class, PROP_MONTH,
243                                     g_param_spec_int ("month",
244                                                       "Month",
245                                                       "currently selected month",
246                                                       G_MININT,
247                                                       G_MAXINT,
248                                                       0,
249                                                       G_PARAM_READWRITE));
250
251     g_object_class_install_property(object_class, PROP_YEAR,
252                                     g_param_spec_int ("year",
253                                                       "Year",
254                                                       "the currently selected year",
255                                                       G_MININT,
256                                                       G_MAXINT,
257                                                       0,
258                                                       G_PARAM_READWRITE));
259
260 }
261
262 static void hildon_calendar_popup_init(HildonCalendarPopup * cal)
263 {
264     HildonCalendarPopupPrivate *priv;
265     static int set_domain = 1;
266
267     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
268
269     /* set the domain directory for different language */
270     if (set_domain) {
271         (void) bindtextdomain(PACKAGE, LOCALEDIR);
272         set_domain = 0;
273     }
274
275     priv->cal = gtk_calendar_new();
276
277     /* dialog options and packing */
278     gtk_calendar_set_display_options(GTK_CALENDAR(priv->cal),
279                                      GTK_CALENDAR_SHOW_HEADING |
280                                      GTK_CALENDAR_SHOW_DAY_NAMES |
281                                      GTK_CALENDAR_SHOW_WEEK_NUMBERS);
282
283     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cal)->vbox), priv->cal,
284                        TRUE, TRUE, 0);
285     gtk_dialog_set_has_separator(GTK_DIALOG(cal), FALSE);
286     gtk_dialog_add_button(GTK_DIALOG(cal), _("Ecdg_bd_calendar_popout_done"),
287                             GTK_RESPONSE_OK);
288     gtk_widget_show(priv->cal);
289
290     /* Connect signals */
291     g_signal_connect(G_OBJECT(priv->cal), "key-press-event",
292                      G_CALLBACK(hildon_key_pressed), cal);
293
294     g_signal_connect(G_OBJECT(priv->cal), "selected_date",
295                      G_CALLBACK(hildon_calendar_selected_date), cal);
296
297     /* set decorations, needs realizing first*/
298     gtk_widget_realize(GTK_WIDGET(cal));
299     gdk_window_set_decorations(GTK_WIDGET(cal)->window, GDK_DECOR_BORDER);
300
301 }
302
303
304 /*
305  * Signal handler for key-press-event. Closes the dialog for some
306  * special keys.
307  */
308 static gboolean
309 hildon_key_pressed(GtkWidget * widget, GdkEventKey * event, gpointer cal_popup)
310 {
311     g_assert(HILDON_IS_CALENDAR_POPUP(cal_popup));
312
313     /* Handle Return key press as OK response */
314     if (event->keyval == GDK_Return)
315     {
316         gtk_dialog_response(GTK_DIALOG(cal_popup), GTK_RESPONSE_OK);
317         return TRUE;
318     }
319
320     /* Handle Esc key press as CANCEL response */
321     if ((event->keyval == GDK_Escape))
322     {
323         gtk_dialog_response(GTK_DIALOG(cal_popup), GTK_RESPONSE_CANCEL);
324         return TRUE;
325     }
326
327     return FALSE;
328 }
329
330
331 /*
332  * Validates the given date or initializes it with the current date
333  */
334 static void
335 init_dmy(guint year, guint month, guint day, guint *d, guint *m, guint *y)
336 {
337     GDate date;
338
339     /* Initialize the date with a valid selected date */ 
340     if (g_date_valid_dmy(day, month, year)) {
341         *d = day;
342         *m = month;
343         *y = year;
344     } else { 
345
346       /* If selected date is invalid initialize the date with current date */ 
347         g_date_clear(&date, 1);
348         g_date_set_time(&date, time(NULL));
349
350         *d = g_date_get_day(&date);
351         *m = g_date_get_month(&date);
352         *y = g_date_get_year(&date);
353     }
354 }
355
356 /*
357  * Exits the dialog when "selected_date" signal is emmited. The
358  * "selected_date" signal is a Hildon addition to GtkCalendar and is
359  * emitted on button-release.
360  */
361 static void
362 hildon_calendar_selected_date(GtkWidget * self, gpointer cal_popup)
363 {
364     g_assert(GTK_IS_WIDGET (self));
365     g_assert(HILDON_IS_CALENDAR_POPUP (cal_popup));
366  
367     gtk_dialog_response(GTK_DIALOG(cal_popup), GTK_RESPONSE_OK);
368 }
369
370
371 static void hildon_calendar_popup_set_property(GObject * object, guint property_id,
372                                     const GValue * value, GParamSpec * pspec)
373 {
374     HildonCalendarPopupPrivate *priv = 
375         HILDON_CALENDAR_POPUP_GET_PRIVATE(HILDON_CALENDAR_POPUP (object));
376
377     switch (property_id) {
378     case PROP_DAY:
379         g_object_set_property(G_OBJECT(priv->cal), pspec->name, value);
380         break;
381     case PROP_MONTH:
382         g_object_set_property(G_OBJECT(priv->cal), pspec->name, value);
383         break;
384     case PROP_YEAR:
385         g_object_set_property(G_OBJECT(priv->cal), pspec->name, value);
386         break;
387     case PROP_MIN_YEAR:
388         g_object_set_property(G_OBJECT(priv->cal), "min-year", value);
389         break;
390     case PROP_MAX_YEAR:
391         g_object_set_property(G_OBJECT(priv->cal), "max-year", value);
392         break;
393     default:
394         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
395         break;
396     }
397 }
398
399 static void hildon_calendar_popup_get_property(GObject * object, guint property_id,
400                                     GValue * value, GParamSpec * pspec)
401 {
402     HildonCalendarPopupPrivate *priv = 
403         HILDON_CALENDAR_POPUP_GET_PRIVATE(HILDON_CALENDAR_POPUP (object));
404
405     switch (property_id) {
406     case PROP_DAY:
407         g_object_get_property(G_OBJECT(priv->cal), pspec->name, value);
408         break;
409     case PROP_MONTH:
410         g_object_get_property(G_OBJECT(priv->cal), pspec->name, value);
411         break;
412     case PROP_YEAR:
413         g_object_get_property(G_OBJECT(priv->cal), pspec->name, value);
414         break;
415     default:
416         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
417         break;
418     }
419 }