No issues found
1 /*
2 * e-cal-shell-backend.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "e-cal-shell-backend.h"
27
28 #include <string.h>
29 #include <glib/gi18n.h>
30 #include <libecal/libecal.h>
31 #include <libedataserverui/libedataserverui.h>
32
33 #include "e-util/e-import.h"
34 #include "shell/e-shell.h"
35 #include "shell/e-shell-backend.h"
36 #include "shell/e-shell-window.h"
37 #include "widgets/misc/e-cal-source-config.h"
38 #include "widgets/misc/e-preferences-window.h"
39 #include "widgets/misc/e-source-config-dialog.h"
40
41 #include "calendar/gui/comp-util.h"
42 #include "calendar/gui/dialogs/event-editor.h"
43 #include "calendar/gui/e-calendar-view.h"
44 #include "calendar/gui/gnome-cal.h"
45 #include "calendar/importers/evolution-calendar-importer.h"
46
47 #include "e-cal-shell-content.h"
48 #include "e-cal-shell-migrate.h"
49 #include "e-cal-shell-settings.h"
50 #include "e-cal-shell-sidebar.h"
51 #include "e-cal-shell-view.h"
52
53 #include "e-calendar-preferences.h"
54
55 #define E_CAL_SHELL_BACKEND_GET_PRIVATE(obj) \
56 (G_TYPE_INSTANCE_GET_PRIVATE \
57 ((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendPrivate))
58
59 struct _ECalShellBackendPrivate {
60 gint placeholder;
61 };
62
63 G_DEFINE_DYNAMIC_TYPE (
64 ECalShellBackend,
65 e_cal_shell_backend,
66 E_TYPE_SHELL_BACKEND)
67
68 static void
69 cal_shell_backend_new_event (ESource *source,
70 GAsyncResult *result,
71 EShell *shell,
72 CompEditorFlags flags,
73 gboolean all_day)
74 {
75 EClient *client = NULL;
76 ECalClient *cal_client;
77 ECalComponent *comp;
78 EShellSettings *shell_settings;
79 CompEditor *editor;
80 GError *error = NULL;
81
82 /* XXX Handle errors better. */
83 e_client_utils_open_new_finish (source, result, &client, &error);
84
85 if (error != NULL) {
86 g_warn_if_fail (client == NULL);
87 g_warning (
88 "%s: Failed to open '%s': %s",
89 G_STRFUNC, e_source_get_display_name (source),
90 error->message);
91 g_error_free (error);
92 return;
93 }
94
95 g_return_if_fail (E_IS_CAL_CLIENT (client));
96
97 cal_client = E_CAL_CLIENT (client);
98 shell_settings = e_shell_get_shell_settings (shell);
99
100 editor = event_editor_new (cal_client, shell, flags);
101 comp = cal_comp_event_new_with_current_time (
102 cal_client, all_day,
103 e_shell_settings_get_pointer (
104 shell_settings, "cal-timezone"),
105 e_shell_settings_get_boolean (
106 shell_settings, "cal-use-default-reminder"),
107 e_shell_settings_get_int (
108 shell_settings, "cal-default-reminder-interval"),
109 e_shell_settings_get_int ( /* enum, actually */
110 shell_settings, "cal-default-reminder-units"));
111 e_cal_component_commit_sequence (comp);
112 comp_editor_edit_comp (editor, comp);
113
114 gtk_window_present (GTK_WINDOW (editor));
115
116 g_object_unref (comp);
117 g_object_unref (client);
118 }
119
120 static void
121 cal_shell_backend_event_new_cb (GObject *source_object,
122 GAsyncResult *result,
123 gpointer shell)
124 {
125 CompEditorFlags flags = 0;
126 gboolean all_day = FALSE;
127
128 flags |= COMP_EDITOR_NEW_ITEM;
129 flags |= COMP_EDITOR_USER_ORG;
130
131 cal_shell_backend_new_event (
132 E_SOURCE (source_object), result, shell, flags, all_day);
133
134 g_object_unref (shell);
135 }
136
137 static void
138 cal_shell_backend_event_all_day_new_cb (GObject *source_object,
139 GAsyncResult *result,
140 gpointer shell)
141 {
142 CompEditorFlags flags = 0;
143 gboolean all_day = TRUE;
144
145 flags |= COMP_EDITOR_NEW_ITEM;
146 flags |= COMP_EDITOR_USER_ORG;
147
148 cal_shell_backend_new_event (
149 E_SOURCE (source_object), result, shell, flags, all_day);
150
151 g_object_unref (shell);
152 }
153
154 static void
155 cal_shell_backend_event_meeting_new_cb (GObject *source_object,
156 GAsyncResult *result,
157 gpointer shell)
158 {
159 CompEditorFlags flags = 0;
160 gboolean all_day = FALSE;
161
162 flags |= COMP_EDITOR_NEW_ITEM;
163 flags |= COMP_EDITOR_USER_ORG;
164 flags |= COMP_EDITOR_MEETING;
165
166 cal_shell_backend_new_event (
167 E_SOURCE (source_object), result, shell, flags, all_day);
168
169 g_object_unref (shell);
170 }
171
172 static void
173 action_event_new_cb (GtkAction *action,
174 EShellWindow *shell_window)
175 {
176 EShell *shell;
177 EShellView *shell_view;
178 EShellBackend *shell_backend;
179 ESource *source;
180 ESourceRegistry *registry;
181 EClientSourceType source_type;
182 const gchar *action_name;
183
184 shell = e_shell_window_get_shell (shell_window);
185
186 action_name = gtk_action_get_name (action);
187
188 /* With a 'calendar' active shell view pass the new appointment
189 * request to it, thus the event will inherit selected time from
190 * the view. */
191 shell_view = e_shell_window_peek_shell_view (shell_window, "calendar");
192 if (shell_view != NULL) {
193 EShellContent *shell_content;
194 GnomeCalendar *gcal;
195 GnomeCalendarViewType view_type;
196 ECalendarView *view;
197
198 shell_backend = e_shell_view_get_shell_backend (shell_view);
199 shell_content = e_shell_view_get_shell_content (shell_view);
200
201 gcal = e_cal_shell_content_get_calendar (
202 E_CAL_SHELL_CONTENT (shell_content));
203
204 view_type = gnome_calendar_get_view (gcal);
205 view = gnome_calendar_get_calendar_view (gcal, view_type);
206
207 if (view) {
208 g_object_set (
209 G_OBJECT (shell_backend),
210 "prefer-new-item", action_name, NULL);
211
212 e_calendar_view_new_appointment_full (
213 view,
214 g_str_equal (action_name, "event-all-day-new"),
215 g_str_equal (action_name, "event-meeting-new"),
216 TRUE);
217
218 return;
219 }
220 }
221
222 /* This callback is used for both appointments and meetings. */
223
224 source_type = E_CLIENT_SOURCE_TYPE_EVENTS;
225
226 registry = e_shell_get_registry (shell);
227 source = e_source_registry_ref_default_calendar (registry);
228
229 shell_backend = e_shell_get_backend_by_name (shell, "calendar");
230 g_object_set (G_OBJECT (shell_backend), "prefer-new-item", action_name, NULL);
231
232 /* Use a callback function appropriate for the action.
233 * FIXME Need to obtain a better default time zone. */
234 if (strcmp (action_name, "event-all-day-new") == 0)
235 e_client_utils_open_new (
236 source, source_type, FALSE, NULL,
237 cal_shell_backend_event_all_day_new_cb,
238 g_object_ref (shell));
239 else if (strcmp (action_name, "event-meeting-new") == 0)
240 e_client_utils_open_new (
241 source, source_type, FALSE, NULL,
242 cal_shell_backend_event_meeting_new_cb,
243 g_object_ref (shell));
244 else
245 e_client_utils_open_new (
246 source, source_type, FALSE, NULL,
247 cal_shell_backend_event_new_cb,
248 g_object_ref (shell));
249
250 g_object_unref (source);
251 }
252
253 static void
254 action_calendar_new_cb (GtkAction *action,
255 EShellWindow *shell_window)
256 {
257 EShell *shell;
258 ESourceRegistry *registry;
259 ECalClientSourceType source_type;
260 GtkWidget *config;
261 GtkWidget *dialog;
262 const gchar *icon_name;
263
264 shell = e_shell_window_get_shell (shell_window);
265
266 registry = e_shell_get_registry (shell);
267 source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
268 config = e_cal_source_config_new (registry, NULL, source_type);
269
270 dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
271
272 gtk_window_set_transient_for (
273 GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
274
275 icon_name = gtk_action_get_icon_name (action);
276 gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
277
278 gtk_window_set_title (GTK_WINDOW (dialog), _("New Calendar"));
279
280 gtk_widget_show (dialog);
281 }
282
283 static GtkActionEntry item_entries[] = {
284
285 { "event-new",
286 "appointment-new",
287 NC_("New", "_Appointment"),
288 "<Shift><Control>a",
289 N_("Create a new appointment"),
290 G_CALLBACK (action_event_new_cb) },
291
292 { "event-all-day-new",
293 "stock_new-24h-appointment",
294 NC_("New", "All Day A_ppointment"),
295 NULL,
296 N_("Create a new all-day appointment"),
297 G_CALLBACK (action_event_new_cb) },
298
299 { "event-meeting-new",
300 "stock_new-meeting",
301 NC_("New", "M_eeting"),
302 "<Shift><Control>e",
303 N_("Create a new meeting request"),
304 G_CALLBACK (action_event_new_cb) }
305 };
306
307 static GtkActionEntry source_entries[] = {
308
309 { "calendar-new",
310 "x-office-calendar",
311 NC_("New", "Cale_ndar"),
312 NULL,
313 N_("Create a new calendar"),
314 G_CALLBACK (action_calendar_new_cb) }
315 };
316
317 static void
318 cal_shell_backend_init_importers (void)
319 {
320 EImportClass *import_class;
321 EImportImporter *importer;
322
323 import_class = g_type_class_ref (e_import_get_type ());
324
325 importer = gnome_calendar_importer_peek ();
326 e_import_class_add_importer (import_class, importer, NULL, NULL);
327
328 importer = ical_importer_peek ();
329 e_import_class_add_importer (import_class, importer, NULL, NULL);
330
331 importer = vcal_importer_peek ();
332 e_import_class_add_importer (import_class, importer, NULL, NULL);
333 }
334
335 static time_t
336 utc_to_user_zone (time_t utc_time,
337 icaltimezone *zone)
338 {
339 if (!zone || (gint) utc_time == -1)
340 return utc_time;
341
342 return icaltime_as_timet (
343 icaltime_from_timet_with_zone (utc_time, FALSE, zone));
344 }
345
346 static gboolean
347 cal_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
348 const gchar *uri)
349 {
350 EShell *shell;
351 EShellSettings *shell_settings;
352 CompEditor *editor;
353 CompEditorFlags flags = 0;
354 ECalClient *client;
355 ECalComponent *comp;
356 ESource *source;
357 ESourceRegistry *registry;
358 ECalClientSourceType source_type;
359 SoupURI *soup_uri;
360 icalcomponent *icalcomp;
361 icalproperty *icalprop;
362 const gchar *cp;
363 gchar *source_uid = NULL;
364 gchar *comp_uid = NULL;
365 gchar *comp_rid = NULL;
366 GDate start_date;
367 GDate end_date;
368 icaltimezone *zone;
369 gboolean handled = FALSE;
370 GError *error = NULL;
371
372 source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
373 shell = e_shell_backend_get_shell (shell_backend);
374 shell_settings = e_shell_get_shell_settings (shell);
375
376 zone = e_shell_settings_get_pointer (shell_settings, "cal-timezone");
377
378 if (strncmp (uri, "calendar:", 9) != 0)
379 return FALSE;
380
381 soup_uri = soup_uri_new (uri);
382
383 if (soup_uri == NULL)
384 return FALSE;
385
386 cp = soup_uri_get_query (soup_uri);
387 if (cp == NULL)
388 goto exit;
389
390 g_date_clear (&start_date, 1);
391 g_date_clear (&end_date, 1);
392
393 while (*cp != '\0') {
394 gchar *header;
395 gchar *content;
396 gsize header_len;
397 gsize content_len;
398
399 header_len = strcspn (cp, "=&");
400
401 /* It it's malformed, give up. */
402 if (cp[header_len] != '=')
403 break;
404
405 header = (gchar *) cp;
406 header[header_len] = '\0';
407 cp += header_len + 1;
408
409 content_len = strcspn (cp, "&");
410
411 content = g_strndup (cp, content_len);
412 if (g_ascii_strcasecmp (header, "startdate") == 0)
413 g_date_set_time_t (
414 &start_date, utc_to_user_zone (
415 time_from_isodate (content), zone));
416 else if (g_ascii_strcasecmp (header, "enddate") == 0)
417 g_date_set_time_t (
418 &end_date, utc_to_user_zone (
419 time_from_isodate (content), zone));
420 else if (g_ascii_strcasecmp (header, "source-uid") == 0)
421 source_uid = g_strdup (content);
422 else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
423 comp_uid = g_strdup (content);
424 else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
425 comp_rid = g_strdup (content);
426 g_free (content);
427
428 cp += content_len;
429 if (*cp == '&') {
430 cp++;
431 if (strncmp (cp, "amp;", 4) == 0)
432 cp += 4;
433 }
434 }
435
436 /* This is primarily for launching Evolution
437 * from the calendar in the clock applet. */
438 if (g_date_valid (&start_date)) {
439 if (g_date_valid (&end_date))
440 e_cal_shell_backend_open_date_range (
441 E_CAL_SHELL_BACKEND (shell_backend),
442 &start_date, &end_date);
443 else
444 e_cal_shell_backend_open_date_range (
445 E_CAL_SHELL_BACKEND (shell_backend),
446 &start_date, NULL);
447 handled = TRUE;
448 goto exit;
449 }
450
451 if (source_uid == NULL || comp_uid == NULL)
452 goto exit;
453
454 /* URI is valid, so consider it handled. Whether
455 * we successfully open it is another matter... */
456 handled = TRUE;
457
458 registry = e_shell_get_registry (shell);
459 source = e_source_registry_ref_source (registry, source_uid);
460 if (source == NULL) {
461 g_printerr ("No source for UID '%s'\n", source_uid);
462 goto exit;
463 }
464
465 client = e_cal_client_new (source, source_type, &error);
466
467 if (client != NULL)
468 e_client_open_sync (E_CLIENT (client), TRUE, NULL, &error);
469
470 if (error != NULL) {
471 g_warning (
472 "%s: Failed to create/open client '%s': %s",
473 G_STRFUNC, e_source_get_display_name (source),
474 error->message);
475 if (client != NULL)
476 g_object_unref (client);
477 g_object_unref (source);
478 g_error_free (error);
479 goto exit;
480 }
481
482 g_object_unref (source);
483 source = NULL;
484
485 /* XXX Copied from e_cal_shell_view_open_event().
486 * Clearly a new utility function is needed. */
487
488 editor = comp_editor_find_instance (comp_uid);
489
490 if (editor != NULL)
491 goto present;
492
493 e_cal_client_get_object_sync (
494 client, comp_uid, comp_rid, &icalcomp, NULL, &error);
495
496 if (error != NULL) {
497 g_warning (
498 "%s: Failed to get object from client: %s",
499 G_STRFUNC, error->message);
500 g_object_unref (client);
501 g_error_free (error);
502 goto exit;
503 }
504
505 comp = e_cal_component_new ();
506 if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
507 g_warning ("%s: Failed to set icalcomp to comp\n", G_STRFUNC);
508 icalcomponent_free (icalcomp);
509 icalcomp = NULL;
510 }
511
512 icalprop = icalcomp ? icalcomponent_get_first_property (
513 icalcomp, ICAL_ATTENDEE_PROPERTY) : NULL;
514 if (icalprop != NULL)
515 flags |= COMP_EDITOR_MEETING;
516
517 if (itip_organizer_is_user (registry, comp, client))
518 flags |= COMP_EDITOR_USER_ORG;
519
520 if (itip_sentby_is_user (registry, comp, client))
521 flags |= COMP_EDITOR_USER_ORG;
522
523 if (!e_cal_component_has_attendees (comp))
524 flags |= COMP_EDITOR_USER_ORG;
525
526 editor = event_editor_new (client, shell, flags);
527 comp_editor_edit_comp (editor, comp);
528
529 g_object_unref (comp);
530
531 present:
532 gtk_window_present (GTK_WINDOW (editor));
533
534 g_object_unref (client);
535
536 exit:
537 g_free (source_uid);
538 g_free (comp_uid);
539 g_free (comp_rid);
540
541 soup_uri_free (soup_uri);
542
543 return handled;
544 }
545
546 static void
547 cal_shell_backend_window_added_cb (EShellBackend *shell_backend,
548 GtkWindow *window)
549 {
550 const gchar *backend_name;
551
552 if (!E_IS_SHELL_WINDOW (window))
553 return;
554
555 backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
556
557 e_shell_window_register_new_item_actions (
558 E_SHELL_WINDOW (window), backend_name,
559 item_entries, G_N_ELEMENTS (item_entries));
560
561 e_shell_window_register_new_source_actions (
562 E_SHELL_WINDOW (window), backend_name,
563 source_entries, G_N_ELEMENTS (source_entries));
564 }
565
566 static void
567 ensure_alarm_notify_is_running (void)
568 {
569 const gchar *base_dir;
570 gchar *filename;
571
572 #ifdef G_OS_WIN32
573 base_dir = EVOLUTION_BINDIR;
574 #else
575 base_dir = EVOLUTION_PRIVLIBEXECDIR;
576 #endif
577
578 filename = g_build_filename (base_dir, "evolution-alarm-notify", NULL);
579
580 if (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE)) {
581 gchar *argv[2];
582 GError *error = NULL;
583
584 argv[0] = filename;
585 argv[1] = NULL;
586
587 g_spawn_async (
588 base_dir, argv, NULL, 0, NULL, NULL, NULL, &error);
589
590 if (error != NULL) {
591 g_message (
592 "Failed to start '%s': %s",
593 filename, error->message);
594 g_error_free (error);
595 }
596 }
597
598 g_free (filename);
599 }
600
601 static void
602 cal_shell_backend_constructed (GObject *object)
603 {
604 EShell *shell;
605 EShellBackend *shell_backend;
606 GtkWidget *preferences_window;
607
608 shell_backend = E_SHELL_BACKEND (object);
609 shell = e_shell_backend_get_shell (shell_backend);
610
611 g_signal_connect_swapped (
612 shell, "handle-uri",
613 G_CALLBACK (cal_shell_backend_handle_uri_cb),
614 shell_backend);
615
616 g_signal_connect_swapped (
617 shell, "window-added",
618 G_CALLBACK (cal_shell_backend_window_added_cb),
619 shell_backend);
620
621 cal_shell_backend_init_importers ();
622
623 e_cal_shell_backend_init_settings (shell);
624
625 /* Setup preference widget factories */
626 preferences_window = e_shell_get_preferences_window (shell);
627
628 e_preferences_window_add_page (
629 E_PREFERENCES_WINDOW (preferences_window),
630 "calendar-and-tasks",
631 "preferences-calendar-and-tasks",
632 _("Calendar and Tasks"),
633 "index#calendar",
634 e_calendar_preferences_new,
635 600);
636
637 g_object_bind_property (
638 e_shell_get_shell_settings (shell), "cal-prefer-new-item",
639 shell_backend, "prefer-new-item",
640 G_BINDING_BIDIRECTIONAL |
641 G_BINDING_SYNC_CREATE);
642
643 /* Chain up to parent's constructed() method. */
644 G_OBJECT_CLASS (e_cal_shell_backend_parent_class)->constructed (object);
645
646 ensure_alarm_notify_is_running ();
647 }
648
649 static void
650 e_cal_shell_backend_class_init (ECalShellBackendClass *class)
651 {
652 GObjectClass *object_class;
653 EShellBackendClass *shell_backend_class;
654
655 g_type_class_add_private (class, sizeof (ECalShellBackendPrivate));
656
657 object_class = G_OBJECT_CLASS (class);
658 object_class->constructed = cal_shell_backend_constructed;
659
660 shell_backend_class = E_SHELL_BACKEND_CLASS (class);
661 shell_backend_class->shell_view_type = E_TYPE_CAL_SHELL_VIEW;
662 shell_backend_class->name = "calendar";
663 shell_backend_class->aliases = "";
664 shell_backend_class->schemes = "calendar";
665 shell_backend_class->sort_order = 400;
666 shell_backend_class->preferences_page = "calendar-and-tasks";
667 shell_backend_class->start = NULL;
668 shell_backend_class->migrate = e_cal_shell_backend_migrate;
669
670 /* Register relevant ESource extensions. */
671 E_TYPE_SOURCE_CALENDAR;
672 }
673
674 static void
675 e_cal_shell_backend_class_finalize (ECalShellBackendClass *class)
676 {
677 }
678
679 static void
680 e_cal_shell_backend_init (ECalShellBackend *cal_shell_backend)
681 {
682 icalarray *builtin_timezones;
683 gint ii;
684
685 cal_shell_backend->priv =
686 E_CAL_SHELL_BACKEND_GET_PRIVATE (cal_shell_backend);
687
688 /* XXX Pre-load all built-in timezones in libical.
689 *
690 * Built-in time zones in libical 0.43 are loaded on demand,
691 * but not in a thread-safe manner, resulting in a race when
692 * multiple threads call icaltimezone_load_builtin_timezone()
693 * on the same time zone. Until built-in time zone loading
694 * in libical is made thread-safe, work around the issue by
695 * loading all built-in time zones now, so libical's internal
696 * time zone array will be fully populated before any threads
697 * are spawned.
698 */
699 builtin_timezones = icaltimezone_get_builtin_timezones ();
700 for (ii = 0; ii < builtin_timezones->num_elements; ii++) {
701 icaltimezone *zone;
702
703 zone = icalarray_element_at (builtin_timezones, ii);
704
705 /* We don't care about the component right now,
706 * we just need some function that will trigger
707 * icaltimezone_load_builtin_timezone(). */
708 icaltimezone_get_component (zone);
709 }
710 }
711
712 void
713 e_cal_shell_backend_type_register (GTypeModule *type_module)
714 {
715 /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
716 * function, so we have to wrap it with a public function in
717 * order to register types from a separate compilation unit. */
718 e_cal_shell_backend_register_type (type_module);
719 }
720
721 void
722 e_cal_shell_backend_open_date_range (ECalShellBackend *cal_shell_backend,
723 const GDate *start_date,
724 const GDate *end_date)
725 {
726 EShell *shell;
727 EShellView *shell_view;
728 EShellBackend *shell_backend;
729 EShellSidebar *shell_sidebar;
730 GtkWidget *shell_window = NULL;
731 GtkApplication *application;
732 ECalendar *navigator;
733 GList *list;
734
735 g_return_if_fail (E_IS_CAL_SHELL_BACKEND (cal_shell_backend));
736
737 shell_backend = E_SHELL_BACKEND (cal_shell_backend);
738 shell = e_shell_backend_get_shell (shell_backend);
739
740 application = GTK_APPLICATION (shell);
741 list = gtk_application_get_windows (application);
742
743 /* Try to find an EShellWindow already in calendar view. */
744 while (list != NULL) {
745 GtkWidget *window = GTK_WIDGET (list->data);
746
747 if (E_IS_SHELL_WINDOW (window)) {
748 const gchar *active_view;
749
750 active_view = e_shell_window_get_active_view (
751 E_SHELL_WINDOW (window));
752 if (g_strcmp0 (active_view, "calendar") == 0) {
753 gtk_window_present (GTK_WINDOW (window));
754 shell_window = window;
755 break;
756 }
757 }
758
759 list = g_list_next (list);
760 }
761
762 /* Otherwise create a new EShellWindow in calendar view. */
763 if (shell_window == NULL)
764 shell_window = e_shell_create_shell_window (shell, "calendar");
765
766 /* Now dig up the date navigator and select the date range. */
767
768 shell_view = e_shell_window_get_shell_view (
769 E_SHELL_WINDOW (shell_window), "calendar");
770 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
771 navigator = e_cal_shell_sidebar_get_date_navigator (
772 E_CAL_SHELL_SIDEBAR (shell_sidebar));
773
774 e_calendar_item_set_selection (
775 navigator->calitem, start_date, end_date);
776 }