Make sure that all timeouts in HildonBanner are removed
[hildon] / hildon / hildon-weekday-picker.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-weekday-picker
27  * @short_description: A widget for picking days on which a certain event 
28  * should take place.
29  * @see_also: #HildonWeekdayPicker 
30  *
31  * #HildonWeekdayPicker supports non-mutually exclusive selection of days of 
32  * the week. Selected days of the week are shown with a pushed-in effect.
33  * 
34  * #HildonWeekdayPicker is used where users are required to pick days on which 
35  * a certain event should take place, for example, which days a Calendar event 
36  * should be repeated on. It is used in Calendar in the Repeat dialog, in Tasks 
37  * in the Repeat dialog and in the Email set-up wizard.
38  *
39  * <note>
40  *   <para>
41  * #HildonWeekdayPicker has been deprecated since Hildon 2.2 and should not
42  * be used in newly written code. See
43  * <link linkend="hildon-migrating-date-widgets">Migrating Date Widgets</link>
44  * section to know how to migrate this deprecated widget.
45  *   </para>
46  * </note>
47  *
48  * <example>
49  * <title>HildonWeekdayPicker example</title>
50  * <programlisting>
51  * gint i;
52  * HildonWeekdayPicker *picker = hildon_weekday_picker_new ();
53  * <!-- -->
54  * hildon_weekday_picker_set_day (picker, i);
55  * hildon_weekday_picker_unset_day (picker, i);
56  * hildon_weekday_picker_toggle_day (picker, i);
57  * hildon_weekday_picker_set_all (picker);
58  * <!-- -->
59  * hildon_weekday_picker_unset_all( picker );
60  * </programlisting>
61  * </example>
62  *
63  */  
64  
65  /* GDate numbers days from 1 to 7 and G_DATE_MONDAY is 1st day. However
66     according to locale settings first day is sunday. To get around this
67     problem, we addjust GDate days numbering to be same as locale
68     numbering */
69
70 #undef                                          HILDON_DISABLE_DEPRECATED
71
72 #ifdef                                          HAVE_CONFIG_H
73 #include                                        <config.h>
74 #endif
75
76 #include                                        <stdio.h>
77 #include                                        <stdarg.h>
78 #include                                        <sys/types.h>
79 #include                                        <unistd.h>
80 #include                                        <libintl.h>
81 #include                                        <langinfo.h>
82 #include                                        <time.h>
83 #include                                        <gdk/gdkkeysyms.h>
84
85 #include                                        "hildon-weekday-picker.h"
86 #include                                        "hildon-private.h"
87 #include                                        "hildon-weekday-picker-private.h"
88
89 static GtkContainerClass*                       parent_class;
90
91 static void
92 hildon_weekday_picker_class_init                (HildonWeekdayPickerClass *picker_class);
93
94 static void 
95 hildon_weekday_picker_init                      (HildonWeekdayPicker *picker);
96
97 static void
98 hildon_weekday_picker_size_allocate             (GtkWidget *widget,
99                                                  GtkAllocation *allocation);
100 static gboolean
101 hildon_weekday_picker_focus                     (GtkWidget *widget,
102                                                  GtkDirectionType direction);
103 static void
104 hildon_weekday_picker_size_request              (GtkWidget *widget,
105                                                  GtkRequisition *requisition);
106 static void
107 hildon_weekday_picker_forall                    (GtkContainer *container,
108                                                  gboolean include_internals,
109                                                  GtkCallback callback, 
110                                                  gpointer callback_data);
111
112 static void
113 hildon_weekday_picker_destroy                   (GtkObject *self);
114
115 static void
116 button_toggle                                   (GtkToggleButton *togglebutton, 
117                                                  gpointer wpicker);
118
119 enum 
120 {
121     SELECTION_CHANGED_SIGNAL,
122     LAST_SIGNAL
123 };
124
125 static guint                                    signals [LAST_SIGNAL] = { 0 } ;
126
127 /**
128  * hildon_weekday_picker_get_type:
129  *
130  * Initializes and returns the type of a hildon weekday picker.
131  *
132  * Returns: GType of #HildonWeekdayPicker
133  */
134 GType G_GNUC_CONST
135 hildon_weekday_picker_get_type                  (void)
136 {
137     static GType picker_type = 0;
138
139     if (! picker_type) {
140         static const GTypeInfo picker_info = {
141             sizeof (HildonWeekdayPickerClass),
142             NULL,       /* base_init */
143             NULL,       /* base_finalize */
144             (GClassInitFunc) hildon_weekday_picker_class_init,
145             NULL,       /* class_finalize */
146             NULL,       /* class_data */
147             sizeof (HildonWeekdayPicker),
148             0,  /* n_preallocs */
149             (GInstanceInitFunc) hildon_weekday_picker_init,
150         };
151         picker_type = g_type_register_static (GTK_TYPE_CONTAINER,
152                 "HildonWeekdayPicker",
153                 &picker_info, 0);
154     }
155
156     return picker_type;
157 }
158
159 static void
160 hildon_weekday_picker_class_init                (HildonWeekdayPickerClass *picker_class)
161 {
162     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (picker_class);
163     GtkContainerClass *container_class = GTK_CONTAINER_CLASS (picker_class);
164     GObjectClass *object_class = G_OBJECT_CLASS (picker_class);
165
166     parent_class = g_type_class_peek_parent (picker_class);
167
168     g_type_class_add_private (picker_class,
169             sizeof (HildonWeekdayPickerPrivate));
170
171     /* Override virtual methods */
172     widget_class->size_request                  = hildon_weekday_picker_size_request;
173     widget_class->size_allocate                 = hildon_weekday_picker_size_allocate;
174     widget_class->focus                         = hildon_weekday_picker_focus;
175     container_class->forall                     = hildon_weekday_picker_forall;
176     GTK_OBJECT_CLASS (picker_class)->destroy    = hildon_weekday_picker_destroy;
177
178     /* Create a signal for reporting user actions */
179     signals [SELECTION_CHANGED_SIGNAL] = g_signal_new ("selection_changed",
180             G_OBJECT_CLASS_TYPE
181             (object_class),
182             G_SIGNAL_RUN_LAST |
183             G_SIGNAL_ACTION,
184             G_STRUCT_OFFSET (HildonWeekdayPickerClass, selection_changed), 
185             NULL, NULL,
186             g_cclosure_marshal_VOID__INT,
187             G_TYPE_NONE, 1, G_TYPE_INT);
188 }
189
190 static void
191 hildon_weekday_picker_init                      (HildonWeekdayPicker *picker)
192 {
193     HildonWeekdayPickerPrivate *priv;
194     gint i, day;
195     
196     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
197     g_assert (priv);
198
199     /* weekday indexes to be used with nl_langinfo. These are shifted
200      * by one for glib compability */
201     int wdays[] = {
202         -1,        /* 0 = invalid date */
203         ABDAY_2,   /* 1 = monday    in glib */
204         ABDAY_3,   /* 2 = tuesday   in glib */
205         ABDAY_4,   /* 3 = wednesday in glib */
206         ABDAY_5,   /* 4 = thursday  in glib */
207         ABDAY_6,   /* 5 = friday    in glib */
208         ABDAY_7,   /* 6 = saturday  in glib */
209         ABDAY_1 }; /* 7 = sunday    in glib */
210     GtkSizeGroup *sgroup;
211
212     sgroup = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
213
214     /* Check our first weekday */
215     day = *nl_langinfo (_NL_TIME_FIRST_WEEKDAY); 
216
217
218     /* Shift the days by one. This is done because GDateWeekday 
219      * starts with Monday(1) and langinfo's first day is Sunday */
220     day--;
221
222     if (day < 1)
223         day = 7;
224
225     /* Initialize and pack day buttons */
226     for (i = 1; i <= 7; i++) {
227         priv->buttons [i] = 
228             gtk_toggle_button_new_with_label (nl_langinfo (wdays[day]));
229         priv->day_order_buttons [day] = priv->buttons [i];
230         day++;
231
232         if (day > 7)
233             day = 1;
234
235         g_signal_connect (GTK_WIDGET (priv->buttons [i]),
236                 "toggled", G_CALLBACK (button_toggle), picker);
237
238         gtk_size_group_add_widget (sgroup, priv->buttons [i]);
239
240         gtk_widget_set_parent (priv->buttons [i], GTK_WIDGET (picker));
241         gtk_widget_show (priv->buttons[i]);
242     }
243
244     GTK_WIDGET_SET_FLAGS (picker, GTK_NO_WINDOW);
245
246     g_object_unref (sgroup);
247 }
248
249 /**
250  * hildon_weekday_picker_new:
251  *
252  * Creates a new #HildonWeekdayPicker.
253  *
254  * Returns: pointer to a new #HildonWeekdayPicker widget.
255  */
256 GtkWidget*
257 hildon_weekday_picker_new                       (void)
258 {
259     return g_object_new (HILDON_TYPE_WEEKDAY_PICKER, NULL);
260 }
261
262 static void 
263 hildon_weekday_picker_forall                    (GtkContainer *container,
264                                                  gboolean include_internals, 
265                                                  GtkCallback callback,
266                                                  gpointer callback_data)
267 {
268     HildonWeekdayPicker *picker;
269     HildonWeekdayPickerPrivate *priv;
270     gint i;
271
272     g_assert (container);
273     g_assert (callback);
274
275     picker = HILDON_WEEKDAY_PICKER (container);
276     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
277     g_assert (priv);
278
279     /* We only have internal children */
280     if (! include_internals)
281         return;
282
283     /* Activate callback for each day button */
284     for (i = 1; i <= 7; ++i) {
285         (*callback) (priv->buttons [i], callback_data);
286     }
287 }
288
289 static void 
290 hildon_weekday_picker_destroy                   (GtkObject *self)
291 {
292     HildonWeekdayPickerPrivate *priv;
293     gint i;
294
295     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (self);
296     g_assert (priv);
297
298     /* Destroy internal children... */
299     for (i = 1; i <= 7; ++i) {
300         if (priv->buttons [i])
301         {
302             gtk_widget_unparent (priv->buttons [i]);
303             priv->buttons [i] = NULL;
304         }
305     }
306
307     /* ... and chain to parent. */
308     if (GTK_OBJECT_CLASS (parent_class)->destroy)
309         GTK_OBJECT_CLASS (parent_class)->destroy (self);
310
311 }
312
313 static void 
314 hildon_weekday_picker_size_request              (GtkWidget *widget,
315                                                  GtkRequisition *requisition)
316 {
317     HildonWeekdayPicker *picker;
318     HildonWeekdayPickerPrivate *priv;
319     gint i;
320     GtkRequisition req;
321
322     picker = HILDON_WEEKDAY_PICKER (widget);
323     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
324     g_assert (priv);
325
326     requisition->width = 0;
327     requisition->height = 0;
328
329     /* Request an area that is as wide as all of the buttons
330        together and tall enough to hold heightest button */
331     for (i = 1; i <= 7; ++i) {
332         gtk_widget_size_request (priv->buttons [i], &req);
333         requisition->width += req.width;
334         if (req.height > requisition->height)
335             requisition->height = req.height;
336
337     }
338 }
339
340 static void 
341 hildon_weekday_picker_size_allocate             (GtkWidget *widget,
342                                                  GtkAllocation *allocation)
343 {
344     HildonWeekdayPicker *picker;
345     HildonWeekdayPickerPrivate *priv;
346     gint i;
347     GtkAllocation alloc;
348     GtkRequisition child_requisition;
349     gint header_x;
350     guint sval;
351     GtkTextDirection direction;
352
353     g_assert (widget);
354     g_assert (allocation);
355
356     /* Check orientation */
357     direction = gtk_widget_get_direction (widget);
358
359     picker = HILDON_WEEKDAY_PICKER (widget);
360     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
361     g_assert (priv);
362
363     header_x = allocation->x;
364     widget->allocation = *allocation;
365
366     if (direction == GTK_TEXT_DIR_LTR || direction == GTK_TEXT_DIR_NONE)
367         sval = 1;
368     else
369         sval = 7;
370
371     /* Allocate day buttons side by side honouring the text direction */
372     for (i = 1; i <= 7; ++i) {
373         gtk_widget_get_child_requisition (priv->buttons[sval], &child_requisition);
374
375         alloc.x = header_x;
376         alloc.y = allocation->y;
377         alloc.width = child_requisition.width;
378         alloc.height = child_requisition.height;
379         header_x += alloc.width;
380         gtk_widget_size_allocate (priv->buttons [sval], &alloc);
381         if (direction == GTK_TEXT_DIR_RTL)
382             sval--;
383         else
384             sval++;
385     }
386 }
387
388 static gboolean
389 hildon_weekday_picker_focus                      (GtkWidget *widget,
390                                                   GtkDirectionType direction)
391 {
392   gboolean retval;
393   GtkDirectionType effective_direction;
394
395   g_assert (HILDON_IS_WEEKDAY_PICKER (widget));
396
397   retval = hildon_private_composite_focus (widget, direction, &effective_direction);
398
399   if (retval == TRUE)
400     return GTK_WIDGET_CLASS (parent_class)->focus (widget, effective_direction);
401   else
402     return FALSE;
403 }
404
405 static void
406 button_toggle                                   (GtkToggleButton *button, 
407                                                  gpointer wpicker)
408 {
409     HildonWeekdayPicker *picker;
410     HildonWeekdayPickerPrivate *priv;
411     gint i;
412
413     g_assert(button);
414     g_assert(wpicker);
415
416     picker = HILDON_WEEKDAY_PICKER (wpicker);
417     g_assert (picker);
418     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
419     g_assert (priv);
420
421     for (i = 1; i <= 7; ++i) {
422         if (GTK_WIDGET (button) == priv->day_order_buttons [i]) {
423             g_signal_emit (GTK_WIDGET (picker), 
424                     signals [SELECTION_CHANGED_SIGNAL], 0, i);
425             break;
426         }
427     }
428 }
429
430 /**
431  * hildon_weekday_picker_set_day:
432  * @picker: the #HildonWeekdayPicker widget
433  * @day: day to be set active
434  *
435  * Sets specified weekday active.
436  */
437 void 
438 hildon_weekday_picker_set_day                   (HildonWeekdayPicker *picker,
439                                                  GDateWeekday day)
440 {
441     HildonWeekdayPickerPrivate *priv;
442
443     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
444     g_return_if_fail (g_date_valid_weekday(day));
445
446     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
447
448     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
449             (priv->day_order_buttons[day]), TRUE);
450 }
451
452 /**
453  * hildon_weekday_picker_unset_day:
454  * @picker: the #HildonWeekdayPicker widget
455  * @day: day to be set inactive 
456  *
457  * Unselect specified weekday.
458  */
459 void 
460 hildon_weekday_picker_unset_day                 (HildonWeekdayPicker *picker,
461                                                  GDateWeekday day)
462 {
463     HildonWeekdayPickerPrivate *priv;
464
465     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
466     g_return_if_fail (g_date_valid_weekday (day));
467
468     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
469     g_assert (priv);
470
471     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
472             (priv->day_order_buttons [day]), FALSE);
473 }
474
475 /**
476  * hildon_weekday_picker_toggle_day:
477  * @picker: the #HildonWeekdayPicker widget
478  * @day: day to be toggled
479  *
480  * Toggles current status of the specified weekday.
481  */
482 void 
483 hildon_weekday_picker_toggle_day                (HildonWeekdayPicker *picker,
484                                                  GDateWeekday day)
485 {
486     HildonWeekdayPickerPrivate *priv;
487     
488     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
489     g_return_if_fail (g_date_valid_weekday (day));
490
491     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
492     g_assert (priv);
493
494     gtk_toggle_button_set_active (
495             GTK_TOGGLE_BUTTON (priv->day_order_buttons [day]), 
496             ! gtk_toggle_button_get_active(
497                 GTK_TOGGLE_BUTTON (priv->day_order_buttons[day])));
498 }
499
500 /**
501  * hildon_weekday_picker_set_all:
502  * @picker: the #HildonWeekdayPicker widget
503  *
504  * Sets all weekdays active.
505  */
506 void 
507 hildon_weekday_picker_set_all                   (HildonWeekdayPicker *picker)
508 {
509     HildonWeekdayPickerPrivate *priv;
510     gint i;
511
512     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
513
514     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
515     g_assert (priv);
516
517     for (i = 1; i <= 7; i++)
518         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->buttons [i]), TRUE);
519 }
520
521 /**
522  * hildon_weekday_picker_unset_all:
523  * @picker: the #HildonWeekdayPicker widget
524  *
525  * Sets all weekdays inactive.
526  */
527 void 
528 hildon_weekday_picker_unset_all                 (HildonWeekdayPicker *picker)
529 {
530     HildonWeekdayPickerPrivate *priv;
531     gint i;
532
533     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
534
535     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
536     g_assert (priv);
537
538     for (i = 1; i <= 7; i++)
539         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->buttons [i]), FALSE);
540 }
541
542 /**
543  * hildon_weekday_picker_isset_day:
544  * @picker: the #HildonWeekdayPicker widget
545  * @day: day to be checked.
546  *
547  * Checks if the specified weekday is set active.
548  *
549  * Returns: TRUE if the day is set, FALSE if the day is not set
550  */
551 gboolean 
552 hildon_weekday_picker_isset_day                 (HildonWeekdayPicker *picker,
553                                                  GDateWeekday day)
554 {
555     HildonWeekdayPickerPrivate *priv;
556
557     g_return_val_if_fail (HILDON_IS_WEEKDAY_PICKER (picker), FALSE);
558     g_return_val_if_fail (g_date_valid_weekday (day), FALSE);
559
560     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
561     g_assert (picker);
562
563     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->day_order_buttons[day]));
564 }
565