latest update
[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
29  * either a mouse click outside of the dialog or pressing the ESC
30  * key.
31  * </para><para>
32  * 
33  * @seealso: #HildonDateEditor, #HildonTimeEditor
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <gtk/gtk.h>
41 #include <gtk/gtkcalendar.h>
42 #include <gdk/gdk.h>
43 #include <gdk/gdkkeysyms.h>
44 #include <langinfo.h>
45 #include <time.h>
46 #include <libintl.h>
47 #include <hildon-widgets/hildon-calendar-popup.h>
48 #include <hildon-widgets/gtk-infoprint.h>
49
50 #define _(String) dgettext(PACKAGE, String)
51
52 #define HILDON_CALENDAR_POPUP_GET_PRIVATE(obj) \
53         (G_TYPE_INSTANCE_GET_PRIVATE\
54         ((obj), HILDON_CALENDAR_POPUP_TYPE, HildonCalendarPopupPrivate));
55
56 static GtkDialog *parent_class;
57
58 typedef struct _HildonCalendarPopupPrivate HildonCalendarPopupPrivate;
59
60 static void init_dmy(guint year, guint month, guint day, guint * d,
61                      guint * m, guint * y);
62
63 static void
64 hildon_calendar_popup_class_init(HildonCalendarPopupClass * cal_class);
65
66 static void hildon_calendar_popup_init(HildonCalendarPopup * cal);
67
68 static gboolean hildon_calendar_day_selected(GtkWidget * widget,
69                                              gpointer data);
70
71 static void hildon_calendar_allow_exit(GtkWidget * self, gpointer data);
72
73 static gboolean hildon_calendar_deny_exit(GtkWidget * self);
74
75 static gboolean hildon_key_pressed(GtkWidget * widget, GdkEventKey * event,
76                                    gpointer data);
77
78 struct _HildonCalendarPopupPrivate {
79     GtkWidget *cal;
80     gboolean can_exit;
81 };
82
83 GType hildon_calendar_popup_get_type(void)
84 {
85     static GType popup_type = 0;
86
87     if (!popup_type) {
88         static const GTypeInfo popup_info = {
89             sizeof(HildonCalendarPopupClass),
90             NULL,       /* base_init */
91             NULL,       /* base_finalize */
92             (GClassInitFunc) hildon_calendar_popup_class_init,
93             NULL,       /* class_finalize */
94             NULL,       /* class_data */
95             sizeof(HildonCalendarPopup),
96             0,  /* n_preallocs */
97             (GInstanceInitFunc) hildon_calendar_popup_init,
98         };
99         popup_type = g_type_register_static(GTK_TYPE_DIALOG,
100                                             "HildonCalendarPopup",
101                                             &popup_info, 0);
102     }
103
104     return popup_type;
105 }
106
107 /**
108  * hildon_calendar_popup_new:
109  * @parent: parent window for dialog
110  * @year: initial year
111  * @month: initial month
112  * @day: initial day
113  *
114  * This function returns a new HildonCalendarPopup. The initially
115  * selected date is specified by the parameters (year, month, day).
116  * If the specified date is invalid, the current date is used. 
117  *
118  * Return value: Pointer to a new @HildonCalendarPopup widget.
119  **/
120 GtkWidget *hildon_calendar_popup_new(GtkWindow * parent, guint year,
121                                      guint month, guint day)
122 {
123     HildonCalendarPopup *cal = NULL;
124     HildonCalendarPopupPrivate *priv;
125     guint dtmp, mtmp, ytmp;
126
127     init_dmy(year, month, day, &dtmp, &mtmp, &ytmp);
128
129     cal = HILDON_CALENDAR_POPUP(g_object_new(HILDON_CALENDAR_POPUP_TYPE,
130                                              NULL));
131     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
132
133     if (parent) {
134         gtk_window_set_transient_for(GTK_WINDOW(cal), parent);
135     }
136
137     /* Select day, month, year */
138     gtk_calendar_select_month(GTK_CALENDAR(priv->cal), mtmp - 1, ytmp);
139     gtk_calendar_select_day(GTK_CALENDAR(priv->cal), dtmp);
140
141     return GTK_WIDGET(cal);
142 }
143
144 /**
145  * hildon_calendar_popup_set_date:
146  * @cal: the @HildonCalendarPopup widget
147  * @year: year
148  * @month: month
149  * @day: day
150  *
151  * This function activates a new date on the calendar popup.
152  **/
153
154
155 void
156 hildon_calendar_popup_set_date(HildonCalendarPopup * cal,
157                                guint year, guint month, guint day)
158 {
159     HildonCalendarPopupPrivate *priv;
160
161     g_return_if_fail(HILDON_IS_CALENDAR_POPUP(cal));
162
163     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
164     gtk_calendar_clear_marks(GTK_CALENDAR(priv->cal));
165
166     gtk_calendar_select_month(GTK_CALENDAR(priv->cal), month - 1, year);
167     gtk_calendar_select_day(GTK_CALENDAR(priv->cal), day);
168 }
169
170 /**
171  * hildon_calendar_popup_get_date:
172  * @cal: the @HildonCalendarPopup widget
173  * @year: year
174  * @month: month
175  * @day: day
176  *
177  * This function is used to get the currently selected year, month,
178  * and day. 
179  **/
180
181 void
182 hildon_calendar_popup_get_date(HildonCalendarPopup * cal,
183                                guint * year, guint * month, guint * day)
184 {
185     HildonCalendarPopupPrivate *priv;
186
187     g_return_if_fail(HILDON_IS_CALENDAR_POPUP(cal));
188
189     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
190     gtk_calendar_get_date(GTK_CALENDAR(priv->cal), year, month, day);
191     *month = *month + 1;
192
193     if (!g_date_valid_dmy(*day, *month, *year)) {
194         *day = g_date_get_days_in_month(*month, *year);
195     }
196 }
197
198 static void
199 hildon_calendar_popup_class_init(HildonCalendarPopupClass * cal_class)
200 {
201     parent_class = g_type_class_peek_parent(cal_class);
202     g_type_class_add_private(cal_class,
203                              sizeof(HildonCalendarPopupPrivate));
204 }
205
206 static void hildon_calendar_popup_init(HildonCalendarPopup * cal)
207 {
208     HildonCalendarPopupPrivate *priv;
209     static int set_domain = 1;
210     gchar *week_start;
211
212     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
213
214     if (set_domain) {
215         (void) bindtextdomain(PACKAGE, LOCALEDIR);
216         set_domain = 0;
217     }
218
219     priv->can_exit = FALSE;
220     priv->cal = gtk_calendar_new();
221
222     /* first day of the week is obtained from the PO file */
223     week_start = _("week_start");
224     if (week_start[0] >= '0' && week_start[0] <= '6' && week_start[1] == 0)
225       g_object_set(G_OBJECT(priv->cal),
226                    "week-start", week_start[0] - '0', NULL);
227
228     gtk_calendar_set_display_options(GTK_CALENDAR(priv->cal),
229                                      GTK_CALENDAR_SHOW_HEADING |
230                                      GTK_CALENDAR_SHOW_DAY_NAMES |
231                                      GTK_CALENDAR_SHOW_WEEK_NUMBERS);
232
233     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cal)->vbox), priv->cal,
234                        TRUE, TRUE, 0);
235     gtk_dialog_set_has_separator(GTK_DIALOG(cal), FALSE);
236     gtk_dialog_add_button(GTK_DIALOG(cal), _("Ecdg_bd_calendar_popout_done"),
237                             GTK_RESPONSE_OK);
238     gtk_widget_show(priv->cal);
239
240     /* Connect signals */
241     g_signal_connect(G_OBJECT(priv->cal), "day-selected",
242                      G_CALLBACK(hildon_calendar_day_selected), cal);
243
244     g_signal_connect(G_OBJECT(priv->cal), "key-press-event",
245                      G_CALLBACK(hildon_key_pressed), cal);
246     g_signal_connect_swapped(G_OBJECT(priv->cal), "button-release-event",
247                              G_CALLBACK(hildon_calendar_deny_exit), cal);
248     g_signal_connect_swapped(G_OBJECT(priv->cal), "month-changed",
249                              G_CALLBACK(hildon_calendar_deny_exit), cal);
250     g_signal_connect_swapped(G_OBJECT(priv->cal), "button-press-event",
251                              G_CALLBACK(hildon_calendar_deny_exit), cal);
252
253     g_signal_connect(G_OBJECT(priv->cal), "selected_date",
254                      G_CALLBACK(hildon_calendar_allow_exit), cal);
255
256     gtk_widget_realize(GTK_WIDGET(cal));
257     gdk_window_set_decorations(GTK_WIDGET(cal)->window, GDK_DECOR_BORDER);
258     gtk_widget_grab_focus(priv->cal);
259 }
260
261 static gboolean
262 hildon_calendar_day_selected(GtkWidget * widget, gpointer data)
263 {
264     HildonCalendarPopup *cal;
265     HildonCalendarPopupPrivate *priv;
266
267     cal = HILDON_CALENDAR_POPUP(data);
268     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
269
270     if (priv->can_exit) {
271         gtk_dialog_response(GTK_DIALOG(data), GTK_RESPONSE_ACCEPT);
272         return TRUE;
273     }
274     return FALSE;
275 }
276
277 static gboolean
278 hildon_key_pressed(GtkWidget * widget, GdkEventKey * event, gpointer data)
279 {
280     HildonCalendarPopup *cal;
281     HildonCalendarPopupPrivate *priv;
282
283     g_return_val_if_fail(data, FALSE);
284
285     cal = HILDON_CALENDAR_POPUP(data);
286     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
287
288     if (event->keyval == GDK_Return) {
289         priv->can_exit = TRUE;
290         gtk_dialog_response(GTK_DIALOG(cal), GTK_RESPONSE_OK);
291         return TRUE;
292     }
293
294     if ((event->keyval == GDK_Escape) || (event->keyval == GDK_F1) ||
295         (event->keyval == GDK_F2) || (event->keyval == GDK_F3) ||
296         (event->keyval == GDK_F4) || (event->keyval == GDK_F5) ||
297         (event->keyval == GDK_F6) || (event->keyval == GDK_F7) ||
298         (event->keyval == GDK_F8)) {
299         gtk_dialog_response(GTK_DIALOG(cal), GTK_RESPONSE_CANCEL);
300         return TRUE;
301     }
302
303     return FALSE;
304 }
305
306 static void
307 init_dmy(guint year, guint month, guint day, guint * d, guint * m,
308          guint * y)
309 {
310     GDate date;
311
312     if (year > 2100) {
313         *d = 31;
314         *m = 12;
315         *y = 2100;
316     } else if (year < 1980) {
317         *d = 1;
318         *m = 1;
319         *y = 1980;
320     } else if (!g_date_valid_dmy(day, month, year)) {
321         g_date_clear(&date, 1);
322         g_date_set_time(&date, time(NULL));
323
324         *d = g_date_get_day(&date);
325         *m = g_date_get_month(&date);
326         *y = g_date_get_year(&date);
327     } else {
328         *d = day;
329         *m = month;
330         *y = year;
331     }
332 }
333
334 static void
335 hildon_calendar_allow_exit(GtkWidget * self, gpointer data)
336 {
337     HildonCalendarPopup *cal;
338     HildonCalendarPopupPrivate *priv;
339
340     g_return_if_fail (GTK_IS_WIDGET (self));
341     g_return_if_fail (HILDON_IS_CALENDAR_POPUP (data)); 
342     
343     cal = HILDON_CALENDAR_POPUP(data);
344     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
345   
346     gtk_dialog_response(GTK_DIALOG(cal), GTK_RESPONSE_OK);
347 }
348
349 static gboolean hildon_calendar_deny_exit(GtkWidget * self)
350 {
351     HildonCalendarPopup *cal;
352     HildonCalendarPopupPrivate *priv;
353
354     cal = HILDON_CALENDAR_POPUP(self);
355     priv = HILDON_CALENDAR_POPUP_GET_PRIVATE(cal);
356
357     priv->can_exit = FALSE;
358     return FALSE;
359 }