Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
e-cal-shell-view-private.c:938:3 | clang-analyzer | Value stored to 'success' is never read | ||
e-cal-shell-view-private.c:938:3 | clang-analyzer | Value stored to 'success' is never read |
1 /*
2 * e-cal-shell-view-private.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-util/e-util-private.h"
27
28 #include "e-cal-shell-view-private.h"
29
30 #include "calendar/gui/calendar-view-factory.h"
31 #include "widgets/menus/gal-view-factory-etable.h"
32
33 #define CHECK_NB 5
34
35 /* be compatible with older e-d-s for MeeGo */
36 #ifndef ETC_TIMEZONE
37 # define ETC_TIMEZONE "/etc/timezone"
38 # define ETC_TIMEZONE_MAJ "/etc/TIMEZONE"
39 # define ETC_RC_CONF "/etc/rc.conf"
40 # define ETC_SYSCONFIG_CLOCK "/etc/sysconfig/clock"
41 # define ETC_CONF_D_CLOCK "/etc/conf.d/clock"
42 # define ETC_LOCALTIME "/etc/localtime"
43 #endif
44
45 static const gchar * files_to_check[CHECK_NB] = {
46 ETC_TIMEZONE,
47 ETC_TIMEZONE_MAJ,
48 ETC_SYSCONFIG_CLOCK,
49 ETC_CONF_D_CLOCK,
50 ETC_LOCALTIME
51 };
52
53 static struct tm
54 cal_shell_view_get_current_time (ECalendarItem *calitem,
55 ECalShellView *cal_shell_view)
56 {
57 ECalShellContent *cal_shell_content;
58 struct icaltimetype tt;
59 icaltimezone *timezone;
60 ECalModel *model;
61
62 cal_shell_content = cal_shell_view->priv->cal_shell_content;
63 model = e_cal_shell_content_get_model (cal_shell_content);
64 timezone = e_cal_model_get_timezone (model);
65
66 tt = icaltime_from_timet_with_zone (time (NULL), FALSE, timezone);
67
68 return icaltimetype_to_tm (&tt);
69 }
70
71 static void
72 cal_shell_view_date_navigator_date_range_changed_cb (ECalShellView *cal_shell_view,
73 ECalendarItem *calitem)
74 {
75 ECalShellContent *cal_shell_content;
76 GnomeCalendar *calendar;
77
78 cal_shell_content = cal_shell_view->priv->cal_shell_content;
79 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
80
81 gnome_calendar_update_query (calendar);
82 }
83
84 static void
85 cal_shell_view_date_navigator_selection_changed_cb (ECalShellView *cal_shell_view,
86 ECalendarItem *calitem)
87 {
88 ECalShellContent *cal_shell_content;
89 GnomeCalendarViewType switch_to;
90 GnomeCalendarViewType view_type;
91 GnomeCalendar *calendar;
92 ECalModel *model;
93 GDate start_date, end_date;
94 GDate new_start_date, new_end_date;
95 icaltimetype tt;
96 icaltimezone *timezone;
97 time_t start, end, new_time;
98 gboolean starts_on_week_start_day;
99 gint new_days_shown, old_days_shown;
100 gint week_start_day;
101
102 cal_shell_content = cal_shell_view->priv->cal_shell_content;
103 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
104
105 model = gnome_calendar_get_model (calendar);
106 view_type = gnome_calendar_get_view (calendar);
107 switch_to = view_type;
108
109 timezone = e_cal_model_get_timezone (model);
110 week_start_day = e_cal_model_get_week_start_day (model);
111 e_cal_model_get_time_range (model, &start, &end);
112
113 time_to_gdate_with_zone (&start_date, start, timezone);
114 time_to_gdate_with_zone (&end_date, end, timezone);
115
116 if (view_type == GNOME_CAL_MONTH_VIEW) {
117 EWeekView *week_view;
118 ECalendarView *calendar_view;
119 gboolean multi_week_view;
120 gboolean compress_weekend;
121
122 calendar_view = gnome_calendar_get_calendar_view (
123 calendar, GNOME_CAL_MONTH_VIEW);
124
125 week_view = E_WEEK_VIEW (calendar_view);
126 multi_week_view = e_week_view_get_multi_week_view (week_view);
127 compress_weekend = e_week_view_get_compress_weekend (week_view);
128
129 if (week_start_day == 0 && (!multi_week_view || compress_weekend))
130 g_date_add_days (&start_date, 1);
131 }
132
133 g_date_subtract_days (&end_date, 1);
134
135 e_calendar_item_get_selection (
136 calitem, &new_start_date, &new_end_date);
137
138 /* If the selection hasn't changed, just return. */
139 if (g_date_compare (&start_date, &new_start_date) == 0 &&
140 g_date_compare (&end_date, &new_end_date) == 0)
141 return;
142
143 old_days_shown =
144 g_date_get_julian (&end_date) -
145 g_date_get_julian (&start_date) + 1;
146 new_days_shown =
147 g_date_get_julian (&new_end_date) -
148 g_date_get_julian (&new_start_date) + 1;
149
150 /* If a complete week is selected we show the week view.
151 * Note that if weekends are compressed and the week start
152 * day is set to Sunday, we don't actually show complete
153 * weeks in the week view, so this may need tweaking. */
154 starts_on_week_start_day =
155 (g_date_get_weekday (&new_start_date) % 7 == week_start_day);
156
157 /* Update selection to be in the new time range. */
158 tt = icaltime_null_time ();
159 tt.year = g_date_get_year (&new_start_date);
160 tt.month = g_date_get_month (&new_start_date);
161 tt.day = g_date_get_day (&new_start_date);
162 new_time = icaltime_as_timet_with_zone (tt, timezone);
163
164 /* Switch views as appropriate, and change the number of
165 * days or weeks shown. */
166 if (view_type == GNOME_CAL_WORK_WEEK_VIEW && old_days_shown == new_days_shown) {
167 /* keep the work week view when has same days shown */
168 switch_to = GNOME_CAL_WORK_WEEK_VIEW;
169 } else if (new_days_shown > 9) {
170 if (view_type != GNOME_CAL_LIST_VIEW) {
171 ECalendarView *calendar_view;
172
173 calendar_view = gnome_calendar_get_calendar_view (
174 calendar, GNOME_CAL_MONTH_VIEW);
175 e_week_view_set_weeks_shown (
176 E_WEEK_VIEW (calendar_view),
177 (new_days_shown + 6) / 7);
178 switch_to = GNOME_CAL_MONTH_VIEW;
179 }
180 } else if (new_days_shown == 7 && starts_on_week_start_day) {
181 switch_to = GNOME_CAL_WEEK_VIEW;
182 } else if (new_days_shown == 1 && (view_type == GNOME_CAL_WORK_WEEK_VIEW || view_type == GNOME_CAL_WEEK_VIEW)) {
183 /* preserve week views when clicking on one day */
184 switch_to = view_type;
185 } else {
186 ECalendarView *calendar_view;
187
188 calendar_view = gnome_calendar_get_calendar_view (
189 calendar, GNOME_CAL_DAY_VIEW);
190 e_day_view_set_days_shown (
191 E_DAY_VIEW (calendar_view), new_days_shown);
192
193 if (new_days_shown != 5 || !starts_on_week_start_day)
194 switch_to = GNOME_CAL_DAY_VIEW;
195
196 else if (view_type != GNOME_CAL_WORK_WEEK_VIEW)
197 switch_to = GNOME_CAL_DAY_VIEW;
198 }
199
200 /* Make the views display things properly. */
201 gnome_calendar_update_view_times (calendar, new_time);
202 gnome_calendar_set_view (calendar, switch_to);
203 gnome_calendar_set_range_selected (calendar, TRUE);
204
205 gnome_calendar_notify_dates_shown_changed (calendar);
206
207 g_signal_handlers_block_by_func (
208 calitem,
209 cal_shell_view_date_navigator_selection_changed_cb, cal_shell_view);
210
211 /* make sure the selected days in the calendar matches shown days */
212 e_cal_model_get_time_range (model, &start, &end);
213
214 time_to_gdate_with_zone (&start_date, start, timezone);
215 time_to_gdate_with_zone (&end_date, end, timezone);
216
217 g_date_subtract_days (&end_date, 1);
218
219 e_calendar_item_set_selection (calitem, &start_date, &end_date);
220
221 g_signal_handlers_unblock_by_func (
222 calitem,
223 cal_shell_view_date_navigator_selection_changed_cb, cal_shell_view);
224 }
225
226 static gboolean
227 cal_shell_view_date_navigator_scroll_event_cb (ECalShellView *cal_shell_view,
228 GdkEventScroll *event,
229 ECalendar *date_navigator)
230 {
231 ECalendarItem *calitem;
232 GDate start_date, end_date;
233 GdkScrollDirection direction;
234
235 calitem = date_navigator->calitem;
236 if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
237 return FALSE;
238
239 direction = event->direction;
240
241 #if GTK_CHECK_VERSION(3,3,18)
242 if (direction == GDK_SCROLL_SMOOTH) {
243 static gdouble total_delta_y = 0.0;
244
245 total_delta_y += event->delta_y;
246
247 if (total_delta_y >= 1.0) {
248 total_delta_y = 0.0;
249 direction = GDK_SCROLL_DOWN;
250 } else if (total_delta_y <= -1.0) {
251 total_delta_y = 0.0;
252 direction = GDK_SCROLL_UP;
253 } else {
254 return FALSE;
255 }
256 }
257 #endif
258
259 switch (direction) {
260 case GDK_SCROLL_UP:
261 g_date_subtract_months (&start_date, 1);
262 g_date_subtract_months (&end_date, 1);
263 break;
264
265 case GDK_SCROLL_DOWN:
266 g_date_add_months (&start_date, 1);
267 g_date_add_months (&end_date, 1);
268 break;
269
270 default:
271 g_return_val_if_reached (FALSE);
272 }
273
274 /* XXX Does ECalendarItem emit a signal for this? If so, maybe
275 * we could move this handler into ECalShellSidebar. */
276 e_calendar_item_set_selection (calitem, &start_date, &end_date);
277
278 cal_shell_view_date_navigator_selection_changed_cb (
279 cal_shell_view, calitem);
280
281 return TRUE;
282 }
283
284 static void
285 cal_shell_view_popup_event_cb (EShellView *shell_view,
286 GdkEventButton *event)
287 {
288 GList *list;
289 GnomeCalendar *calendar;
290 GnomeCalendarViewType view_type;
291 ECalendarView *view;
292 ECalShellViewPrivate *priv;
293 const gchar *widget_path;
294 gint n_selected;
295
296 priv = E_CAL_SHELL_VIEW_GET_PRIVATE (shell_view);
297
298 calendar = e_cal_shell_content_get_calendar (priv->cal_shell_content);
299
300 view_type = gnome_calendar_get_view (calendar);
301 view = gnome_calendar_get_calendar_view (calendar, view_type);
302
303 list = e_calendar_view_get_selected_events (view);
304 n_selected = g_list_length (list);
305 g_list_free (list);
306
307 if (n_selected <= 0)
308 widget_path = "/calendar-empty-popup";
309 else
310 widget_path = "/calendar-event-popup";
311
312 e_shell_view_show_popup_menu (shell_view, widget_path, event);
313 }
314
315 static gboolean
316 cal_shell_view_selector_popup_event_cb (EShellView *shell_view,
317 ESource *primary_source,
318 GdkEventButton *event)
319 {
320 const gchar *widget_path;
321
322 widget_path = "/calendar-popup";
323 e_shell_view_show_popup_menu (shell_view, widget_path, event);
324
325 return TRUE;
326 }
327
328 static void
329 cal_shell_view_selector_client_added_cb (ECalShellView *cal_shell_view,
330 ECalClient *client)
331 {
332 ECalShellContent *cal_shell_content;
333 GnomeCalendar *calendar;
334 ECalModel *model;
335
336 cal_shell_content = cal_shell_view->priv->cal_shell_content;
337 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
338 model = gnome_calendar_get_model (calendar);
339
340 e_cal_model_add_client (model, client);
341
342 gnome_calendar_update_query (calendar);
343 }
344
345 static void
346 cal_shell_view_selector_client_removed_cb (ECalShellView *cal_shell_view,
347 ECalClient *client)
348 {
349 ECalShellContent *cal_shell_content;
350 GnomeCalendar *calendar;
351 ECalModel *model;
352
353 cal_shell_content = cal_shell_view->priv->cal_shell_content;
354 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
355 model = gnome_calendar_get_model (calendar);
356
357 e_cal_model_remove_client (model, client);
358
359 gnome_calendar_update_query (calendar);
360 }
361
362 static void
363 cal_shell_view_memopad_popup_event_cb (EShellView *shell_view,
364 GdkEventButton *event)
365 {
366 const gchar *widget_path;
367
368 widget_path = "/calendar-memopad-popup";
369 e_shell_view_show_popup_menu (shell_view, widget_path, event);
370 }
371
372 static void
373 cal_shell_view_taskpad_popup_event_cb (EShellView *shell_view,
374 GdkEventButton *event)
375 {
376 const gchar *widget_path;
377
378 widget_path = "/calendar-taskpad-popup";
379 e_shell_view_show_popup_menu (shell_view, widget_path, event);
380 }
381
382 static void
383 cal_shell_view_user_created_cb (ECalShellView *cal_shell_view,
384 ECalClient *where_was_created,
385 ECalendarView *calendar_view)
386 {
387 ECalShellSidebar *cal_shell_sidebar;
388 ESource *source;
389
390 g_return_if_fail (where_was_created != NULL);
391
392 source = e_client_get_source (E_CLIENT (where_was_created));
393
394 cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
395 e_cal_shell_sidebar_add_source (cal_shell_sidebar, source);
396 }
397
398 static void
399 cal_shell_view_load_view_collection (EShellViewClass *shell_view_class)
400 {
401 GalViewCollection *collection;
402 GalViewFactory *factory;
403 ETableSpecification *spec;
404 const gchar *base_dir;
405 gchar *filename;
406
407 collection = shell_view_class->view_collection;
408
409 base_dir = EVOLUTION_ETSPECDIR;
410 spec = e_table_specification_new ();
411 filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
412 if (!e_table_specification_load_from_file (spec, filename))
413 g_critical (
414 "Unable to load ETable specification file "
415 "for calendars");
416 g_free (filename);
417
418 factory = calendar_view_factory_new (GNOME_CAL_DAY_VIEW);
419 gal_view_collection_add_factory (collection, factory);
420 g_object_unref (factory);
421
422 factory = calendar_view_factory_new (GNOME_CAL_WORK_WEEK_VIEW);
423 gal_view_collection_add_factory (collection, factory);
424 g_object_unref (factory);
425
426 factory = calendar_view_factory_new (GNOME_CAL_WEEK_VIEW);
427 gal_view_collection_add_factory (collection, factory);
428 g_object_unref (factory);
429
430 factory = calendar_view_factory_new (GNOME_CAL_MONTH_VIEW);
431 gal_view_collection_add_factory (collection, factory);
432 g_object_unref (factory);
433
434 factory = gal_view_factory_etable_new (spec);
435 gal_view_collection_add_factory (collection, factory);
436 g_object_unref (factory);
437 g_object_unref (spec);
438
439 gal_view_collection_load (collection);
440 }
441
442 static void
443 cal_shell_view_notify_view_id_cb (ECalShellView *cal_shell_view)
444 {
445 ECalShellContent *cal_shell_content;
446 GalViewInstance *view_instance;
447 const gchar *view_id;
448
449 cal_shell_content = cal_shell_view->priv->cal_shell_content;
450 view_instance =
451 e_cal_shell_content_get_view_instance (cal_shell_content);
452 view_id = e_shell_view_get_view_id (E_SHELL_VIEW (cal_shell_view));
453
454 /* A NULL view ID implies we're in a custom view. But you can
455 * only get to a custom view via the "Define Views" dialog, which
456 * would have already modified the view instance appropriately.
457 * Furthermore, there's no way to refer to a custom view by ID
458 * anyway, since custom views have no IDs. */
459 if (view_id == NULL)
460 return;
461
462 gal_view_instance_set_current_view_id (view_instance, view_id);
463 }
464
465 void
466 e_cal_shell_view_private_init (ECalShellView *cal_shell_view,
467 EShellViewClass *shell_view_class)
468 {
469 if (!gal_view_collection_loaded (shell_view_class->view_collection))
470 cal_shell_view_load_view_collection (shell_view_class);
471
472 g_signal_connect (
473 cal_shell_view, "notify::view-id",
474 G_CALLBACK (cal_shell_view_notify_view_id_cb), NULL);
475 }
476
477 static void
478 system_timezone_monitor_changed (GFileMonitor *handle,
479 GFile *file,
480 GFile *other_file,
481 GFileMonitorEvent event,
482 gpointer user_data)
483 {
484 ECalShellView *view = E_CAL_SHELL_VIEW (user_data);
485 ECalShellViewPrivate *priv = view->priv;
486 ECalShellContent *cal_shell_content;
487 icaltimezone *timezone = NULL, *current_zone = NULL;
488 EShellSettings *settings;
489 EShellBackend *shell_backend;
490 EShell *shell;
491 ECalModel *model;
492 const gchar *location;
493
494 if (event != G_FILE_MONITOR_EVENT_CHANGED &&
495 event != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT &&
496 event != G_FILE_MONITOR_EVENT_DELETED &&
497 event != G_FILE_MONITOR_EVENT_CREATED)
498 return;
499
500 cal_shell_content = priv->cal_shell_content;
501 model = e_cal_shell_content_get_model (cal_shell_content);
502 current_zone = e_cal_model_get_timezone (model);
503 timezone = e_cal_util_get_system_timezone ();
504
505 if (!g_strcmp0 (
506 icaltimezone_get_tzid (timezone),
507 icaltimezone_get_tzid (current_zone)))
508 return;
509
510 shell_backend = e_shell_view_get_shell_backend ((EShellView *) view);
511 shell = e_shell_backend_get_shell (shell_backend);
512 settings = e_shell_get_shell_settings (shell);
513 location = icaltimezone_get_location (timezone);
514 if (location == NULL)
515 location = "UTC";
516
517 g_object_set (settings, "cal-timezone-string", location, NULL);
518 g_object_set (settings, "cal-timezone", timezone, NULL);
519 }
520
521 static void
522 init_timezone_monitors (ECalShellView *view)
523 {
524 ECalShellViewPrivate *priv = view->priv;
525 gint i;
526
527 for (i = 0; i < CHECK_NB; i++) {
528 GFile *file;
529
530 file = g_file_new_for_path (files_to_check[i]);
531 priv->monitors[i] = g_file_monitor_file (
532 file, G_FILE_MONITOR_NONE, NULL, NULL);
533 g_object_unref (file);
534
535 if (priv->monitors[i])
536 g_signal_connect_object (
537 priv->monitors[i], "changed",
538 G_CALLBACK (system_timezone_monitor_changed),
539 view, 0);
540 }
541 }
542
543 void
544 e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
545 {
546 ECalShellViewPrivate *priv = cal_shell_view->priv;
547 ECalShellContent *cal_shell_content;
548 ECalShellSidebar *cal_shell_sidebar;
549 EShellBackend *shell_backend;
550 EShellContent *shell_content;
551 EShellSidebar *shell_sidebar;
552 EShellWindow *shell_window;
553 EShellView *shell_view;
554 GnomeCalendar *calendar;
555 ECalendar *date_navigator;
556 EMemoTable *memo_table;
557 ETaskTable *task_table;
558 ESourceSelector *selector;
559 GtkWidget *widget;
560 ECalModel *model;
561 gint ii;
562
563 shell_view = E_SHELL_VIEW (cal_shell_view);
564 shell_backend = e_shell_view_get_shell_backend (shell_view);
565 shell_content = e_shell_view_get_shell_content (shell_view);
566 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
567 shell_window = e_shell_view_get_shell_window (shell_view);
568
569 e_shell_window_add_action_group (shell_window, "calendar");
570 e_shell_window_add_action_group (shell_window, "calendar-filter");
571
572 /* Cache these to avoid lots of awkward casting. */
573 priv->cal_shell_backend = g_object_ref (shell_backend);
574 priv->cal_shell_content = g_object_ref (shell_content);
575 priv->cal_shell_sidebar = g_object_ref (shell_sidebar);
576
577 cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
578 model = e_cal_shell_content_get_model (cal_shell_content);
579 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
580 memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
581 task_table = e_cal_shell_content_get_task_table (cal_shell_content);
582
583 cal_shell_sidebar = E_CAL_SHELL_SIDEBAR (shell_sidebar);
584 selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
585 date_navigator = e_cal_shell_sidebar_get_date_navigator (cal_shell_sidebar);
586
587 /* Give GnomeCalendar a handle to the date navigator, memo and task table. */
588 gnome_calendar_set_date_navigator (calendar, date_navigator);
589 gnome_calendar_set_memo_table (
590 calendar, memo_table ? GTK_WIDGET (memo_table) : NULL);
591 gnome_calendar_set_task_table (
592 calendar, task_table ? GTK_WIDGET (task_table) : NULL);
593
594 e_calendar_item_set_get_time_callback (
595 date_navigator->calitem, (ECalendarItemGetTimeCallback)
596 cal_shell_view_get_current_time, cal_shell_view, NULL);
597
598 for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
599 ECalendarView *calendar_view;
600
601 calendar_view =
602 gnome_calendar_get_calendar_view (calendar, ii);
603
604 g_signal_connect_object (
605 calendar_view, "popup-event",
606 G_CALLBACK (cal_shell_view_popup_event_cb),
607 cal_shell_view, G_CONNECT_SWAPPED);
608
609 g_signal_connect_object (
610 calendar_view, "selection-changed",
611 G_CALLBACK (e_shell_view_update_actions),
612 cal_shell_view, G_CONNECT_SWAPPED);
613
614 g_signal_connect_object (
615 calendar_view, "user-created",
616 G_CALLBACK (cal_shell_view_user_created_cb),
617 cal_shell_view, G_CONNECT_SWAPPED);
618 }
619
620 g_signal_connect_object (
621 calendar, "dates-shown-changed",
622 G_CALLBACK (e_cal_shell_view_update_sidebar),
623 cal_shell_view, G_CONNECT_SWAPPED);
624
625 g_signal_connect_object (
626 model, "status-message",
627 G_CALLBACK (e_cal_shell_view_set_status_message),
628 cal_shell_view, G_CONNECT_SWAPPED);
629
630 g_signal_connect_object (
631 model, "notify::timezone",
632 G_CALLBACK (e_cal_shell_view_update_timezone),
633 cal_shell_view, G_CONNECT_SWAPPED);
634
635 g_signal_connect_object (
636 date_navigator, "scroll-event",
637 G_CALLBACK (cal_shell_view_date_navigator_scroll_event_cb),
638 cal_shell_view, G_CONNECT_SWAPPED);
639
640 g_signal_connect_object (
641 date_navigator->calitem, "date-range-changed",
642 G_CALLBACK (cal_shell_view_date_navigator_date_range_changed_cb),
643 cal_shell_view, G_CONNECT_SWAPPED);
644
645 g_signal_connect_object (
646 date_navigator->calitem, "selection-changed",
647 G_CALLBACK (cal_shell_view_date_navigator_selection_changed_cb),
648 cal_shell_view, G_CONNECT_SWAPPED);
649
650 g_signal_connect_object (
651 selector, "popup-event",
652 G_CALLBACK (cal_shell_view_selector_popup_event_cb),
653 cal_shell_view, G_CONNECT_SWAPPED);
654
655 g_signal_connect_object (
656 cal_shell_sidebar, "client-added",
657 G_CALLBACK (cal_shell_view_selector_client_added_cb),
658 cal_shell_view, G_CONNECT_SWAPPED);
659
660 g_signal_connect_object (
661 cal_shell_sidebar, "client-removed",
662 G_CALLBACK (cal_shell_view_selector_client_removed_cb),
663 cal_shell_view, G_CONNECT_SWAPPED);
664
665 if (memo_table)
666 g_signal_connect_object (
667 memo_table, "popup-event",
668 G_CALLBACK (cal_shell_view_memopad_popup_event_cb),
669 cal_shell_view, G_CONNECT_SWAPPED);
670
671 if (memo_table)
672 g_signal_connect_object (
673 memo_table, "selection-change",
674 G_CALLBACK (e_cal_shell_view_memopad_actions_update),
675 cal_shell_view, G_CONNECT_SWAPPED);
676
677 if (memo_table)
678 g_signal_connect_object (
679 memo_table, "status-message",
680 G_CALLBACK (e_cal_shell_view_memopad_set_status_message),
681 cal_shell_view, G_CONNECT_SWAPPED);
682
683 if (task_table)
684 g_signal_connect_object (
685 task_table, "popup-event",
686 G_CALLBACK (cal_shell_view_taskpad_popup_event_cb),
687 cal_shell_view, G_CONNECT_SWAPPED);
688
689 if (task_table)
690 g_signal_connect_object (
691 task_table, "status-message",
692 G_CALLBACK (e_cal_shell_view_taskpad_set_status_message),
693 cal_shell_view, G_CONNECT_SWAPPED);
694
695 if (task_table)
696 g_signal_connect_object (
697 task_table, "selection-change",
698 G_CALLBACK (e_cal_shell_view_taskpad_actions_update),
699 cal_shell_view, G_CONNECT_SWAPPED);
700
701 e_categories_add_change_hook (
702 (GHookFunc) e_cal_shell_view_update_search_filter,
703 cal_shell_view);
704
705 init_timezone_monitors (cal_shell_view);
706 e_cal_shell_view_actions_init (cal_shell_view);
707 e_cal_shell_view_update_sidebar (cal_shell_view);
708 e_cal_shell_view_update_search_filter (cal_shell_view);
709 e_cal_shell_view_update_timezone (cal_shell_view);
710
711 /* Express mode only: Bind the "New Calendar"
712 * sidebar button to the appropriate action. */
713 widget = e_cal_shell_sidebar_get_new_calendar_button (cal_shell_sidebar);
714 if (widget != NULL)
715 gtk_activatable_set_related_action (
716 GTK_ACTIVATABLE (widget), ACTION (CALENDAR_NEW));
717
718 /* Keep the ECalModel in sync with the sidebar. */
719 g_object_bind_property (
720 shell_sidebar, "default-client",
721 model, "default-client",
722 G_BINDING_SYNC_CREATE);
723
724 /* Keep the toolbar view buttons in sync with the calendar. */
725 g_object_bind_property (
726 calendar, "view",
727 ACTION (CALENDAR_VIEW_DAY), "current-value",
728 G_BINDING_BIDIRECTIONAL |
729 G_BINDING_SYNC_CREATE);
730
731 /* Force the main calendar to update its default source. */
732 g_signal_emit_by_name (selector, "primary-selection-changed");
733 }
734
735 void
736 e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
737 {
738 ECalShellViewPrivate *priv = cal_shell_view->priv;
739 gint i;
740
741 e_cal_shell_view_search_stop (cal_shell_view);
742
743 /* Calling ECalShellContent's save state from here,
744 * because it is too late in its own dispose(). */
745 if (priv->cal_shell_content != NULL)
746 e_cal_shell_content_save_state (priv->cal_shell_content);
747
748 DISPOSE (priv->cal_shell_backend);
749 DISPOSE (priv->cal_shell_content);
750 DISPOSE (priv->cal_shell_sidebar);
751
752 if (priv->calendar_activity != NULL) {
753 /* XXX Activity is not cancellable. */
754 e_activity_set_state (
755 priv->calendar_activity, E_ACTIVITY_COMPLETED);
756 g_object_unref (priv->calendar_activity);
757 priv->calendar_activity = NULL;
758 }
759
760 if (priv->memopad_activity != NULL) {
761 /* XXX Activity is not cancellable. */
762 e_activity_set_state (
763 priv->memopad_activity, E_ACTIVITY_COMPLETED);
764 g_object_unref (priv->memopad_activity);
765 priv->memopad_activity = NULL;
766 }
767
768 if (priv->taskpad_activity != NULL) {
769 /* XXX Activity is not cancellable. */
770 e_activity_set_state (
771 priv->taskpad_activity, E_ACTIVITY_COMPLETED);
772 g_object_unref (priv->taskpad_activity);
773 priv->taskpad_activity = NULL;
774 }
775
776 for (i = 0; i < CHECK_NB; i++) {
777 g_object_unref (priv->monitors[i]);
778 priv->monitors[i] = NULL;
779 }
780 }
781
782 void
783 e_cal_shell_view_private_finalize (ECalShellView *cal_shell_view)
784 {
785 /* XXX Nothing to do? */
786 }
787
788 void
789 e_cal_shell_view_open_event (ECalShellView *cal_shell_view,
790 ECalModelComponent *comp_data)
791 {
792 EShell *shell;
793 EShellView *shell_view;
794 EShellWindow *shell_window;
795 ESourceRegistry *registry;
796 CompEditor *editor;
797 CompEditorFlags flags = 0;
798 ECalComponent *comp;
799 icalcomponent *clone;
800 icalproperty *prop;
801 const gchar *uid;
802
803 g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
804 g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
805
806 shell_view = E_SHELL_VIEW (cal_shell_view);
807 shell_window = e_shell_view_get_shell_window (shell_view);
808 shell = e_shell_window_get_shell (shell_window);
809
810 registry = e_shell_get_registry (shell);
811
812 uid = icalcomponent_get_uid (comp_data->icalcomp);
813 editor = comp_editor_find_instance (uid);
814
815 if (editor != NULL)
816 goto exit;
817
818 comp = e_cal_component_new ();
819 clone = icalcomponent_new_clone (comp_data->icalcomp);
820 e_cal_component_set_icalcomponent (comp, clone);
821
822 prop = icalcomponent_get_first_property (
823 comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
824 if (prop != NULL)
825 flags |= COMP_EDITOR_MEETING;
826
827 if (itip_organizer_is_user (registry, comp, comp_data->client))
828 flags |= COMP_EDITOR_USER_ORG;
829
830 if (itip_sentby_is_user (registry, comp, comp_data->client))
831 flags |= COMP_EDITOR_USER_ORG;
832
833 if (!e_cal_component_has_attendees (comp))
834 flags |= COMP_EDITOR_USER_ORG;
835
836 editor = event_editor_new (comp_data->client, shell, flags);
837 comp_editor_edit_comp (editor, comp);
838
839 g_object_unref (comp);
840
841 exit:
842 gtk_window_present (GTK_WINDOW (editor));
843 }
844
845 void
846 e_cal_shell_view_set_status_message (ECalShellView *cal_shell_view,
847 const gchar *status_message,
848 gdouble percent)
849 {
850 EActivity *activity;
851 EShellView *shell_view;
852 EShellBackend *shell_backend;
853
854 g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
855
856 shell_view = E_SHELL_VIEW (cal_shell_view);
857 shell_backend = e_shell_view_get_shell_backend (shell_view);
858
859 activity = cal_shell_view->priv->calendar_activity;
860
861 if (status_message == NULL || *status_message == '\0') {
862 if (activity != NULL) {
863 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
864 g_object_unref (activity);
865 activity = NULL;
866 }
867 } else if (activity == NULL) {
868 activity = e_activity_new ();
869 e_activity_set_percent (activity, percent);
870 e_activity_set_text (activity, status_message);
871 e_shell_backend_add_activity (shell_backend, activity);
872 } else {
873 e_activity_set_percent (activity, percent);
874 e_activity_set_text (activity, status_message);
875 }
876
877 cal_shell_view->priv->calendar_activity = activity;
878 }
879
880 struct ForeachTzidData
881 {
882 ECalClient *source_client;
883 ECalClient *dest_client;
884 };
885
886 static void
887 add_timezone_to_cal_cb (icalparameter *param,
888 gpointer data)
889 {
890 struct ForeachTzidData *ftd = data;
891 icaltimezone *tz = NULL;
892 const gchar *tzid;
893
894 g_return_if_fail (ftd != NULL);
895 g_return_if_fail (ftd->source_client != NULL);
896 g_return_if_fail (ftd->dest_client != NULL);
897
898 tzid = icalparameter_get_tzid (param);
899 if (!tzid || !*tzid)
900 return;
901
902 if (e_cal_client_get_timezone_sync (ftd->source_client, tzid, &tz, NULL, NULL) && tz)
903 e_cal_client_add_timezone_sync (ftd->dest_client, tz, NULL, NULL);
904 }
905
906 void
907 e_cal_shell_view_transfer_item_to (ECalShellView *cal_shell_view,
908 ECalendarViewEvent *event,
909 ECalClient *destination_client,
910 gboolean remove)
911 {
912 icalcomponent *icalcomp;
913 icalcomponent *icalcomp_clone;
914 icalcomponent *icalcomp_event;
915 gboolean success;
916 const gchar *uid;
917
918 /* XXX This function should be split up into
919 * smaller, more understandable pieces. */
920
921 g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
922 g_return_if_fail (event != NULL);
923 g_return_if_fail (E_IS_CAL_CLIENT (destination_client));
924
925 if (!is_comp_data_valid (event))
926 return;
927
928 icalcomp_event = event->comp_data->icalcomp;
929 uid = icalcomponent_get_uid (icalcomp_event);
930
931 /* Put the new object into the destination calendar. */
932
933 success = e_cal_client_get_object_sync (
934 destination_client, uid, NULL, &icalcomp, NULL, NULL);
935
936 if (success) {
937 icalcomponent_free (icalcomp);
938 success = e_cal_client_modify_object_sync (
(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)
939 destination_client, icalcomp_event,
940 CALOBJ_MOD_ALL, NULL, NULL);
941
942 /* do not delete the event when it was found in the calendar */
943 return;
944 } else {
945 icalproperty *icalprop;
946 gchar *new_uid;
947 GError *error = NULL;
948 struct ForeachTzidData ftd;
949
950 ftd.source_client = event->comp_data->client;
951 ftd.dest_client = destination_client;
952
953 if (e_cal_util_component_is_instance (icalcomp_event)) {
954 success = e_cal_client_get_object_sync (
955 event->comp_data->client,
956 uid, NULL, &icalcomp, NULL, NULL);
957 if (success) {
958 /* Use master object when working
959 * with a recurring event ... */
960 icalcomp_clone = icalcomponent_new_clone (icalcomp);
961 icalcomponent_free (icalcomp);
962 } else {
963 /* ... or remove the recurrence ID ... */
964 icalcomp_clone =
965 icalcomponent_new_clone (icalcomp_event);
966 if (e_cal_util_component_has_recurrences (icalcomp_clone)) {
967 /* ... for non-detached instances,
968 * to make it a master object. */
969 icalprop = icalcomponent_get_first_property (
970 icalcomp_clone, ICAL_RECURRENCEID_PROPERTY);
971 if (icalprop != NULL)
972 icalcomponent_remove_property (
973 icalcomp_clone, icalprop);
974 }
975 }
976 } else
977 icalcomp_clone =
978 icalcomponent_new_clone (icalcomp_event);
979
980 icalprop = icalproperty_new_x ("1");
981 icalproperty_set_x_name (icalprop, "X-EVOLUTION-MOVE-CALENDAR");
982 icalcomponent_add_property (icalcomp_clone, icalprop);
983
984 if (!remove) {
985 /* Change the UID to avoid problems with
986 * duplicated UIDs. */
987 new_uid = e_cal_component_gen_uid ();
988 icalcomponent_set_uid (icalcomp_clone, new_uid);
989 g_free (new_uid);
990 }
991
992 new_uid = NULL;
993 icalcomponent_foreach_tzid (
994 icalcomp_clone, add_timezone_to_cal_cb, &ftd);
995 success = e_cal_client_create_object_sync (
996 destination_client, icalcomp_clone,
997 &new_uid, NULL, &error);
998 if (!success) {
999 icalcomponent_free (icalcomp_clone);
1000 g_warning (
1001 "%s: Failed to create object: %s",
1002 G_STRFUNC, error->message);
1003 g_error_free (error);
1004 return;
1005 }
1006
1007 icalcomponent_free (icalcomp_clone);
1008 g_free (new_uid);
1009 }
1010
1011 if (remove) {
1012 ECalClient *source_client = event->comp_data->client;
1013
1014 /* Remove the item from the source calendar. */
1015 if (e_cal_util_component_is_instance (icalcomp_event) ||
1016 e_cal_util_component_has_recurrences (icalcomp_event)) {
1017 icaltimetype icaltime;
1018 gchar *rid;
1019
1020 icaltime =
1021 icalcomponent_get_recurrenceid (icalcomp_event);
1022 if (!icaltime_is_null_time (icaltime))
1023 rid = icaltime_as_ical_string_r (icaltime);
1024 else
1025 rid = NULL;
1026 e_cal_client_remove_object_sync (
1027 source_client, uid, rid,
1028 CALOBJ_MOD_ALL, NULL, NULL);
1029 g_free (rid);
1030 } else
1031 e_cal_client_remove_object_sync (
1032 source_client, uid, NULL,
1033 CALOBJ_MOD_THIS, NULL, NULL);
1034 }
1035 }
1036
1037 void
1038 e_cal_shell_view_update_sidebar (ECalShellView *cal_shell_view)
1039 {
1040 EShellView *shell_view;
1041 EShellSidebar *shell_sidebar;
1042 ECalShellContent *cal_shell_content;
1043 GnomeCalendar *calendar;
1044 GnomeCalendarViewType view_type;
1045 ECalendarView *calendar_view;
1046 ECalModel *model;
1047 time_t start_time, end_time;
1048 struct tm start_tm, end_tm;
1049 struct icaltimetype start_tt, end_tt;
1050 icaltimezone *timezone;
1051 gchar buffer[512] = { 0 };
1052 gchar end_buffer[512] = { 0 };
1053
1054 g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
1055
1056 shell_view = E_SHELL_VIEW (cal_shell_view);
1057 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
1058
1059 cal_shell_content = cal_shell_view->priv->cal_shell_content;
1060 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
1061
1062 model = gnome_calendar_get_model (calendar);
1063 timezone = e_cal_model_get_timezone (model);
1064
1065 view_type = gnome_calendar_get_view (calendar);
1066 calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
1067
1068 if (!e_calendar_view_get_visible_time_range (
1069 calendar_view, &start_time, &end_time)) {
1070 e_shell_sidebar_set_secondary_text (shell_sidebar, "");
1071 return;
1072 }
1073
1074 start_tt = icaltime_from_timet_with_zone (start_time, FALSE, timezone);
1075 start_tm.tm_year = start_tt.year - 1900;
1076 start_tm.tm_mon = start_tt.month - 1;
1077 start_tm.tm_mday = start_tt.day;
1078 start_tm.tm_hour = start_tt.hour;
1079 start_tm.tm_min = start_tt.minute;
1080 start_tm.tm_sec = start_tt.second;
1081 start_tm.tm_isdst = -1;
1082 start_tm.tm_wday = time_day_of_week (
1083 start_tt.day, start_tt.month - 1, start_tt.year);
1084
1085 /* Subtract one from end_time so we don't get an extra day. */
1086 end_tt = icaltime_from_timet_with_zone (end_time - 1, FALSE, timezone);
1087 end_tm.tm_year = end_tt.year - 1900;
1088 end_tm.tm_mon = end_tt.month - 1;
1089 end_tm.tm_mday = end_tt.day;
1090 end_tm.tm_hour = end_tt.hour;
1091 end_tm.tm_min = end_tt.minute;
1092 end_tm.tm_sec = end_tt.second;
1093 end_tm.tm_isdst = -1;
1094 end_tm.tm_wday = time_day_of_week (
1095 end_tt.day, end_tt.month - 1, end_tt.year);
1096
1097 switch (view_type) {
1098 case GNOME_CAL_DAY_VIEW:
1099 case GNOME_CAL_WORK_WEEK_VIEW:
1100 case GNOME_CAL_WEEK_VIEW:
1101 if (start_tm.tm_year == end_tm.tm_year &&
1102 start_tm.tm_mon == end_tm.tm_mon &&
1103 start_tm.tm_mday == end_tm.tm_mday) {
1104 e_utf8_strftime (
1105 buffer, sizeof (buffer),
1106 _("%A %d %b %Y"), &start_tm);
1107 } else if (start_tm.tm_year == end_tm.tm_year) {
1108 e_utf8_strftime (
1109 buffer, sizeof (buffer),
1110 _("%a %d %b"), &start_tm);
1111 e_utf8_strftime (
1112 end_buffer, sizeof (end_buffer),
1113 _("%a %d %b %Y"), &end_tm);
1114 strcat (buffer, " - ");
1115 strcat (buffer, end_buffer);
1116 } else {
1117 e_utf8_strftime (
1118 buffer, sizeof (buffer),
1119 _("%a %d %b %Y"), &start_tm);
1120 e_utf8_strftime (
1121 end_buffer, sizeof (end_buffer),
1122 _("%a %d %b %Y"), &end_tm);
1123 strcat (buffer, " - ");
1124 strcat (buffer, end_buffer);
1125 }
1126 break;
1127
1128 case GNOME_CAL_MONTH_VIEW:
1129 case GNOME_CAL_LIST_VIEW:
1130 if (start_tm.tm_year == end_tm.tm_year) {
1131 if (start_tm.tm_mon == end_tm.tm_mon) {
1132 e_utf8_strftime (
1133 buffer,
1134 sizeof (buffer),
1135 "%d", &start_tm);
1136 e_utf8_strftime (
1137 end_buffer,
1138 sizeof (end_buffer),
1139 _("%d %b %Y"), &end_tm);
1140 strcat (buffer, " - ");
1141 strcat (buffer, end_buffer);
1142 } else {
1143 e_utf8_strftime (
1144 buffer,
1145 sizeof (buffer),
1146 _("%d %b"), &start_tm);
1147 e_utf8_strftime (
1148 end_buffer,
1149 sizeof (end_buffer),
1150 _("%d %b %Y"), &end_tm);
1151 strcat (buffer, " - ");
1152 strcat (buffer, end_buffer);
1153 }
1154 } else {
1155 e_utf8_strftime (
1156 buffer, sizeof (buffer),
1157 _("%d %b %Y"), &start_tm);
1158 e_utf8_strftime (
1159 end_buffer, sizeof (end_buffer),
1160 _("%d %b %Y"), &end_tm);
1161 strcat (buffer, " - ");
1162 strcat (buffer, end_buffer);
1163 }
1164 break;
1165
1166 default:
1167 g_return_if_reached ();
1168 }
1169
1170 e_shell_sidebar_set_secondary_text (shell_sidebar, buffer);
1171 }
1172
1173 void
1174 e_cal_shell_view_update_timezone (ECalShellView *cal_shell_view)
1175 {
1176 ECalShellContent *cal_shell_content;
1177 ECalShellSidebar *cal_shell_sidebar;
1178 icaltimezone *timezone;
1179 ECalModel *model;
1180 GList *clients, *iter;
1181
1182 cal_shell_content = cal_shell_view->priv->cal_shell_content;
1183 model = e_cal_shell_content_get_model (cal_shell_content);
1184 timezone = e_cal_model_get_timezone (model);
1185
1186 cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
1187 clients = e_cal_shell_sidebar_get_clients (cal_shell_sidebar);
1188
1189 for (iter = clients; iter != NULL; iter = iter->next) {
1190 ECalClient *client = iter->data;
1191
1192 if (e_client_is_opened (E_CLIENT (client)))
1193 e_cal_client_set_default_timezone (client, timezone);
1194 }
1195
1196 g_list_free (clients);
1197 }
1198
1199 static gint
1200 cal_searching_get_search_range_years (ECalShellView *cal_shell_view)
1201 {
1202 EShellBackend *backend;
1203 EShellSettings *shell_settings;
1204 gint value;
1205
1206 backend = e_shell_view_get_shell_backend (E_SHELL_VIEW (cal_shell_view));
1207 shell_settings = e_shell_get_shell_settings (e_shell_backend_get_shell (backend));
1208
1209 value = e_shell_settings_get_int (shell_settings, "cal-search-range-years");
1210 if (value <= 0)
1211 value = 10;
1212
1213 return value;
1214 }
1215
1216 static gint
1217 cal_time_t_ptr_compare (gconstpointer a,
1218 gconstpointer b)
1219 {
1220 const time_t *ta = a, *tb = b;
1221
1222 return (ta ? *ta : 0) - (tb ? *tb : 0);
1223 }
1224
1225 static void cal_iterate_searching (ECalShellView *cal_shell_view);
1226
1227 struct GenerateInstancesData {
1228 ECalClient *client;
1229 ECalShellView *cal_shell_view;
1230 GCancellable *cancellable;
1231 };
1232
1233 static void
1234 cal_searching_instances_done_cb (gpointer user_data)
1235 {
1236 struct GenerateInstancesData *gid = user_data;
1237
1238 g_return_if_fail (gid != NULL);
1239 g_return_if_fail (gid->cal_shell_view != NULL);
1240
1241 if (!g_cancellable_is_cancelled (gid->cancellable)) {
1242 gid->cal_shell_view->priv->search_pending_count--;
1243 if (!gid->cal_shell_view->priv->search_pending_count) {
1244 gid->cal_shell_view->priv->search_hit_cache =
1245 g_slist_sort (
1246 gid->cal_shell_view->priv->search_hit_cache,
1247 cal_time_t_ptr_compare);
1248 cal_iterate_searching (gid->cal_shell_view);
1249 }
1250 }
1251
1252 g_object_unref (gid->cancellable);
1253 g_free (gid);
1254 }
1255
1256 static gboolean
1257 cal_searching_got_instance_cb (ECalComponent *comp,
1258 time_t instance_start,
1259 time_t instance_end,
1260 gpointer user_data)
1261 {
1262 struct GenerateInstancesData *gid = user_data;
1263 ECalShellViewPrivate *priv;
1264 ECalComponentDateTime dt;
1265 time_t *value;
1266
1267 g_return_val_if_fail (gid != NULL, FALSE);
1268
1269 if (g_cancellable_is_cancelled (gid->cancellable))
1270 return FALSE;
1271
1272 g_return_val_if_fail (gid->cal_shell_view != NULL, FALSE);
1273 g_return_val_if_fail (gid->cal_shell_view->priv != NULL, FALSE);
1274
1275 e_cal_component_get_dtstart (comp, &dt);
1276
1277 if (dt.tzid && dt.value) {
1278 icaltimezone *zone = NULL;
1279 if (!e_cal_client_get_timezone_sync (gid->client, dt.tzid, &zone, gid->cancellable, NULL)) {
1280 zone = NULL;
1281 }
1282
1283 if (g_cancellable_is_cancelled (gid->cancellable))
1284 return FALSE;
1285
1286 if (zone)
1287 instance_start = icaltime_as_timet_with_zone (*dt.value, zone);
1288 }
1289
1290 e_cal_component_free_datetime (&dt);
1291
1292 priv = gid->cal_shell_view->priv;
1293 value = g_new (time_t, 1);
1294 *value = instance_start;
1295 if (!g_slist_find_custom (priv->search_hit_cache, value, cal_time_t_ptr_compare))
1296 priv->search_hit_cache = g_slist_append (priv->search_hit_cache, value);
1297 else
1298 g_free (value);
1299
1300 return TRUE;
1301 }
1302
1303 static void
1304 cal_search_get_object_list_cb (GObject *source,
1305 GAsyncResult *result,
1306 gpointer user_data)
1307 {
1308 ECalClient *client = E_CAL_CLIENT (source);
1309 ECalShellView *cal_shell_view = user_data;
1310 GSList *icalcomps = NULL;
1311 GError *error = NULL;
1312
1313 g_return_if_fail (client != NULL);
1314 g_return_if_fail (result != NULL);
1315 g_return_if_fail (cal_shell_view != NULL);
1316
1317 if (!e_cal_client_get_object_list_finish (client, result, &icalcomps, &error) || !icalcomps) {
1318 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
1319 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
1320 g_clear_error (&error);
1321 return;
1322 }
1323
1324 g_clear_error (&error);
1325 cal_shell_view->priv->search_pending_count--;
1326 if (!cal_shell_view->priv->search_pending_count) {
1327 cal_shell_view->priv->search_hit_cache =
1328 g_slist_sort (
1329 cal_shell_view->priv->search_hit_cache,
1330 cal_time_t_ptr_compare);
1331 cal_iterate_searching (cal_shell_view);
1332 }
1333 } else {
1334 GSList *iter;
1335 GCancellable *cancellable;
1336 time_t start, end;
1337
1338 cancellable = e_activity_get_cancellable (
1339 cal_shell_view->priv->searching_activity);
1340 start = time_add_day (
1341 cal_shell_view->priv->search_time,
1342 (-1) * cal_shell_view->priv->search_direction);
1343 end = cal_shell_view->priv->search_time;
1344 if (start > end) {
1345 time_t tmp = start;
1346 start = end;
1347 end = tmp;
1348 }
1349
1350 for (iter = icalcomps; iter; iter = iter->next) {
1351 icalcomponent *icalcomp = iter->data;
1352 struct GenerateInstancesData *gid;
1353
1354 gid = g_new0 (struct GenerateInstancesData, 1);
1355 gid->client = client;
1356 gid->cal_shell_view = cal_shell_view;
1357 gid->cancellable = g_object_ref (cancellable);
1358
1359 e_cal_client_generate_instances_for_object (
1360 client, icalcomp, start, end, cancellable,
1361 cal_searching_got_instance_cb, gid,
1362 cal_searching_instances_done_cb);
1363 }
1364
1365 e_cal_client_free_icalcomp_slist (icalcomps);
1366 }
1367 }
1368
1369 static gboolean
1370 cal_searching_check_candidates (ECalShellView *cal_shell_view)
1371 {
1372 ECalShellContent *cal_shell_content;
1373 GnomeCalendarViewType view_type;
1374 ECalendarView *calendar_view;
1375 GnomeCalendar *calendar;
1376 GSList *iter;
1377 time_t value, candidate = -1;
1378
1379 g_return_val_if_fail (cal_shell_view != NULL, FALSE);
1380 g_return_val_if_fail (cal_shell_view->priv != NULL, FALSE);
1381
1382 cal_shell_content = cal_shell_view->priv->cal_shell_content;
1383 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
1384 view_type = gnome_calendar_get_view (calendar);
1385 calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
1386
1387 if (!e_calendar_view_get_selected_time_range (calendar_view, &value, NULL))
1388 return FALSE;
1389
1390 if (cal_shell_view->priv->search_direction > 0 && (view_type == GNOME_CAL_WEEK_VIEW || view_type == GNOME_CAL_MONTH_VIEW))
1391 value = time_add_day (value, 1);
1392
1393 for (iter = cal_shell_view->priv->search_hit_cache; iter; iter = iter->next) {
1394 time_t cache = *((time_t *) iter->data);
1395
1396 /* list is sorted, once the search iteration is complete */
1397 if (cache > value) {
1398 if (cal_shell_view->priv->search_direction > 0)
1399 candidate = cache;
1400 break;
1401 } else if (cal_shell_view->priv->search_direction < 0 && cache != value)
1402 candidate = cache;
1403 }
1404
1405 if (candidate > 0) {
1406 gnome_calendar_goto (calendar, candidate);
1407 return TRUE;
1408 }
1409
1410 return FALSE;
1411 }
1412
1413 static void
1414 cal_searching_update_alert (ECalShellView *cal_shell_view,
1415 const gchar *message)
1416 {
1417 ECalShellViewPrivate *priv;
1418 EShellContent *shell_content;
1419 EAlert *alert;
1420
1421 g_return_if_fail (cal_shell_view != NULL);
1422 g_return_if_fail (cal_shell_view->priv != NULL);
1423
1424 priv = cal_shell_view->priv;
1425
1426 if (priv->search_alert) {
1427 e_alert_response (
1428 priv->search_alert,
1429 e_alert_get_default_response (priv->search_alert));
1430 priv->search_alert = NULL;
1431 }
1432
1433 if (!message)
1434 return;
1435
1436 alert = e_alert_new ("calendar:search-error-generic", message, NULL);
1437 g_return_if_fail (alert != NULL);
1438
1439 priv->search_alert = alert;
1440 g_object_add_weak_pointer (G_OBJECT (alert), &priv->search_alert);
1441 e_alert_start_timer (priv->search_alert, 5);
1442
1443 shell_content = e_shell_view_get_shell_content (
1444 E_SHELL_VIEW (cal_shell_view));
1445 e_alert_sink_submit_alert (
1446 E_ALERT_SINK (shell_content), priv->search_alert);
1447 g_object_unref (priv->search_alert);
1448 }
1449
1450 static void
1451 cal_iterate_searching (ECalShellView *cal_shell_view)
1452 {
1453 ECalShellViewPrivate *priv;
1454 GList *clients, *iter;
1455 ECalModel *model;
1456 time_t new_time, range1, range2;
1457 icaltimezone *timezone;
1458 const gchar *default_tzloc = NULL;
1459 GCancellable *cancellable;
1460 gchar *sexp, *start, *end;
1461
1462 g_return_if_fail (cal_shell_view != NULL);
1463 g_return_if_fail (cal_shell_view->priv != NULL);
1464
1465 priv = cal_shell_view->priv;
1466 g_return_if_fail (priv->search_direction != 0);
1467 g_return_if_fail (priv->search_pending_count == 0);
1468
1469 cal_searching_update_alert (cal_shell_view, NULL);
1470
1471 if (cal_searching_check_candidates (cal_shell_view)) {
1472 if (priv->searching_activity) {
1473 e_activity_set_state (
1474 priv->searching_activity,
1475 E_ACTIVITY_COMPLETED);
1476 g_object_unref (priv->searching_activity);
1477 priv->searching_activity = NULL;
1478 }
1479
1480 return;
1481 }
1482
1483 if (!priv->searching_activity) {
1484 EShellBackend *shell_backend;
1485
1486 shell_backend = e_shell_view_get_shell_backend (
1487 E_SHELL_VIEW (cal_shell_view));
1488
1489 cancellable = g_cancellable_new ();
1490 priv->searching_activity = e_activity_new ();
1491 e_activity_set_cancellable (
1492 priv->searching_activity, cancellable);
1493 e_activity_set_state (
1494 priv->searching_activity, E_ACTIVITY_RUNNING);
1495 e_activity_set_text (
1496 priv->searching_activity,
1497 priv->search_direction > 0 ?
1498 _("Searching next matching event") :
1499 _("Searching previous matching event"));
1500
1501 e_shell_backend_add_activity (
1502 shell_backend, priv->searching_activity);
1503 }
1504
1505 new_time = time_add_day (priv->search_time, priv->search_direction);
1506 if (new_time > priv->search_max_time || new_time < priv->search_min_time) {
1507 gchar *alert_msg;
1508 gint range_years;
1509
1510 /* would get out of bounds, stop searching */
1511 e_activity_set_state (
1512 priv->searching_activity, E_ACTIVITY_COMPLETED);
1513 g_object_unref (priv->searching_activity);
1514 priv->searching_activity = NULL;
1515
1516 range_years = cal_searching_get_search_range_years (cal_shell_view);
1517 alert_msg = g_strdup_printf (
1518 priv->search_direction > 0 ?
1519 ngettext (
1520 "Cannot find matching event in the next %d year",
1521 "Cannot find matching event in the next %d years",
1522 range_years) :
1523 ngettext (
1524 "Cannot find matching event in the previous %d year",
1525 "Cannot find matching event in the previous %d years",
1526 range_years),
1527 range_years);
1528 cal_searching_update_alert (cal_shell_view, alert_msg);
1529 g_free (alert_msg);
1530
1531 e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
1532
1533 return;
1534 }
1535
1536 model = gnome_calendar_get_model (
1537 e_cal_shell_content_get_calendar (
1538 cal_shell_view->priv->cal_shell_content));
1539 clients = e_cal_model_get_client_list (model);
1540
1541 if (!clients) {
1542 e_activity_set_state (
1543 priv->searching_activity, E_ACTIVITY_COMPLETED);
1544 g_object_unref (priv->searching_activity);
1545 priv->searching_activity = NULL;
1546
1547 cal_searching_update_alert (
1548 cal_shell_view,
1549 _("Cannot search with no active calendar"));
1550
1551 e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
1552
1553 return;
1554 }
1555
1556 timezone = e_cal_model_get_timezone (model);
1557 range1 = priv->search_time;
1558 range2 = time_add_day (range1, priv->search_direction);
1559 if (range1 < range2) {
1560 start = isodate_from_time_t (time_day_begin (range1));
1561 end = isodate_from_time_t (time_day_end (range2));
1562 } else {
1563 start = isodate_from_time_t (time_day_begin (range2));
1564 end = isodate_from_time_t (time_day_end (range1));
1565 }
1566
1567 if (timezone && timezone != icaltimezone_get_utc_timezone ())
1568 default_tzloc = icaltimezone_get_location (timezone);
1569 if (!default_tzloc)
1570 default_tzloc = "";
1571
1572 sexp = g_strdup_printf (
1573 "(and %s (occur-in-time-range? "
1574 "(make-time \"%s\") "
1575 "(make-time \"%s\") \"%s\"))",
1576 e_cal_model_get_search_query (model), start, end, default_tzloc);
1577
1578 g_free (start);
1579 g_free (end);
1580
1581 cancellable = e_activity_get_cancellable (priv->searching_activity);
1582 g_list_foreach (clients, (GFunc) g_object_ref, NULL);
1583 priv->search_pending_count = g_list_length (clients);
1584 priv->search_time = new_time;
1585
1586 for (iter = clients; iter; iter = iter->next) {
1587 ECalClient *client = iter->data;
1588
1589 e_cal_client_get_object_list (
1590 client, sexp, cancellable,
1591 cal_search_get_object_list_cb, cal_shell_view);
1592 }
1593
1594 g_list_free_full (clients, g_object_unref);
1595 g_free (sexp);
1596 }
1597
1598 void
1599 e_cal_shell_view_search_events (ECalShellView *cal_shell_view,
1600 gboolean search_forward)
1601 {
1602 ECalShellViewPrivate *priv = cal_shell_view->priv;
1603 ECalShellContent *cal_shell_content;
1604 GnomeCalendarViewType view_type;
1605 ECalendarView *calendar_view;
1606 GnomeCalendar *calendar;
1607 time_t start_time = 0;
1608 gint range_years;
1609
1610 if (priv->searching_activity || !priv->search_direction)
1611 e_cal_shell_view_search_stop (cal_shell_view);
1612
1613 cal_shell_content = cal_shell_view->priv->cal_shell_content;
1614 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
1615 view_type = gnome_calendar_get_view (calendar);
1616 calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
1617
1618 if (!e_calendar_view_get_selected_time_range (calendar_view, &start_time, NULL)) {
1619 e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
1620 return;
1621 }
1622
1623 start_time = time_day_begin (start_time);
1624 if (priv->search_direction) {
1625 time_t cached_start, cached_end, tmp;
1626
1627 cached_start = priv->search_time;
1628 cached_end = time_add_day (
1629 cached_start, (-1) * priv->search_direction);
1630
1631 if (priv->search_direction > 0) {
1632 tmp = cached_start;
1633 cached_start = cached_end;
1634 cached_end = tmp;
1635 }
1636
1637 /* clear cached results if searching out of cached bounds */
1638 if (start_time < cached_start || start_time > cached_end)
1639 e_cal_shell_view_search_stop (cal_shell_view);
1640 }
1641
1642 priv->search_direction = search_forward ? +30 : -30;
1643
1644 if (cal_searching_check_candidates (cal_shell_view))
1645 return;
1646
1647 range_years = cal_searching_get_search_range_years (cal_shell_view);
1648
1649 priv->search_pending_count = 0;
1650 priv->search_time = start_time;
1651 priv->search_min_time = start_time - (range_years * 365 * 24 * 60 * 60);
1652 priv->search_max_time = start_time + (range_years * 365 * 24 * 60 * 60);
1653
1654 if (priv->search_min_time < 0)
1655 priv->search_min_time = 0;
1656 if (priv->search_hit_cache) {
1657 g_slist_free_full (priv->search_hit_cache, g_free);
1658 priv->search_hit_cache = NULL;
1659 }
1660
1661 cal_iterate_searching (cal_shell_view);
1662 }
1663
1664 void
1665 e_cal_shell_view_search_stop (ECalShellView *cal_shell_view)
1666 {
1667 ECalShellViewPrivate *priv;
1668
1669 g_return_if_fail (cal_shell_view != NULL);
1670 g_return_if_fail (cal_shell_view->priv != NULL);
1671
1672 priv = cal_shell_view->priv;
1673
1674 cal_searching_update_alert (cal_shell_view, NULL);
1675
1676 if (priv->searching_activity) {
1677 g_cancellable_cancel (
1678 e_activity_get_cancellable (priv->searching_activity));
1679 e_activity_set_state (
1680 priv->searching_activity, E_ACTIVITY_CANCELLED);
1681 g_object_unref (priv->searching_activity);
1682 priv->searching_activity = NULL;
1683 }
1684
1685 if (priv->search_hit_cache) {
1686 g_slist_free_full (priv->search_hit_cache, g_free);
1687 priv->search_hit_cache = NULL;
1688 }
1689
1690 priv->search_direction = 0;
1691 }