Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
alarm-dialog.c:293:3 | clang-analyzer | Passed-by-value struct argument contains uninitialized data (e.g., via the field chain: 'duration.is_neg') | ||
alarm-dialog.c:293:3 | clang-analyzer | Passed-by-value struct argument contains uninitialized data (e.g., via the field chain: 'duration.is_neg') |
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Federico Mena-Quintero <federico@ximian.com>
18 * Miguel de Icaza <miguel@ximian.com>
19 * Seth Alves <alves@hungry.com>
20 * JP Rosevear <jpr@ximian.com>
21 * Hans Petter Jansson <hpj@ximian.com>
22 *
23 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
24 *
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <string.h>
32 #include <gtk/gtk.h>
33 #include <glib/gi18n.h>
34 #include <libebook/libebook.h>
35 #include <libedataserverui/libedataserverui.h>
36
37 #include "e-util/e-util.h"
38 #include "e-util/e-dialog-widgets.h"
39 #include "e-util/e-util-private.h"
40 #include <libical/icalattach.h>
41 #include "../calendar-config.h"
42 #include "comp-editor-util.h"
43 #include "alarm-dialog.h"
44
45 typedef struct {
46 GtkBuilder *builder;
47
48 /* The alarm */
49 ECalComponentAlarm *alarm;
50
51 /* The client */
52 ECalClient *cal_client;
53
54 ESourceRegistry *registry;
55
56 /* Toplevel */
57 GtkWidget *toplevel;
58
59 GtkWidget *action_combo;
60 GtkWidget *interval_value;
61 GtkWidget *value_units_combo;
62 GtkWidget *relative_combo;
63 GtkWidget *time_combo;
64
65 /* Alarm repeat widgets */
66 GtkWidget *repeat_toggle;
67 GtkWidget *repeat_group;
68 GtkWidget *repeat_quantity;
69 GtkWidget *repeat_value;
70 GtkWidget *repeat_unit_combo;
71
72 GtkWidget *option_notebook;
73
74 /* Display alarm widgets */
75 GtkWidget *dalarm_group;
76 GtkWidget *dalarm_message;
77 GtkWidget *dalarm_description;
78
79 /* Audio alarm widgets */
80 GtkWidget *aalarm_group;
81 GtkWidget *aalarm_sound;
82 GtkWidget *aalarm_file_chooser;
83
84 /* Mail alarm widgets */
85 const gchar *email;
86 GtkWidget *malarm_group;
87 GtkWidget *malarm_address_group;
88 GtkWidget *malarm_addresses;
89 GtkWidget *malarm_addressbook;
90 GtkWidget *malarm_message;
91 GtkWidget *malarm_description;
92
93 /* Procedure alarm widgets */
94 GtkWidget *palarm_group;
95 GtkWidget *palarm_program;
96 GtkWidget *palarm_args;
97
98 /* Addressbook name selector */
99 ENameSelector *name_selector;
100 } Dialog;
101
102 static const gchar *section_name = "Send To";
103
104 /* "relative" types */
105 enum {
106 BEFORE,
107 AFTER
108 };
109
110 /* Time units */
111 enum {
112 MINUTES,
113 HOURS,
114 DAYS
115 };
116
117 /* Combo box maps */
118 static const gint action_map[] = {
119 E_CAL_COMPONENT_ALARM_DISPLAY,
120 E_CAL_COMPONENT_ALARM_AUDIO,
121 E_CAL_COMPONENT_ALARM_PROCEDURE,
122 E_CAL_COMPONENT_ALARM_EMAIL,
123 -1
124 };
125
126 static const gchar *action_map_cap[] = {
127 CAL_STATIC_CAPABILITY_NO_DISPLAY_ALARMS,
128 CAL_STATIC_CAPABILITY_NO_AUDIO_ALARMS,
129 CAL_STATIC_CAPABILITY_NO_PROCEDURE_ALARMS,
130 CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS
131 };
132
133 static const gint value_map[] = {
134 MINUTES,
135 HOURS,
136 DAYS,
137 -1
138 };
139
140 static const gint relative_map[] = {
141 BEFORE,
142 AFTER,
143 -1
144 };
145
146 static const gint time_map[] = {
147 E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START,
148 E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_END,
149 -1
150 };
151
152 enum duration_units {
153 DUR_MINUTES,
154 DUR_HOURS,
155 DUR_DAYS
156 };
157
158 static const gint duration_units_map[] = {
159 DUR_MINUTES,
160 DUR_HOURS,
161 DUR_DAYS,
162 -1
163 };
164
165 static void populate_widgets_from_alarm (Dialog *dialog);
166 static void action_changed_cb (GtkWidget *action_combo, gpointer data);
167
168 /* Fills the widgets with default values */
169 static void
170 clear_widgets (Dialog *dialog)
171 {
172 /* Sane defaults */
173 e_dialog_combo_box_set (dialog->action_combo, E_CAL_COMPONENT_ALARM_DISPLAY, action_map);
174 gtk_spin_button_set_value (
175 GTK_SPIN_BUTTON (dialog->interval_value), 15);
176 e_dialog_combo_box_set (dialog->value_units_combo, MINUTES, value_map);
177 e_dialog_combo_box_set (dialog->relative_combo, BEFORE, relative_map);
178 e_dialog_combo_box_set (dialog->time_combo, E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START, time_map);
179
180 gtk_widget_set_sensitive (dialog->repeat_group, FALSE);
181 gtk_widget_set_sensitive (dialog->dalarm_group, FALSE);
182 gtk_widget_set_sensitive (dialog->aalarm_group, FALSE);
183 gtk_widget_set_sensitive (dialog->malarm_group, FALSE);
184
185 gtk_notebook_set_current_page (GTK_NOTEBOOK (dialog->option_notebook), 0);
186 }
187
188 /* fill_widgets handler for the alarm page */
189 static void
190 alarm_to_dialog (Dialog *dialog)
191 {
192 GtkTreeModel *model;
193 GtkTreeIter iter;
194 gboolean valid;
195 gboolean repeat;
196 ECalComponentAlarmAction action;
197 gchar *email;
198 gint i;
199
200 /* Clean the page */
201 clear_widgets (dialog);
202
203 /* Alarm types */
204 model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->action_combo));
205 valid = gtk_tree_model_get_iter_first (model, &iter);
206 for (i = 0; valid && action_map[i] != -1; i++) {
207 gtk_list_store_set (
208 GTK_LIST_STORE (model), &iter,
209 1, !e_client_check_capability (E_CLIENT (dialog->cal_client), action_map_cap[i]),
210 -1);
211
212 valid = gtk_tree_model_iter_next (model, &iter);
213 }
214
215 /* Set a default address if possible */
216 if (!e_client_check_capability (E_CLIENT (dialog->cal_client), CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS)
217 && !e_cal_component_alarm_has_attendees (dialog->alarm)
218 && e_client_get_backend_property_sync (E_CLIENT (dialog->cal_client), CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS, &email, NULL, NULL)) {
219 ECalComponentAttendee *a;
220 GSList attendee_list;
221
222 a = g_new0 (ECalComponentAttendee, 1);
223 a->value = email;
224 a->cutype = ICAL_CUTYPE_INDIVIDUAL;
225 a->status = ICAL_PARTSTAT_NEEDSACTION;
226 a->role = ICAL_ROLE_REQPARTICIPANT;
227 attendee_list.data = a;
228 attendee_list.next = NULL;
229 e_cal_component_alarm_set_attendee_list (dialog->alarm, &attendee_list);
230 g_free (email);
231 g_free (a);
232 }
233
234 /* If we can repeat */
235 repeat = !e_client_check_capability (E_CLIENT (dialog->cal_client), CAL_STATIC_CAPABILITY_NO_ALARM_REPEAT);
236 gtk_widget_set_sensitive (dialog->repeat_toggle, repeat);
237
238 /* if we are editing a exiting alarm */
239 e_cal_component_alarm_get_action (dialog->alarm, &action);
240
241 if (action)
242 populate_widgets_from_alarm (dialog);
243 }
244
245 static void
246 alarm_to_repeat_widgets (Dialog *dialog,
247 ECalComponentAlarm *alarm)
248 {
249 ECalComponentAlarmRepeat repeat;
250
251 e_cal_component_alarm_get_repeat (dialog->alarm, &repeat);
252
253 if (repeat.repetitions) {
254 gtk_toggle_button_set_active (
255 GTK_TOGGLE_BUTTON (dialog->repeat_toggle), TRUE);
256 gtk_spin_button_set_value (
257 GTK_SPIN_BUTTON (dialog->repeat_quantity),
258 repeat.repetitions);
259 } else
260 return;
261
262 if (repeat.duration.minutes) {
263 e_dialog_combo_box_set (dialog->repeat_unit_combo, DUR_MINUTES, duration_units_map);
264 gtk_spin_button_set_value (
265 GTK_SPIN_BUTTON (dialog->repeat_value),
266 repeat.duration.minutes);
267 }
268
269 if (repeat.duration.hours) {
270 e_dialog_combo_box_set (dialog->repeat_unit_combo, DUR_HOURS, duration_units_map);
271 gtk_spin_button_set_value (
272 GTK_SPIN_BUTTON (dialog->repeat_value),
273 repeat.duration.hours);
274 }
275
276 if (repeat.duration.days) {
277 e_dialog_combo_box_set (dialog->repeat_unit_combo, DUR_DAYS, duration_units_map);
278 gtk_spin_button_set_value (
279 GTK_SPIN_BUTTON (dialog->repeat_value),
280 repeat.duration.days);
281 }
282 }
283
284 static void
285 repeat_widgets_to_alarm (Dialog *dialog,
286 ECalComponentAlarm *alarm)
287 {
288 ECalComponentAlarmRepeat repeat;
289
290 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->repeat_toggle))) {
291 repeat.repetitions = 0;
292
293 e_cal_component_alarm_set_repeat (alarm, repeat);
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
294 return;
295 }
296
297 repeat.repetitions = gtk_spin_button_get_value_as_int (
298 GTK_SPIN_BUTTON (dialog->repeat_quantity));
299
300 memset (&repeat.duration, 0, sizeof (repeat.duration));
301 switch (e_dialog_combo_box_get (dialog->repeat_unit_combo, duration_units_map)) {
302 case DUR_MINUTES:
303 repeat.duration.minutes = gtk_spin_button_get_value_as_int (
304 GTK_SPIN_BUTTON (dialog->repeat_value));
305 break;
306
307 case DUR_HOURS:
308 repeat.duration.hours = gtk_spin_button_get_value_as_int (
309 GTK_SPIN_BUTTON (dialog->repeat_value));
310 break;
311
312 case DUR_DAYS:
313 repeat.duration.days = gtk_spin_button_get_value_as_int (
314 GTK_SPIN_BUTTON (dialog->repeat_value));
315 break;
316
317 default:
318 g_return_if_reached ();
319 }
320
321 e_cal_component_alarm_set_repeat (alarm, repeat);
322
323 }
324
325 /* Fills the audio alarm data with the values from the widgets */
326 static void
327 aalarm_widgets_to_alarm (Dialog *dialog,
328 ECalComponentAlarm *alarm)
329 {
330 gchar *url;
331 icalattach *attach;
332
333 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->aalarm_sound)))
334 return;
335
336 url = gtk_file_chooser_get_uri (
337 GTK_FILE_CHOOSER (dialog->aalarm_file_chooser));
338 attach = icalattach_new_from_url (url ? url : "");
339 g_free (url);
340
341 e_cal_component_alarm_set_attach (alarm, attach);
342 icalattach_unref (attach);
343 }
344
345 /* Fills the widgets with audio alarm data */
346 static void
347 alarm_to_aalarm_widgets (Dialog *dialog,
348 ECalComponentAlarm *alarm)
349 {
350 const gchar *url;
351 icalattach *attach;
352
353 e_cal_component_alarm_get_attach (alarm, (&attach));
354 url = icalattach_get_url (attach);
355 icalattach_unref (attach);
356
357 if (!(url && *url))
358 return;
359
360 gtk_toggle_button_set_active (
361 GTK_TOGGLE_BUTTON (dialog->aalarm_sound), TRUE);
362 gtk_file_chooser_set_uri (
363 GTK_FILE_CHOOSER (dialog->aalarm_file_chooser), url);
364 }
365
366 /* Fills the widgets with display alarm data */
367 static void
368 alarm_to_dalarm_widgets (Dialog *dialog,
369 ECalComponentAlarm *alarm)
370 {
371 ECalComponentText description;
372 GtkTextBuffer *text_buffer;
373
374 e_cal_component_alarm_get_description (alarm, &description);
375
376 if (description.value) {
377 gtk_toggle_button_set_active (
378 GTK_TOGGLE_BUTTON (dialog->dalarm_message), TRUE);
379 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->dalarm_description));
380 gtk_text_buffer_set_text (text_buffer, description.value, -1);
381 }
382 }
383
384 /* Fills the display alarm data with the values from the widgets */
385 static void
386 dalarm_widgets_to_alarm (Dialog *dialog,
387 ECalComponentAlarm *alarm)
388 {
389 gchar *str;
390 ECalComponentText description;
391 GtkTextBuffer *text_buffer;
392 GtkTextIter text_iter_start, text_iter_end;
393 icalcomponent *icalcomp;
394 icalproperty *icalprop;
395
396 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->dalarm_message)))
397 return;
398
399 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->dalarm_description));
400 gtk_text_buffer_get_start_iter (text_buffer, &text_iter_start);
401 gtk_text_buffer_get_end_iter (text_buffer, &text_iter_end);
402 str = gtk_text_buffer_get_text (text_buffer, &text_iter_start, &text_iter_end, FALSE);
403
404 description.value = str;
405 description.altrep = NULL;
406
407 e_cal_component_alarm_set_description (alarm, &description);
408 g_free (str);
409
410 /* remove the X-EVOLUTION-NEEDS-DESCRIPTION property, so that
411 * we don't re-set the alarm's description */
412 icalcomp = e_cal_component_alarm_get_icalcomponent (alarm);
413 icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
414 while (icalprop) {
415 const gchar *x_name;
416
417 x_name = icalproperty_get_x_name (icalprop);
418 if (!strcmp (x_name, "X-EVOLUTION-NEEDS-DESCRIPTION")) {
419 icalcomponent_remove_property (icalcomp, icalprop);
420 break;
421 }
422
423 icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
424 }
425 }
426
427 /* Fills the mail alarm data with the values from the widgets */
428 static void
429 malarm_widgets_to_alarm (Dialog *dialog,
430 ECalComponentAlarm *alarm)
431 {
432 gchar *str;
433 ECalComponentText description;
434 GSList *attendee_list = NULL;
435 GtkTextBuffer *text_buffer;
436 GtkTextIter text_iter_start, text_iter_end;
437 ENameSelectorModel *name_selector_model;
438 EDestinationStore *destination_store;
439 GList *destinations;
440 icalcomponent *icalcomp;
441 icalproperty *icalprop;
442 GList *l;
443
444 /* Attendees */
445 name_selector_model = e_name_selector_peek_model (dialog->name_selector);
446 e_name_selector_model_peek_section (name_selector_model, section_name, NULL, &destination_store);
447 destinations = e_destination_store_list_destinations (destination_store);
448
449 for (l = destinations; l; l = g_list_next (l)) {
450 EDestination *dest;
451 ECalComponentAttendee *a;
452
453 dest = l->data;
454
455 a = g_new0 (ECalComponentAttendee, 1);
456 a->value = e_destination_get_email (dest);
457 a->cn = e_destination_get_name (dest);
458 a->cutype = ICAL_CUTYPE_INDIVIDUAL;
459 a->status = ICAL_PARTSTAT_NEEDSACTION;
460 a->role = ICAL_ROLE_REQPARTICIPANT;
461
462 attendee_list = g_slist_append (attendee_list, a);
463 }
464
465 e_cal_component_alarm_set_attendee_list (alarm, attendee_list);
466
467 e_cal_component_free_attendee_list (attendee_list);
468 g_list_free (destinations);
469
470 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->malarm_message)))
471 return;
472
473 /* Description */
474 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->malarm_description));
475 gtk_text_buffer_get_start_iter (text_buffer, &text_iter_start);
476 gtk_text_buffer_get_end_iter (text_buffer, &text_iter_end);
477 str = gtk_text_buffer_get_text (text_buffer, &text_iter_start, &text_iter_end, FALSE);
478
479 description.value = str;
480 description.altrep = NULL;
481
482 e_cal_component_alarm_set_description (alarm, &description);
483 g_free (str);
484
485 /* remove the X-EVOLUTION-NEEDS-DESCRIPTION property, so that
486 * we don't re-set the alarm's description */
487 icalcomp = e_cal_component_alarm_get_icalcomponent (alarm);
488 icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
489 while (icalprop) {
490 const gchar *x_name;
491
492 x_name = icalproperty_get_x_name (icalprop);
493 if (!strcmp (x_name, "X-EVOLUTION-NEEDS-DESCRIPTION")) {
494 icalcomponent_remove_property (icalcomp, icalprop);
495 break;
496 }
497
498 icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
499 }
500 }
501
502 /* Fills the widgets from mail alarm data */
503 static void
504 alarm_to_malarm_widgets (Dialog *dialog,
505 ECalComponentAlarm *alarm)
506 {
507 ENameSelectorModel *name_selector_model;
508 EDestinationStore *destination_store;
509 ECalComponentText description;
510 GtkTextBuffer *text_buffer;
511 GSList *attendee_list, *l;
512 gint len;
513
514 /* Attendees */
515 name_selector_model = e_name_selector_peek_model (dialog->name_selector);
516 e_name_selector_model_peek_section (name_selector_model, section_name, NULL, &destination_store);
517
518 e_cal_component_alarm_get_attendee_list (alarm, &attendee_list);
519 len = g_slist_length (attendee_list);
520 if (len > 0) {
521 for (l = attendee_list; l; l = g_slist_next (l)) {
522 ECalComponentAttendee *a = l->data;
523 EDestination *dest;
524
525 dest = e_destination_new ();
526 if (a->cn != NULL && *a->cn)
527 e_destination_set_name (dest, a->cn);
528 if (a->value != NULL && *a->value) {
529 if (!strncasecmp (a->value, "MAILTO:", 7))
530 e_destination_set_email (dest, a->value + 7);
531 else
532 e_destination_set_email (dest, a->value);
533 }
534 e_destination_store_append_destination (destination_store, dest);
535 g_object_unref (dest);
536 }
537 e_cal_component_free_attendee_list (attendee_list);
538 }
539
540 /* Description */
541 e_cal_component_alarm_get_description (alarm, &description);
542 if (description.value) {
543 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->malarm_message), TRUE);
544 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->malarm_description));
545 gtk_text_buffer_set_text (text_buffer, description.value, -1);
546 }
547 }
548
549 /* Fills the widgets from procedure alarm data */
550 static void
551 alarm_to_palarm_widgets (Dialog *dialog,
552 ECalComponentAlarm *alarm)
553 {
554 ECalComponentText description;
555 GtkEntry *entry;
556 const gchar *url;
557 icalattach *attach;
558
559 e_cal_component_alarm_get_attach (alarm, (&attach));
560 url = icalattach_get_url (attach);
561 icalattach_unref (attach);
562
563 if (!(url && *url))
564 return;
565
566 entry = GTK_ENTRY (dialog->palarm_program);
567 gtk_entry_set_text (entry, url);
568
569 entry = GTK_ENTRY (dialog->palarm_args);
570 e_cal_component_alarm_get_description (alarm, &description);
571 gtk_entry_set_text (entry, description.value);
572 }
573
574 /* Fills the procedure alarm data with the values from the widgets */
575 static void
576 palarm_widgets_to_alarm (Dialog *dialog,
577 ECalComponentAlarm *alarm)
578 {
579 icalattach *attach;
580 ECalComponentText description;
581 icalcomponent *icalcomp;
582 icalproperty *icalprop;
583 const gchar *text;
584
585 text = gtk_entry_get_text (GTK_ENTRY (dialog->palarm_program));
586 attach = icalattach_new_from_url ((text != NULL) ? text : "");
587
588 e_cal_component_alarm_set_attach (alarm, attach);
589 icalattach_unref (attach);
590
591 text = gtk_entry_get_text (GTK_ENTRY (dialog->palarm_args));
592
593 description.value = text;
594 description.altrep = NULL;
595
596 e_cal_component_alarm_set_description (alarm, &description);
597
598 /* remove the X-EVOLUTION-NEEDS-DESCRIPTION property, so that
599 * we don't re-set the alarm's description */
600 icalcomp = e_cal_component_alarm_get_icalcomponent (alarm);
601 icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
602 while (icalprop) {
603 const gchar *x_name;
604
605 x_name = icalproperty_get_x_name (icalprop);
606 if (!strcmp (x_name, "X-EVOLUTION-NEEDS-DESCRIPTION")) {
607 icalcomponent_remove_property (icalcomp, icalprop);
608 break;
609 }
610
611 icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
612 }
613 }
614
615 static void
616 populate_widgets_from_alarm (Dialog *dialog)
617 {
618 ECalComponentAlarmTrigger *trigger;
619 ECalComponentAlarmAction *action;
620
621 action = g_new0 (ECalComponentAlarmAction, 1);
622 e_cal_component_alarm_get_action (dialog->alarm, action);
623 g_return_if_fail (action != NULL);
624
625 trigger = g_new0 (ECalComponentAlarmTrigger, 1);
626 e_cal_component_alarm_get_trigger (dialog->alarm, trigger);
627 g_return_if_fail (trigger != NULL);
628
629 if (*action == E_CAL_COMPONENT_ALARM_NONE)
630 return;
631
632 gtk_window_set_title (GTK_WINDOW (dialog->toplevel),_("Edit Reminder"));
633
634 /* Alarm Types */
635 switch (trigger->type) {
636 case E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START:
637 e_dialog_combo_box_set (dialog->time_combo, E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START, time_map);
638 break;
639
640 case E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_END:
641 e_dialog_combo_box_set (dialog->time_combo, E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_END, time_map);
642 break;
643 default:
644 g_warning ("%s: Unexpected alarm type (%d)", G_STRLOC, trigger->type);
645 }
646
647 switch (trigger->u.rel_duration.is_neg) {
648 case 1:
649 e_dialog_combo_box_set (dialog->relative_combo, BEFORE, relative_map);
650 break;
651
652 case 0:
653 e_dialog_combo_box_set (dialog->relative_combo, AFTER, relative_map);
654 break;
655 }
656
657 if (trigger->u.rel_duration.days) {
658 e_dialog_combo_box_set (dialog->value_units_combo, DAYS, value_map);
659 gtk_spin_button_set_value (
660 GTK_SPIN_BUTTON (dialog->interval_value),
661 trigger->u.rel_duration.days);
662 } else if (trigger->u.rel_duration.hours) {
663 e_dialog_combo_box_set (dialog->value_units_combo, HOURS, value_map);
664 gtk_spin_button_set_value (
665 GTK_SPIN_BUTTON (dialog->interval_value),
666 trigger->u.rel_duration.hours);
667 } else if (trigger->u.rel_duration.minutes) {
668 e_dialog_combo_box_set (dialog->value_units_combo, MINUTES, value_map);
669 gtk_spin_button_set_value (
670 GTK_SPIN_BUTTON (dialog->interval_value),
671 trigger->u.rel_duration.minutes);
672 } else {
673 e_dialog_combo_box_set (dialog->value_units_combo, MINUTES, value_map);
674 gtk_spin_button_set_value (
675 GTK_SPIN_BUTTON (dialog->interval_value), 0);
676 }
677
678 /* Repeat options */
679 alarm_to_repeat_widgets (dialog, dialog->alarm);
680
681 /* Alarm options */
682 e_dialog_combo_box_set (dialog->action_combo, *action, action_map);
683 action_changed_cb (dialog->action_combo, dialog);
684
685 switch (*action) {
686 case E_CAL_COMPONENT_ALARM_AUDIO:
687 alarm_to_aalarm_widgets (dialog, dialog->alarm);
688 break;
689
690 case E_CAL_COMPONENT_ALARM_DISPLAY:
691 alarm_to_dalarm_widgets (dialog, dialog->alarm);
692 break;
693
694 case E_CAL_COMPONENT_ALARM_EMAIL:
695 alarm_to_malarm_widgets (dialog, dialog->alarm);
696 break;
697
698 case E_CAL_COMPONENT_ALARM_PROCEDURE:
699 alarm_to_palarm_widgets (dialog, dialog->alarm);
700 break;
701 default:
702 g_warning ("%s: Unexpected alarm action (%d)", G_STRLOC, *action);
703 }
704 }
705
706 /* fill_component handler for the alarm page */
707 static void
708 dialog_to_alarm (Dialog *dialog)
709 {
710 ECalComponentAlarmTrigger trigger;
711 ECalComponentAlarmAction action;
712
713 /* Fill out the alarm */
714 memset (&trigger, 0, sizeof (ECalComponentAlarmTrigger));
715 trigger.type = e_dialog_combo_box_get (dialog->time_combo, time_map);
716 if (e_dialog_combo_box_get (dialog->relative_combo, relative_map) == BEFORE)
717 trigger.u.rel_duration.is_neg = 1;
718 else
719 trigger.u.rel_duration.is_neg = 0;
720
721 switch (e_dialog_combo_box_get (dialog->value_units_combo, value_map)) {
722 case MINUTES:
723 trigger.u.rel_duration.minutes =
724 gtk_spin_button_get_value_as_int (
725 GTK_SPIN_BUTTON (dialog->interval_value));
726 break;
727
728 case HOURS:
729 trigger.u.rel_duration.hours =
730 gtk_spin_button_get_value_as_int (
731 GTK_SPIN_BUTTON (dialog->interval_value));
732 break;
733
734 case DAYS:
735 trigger.u.rel_duration.days =
736 gtk_spin_button_get_value_as_int (
737 GTK_SPIN_BUTTON (dialog->interval_value));
738 break;
739
740 default:
741 g_return_if_reached ();
742 }
743 e_cal_component_alarm_set_trigger (dialog->alarm, trigger);
744
745 action = e_dialog_combo_box_get (dialog->action_combo, action_map);
746 e_cal_component_alarm_set_action (dialog->alarm, action);
747
748 /* Repeat stuff */
749 repeat_widgets_to_alarm (dialog, dialog->alarm);
750
751 /* Options */
752 switch (action) {
753 case E_CAL_COMPONENT_ALARM_NONE:
754 g_return_if_reached ();
755 break;
756
757 case E_CAL_COMPONENT_ALARM_AUDIO:
758 aalarm_widgets_to_alarm (dialog, dialog->alarm);
759 break;
760
761 case E_CAL_COMPONENT_ALARM_DISPLAY:
762 dalarm_widgets_to_alarm (dialog, dialog->alarm);
763 break;
764
765 case E_CAL_COMPONENT_ALARM_EMAIL:
766 malarm_widgets_to_alarm (dialog, dialog->alarm);
767 break;
768
769 case E_CAL_COMPONENT_ALARM_PROCEDURE:
770 palarm_widgets_to_alarm (dialog, dialog->alarm);
771 break;
772
773 case E_CAL_COMPONENT_ALARM_UNKNOWN:
774 break;
775
776 default:
777 g_return_if_reached ();
778 }
779 }
780
781 /* Gets the widgets from the XML file and returns TRUE if they are all available. */
782 static gboolean
783 get_widgets (Dialog *dialog)
784 {
785 dialog->toplevel = e_builder_get_widget (dialog->builder, "alarm-dialog");
786 if (!dialog->toplevel)
787 return FALSE;
788
789 dialog->action_combo = e_builder_get_widget (dialog->builder, "action-combobox");
790 dialog->interval_value = e_builder_get_widget (dialog->builder, "interval-value");
791 dialog->value_units_combo = e_builder_get_widget (dialog->builder, "value-units-combobox");
792 dialog->relative_combo = e_builder_get_widget (dialog->builder, "relative-combobox");
793 dialog->time_combo = e_builder_get_widget (dialog->builder, "time-combobox");
794
795 dialog->repeat_toggle = e_builder_get_widget (dialog->builder, "repeat-toggle");
796 dialog->repeat_group = e_builder_get_widget (dialog->builder, "repeat-group");
797 dialog->repeat_quantity = e_builder_get_widget (dialog->builder, "repeat-quantity");
798 dialog->repeat_value = e_builder_get_widget (dialog->builder, "repeat-value");
799 dialog->repeat_unit_combo = e_builder_get_widget (dialog->builder, "repeat-unit-combobox");
800
801 dialog->option_notebook = e_builder_get_widget (dialog->builder, "option-notebook");
802
803 dialog->dalarm_group = e_builder_get_widget (dialog->builder, "dalarm-group");
804 dialog->dalarm_message = e_builder_get_widget (dialog->builder, "dalarm-message");
805 dialog->dalarm_description = e_builder_get_widget (dialog->builder, "dalarm-description");
806
807 dialog->aalarm_group = e_builder_get_widget (dialog->builder, "aalarm-group");
808 dialog->aalarm_sound = e_builder_get_widget (dialog->builder, "aalarm-sound");
809 dialog->aalarm_file_chooser = e_builder_get_widget (dialog->builder, "aalarm-file-chooser");
810
811 dialog->malarm_group = e_builder_get_widget (dialog->builder, "malarm-group");
812 dialog->malarm_address_group = e_builder_get_widget (dialog->builder, "malarm-address-group");
813 dialog->malarm_addressbook = e_builder_get_widget (dialog->builder, "malarm-addressbook");
814 dialog->malarm_message = e_builder_get_widget (dialog->builder, "malarm-message");
815 dialog->malarm_description = e_builder_get_widget (dialog->builder, "malarm-description");
816
817 dialog->palarm_group = e_builder_get_widget (dialog->builder, "palarm-group");
818 dialog->palarm_program = e_builder_get_widget (dialog->builder, "palarm-program");
819 dialog->palarm_args = e_builder_get_widget (dialog->builder, "palarm-args");
820
821 if (dialog->action_combo) {
822 const gchar *actions[] = {
823 N_("Pop up an alert"),
824 N_("Play a sound"),
825 N_("Run a program"),
826 N_("Send an email")
827 };
828
829 GtkComboBox *combo = (GtkComboBox *) dialog->action_combo;
830 GtkCellRenderer *cell;
831 GtkListStore *store;
832 gint i;
833
834 g_return_val_if_fail (combo != NULL, FALSE);
835 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo), FALSE);
836
837 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
838 gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
839 g_object_unref (store);
840
841 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo));
842
843 cell = gtk_cell_renderer_text_new ();
844 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
845 gtk_cell_layout_set_attributes (
846 GTK_CELL_LAYOUT (combo), cell,
847 "text", 0,
848 "sensitive", 1,
849 NULL);
850
851 for (i = 0; i < G_N_ELEMENTS (actions); i++) {
852 GtkTreeIter iter;
853
854 gtk_list_store_append (store, &iter);
855 gtk_list_store_set (
856 store, &iter,
857 0, _(actions[i]),
858 1, TRUE,
859 -1);
860 }
861 }
862
863 return (dialog->action_combo
864 && dialog->interval_value
865 && dialog->value_units_combo
866 && dialog->relative_combo
867 && dialog->time_combo
868 && dialog->repeat_toggle
869 && dialog->repeat_group
870 && dialog->repeat_quantity
871 && dialog->repeat_value
872 && dialog->repeat_unit_combo
873 && dialog->option_notebook
874 && dialog->dalarm_group
875 && dialog->dalarm_message
876 && dialog->dalarm_description
877 && dialog->aalarm_group
878 && dialog->aalarm_sound
879 && dialog->aalarm_file_chooser
880 && dialog->malarm_group
881 && dialog->malarm_address_group
882 && dialog->malarm_addressbook
883 && dialog->malarm_message
884 && dialog->malarm_description
885 && dialog->palarm_group
886 && dialog->palarm_program
887 && dialog->palarm_args);
888 }
889
890 static void
891 addressbook_clicked_cb (GtkWidget *widget,
892 Dialog *dialog)
893 {
894 e_name_selector_show_dialog (dialog->name_selector, dialog->toplevel);
895 }
896
897 static void
898 addressbook_response_cb (GtkWidget *widget,
899 gint response,
900 gpointer data)
901 {
902 Dialog *dialog = data;
903 ENameSelectorDialog *name_selector_dialog;
904
905 name_selector_dialog = e_name_selector_peek_dialog (dialog->name_selector);
906 gtk_widget_hide (GTK_WIDGET (name_selector_dialog));
907 }
908
909 static gboolean
910 setup_select_names (Dialog *dialog)
911 {
912 ENameSelectorModel *name_selector_model;
913 ENameSelectorDialog *name_selector_dialog;
914
915 dialog->name_selector = e_name_selector_new (dialog->registry);
916 e_name_selector_load_books (dialog->name_selector);
917 name_selector_model = e_name_selector_peek_model (dialog->name_selector);
918
919 e_name_selector_model_add_section (name_selector_model, section_name, section_name, NULL);
920
921 dialog->malarm_addresses =
922 GTK_WIDGET (e_name_selector_peek_section_entry (dialog->name_selector, section_name));
923 gtk_widget_show (dialog->malarm_addresses);
924 gtk_box_pack_end (GTK_BOX (dialog->malarm_address_group), dialog->malarm_addresses, TRUE, TRUE, 0);
925
926 g_signal_connect (
927 dialog->malarm_addressbook, "clicked",
928 G_CALLBACK (addressbook_clicked_cb), dialog);
929
930 name_selector_dialog = e_name_selector_peek_dialog (dialog->name_selector);
931 g_signal_connect (
932 name_selector_dialog, "response",
933 G_CALLBACK (addressbook_response_cb), dialog);
934
935 return TRUE;
936 }
937
938 /* Callback used when the repeat toggle button is toggled. We sensitize the
939 * repeat group options as appropriate.
940 */
941 static void
942 repeat_toggle_toggled_cb (GtkToggleButton *toggle,
943 gpointer data)
944 {
945 Dialog *dialog = data;
946 gboolean active;
947
948 active = gtk_toggle_button_get_active (toggle);
949
950 gtk_widget_set_sensitive (dialog->repeat_group, active);
951 }
952
953 static void
954 check_custom_sound (Dialog *dialog)
955 {
956 gchar *str, *dir;
957 gboolean sens;
958
959 str = gtk_file_chooser_get_filename (
960 GTK_FILE_CHOOSER (dialog->aalarm_file_chooser));
961
962 if (str && *str) {
963 dir = g_path_get_dirname (str);
964 if (dir && *dir) {
965 calendar_config_set_dir_path (dir);
966 }
967 }
968
969 sens = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->aalarm_sound)) ? str && *str : TRUE;
970 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog->toplevel), GTK_RESPONSE_OK, sens);
971
972 g_free (str);
973 }
974
975 static void
976 aalarm_sound_toggled_cb (GtkToggleButton *toggle,
977 gpointer data)
978 {
979 Dialog *dialog = data;
980 gboolean active;
981
982 active = gtk_toggle_button_get_active (toggle);
983
984 gtk_widget_set_sensitive (dialog->aalarm_group, active);
985 check_custom_sound (dialog);
986 }
987
988 static void
989 aalarm_attach_changed_cb (GtkWidget *widget,
990 gpointer data)
991 {
992 Dialog *dialog = data;
993
994 check_custom_sound (dialog);
995 }
996
997 static void
998 check_custom_message (Dialog *dialog)
999 {
1000 gchar *str;
1001 GtkTextBuffer *text_buffer;
1002 GtkTextIter text_iter_start, text_iter_end;
1003 gboolean sens;
1004
1005 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->dalarm_description));
1006 gtk_text_buffer_get_start_iter (text_buffer, &text_iter_start);
1007 gtk_text_buffer_get_end_iter (text_buffer, &text_iter_end);
1008 str = gtk_text_buffer_get_text (text_buffer, &text_iter_start, &text_iter_end, FALSE);
1009
1010 sens = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->dalarm_message)) ? str && *str : TRUE;
1011 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog->toplevel), GTK_RESPONSE_OK, sens);
1012
1013 g_free (str);
1014 }
1015
1016 static void
1017 dalarm_message_toggled_cb (GtkToggleButton *toggle,
1018 gpointer data)
1019 {
1020 Dialog *dialog = data;
1021 gboolean active;
1022
1023 active = gtk_toggle_button_get_active (toggle);
1024
1025 gtk_widget_set_sensitive (dialog->dalarm_group, active);
1026 check_custom_message (dialog);
1027 }
1028
1029 static void
1030 dalarm_description_changed_cb (GtkWidget *widget,
1031 gpointer data)
1032 {
1033 Dialog *dialog = data;
1034
1035 check_custom_message (dialog);
1036 }
1037
1038 static void
1039 check_custom_program (Dialog *dialog)
1040 {
1041 GtkEntry *entry;
1042 const gchar *text;
1043 gboolean sensitive;
1044
1045 entry = GTK_ENTRY (dialog->palarm_program);
1046 text = gtk_entry_get_text (entry);
1047 sensitive = (text != NULL && *text != '\0');
1048
1049 gtk_dialog_set_response_sensitive (
1050 GTK_DIALOG (dialog->toplevel),
1051 GTK_RESPONSE_OK, sensitive);
1052 }
1053
1054 static void
1055 palarm_program_changed_cb (GtkWidget *widget,
1056 gpointer data)
1057 {
1058 Dialog *dialog = data;
1059
1060 check_custom_program (dialog);
1061 }
1062
1063 static void
1064 check_custom_email (Dialog *dialog)
1065 {
1066 gchar *str;
1067 GtkTextBuffer *text_buffer;
1068 GtkTextIter text_iter_start, text_iter_end;
1069 ENameSelectorModel *name_selector_model;
1070 EDestinationStore *destination_store;
1071 GList *destinations;
1072 gboolean sens;
1073
1074 name_selector_model = e_name_selector_peek_model (dialog->name_selector);
1075 e_name_selector_model_peek_section (name_selector_model, section_name, NULL, &destination_store);
1076 destinations = e_destination_store_list_destinations (destination_store);
1077
1078 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->malarm_description));
1079 gtk_text_buffer_get_start_iter (text_buffer, &text_iter_start);
1080 gtk_text_buffer_get_end_iter (text_buffer, &text_iter_end);
1081 str = gtk_text_buffer_get_text (text_buffer, &text_iter_start, &text_iter_end, FALSE);
1082
1083 sens = (destinations != NULL) && (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->malarm_message)) ? str && *str : TRUE);
1084 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog->toplevel), GTK_RESPONSE_OK, sens);
1085
1086 g_list_free (destinations);
1087 }
1088
1089 static void
1090 malarm_addresses_changed_cb (GtkWidget *editable,
1091 gpointer data)
1092 {
1093 Dialog *dialog = data;
1094
1095 check_custom_email (dialog);
1096 }
1097
1098 static void
1099 malarm_message_toggled_cb (GtkToggleButton *toggle,
1100 gpointer data)
1101 {
1102 Dialog *dialog = data;
1103 gboolean active;
1104
1105 active = gtk_toggle_button_get_active (toggle);
1106
1107 gtk_widget_set_sensitive (dialog->malarm_group, active);
1108 check_custom_email (dialog);
1109 }
1110
1111 static void
1112 malarm_description_changed_cb (GtkWidget *widget,
1113 gpointer data)
1114 {
1115 Dialog *dialog = data;
1116
1117 check_custom_email (dialog);
1118 }
1119
1120 static void
1121 action_changed_cb (GtkWidget *action_combo,
1122 gpointer data)
1123 {
1124 Dialog *dialog = data;
1125 gchar *dir;
1126 ECalComponentAlarmAction action;
1127 gint page = 0, i;
1128
1129 action = e_dialog_combo_box_get (dialog->action_combo, action_map);
1130 for (i = 0; action_map[i] != -1; i++) {
1131 if (action == action_map[i]) {
1132 page = i;
1133 break;
1134 }
1135 }
1136
1137 gtk_notebook_set_current_page (
1138 GTK_NOTEBOOK (dialog->option_notebook), page);
1139
1140 switch (action) {
1141 case E_CAL_COMPONENT_ALARM_AUDIO:
1142 dir = calendar_config_get_dir_path ();
1143 if (dir && *dir)
1144 gtk_file_chooser_set_current_folder (
1145 GTK_FILE_CHOOSER (dialog->aalarm_file_chooser),
1146 dir);
1147 g_free (dir);
1148 check_custom_sound (dialog);
1149 break;
1150
1151 case E_CAL_COMPONENT_ALARM_DISPLAY:
1152 check_custom_message (dialog);
1153 break;
1154
1155 case E_CAL_COMPONENT_ALARM_EMAIL:
1156 check_custom_email (dialog);
1157 break;
1158
1159 case E_CAL_COMPONENT_ALARM_PROCEDURE:
1160 check_custom_program (dialog);
1161 break;
1162 default:
1163 g_return_if_reached ();
1164 return;
1165 }
1166 }
1167
1168 /* Hooks the widget signals */
1169 static void
1170 init_widgets (Dialog *dialog)
1171 {
1172 GtkTextBuffer *text_buffer;
1173
1174 g_signal_connect (
1175 dialog->action_combo, "changed",
1176 G_CALLBACK (action_changed_cb), dialog);
1177
1178 g_signal_connect (
1179 dialog->repeat_toggle, "toggled",
1180 G_CALLBACK (repeat_toggle_toggled_cb), dialog);
1181
1182 /* Handle custom sounds */
1183 g_signal_connect (
1184 dialog->aalarm_sound, "toggled",
1185 G_CALLBACK (aalarm_sound_toggled_cb), dialog);
1186 g_signal_connect (
1187 dialog->aalarm_file_chooser, "selection-changed",
1188 G_CALLBACK (aalarm_attach_changed_cb), dialog);
1189
1190 /* Handle custom messages */
1191 g_signal_connect (
1192 dialog->dalarm_message, "toggled",
1193 G_CALLBACK (dalarm_message_toggled_cb), dialog);
1194 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->dalarm_description));
1195 g_signal_connect (
1196 text_buffer, "changed",
1197 G_CALLBACK (dalarm_description_changed_cb), dialog);
1198
1199 /* Handle program */
1200 g_signal_connect (
1201 dialog->palarm_program, "changed",
1202 G_CALLBACK (palarm_program_changed_cb), dialog);
1203
1204 /* Handle custom email */
1205 g_signal_connect (
1206 dialog->malarm_message, "toggled",
1207 G_CALLBACK (malarm_message_toggled_cb), dialog);
1208 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->malarm_description));
1209 g_signal_connect (
1210 text_buffer, "changed",
1211 G_CALLBACK (malarm_description_changed_cb), dialog);
1212
1213 g_signal_connect (
1214 dialog->malarm_addresses, "changed",
1215 G_CALLBACK (malarm_addresses_changed_cb), dialog);
1216 }
1217
1218 gboolean
1219 alarm_dialog_run (GtkWidget *parent,
1220 ESourceRegistry *registry,
1221 ECalClient *cal_client,
1222 ECalComponentAlarm *alarm)
1223 {
1224 Dialog dialog;
1225 GtkWidget *container;
1226 gint response_id;
1227
1228 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
1229 g_return_val_if_fail (alarm != NULL, FALSE);
1230
1231 dialog.alarm = alarm;
1232 dialog.cal_client = cal_client;
1233 dialog.registry = registry;
1234
1235 dialog.builder = gtk_builder_new ();
1236 e_load_ui_builder_definition (dialog.builder, "alarm-dialog.ui");
1237
1238 if (!get_widgets (&dialog)) {
1239 g_object_unref (dialog.builder);
1240 return FALSE;
1241 }
1242
1243 if (!setup_select_names (&dialog)) {
1244 g_object_unref (dialog.builder);
1245 return FALSE;
1246 }
1247
1248 init_widgets (&dialog);
1249
1250 alarm_to_dialog (&dialog);
1251
1252 gtk_widget_ensure_style (dialog.toplevel);
1253
1254 container = gtk_dialog_get_action_area (GTK_DIALOG (dialog.toplevel));
1255 gtk_container_set_border_width (GTK_CONTAINER (container), 12);
1256
1257 container = gtk_dialog_get_content_area (GTK_DIALOG (dialog.toplevel));
1258 gtk_container_set_border_width (GTK_CONTAINER (container), 0);
1259
1260 gtk_window_set_icon_name (
1261 GTK_WINDOW (dialog.toplevel), "x-office-calendar");
1262
1263 gtk_window_set_transient_for (
1264 GTK_WINDOW (dialog.toplevel),
1265 GTK_WINDOW (parent));
1266
1267 response_id = gtk_dialog_run (GTK_DIALOG (dialog.toplevel));
1268
1269 if (response_id == GTK_RESPONSE_OK)
1270 dialog_to_alarm (&dialog);
1271
1272 if (dialog.name_selector) {
1273 e_name_selector_cancel_loading (dialog.name_selector);
1274 g_object_unref (dialog.name_selector);
1275 }
1276 gtk_widget_destroy (dialog.toplevel);
1277 g_object_unref (dialog.builder);
1278
1279 return response_id == GTK_RESPONSE_OK ? TRUE : FALSE;
1280 }