Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
gnome-cal.c:1737:2 | clang-analyzer | Function call argument is an uninitialized value | ||
gnome-cal.c:1737:2 | clang-analyzer | Function call argument is an uninitialized value |
1 /*
2 * Evolution calendar - Main calendar view widget
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 * Authors:
19 * Miguel de Icaza <miguel@ximian.com>
20 * Federico Mena-Quintero <federico@ximian.com>
21 * Seth Alves <alves@hungry.com>
22 * Rodrigo Moya <rodrigo@ximian.com>
23 *
24 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
25 *
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #include <unistd.h>
33 #include <math.h>
34 #include <signal.h>
35 #include <fcntl.h>
36 #include <gdk/gdkkeysyms.h>
37 #include <glib/gi18n.h>
38
39 #include <widgets/menus/gal-view-factory-etable.h>
40 #include <widgets/menus/gal-view-etable.h>
41 #include <widgets/menus/gal-define-views-dialog.h>
42 #include "e-util/e-util.h"
43 #include "libevolution-utils/e-alert-dialog.h"
44 #include "e-util/e-util-private.h"
45 #include "shell/e-shell.h"
46 #include "dialogs/delete-error.h"
47 #include "dialogs/event-editor.h"
48 #include "comp-util.h"
49 #include "e-cal-model-calendar.h"
50 #include "e-day-view.h"
51 #include "e-day-view-time-item.h"
52 #include "e-month-view.h"
53 #include "e-week-view.h"
54 #include "e-cal-list-view.h"
55 #include "gnome-cal.h"
56 #include "calendar-config.h"
57 #include "calendar-view.h"
58 #include "calendar-view-factory.h"
59 #include "tag-calendar.h"
60 #include "misc.h"
61 #include "ea-calendar.h"
62 #include "e-memo-table.h"
63 #include "e-task-table.h"
64
65 #define d(x)
66
67 #define GNOME_CALENDAR_GET_PRIVATE(obj) \
68 (G_TYPE_INSTANCE_GET_PRIVATE \
69 ((obj), GNOME_TYPE_CALENDAR, GnomeCalendarPrivate))
70
71 /* Private part of the GnomeCalendar structure */
72 struct _GnomeCalendarPrivate {
73 ESourceRegistry *registry;
74 ECalModel *model;
75
76 /*
77 * Fields for the calendar view
78 */
79
80 /* This is the last time explicitly selected by the user */
81 time_t base_view_time;
82
83 /* Widgets */
84
85 GtkWidget *hpane;
86
87 ECalendar *date_navigator;
88 GtkWidget *memo_table; /* EMemoTable, but can be NULL */
89 GtkWidget *task_table; /* ETaskTable, but can be NULL */
90
91 /* Calendar query for the date navigator */
92 GMutex *dn_query_lock;
93 GList *dn_queries; /* list of CalQueries */
94 gchar *sexp;
95 gchar *todo_sexp;
96 gchar *memo_sexp;
97 guint update_timeout;
98 guint update_marcus_bains_line_timeout;
99
100 /* This is the view currently shown. We use it to keep track of the
101 * positions of the panes. range_selected is TRUE if a range of dates
102 * was selected in the date navigator to show the view. */
103 ECalendarView *views[GNOME_CAL_LAST_VIEW];
104 GnomeCalendarViewType current_view_type;
105
106 gboolean range_selected;
107
108 /* These are the saved positions of the panes. They are multiples of
109 * calendar month widths & heights in the date navigator, so that they
110 * will work OK after theme changes. */
111 gint hpane_pos;
112 gint hpane_pos_month_view;
113
114 /* The signal handler id for our GtkCalendar "day_selected" handler. */
115 guint day_selected_id;
116
117 /* The dates currently shown. If they are -1 then we have no dates
118 * shown. We only use these to check if we need to emit a
119 * 'dates-shown-changed' signal.*/
120 time_t visible_start;
121 time_t visible_end;
122 gboolean updating;
123
124 /* If this is true, list view uses range of showing the events
125 * as the dates selected in date navigator which is one month,
126 * else it uses the date range set in search bar. */
127 gboolean lview_select_daten_range;
128
129 /* Used in update_todo_view, to prevent interleaving when
130 * called in separate thread. */
131 GMutex *todo_update_lock;
132
133 GCancellable *cancellable;
134 };
135
136 enum {
137 PROP_0,
138 PROP_DATE_NAVIGATOR,
139 PROP_MEMO_TABLE,
140 PROP_REGISTRY,
141 PROP_TASK_TABLE,
142 PROP_VIEW
143 };
144
145 enum {
146 DATES_SHOWN_CHANGED,
147 CALENDAR_SELECTION_CHANGED,
148 GOTO_DATE,
149 SOURCE_ADDED,
150 SOURCE_REMOVED,
151 CHANGE_VIEW,
152 LAST_SIGNAL
153 };
154
155 static guint signals[LAST_SIGNAL];
156
157 static void gnome_calendar_do_dispose (GObject *object);
158 static void gnome_calendar_finalize (GObject *object);
159 static void gnome_calendar_goto_date (GnomeCalendar *gcal,
160 GnomeCalendarGotoDateType goto_date);
161
162 static void gnome_calendar_update_date_navigator (GnomeCalendar *gcal);
163
164 static void update_todo_view (GnomeCalendar *gcal);
165 static void update_memo_view (GnomeCalendar *gcal);
166
167 /* Simple asynchronous message dispatcher */
168 typedef struct _Message Message;
169 typedef void (*MessageFunc) (Message *msg);
170
171 struct _Message {
172 MessageFunc func;
173 GSourceFunc done;
174 };
175
176 static void
177 message_proxy (Message *msg)
178 {
179 g_return_if_fail (msg->func != NULL);
180
181 msg->func (msg);
182 if (msg->done)
183 g_idle_add (msg->done, msg);
184 }
185
186 static gpointer
187 create_thread_pool (void)
188 {
189 /* once created, run forever */
190 return g_thread_pool_new ((GFunc) message_proxy, NULL, 1, FALSE, NULL);
191 }
192
193 static void
194 message_push (Message *msg)
195 {
196 static GOnce once = G_ONCE_INIT;
197
198 g_once (&once, (GThreadFunc) create_thread_pool, NULL);
199
200 g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL);
201 }
202
203 G_DEFINE_TYPE (GnomeCalendar, gnome_calendar, G_TYPE_OBJECT)
204
205 static void
206 gcal_update_status_message (GnomeCalendar *gcal,
207 const gchar *message,
208 gdouble percent)
209 {
210 ECalModel *model;
211
212 g_return_if_fail (gcal != NULL);
213
214 model = gnome_calendar_get_model (gcal);
215 g_return_if_fail (model != NULL);
216
217 e_cal_model_update_status_message (model, message, percent);
218 }
219
220 static void
221 update_adjustment (GnomeCalendar *gcal,
222 GtkAdjustment *adjustment,
223 EWeekView *week_view)
224 {
225 GDate date;
226 ECalModel *model;
227 gint week_offset;
228 struct icaltimetype start_tt = icaltime_null_time ();
229 time_t lower;
230 guint32 old_first_day_julian, new_first_day_julian;
231 icaltimezone *timezone;
232 gdouble value;
233
234 /* If we don't have a valid date set yet, just return. */
235 if (!g_date_valid (&week_view->first_day_shown))
236 return;
237
238 value = gtk_adjustment_get_value (adjustment);
239
240 /* Determine the first date shown. */
241 date = week_view->base_date;
242 week_offset = floor (value + 0.5);
243 g_date_add_days (&date, week_offset * 7);
244
245 /* Convert the old & new first days shown to julian values. */
246 old_first_day_julian = g_date_get_julian (&week_view->first_day_shown);
247 new_first_day_julian = g_date_get_julian (&date);
248
249 /* If we are already showing the date, just return. */
250 if (old_first_day_julian == new_first_day_julian)
251 return;
252
253 /* Convert it to a time_t. */
254 start_tt.year = g_date_get_year (&date);
255 start_tt.month = g_date_get_month (&date);
256 start_tt.day = g_date_get_day (&date);
257
258 model = gnome_calendar_get_model (gcal);
259 timezone = e_cal_model_get_timezone (model);
260 lower = icaltime_as_timet_with_zone (start_tt, timezone);
261
262 e_week_view_set_update_base_date (week_view, FALSE);
263 gnome_calendar_set_selected_time_range (gcal, lower);
264 e_week_view_set_update_base_date (week_view, TRUE);
265 }
266
267 static void
268 week_view_adjustment_changed_cb (GtkAdjustment *adjustment,
269 GnomeCalendar *gcal)
270 {
271 ECalendarView *view;
272
273 view = gnome_calendar_get_calendar_view (gcal, GNOME_CAL_WEEK_VIEW);
274 update_adjustment (gcal, adjustment, E_WEEK_VIEW (view));
275 }
276
277 static void
278 month_view_adjustment_changed_cb (GtkAdjustment *adjustment,
279 GnomeCalendar *gcal)
280 {
281 ECalendarView *view;
282
283 view = gnome_calendar_get_calendar_view (gcal, GNOME_CAL_MONTH_VIEW);
284 update_adjustment (gcal, adjustment, E_WEEK_VIEW (view));
285 }
286
287 static void
288 view_selection_changed_cb (GnomeCalendar *gcal)
289 {
290 g_signal_emit (gcal, signals[CALENDAR_SELECTION_CHANGED], 0);
291 }
292
293 static void
294 view_progress_cb (ECalModel *model,
295 const gchar *message,
296 gint percent,
297 ECalClientSourceType type,
298 GnomeCalendar *gcal)
299 {
300 gcal_update_status_message (gcal, message, percent);
301 }
302
303 static void
304 view_complete_cb (ECalModel *model,
305 const GError *error,
306 ECalClientSourceType type,
307 GnomeCalendar *gcal)
308 {
309 gcal_update_status_message (gcal, NULL, -1);
310 }
311
312 static void
313 gnome_calendar_notify_week_start_day_cb (GnomeCalendar *gcal)
314 {
315 time_t start_time;
316
317 start_time = gcal->priv->base_view_time;
318 gnome_calendar_set_selected_time_range (gcal, start_time);
319 }
320
321 static void
322 gnome_calendar_update_time_range (GnomeCalendar *gcal)
323 {
324 time_t start_time;
325
326 start_time = gcal->priv->base_view_time;
327 gnome_calendar_set_selected_time_range (gcal, start_time);
328 }
329
330 static void
331 gnome_calendar_set_registry (GnomeCalendar *gcal,
332 ESourceRegistry *registry)
333 {
334 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
335 g_return_if_fail (gcal->priv->registry == NULL);
336
337 gcal->priv->registry = g_object_ref (registry);
338 }
339
340 static void
341 gnome_calendar_set_property (GObject *object,
342 guint property_id,
343 const GValue *value,
344 GParamSpec *pspec)
345 {
346 switch (property_id) {
347 case PROP_DATE_NAVIGATOR:
348 gnome_calendar_set_date_navigator (
349 GNOME_CALENDAR (object),
350 g_value_get_object (value));
351 return;
352
353 case PROP_MEMO_TABLE:
354 gnome_calendar_set_memo_table (
355 GNOME_CALENDAR (object),
356 g_value_get_object (value));
357 return;
358
359 case PROP_REGISTRY:
360 gnome_calendar_set_registry (
361 GNOME_CALENDAR (object),
362 g_value_get_object (value));
363 return;
364
365 case PROP_TASK_TABLE:
366 gnome_calendar_set_task_table (
367 GNOME_CALENDAR (object),
368 g_value_get_object (value));
369 return;
370
371 case PROP_VIEW:
372 gnome_calendar_set_view (
373 GNOME_CALENDAR (object),
374 g_value_get_int (value));
375 return;
376 }
377
378 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
379 }
380
381 static void
382 gnome_calendar_get_property (GObject *object,
383 guint property_id,
384 GValue *value,
385 GParamSpec *pspec)
386 {
387 switch (property_id) {
388 case PROP_DATE_NAVIGATOR:
389 g_value_set_object (
390 value, gnome_calendar_get_date_navigator (
391 GNOME_CALENDAR (object)));
392 return;
393
394 case PROP_MEMO_TABLE:
395 g_value_set_object (
396 value, gnome_calendar_get_memo_table (
397 GNOME_CALENDAR (object)));
398 return;
399
400 case PROP_REGISTRY:
401 g_value_set_object (
402 value, gnome_calendar_get_registry (
403 GNOME_CALENDAR (object)));
404 return;
405
406 case PROP_TASK_TABLE:
407 g_value_set_object (
408 value, gnome_calendar_get_task_table (
409 GNOME_CALENDAR (object)));
410 return;
411
412 case PROP_VIEW:
413 g_value_set_int (
414 value, gnome_calendar_get_view (
415 GNOME_CALENDAR (object)));
416 return;
417 }
418
419 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
420 }
421
422 static void
423 gnome_calendar_constructed (GObject *object)
424 {
425 GnomeCalendar *gcal = GNOME_CALENDAR (object);
426 ECalendarView *calendar_view;
427 ESourceRegistry *registry;
428 ECalModel *model;
429 GtkAdjustment *adjustment;
430
431 registry = gnome_calendar_get_registry (gcal);
432
433 /* Create the model for the views. */
434 model = e_cal_model_calendar_new (registry);
435 e_cal_model_set_flags (model, E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES);
436 gcal->priv->model = model;
437
438 g_signal_connect (
439 model, "cal-view-progress",
440 G_CALLBACK (view_progress_cb), gcal);
441
442 g_signal_connect (
443 model, "cal-view-complete",
444 G_CALLBACK (view_complete_cb), gcal);
445
446 /* Day View */
447 calendar_view = e_day_view_new (model);
448 e_calendar_view_set_calendar (calendar_view, gcal);
449 gcal->priv->views[GNOME_CAL_DAY_VIEW] = calendar_view;
450 g_object_ref_sink (calendar_view);
451
452 g_signal_connect_swapped (
453 calendar_view, "selection-changed",
454 G_CALLBACK (view_selection_changed_cb), gcal);
455
456 /* Work Week View */
457 calendar_view = e_day_view_new (model);
458 e_day_view_set_work_week_view (E_DAY_VIEW (calendar_view), TRUE);
459 e_day_view_set_days_shown (E_DAY_VIEW (calendar_view), 5);
460 e_calendar_view_set_calendar (calendar_view, gcal);
461 gcal->priv->views[GNOME_CAL_WORK_WEEK_VIEW] = calendar_view;
462 g_object_ref_sink (calendar_view);
463
464 g_signal_connect_swapped (
465 calendar_view, "notify::working-days",
466 G_CALLBACK (gnome_calendar_update_time_range), gcal);
467
468 /* Week View */
469 calendar_view = e_week_view_new (model);
470 e_calendar_view_set_calendar (calendar_view, gcal);
471 gcal->priv->views[GNOME_CAL_WEEK_VIEW] = calendar_view;
472 g_object_ref_sink (calendar_view);
473
474 g_signal_connect_swapped (
475 calendar_view, "selection-changed",
476 G_CALLBACK (view_selection_changed_cb), gcal);
477
478 adjustment = gtk_range_get_adjustment (
479 GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar));
480 g_signal_connect (
481 adjustment, "value-changed",
482 G_CALLBACK (week_view_adjustment_changed_cb), gcal);
483
484 /* Month View */
485 calendar_view = e_month_view_new (model);
486 e_week_view_set_multi_week_view (E_WEEK_VIEW (calendar_view), TRUE);
487 e_week_view_set_weeks_shown (E_WEEK_VIEW (calendar_view), 6);
488 e_calendar_view_set_calendar (calendar_view, gcal);
489 gcal->priv->views[GNOME_CAL_MONTH_VIEW] = calendar_view;
490 g_object_ref_sink (calendar_view);
491
492 g_signal_connect_swapped (
493 calendar_view, "selection-changed",
494 G_CALLBACK (view_selection_changed_cb), gcal);
495
496 adjustment = gtk_range_get_adjustment (
497 GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar));
498 g_signal_connect (
499 adjustment, "value-changed",
500 G_CALLBACK (month_view_adjustment_changed_cb), gcal);
501
502 /* List View */
503 calendar_view = e_cal_list_view_new (model);
504 e_calendar_view_set_calendar (calendar_view, gcal);
505 gcal->priv->views[GNOME_CAL_LIST_VIEW] = calendar_view;
506 g_object_ref_sink (calendar_view);
507
508 g_signal_connect_swapped (
509 calendar_view, "selection-changed",
510 G_CALLBACK (view_selection_changed_cb), gcal);
511
512 g_signal_connect_swapped (
513 model, "notify::week-start-day",
514 G_CALLBACK (gnome_calendar_notify_week_start_day_cb), gcal);
515
516 gnome_calendar_goto_today (gcal);
517
518 /* Chain up to parent's constructed() method. */
519 G_OBJECT_CLASS (gnome_calendar_parent_class)->constructed (object);
520 }
521
522 /* Class initialization function for the gnome calendar */
523 static void
524 gnome_calendar_class_init (GnomeCalendarClass *class)
525 {
526 GObjectClass *object_class;
527 GtkBindingSet *binding_set;
528
529 g_type_class_add_private (class, sizeof (GnomeCalendarPrivate));
530
531 object_class = G_OBJECT_CLASS (class);
532 object_class->set_property = gnome_calendar_set_property;
533 object_class->get_property = gnome_calendar_get_property;
534 object_class->constructed = gnome_calendar_constructed;
535 object_class->dispose = gnome_calendar_do_dispose;
536 object_class->finalize = gnome_calendar_finalize;
537
538 class->dates_shown_changed = NULL;
539 class->calendar_selection_changed = NULL;
540 class->source_added = NULL;
541 class->source_removed = NULL;
542 class->goto_date = gnome_calendar_goto_date;
543 class->change_view = gnome_calendar_set_view;
544
545 g_object_class_install_property (
546 object_class,
547 PROP_DATE_NAVIGATOR,
548 g_param_spec_object (
549 "date-navigator",
550 "Date Navigator",
551 NULL,
552 E_TYPE_CALENDAR,
553 G_PARAM_READWRITE));
554
555 g_object_class_install_property (
556 object_class,
557 PROP_MEMO_TABLE,
558 g_param_spec_object (
559 "memo-table",
560 "Memo table",
561 NULL,
562 E_TYPE_MEMO_TABLE,
563 G_PARAM_READWRITE));
564
565 g_object_class_install_property (
566 object_class,
567 PROP_REGISTRY,
568 g_param_spec_object (
569 "registry",
570 "Registry",
571 "Data source registry",
572 E_TYPE_SOURCE_REGISTRY,
573 G_PARAM_READWRITE |
574 G_PARAM_CONSTRUCT_ONLY |
575 G_PARAM_STATIC_STRINGS));
576
577 g_object_class_install_property (
578 object_class,
579 PROP_TASK_TABLE,
580 g_param_spec_object (
581 "task-table",
582 "Task table",
583 NULL,
584 E_TYPE_TASK_TABLE,
585 G_PARAM_READWRITE));
586
587 g_object_class_install_property (
588 object_class,
589 PROP_VIEW,
590 g_param_spec_int (
591 "view",
592 "View",
593 NULL,
594 GNOME_CAL_DAY_VIEW,
595 GNOME_CAL_LIST_VIEW,
596 GNOME_CAL_DAY_VIEW,
597 G_PARAM_READWRITE));
598
599 signals[DATES_SHOWN_CHANGED] = g_signal_new (
600 "dates_shown_changed",
601 G_TYPE_FROM_CLASS (object_class),
602 G_SIGNAL_RUN_LAST,
603 G_STRUCT_OFFSET (GnomeCalendarClass, dates_shown_changed),
604 NULL, NULL,
605 g_cclosure_marshal_VOID__VOID,
606 G_TYPE_NONE, 0);
607
608 signals[CALENDAR_SELECTION_CHANGED] = g_signal_new (
609 "calendar_selection_changed",
610 G_TYPE_FROM_CLASS (object_class),
611 G_SIGNAL_RUN_LAST,
612 G_STRUCT_OFFSET (GnomeCalendarClass, calendar_selection_changed),
613 NULL, NULL,
614 g_cclosure_marshal_VOID__VOID,
615 G_TYPE_NONE, 0);
616
617 signals[SOURCE_ADDED] = g_signal_new (
618 "source_added",
619 G_TYPE_FROM_CLASS (object_class),
620 G_SIGNAL_RUN_FIRST,
621 G_STRUCT_OFFSET (GnomeCalendarClass, source_added),
622 NULL, NULL,
623 e_marshal_VOID__INT_OBJECT,
624 G_TYPE_NONE, 2,
625 G_TYPE_INT,
626 G_TYPE_OBJECT);
627
628 signals[SOURCE_REMOVED] = g_signal_new (
629 "source_removed",
630 G_TYPE_FROM_CLASS (object_class),
631 G_SIGNAL_RUN_FIRST,
632 G_STRUCT_OFFSET (GnomeCalendarClass, source_removed),
633 NULL, NULL,
634 e_marshal_VOID__INT_OBJECT,
635 G_TYPE_NONE, 2,
636 G_TYPE_INT,
637 G_TYPE_OBJECT);
638
639 signals[GOTO_DATE] = g_signal_new (
640 "goto_date",
641 G_TYPE_FROM_CLASS (object_class),
642 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
643 G_STRUCT_OFFSET (GnomeCalendarClass, goto_date),
644 NULL, NULL,
645 g_cclosure_marshal_VOID__INT,
646 G_TYPE_NONE, 1,
647 G_TYPE_INT);
648
649 signals[CHANGE_VIEW] = g_signal_new (
650 "change_view",
651 G_TYPE_FROM_CLASS (object_class),
652 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
653 G_STRUCT_OFFSET (GnomeCalendarClass, change_view),
654 NULL, NULL,
655 g_cclosure_marshal_VOID__INT,
656 G_TYPE_NONE, 1,
657 G_TYPE_INT);
658
659 /*
660 * Key bindings
661 */
662
663 binding_set = gtk_binding_set_new (G_OBJECT_CLASS_NAME (class));
664
665 /* Alt+PageUp/PageDown, go to the first/last day of the month */
666 gtk_binding_entry_add_signal (
667 binding_set, GDK_KEY_Page_Up,
668 GDK_MOD1_MASK,
669 "goto_date", 1,
670 G_TYPE_ENUM,
671 GNOME_CAL_GOTO_FIRST_DAY_OF_MONTH);
672 gtk_binding_entry_add_signal (
673 binding_set, GDK_KEY_KP_Page_Up,
674 GDK_MOD1_MASK,
675 "goto_date", 1,
676 G_TYPE_ENUM,
677 GNOME_CAL_GOTO_FIRST_DAY_OF_MONTH);
678 gtk_binding_entry_add_signal (
679 binding_set, GDK_KEY_Page_Down,
680 GDK_MOD1_MASK,
681 "goto_date", 1,
682 G_TYPE_ENUM,
683 GNOME_CAL_GOTO_LAST_DAY_OF_MONTH);
684 gtk_binding_entry_add_signal (
685 binding_set, GDK_KEY_KP_Page_Down,
686 GDK_MOD1_MASK,
687 "goto_date", 1,
688 G_TYPE_ENUM,
689 GNOME_CAL_GOTO_LAST_DAY_OF_MONTH);
690
691 /* Alt+Home/End, go to the first/last day of the week */
692 gtk_binding_entry_add_signal (
693 binding_set, GDK_KEY_Home,
694 GDK_MOD1_MASK,
695 "goto_date", 1,
696 G_TYPE_ENUM,
697 GNOME_CAL_GOTO_FIRST_DAY_OF_WEEK);
698 gtk_binding_entry_add_signal (
699 binding_set, GDK_KEY_End,
700 GDK_MOD1_MASK,
701 "goto_date", 1,
702 G_TYPE_ENUM,
703 GNOME_CAL_GOTO_LAST_DAY_OF_WEEK);
704 gtk_binding_entry_add_signal (
705 binding_set, GDK_KEY_KP_Home,
706 GDK_MOD1_MASK,
707 "goto_date", 1,
708 G_TYPE_ENUM,
709 GNOME_CAL_GOTO_FIRST_DAY_OF_WEEK);
710 gtk_binding_entry_add_signal (
711 binding_set, GDK_KEY_KP_End,
712 GDK_MOD1_MASK,
713 "goto_date", 1,
714 G_TYPE_ENUM,
715 GNOME_CAL_GOTO_LAST_DAY_OF_WEEK);
716
717 /*Alt+Left/Right, go to the same day of the previous/next week*/
718 gtk_binding_entry_add_signal (
719 binding_set,GDK_KEY_Left,
720 GDK_MOD1_MASK,
721 "goto_date",1,
722 G_TYPE_ENUM,
723 GNOME_CAL_GOTO_SAME_DAY_OF_PREVIOUS_WEEK);
724 gtk_binding_entry_add_signal (
725 binding_set,GDK_KEY_KP_Left,
726 GDK_MOD1_MASK,
727 "goto_date",1,
728 G_TYPE_ENUM,
729 GNOME_CAL_GOTO_SAME_DAY_OF_PREVIOUS_WEEK);
730 gtk_binding_entry_add_signal (
731 binding_set,GDK_KEY_Right,
732 GDK_MOD1_MASK,
733 "goto_date",1,
734 G_TYPE_ENUM,
735 GNOME_CAL_GOTO_SAME_DAY_OF_NEXT_WEEK);
736 gtk_binding_entry_add_signal (
737 binding_set,GDK_KEY_KP_Right,
738 GDK_MOD1_MASK,
739 "goto_date",1,
740 G_TYPE_ENUM,
741 GNOME_CAL_GOTO_SAME_DAY_OF_NEXT_WEEK);
742
743 /* Ctrl+Y/J/K/M/L to switch between
744 * DayView/WorkWeekView/WeekView/MonthView/ListView */
745 gtk_binding_entry_add_signal (
746 binding_set, GDK_KEY_y,
747 GDK_CONTROL_MASK,
748 "change_view", 1,
749 G_TYPE_ENUM,
750 GNOME_CAL_DAY_VIEW);
751 gtk_binding_entry_add_signal (
752 binding_set, GDK_KEY_j,
753 GDK_CONTROL_MASK,
754 "change_view", 1,
755 G_TYPE_ENUM,
756 GNOME_CAL_WORK_WEEK_VIEW);
757 gtk_binding_entry_add_signal (
758 binding_set, GDK_KEY_k,
759 GDK_CONTROL_MASK,
760 "change_view", 1,
761 G_TYPE_ENUM,
762 GNOME_CAL_WEEK_VIEW);
763 gtk_binding_entry_add_signal (
764 binding_set, GDK_KEY_m,
765 GDK_CONTROL_MASK,
766 "change_view", 1,
767 G_TYPE_ENUM,
768 GNOME_CAL_MONTH_VIEW);
769 gtk_binding_entry_add_signal (
770 binding_set, GDK_KEY_l,
771 GDK_CONTROL_MASK,
772 "change_view", 1,
773 G_TYPE_ENUM,
774 GNOME_CAL_LIST_VIEW);
775
776 /* init the accessibility support for gnome_calendar */
777 gnome_calendar_a11y_init ();
778
779 }
780
781 /* We do this check since the calendar items are downloaded from the server
782 * in the open_method, since the default timezone might not be set there. */
783 static void
784 ensure_dates_are_in_default_zone (GnomeCalendar *gcal,
785 icalcomponent *icalcomp)
786 {
787 ECalModel *model;
788 icaltimezone *timezone;
789 icaltimetype dt;
790
791 model = gnome_calendar_get_model (gcal);
792 timezone = e_cal_model_get_timezone (model);
793
794 if (timezone == NULL)
795 return;
796
797 dt = icalcomponent_get_dtstart (icalcomp);
798 if (dt.is_utc) {
799 dt = icaltime_convert_to_zone (dt, timezone);
800 icalcomponent_set_dtstart (icalcomp, dt);
801 }
802
803 dt = icalcomponent_get_dtend (icalcomp);
804 if (dt.is_utc) {
805 dt = icaltime_convert_to_zone (dt, timezone);
806 icalcomponent_set_dtend (icalcomp, dt);
807 }
808 }
809
810 /* Callback used when the calendar query reports of an updated object */
811 static void
812 dn_client_view_objects_added_cb (ECalClientView *view,
813 const GSList *objects,
814 gpointer data)
815 {
816 GnomeCalendar *gcal;
817 GnomeCalendarPrivate *priv;
818 const GSList *l;
819
820 gcal = GNOME_CALENDAR (data);
821 priv = gcal->priv;
822
823 for (l = objects; l; l = l->next) {
824 ECalComponent *comp = NULL;
825
826 ensure_dates_are_in_default_zone (gcal, l->data);
827 comp = e_cal_component_new ();
828 if (!e_cal_component_set_icalcomponent (
829 comp, icalcomponent_new_clone (l->data))) {
830 g_object_unref (comp);
831 continue;
832 }
833
834 tag_calendar_by_comp (
835 priv->date_navigator, comp,
836 e_cal_client_view_get_client (view),
837 NULL, FALSE, TRUE, TRUE, priv->cancellable);
838 g_object_unref (comp);
839 }
840 }
841
842 static void
843 dn_client_view_objects_modified_cb (ECalClientView *view,
844 const GSList *objects,
845 gpointer data)
846 {
847 GnomeCalendar *gcal;
848
849 gcal = GNOME_CALENDAR (data);
850
851 /* We have to retag the whole thing: an event may change dates
852 * and the tag_calendar_by_comp() below would not know how to
853 * untag the old dates. */
854 gnome_calendar_update_query (gcal);
855 }
856
857 /* Callback used when the calendar query reports of a removed object */
858 static void
859 dn_client_view_objects_removed_cb (ECalClientView *view,
860 const GSList *ids,
861 gpointer data)
862 {
863 GnomeCalendar *gcal;
864
865 gcal = GNOME_CALENDAR (data);
866
867 /* Just retag the whole thing */
868 gnome_calendar_update_query (gcal);
869 }
870
871 /* Callback used when the calendar query is done */
872 static void
873 dn_client_view_complete_cb (ECalClientView *query,
874 const GError *error,
875 gpointer data)
876 {
877 /* FIXME Better error reporting */
878 if (error != NULL)
879 g_warning (
880 "%s: Query did not complete successfully: %s",
881 G_STRFUNC, error->message);
882 }
883
884 ECalendarView *
885 gnome_calendar_get_calendar_view (GnomeCalendar *gcal,
886 GnomeCalendarViewType view_type)
887 {
888 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
889 g_return_val_if_fail (view_type < GNOME_CAL_LAST_VIEW, NULL);
890
891 return gcal->priv->views[view_type];
892 }
893
894 static void
895 get_times_for_views (GnomeCalendar *gcal,
896 GnomeCalendarViewType view_type,
897 time_t *start_time,
898 time_t *end_time,
899 time_t *select_time)
900 {
901 GnomeCalendarPrivate *priv;
902 ECalModel *model;
903 EDayView *day_view;
904 EWeekView *week_view;
905 gint shown, display_start;
906 GDate date;
907 gint week_start_day;
908 gint weekday, first_day, last_day, days_shown, i;
909 gboolean has_working_days = FALSE;
910 guint offset;
911 struct icaltimetype tt = icaltime_null_time ();
912 icaltimezone *timezone;
913 gboolean range_selected;
914
915 model = gnome_calendar_get_model (gcal);
916 range_selected = gnome_calendar_get_range_selected (gcal);
917
918 timezone = e_cal_model_get_timezone (model);
919 week_start_day = e_cal_model_get_week_start_day (model);
920
921 priv = gcal->priv;
922
923 switch (view_type) {
924 case GNOME_CAL_DAY_VIEW:
925 day_view = E_DAY_VIEW (priv->views[view_type]);
926 shown = e_day_view_get_days_shown (day_view);
927 *start_time = time_day_begin_with_zone (*start_time, timezone);
928 *end_time = time_add_day_with_zone (*start_time, shown, timezone);
929 break;
930 case GNOME_CAL_WORK_WEEK_VIEW:
931 /* FIXME Kind of gross, but it works */
932 day_view = E_DAY_VIEW (priv->views[view_type]);
933 time_to_gdate_with_zone (&date, *start_time, timezone);
934
935 /* The start of the work-week is the first working day after the
936 * week start day. */
937
938 /* Get the weekday corresponding to start_time, 0 (Mon) to 6 (Sun). */
939 weekday = (g_date_get_weekday (&date) + 6) % 7;
940
941 /* Find the first working day in the week, 0 (Mon) to 6 (Sun). */
942 first_day = week_start_day % 7;
943 for (i = 0; i < 7; i++) {
944 /* the working_days has stored 0 (Sun) to 6 (Sat) */
945 if (day_view->working_days & (1 << ((first_day + 1) % 7))) {
946 has_working_days = TRUE;
947 break;
948 }
949 first_day = (first_day + 1) % 7;
950 }
951
952 if (has_working_days) {
953 /* Now find the last working day of the week, backwards. */
954 last_day = (first_day + 6) % 7;
955 for (i = 0; i < 7; i++) {
956 /* the working_days has stored 0 (Sun) to 6 (Sat) */
957 if (day_view->working_days & (1 << ((last_day + 1) % 7)))
958 break;
959 last_day = (last_day + 6) % 7;
960 }
961 /* Now calculate the days we need to show to include all the
962 * working days in the week. Add 1 to make it inclusive. */
963 days_shown = (last_day + 7 - first_day) % 7 + 1;
964 } else {
965 /* If no working days are set, just use 7. */
966 days_shown = 7;
967 }
968
969 /* Calculate how many days we need to go back to the first workday. */
970 if (weekday < first_day) {
971 offset = (7 - first_day + weekday) % 7;
972 } else {
973 offset = (weekday - first_day) % 7;
974 }
975 if (offset)
976 g_date_subtract_days (&date, offset);
977
978 tt.year = g_date_get_year (&date);
979 tt.month = g_date_get_month (&date);
980 tt.day = g_date_get_day (&date);
981
982 *start_time = icaltime_as_timet_with_zone (tt, timezone);
983 *end_time = time_add_day_with_zone (*start_time, days_shown, timezone);
984
985 if (select_time && day_view->selection_start_day == -1)
986 time (select_time);
987 break;
988 case GNOME_CAL_WEEK_VIEW:
989 /* FIXME We should be using the same day
990 * of the week enum everywhere. */
991 week_view = E_WEEK_VIEW (priv->views[view_type]);
992 display_start = (week_view->display_start_day + 1) % 7;
993
994 *start_time = time_week_begin_with_zone (
995 *start_time, display_start, timezone);
996 *end_time = time_add_week_with_zone (
997 *start_time, 1, timezone);
998
999 if (select_time && week_view->selection_start_day == -1)
1000 time (select_time);
1001 break;
1002 case GNOME_CAL_MONTH_VIEW:
1003 /* FIXME We should be using the same day
1004 * of the week enum everywhere. */
1005 week_view = E_WEEK_VIEW (priv->views[view_type]);
1006 shown = e_week_view_get_weeks_shown (week_view);
1007 display_start = (week_view->display_start_day + 1) % 7;
1008
1009 if (!range_selected && (
1010 !week_view->multi_week_view ||
1011 !week_view->month_scroll_by_week))
1012 *start_time = time_month_begin_with_zone (
1013 *start_time, timezone);
1014 *start_time = time_week_begin_with_zone (
1015 *start_time, display_start, timezone);
1016 *end_time = time_add_week_with_zone (
1017 *start_time, shown, timezone);
1018
1019 if (select_time && week_view->selection_start_day == -1)
1020 time (select_time);
1021 break;
1022 case GNOME_CAL_LIST_VIEW:
1023 /* FIXME What to do here? */
1024 *start_time = time_month_begin_with_zone (*start_time, timezone);
1025 *end_time = time_add_month_with_zone (*start_time, 1, timezone);
1026 break;
1027 default:
1028 g_return_if_reached ();
1029 }
1030 }
1031
1032 /* Computes the range of time that the date navigator is showing */
1033 static void
1034 get_date_navigator_range (GnomeCalendar *gcal,
1035 time_t *start_time,
1036 time_t *end_time)
1037 {
1038 ECalModel *model;
1039 gint start_year, start_month, start_day;
1040 gint end_year, end_month, end_day;
1041 struct icaltimetype start_tt;
1042 struct icaltimetype end_tt;
1043 icaltimezone *timezone;
1044
1045 model = gnome_calendar_get_model (gcal);
1046 timezone = e_cal_model_get_timezone (model);
1047
1048 start_tt = icaltime_null_time ();
1049 end_tt = icaltime_null_time ();
1050
1051 if (!e_calendar_item_get_date_range (
1052 gcal->priv->date_navigator->calitem,
1053 &start_year, &start_month, &start_day,
1054 &end_year, &end_month, &end_day)) {
1055 *start_time = -1;
1056 *end_time = -1;
1057 return;
1058 }
1059
1060 start_tt.year = start_year;
1061 start_tt.month = start_month + 1;
1062 start_tt.day = start_day;
1063
1064 end_tt.year = end_year;
1065 end_tt.month = end_month + 1;
1066 end_tt.day = end_day;
1067
1068 icaltime_adjust (&end_tt, 1, 0, 0, 0);
1069
1070 *start_time = icaltime_as_timet_with_zone (start_tt, timezone);
1071 *end_time = icaltime_as_timet_with_zone (end_tt, timezone);
1072 }
1073
1074 static const gchar *
1075 gcal_get_default_tzloc (GnomeCalendar *gcal)
1076 {
1077 ECalModel *model;
1078 icaltimezone *timezone;
1079 const gchar *tzloc = NULL;
1080
1081 g_return_val_if_fail (gcal != NULL, "");
1082
1083 model = gnome_calendar_get_model (gcal);
1084 timezone = e_cal_model_get_timezone (model);
1085
1086 if (timezone && timezone != icaltimezone_get_utc_timezone ())
1087 tzloc = icaltimezone_get_location (timezone);
1088
1089 return tzloc ? tzloc : "";
1090 }
1091
1092 /* Adjusts a given query sexp with the time range of the date navigator */
1093 static gchar *
1094 adjust_client_view_sexp (GnomeCalendar *gcal,
1095 const gchar *sexp)
1096 {
1097 time_t start_time, end_time;
1098 gchar *start, *end;
1099 gchar *new_sexp;
1100
1101 get_date_navigator_range (gcal, &start_time, &end_time);
1102 if (start_time == -1 || end_time == -1)
1103 return NULL;
1104
1105 start = isodate_from_time_t (start_time);
1106 end = isodate_from_time_t (end_time);
1107
1108 if (sexp) {
1109 new_sexp = g_strdup_printf (
1110 "(and (occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\") %s)",
1111 start, end, gcal_get_default_tzloc (gcal), sexp);
1112 } else {
1113 new_sexp = g_strdup_printf (
1114 "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")",
1115 start, end, gcal_get_default_tzloc (gcal));
1116 }
1117
1118 g_free (start);
1119 g_free (end);
1120
1121 return new_sexp;
1122 }
1123
1124 struct _date_query_msg {
1125 Message header;
1126 GnomeCalendar *gcal;
1127 };
1128
1129 static void
1130 free_dn_queries (GnomeCalendar *gcal)
1131 {
1132 GList *l;
1133 GnomeCalendarPrivate *priv;
1134
1135 priv = gcal->priv;
1136
1137 g_mutex_lock (priv->dn_query_lock);
1138
1139 for (l = priv->dn_queries; l != NULL; l = l->next) {
1140 if (!l->data)
1141 continue;
1142 g_signal_handlers_disconnect_matched (
1143 l->data, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gcal);
1144 g_object_unref (l->data);
1145 }
1146
1147 g_list_free (priv->dn_queries);
1148 priv->dn_queries = NULL;
1149
1150 g_mutex_unlock (priv->dn_query_lock);
1151 }
1152
1153 static void
1154 update_query_async (struct _date_query_msg *msg)
1155 {
1156 GnomeCalendar *gcal = msg->gcal;
1157 GnomeCalendarPrivate *priv;
1158 ECalClientView *new_view;
1159 gchar *real_sexp;
1160 GList *list, *iter;
1161
1162 priv = gcal->priv;
1163
1164 /* free the previous queries */
1165 free_dn_queries (gcal);
1166
1167 g_return_if_fail (priv->sexp != NULL);
1168
1169 real_sexp = adjust_client_view_sexp (gcal, priv->sexp);
1170 if (!real_sexp) {
1171 return; /* No time range is set, so don't start a query */
1172 }
1173
1174 list = e_cal_model_get_client_list (priv->model);
1175 g_list_foreach (list, (GFunc) g_object_ref, NULL);
1176
1177 /* create queries for each loaded client */
1178 for (iter = list; iter != NULL; iter = iter->next) {
1179 ECalClient *client = E_CAL_CLIENT (iter->data);
1180 GError *error = NULL;
1181 gint tries = 0;
1182
1183 /* don't create queries for clients not loaded yet */
1184 if (!e_client_is_opened (E_CLIENT (client)))
1185 continue;
1186
1187 try_again:
1188 new_view = NULL;
1189 if (!e_cal_client_get_view_sync (client, real_sexp, &new_view, NULL, &error)) {
1190 /* If calendar is busy try again for 3 times. */
1191 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY) && tries != 10) {
1192 tries++;
1193 /*TODO chose an optimal value */
1194 g_usleep (500);
1195
1196 g_clear_error (&error);
1197 goto try_again;
1198 }
1199
1200 g_warning (G_STRLOC ": Could not create the view: %s ", error->message);
1201 g_clear_error (&error);
1202
1203 continue;
1204 }
1205
1206 g_signal_connect (
1207 new_view, "objects-added",
1208 G_CALLBACK (dn_client_view_objects_added_cb), gcal);
1209 g_signal_connect (
1210 new_view, "objects-modified",
1211 G_CALLBACK (dn_client_view_objects_modified_cb), gcal);
1212 g_signal_connect (
1213 new_view, "objects-removed",
1214 G_CALLBACK (dn_client_view_objects_removed_cb), gcal);
1215 g_signal_connect (
1216 new_view, "complete",
1217 G_CALLBACK (dn_client_view_complete_cb), gcal);
1218
1219 g_mutex_lock (priv->dn_query_lock);
1220 priv->dn_queries = g_list_append (priv->dn_queries, new_view);
1221 e_cal_client_view_start (new_view, &error);
1222 if (error != NULL) {
1223 g_warning (
1224 "%s: Failed to start view: %s",
1225 G_STRFUNC, error->message);
1226 g_clear_error (&error);
1227 }
1228 g_mutex_unlock (priv->dn_query_lock);
1229 }
1230
1231 g_list_foreach (list, (GFunc) g_object_unref, NULL);
1232 g_list_free (list);
1233
1234 /* free memory */
1235 g_free (real_sexp);
1236 update_todo_view (gcal);
1237 }
1238
1239 static gboolean
1240 update_query_done (struct _date_query_msg *msg)
1241 {
1242 g_object_unref (msg->gcal);
1243 g_slice_free (struct _date_query_msg, msg);
1244
1245 return FALSE;
1246 }
1247
1248 /* Restarts a query for the date navigator in the calendar */
1249 void
1250 gnome_calendar_update_query (GnomeCalendar *gcal)
1251 {
1252 struct _date_query_msg *msg;
1253
1254 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1255
1256 e_calendar_item_clear_marks (gcal->priv->date_navigator->calitem);
1257
1258 msg = g_slice_new0 (struct _date_query_msg);
1259 msg->header.func = (MessageFunc) update_query_async;
1260 msg->header.done = (GSourceFunc) update_query_done;
1261 msg->gcal = g_object_ref (gcal);
1262
1263 message_push ((Message *) msg);
1264 }
1265
1266 void
1267 gnome_calendar_set_search_query (GnomeCalendar *gcal,
1268 const gchar *sexp,
1269 gboolean range_search,
1270 time_t start_range,
1271 time_t end_range)
1272 {
1273 GnomeCalendarPrivate *priv;
1274 ECalModel *model;
1275 gint i;
1276 time_t start, end;
1277
1278 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1279 g_return_if_fail (sexp != NULL);
1280
1281 priv = gcal->priv;
1282
1283 model = gnome_calendar_get_model (gcal);
1284
1285 /* Set the query on the date navigator */
1286
1287 g_free (priv->sexp);
1288 priv->sexp = g_strdup (sexp);
1289
1290 priv->lview_select_daten_range = !range_search;
1291 start = start_range;
1292 end = end_range;
1293
1294 d (g_print ("Changing the queries %s \n", sexp));
1295
1296 gnome_calendar_update_query (gcal);
1297
1298 i = priv->current_view_type;
1299
1300 /* Set the query on the views */
1301 if (i == GNOME_CAL_LIST_VIEW && !priv->lview_select_daten_range) {
1302 start = priv->base_view_time;
1303 get_times_for_views (gcal, GNOME_CAL_LIST_VIEW, &start, &end, NULL);
1304
1305 e_cal_model_set_search_query_with_time_range (
1306 model, sexp, start, end);
1307
1308 if (priv->current_view_type == GNOME_CAL_LIST_VIEW)
1309 gnome_calendar_update_date_navigator (gcal);
1310 } else
1311 e_cal_model_set_search_query (model, sexp);
1312 }
1313
1314 struct _mupdate_todo_msg {
1315 Message header;
1316 GnomeCalendar *gcal;
1317 };
1318
1319 static void
1320 update_todo_view_async (struct _mupdate_todo_msg *msg)
1321 {
1322 GnomeCalendar *gcal;
1323 GnomeCalendarPrivate *priv;
1324 ECalModel *model;
1325 gchar *sexp = NULL;
1326
1327 g_return_if_fail (msg != NULL);
1328
1329 gcal = msg->gcal;
1330 priv = gcal->priv;
1331
1332 g_return_if_fail (priv->task_table != NULL);
1333
1334 g_mutex_lock (priv->todo_update_lock);
1335
1336 /* Set the query on the task pad */
1337 if (priv->todo_sexp) {
1338 g_free (priv->todo_sexp);
1339 priv->todo_sexp = NULL;
1340 }
1341
1342 model = e_task_table_get_model (E_TASK_TABLE (priv->task_table));
1343
1344 if ((sexp = calendar_config_get_hide_completed_tasks_sexp (FALSE)) != NULL) {
1345 priv->todo_sexp = g_strdup_printf (
1346 "(and %s %s)", sexp,
1347 priv->sexp ? priv->sexp : "");
1348 e_cal_model_set_search_query (model, priv->todo_sexp);
1349 g_free (sexp);
1350 } else {
1351 priv->todo_sexp = g_strdup (priv->sexp);
1352 e_cal_model_set_search_query (model, priv->todo_sexp);
1353 }
1354
1355 update_memo_view (msg->gcal);
1356
1357 g_mutex_unlock (priv->todo_update_lock);
1358 }
1359
1360 static gboolean
1361 update_todo_view_done (struct _mupdate_todo_msg *msg)
1362 {
1363 EMemoTable *memo_table;
1364 ETaskTable *task_table;
1365 EShellView *shell_view;
1366 GnomeCalendar *gcal;
1367
1368 g_return_val_if_fail (msg != NULL, FALSE);
1369
1370 gcal = msg->gcal;
1371
1372 g_return_val_if_fail (gcal->priv->task_table != NULL, FALSE);
1373 g_return_val_if_fail (gcal->priv->memo_table != NULL, FALSE);
1374
1375 task_table = E_TASK_TABLE (gcal->priv->task_table);
1376 shell_view = e_task_table_get_shell_view (task_table);
1377 e_shell_view_unblock_update_actions (shell_view);
1378
1379 memo_table = E_MEMO_TABLE (gcal->priv->memo_table);
1380 shell_view = e_memo_table_get_shell_view (memo_table);
1381 e_shell_view_unblock_update_actions (shell_view);
1382
1383 g_object_unref (msg->gcal);
1384 g_slice_free (struct _mupdate_todo_msg, msg);
1385
1386 return FALSE;
1387 }
1388
1389 static void
1390 update_todo_view (GnomeCalendar *gcal)
1391 {
1392 EMemoTable *memo_table;
1393 ETaskTable *task_table;
1394 EShellView *shell_view;
1395 struct _mupdate_todo_msg *msg;
1396
1397 /* they are both or none anyway */
1398 if (!gcal->priv->task_table || !gcal->priv->memo_table)
1399 return;
1400
1401 msg = g_slice_new0 (struct _mupdate_todo_msg);
1402 msg->header.func = (MessageFunc) update_todo_view_async;
1403 msg->header.done = (GSourceFunc) update_todo_view_done;
1404 msg->gcal = g_object_ref (gcal);
1405
1406 task_table = E_TASK_TABLE (gcal->priv->task_table);
1407 shell_view = e_task_table_get_shell_view (task_table);
1408 e_shell_view_block_update_actions (shell_view);
1409
1410 memo_table = E_MEMO_TABLE (gcal->priv->memo_table);
1411 shell_view = e_memo_table_get_shell_view (memo_table);
1412 e_shell_view_block_update_actions (shell_view);
1413
1414 message_push ((Message *) msg);
1415 }
1416
1417 static void
1418 update_memo_view (GnomeCalendar *gcal)
1419 {
1420 GnomeCalendarPrivate *priv;
1421 ECalModel *model, *view_model;
1422 time_t start = -1, end = -1;
1423 gchar *iso_start, *iso_end;
1424
1425 priv = gcal->priv;
1426 if (!priv->memo_table)
1427 return;
1428
1429 /* Set the query on the memo pad*/
1430 model = e_memo_table_get_model (E_MEMO_TABLE (priv->memo_table));
1431 view_model = gnome_calendar_get_model (gcal);
1432 e_cal_model_get_time_range (view_model, &start, &end);
1433
1434 if (start != -1 && end != -1) {
1435 iso_start = isodate_from_time_t (start);
1436 iso_end = isodate_from_time_t (end);
1437
1438 g_free (priv->memo_sexp);
1439
1440 priv->memo_sexp = g_strdup_printf (
1441 "(and (or (not (has-start?)) (occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")) %s)",
1442 iso_start, iso_end, gcal_get_default_tzloc (gcal),
1443 priv->sexp ? priv->sexp : "");
1444
1445 e_cal_model_set_search_query (model, priv->memo_sexp);
1446
1447 g_free (iso_start);
1448 g_free (iso_end);
1449 }
1450 }
1451
1452 static gboolean
1453 update_marcus_bains_line_cb (GnomeCalendar *gcal)
1454 {
1455 GnomeCalendarViewType view_type;
1456 ECalendarView *view;
1457 time_t now, day_begin;
1458
1459 view_type = gnome_calendar_get_view (gcal);
1460 view = gnome_calendar_get_calendar_view (gcal, view_type);
1461
1462 if (E_IS_DAY_VIEW (view))
1463 e_day_view_marcus_bains_update (E_DAY_VIEW (view));
1464
1465 time (&now);
1466 day_begin = time_day_begin (now);
1467
1468 /* check in the first two minutes */
1469 if (now >= day_begin && now <= day_begin + 120) {
1470 time_t start_time = 0, end_time = 0;
1471
1472 g_return_val_if_fail (view != NULL, TRUE);
1473
1474 e_calendar_view_get_selected_time_range (view, &start_time, &end_time);
1475
1476 if (end_time >= time_add_day (day_begin, -1) && start_time <= day_begin) {
1477 gnome_calendar_goto (gcal, now);
1478 }
1479 }
1480
1481 return TRUE;
1482 }
1483
1484 static void
1485 setup_widgets (GnomeCalendar *gcal)
1486 {
1487 GnomeCalendarPrivate *priv;
1488
1489 priv = gcal->priv;
1490
1491 /* update_todo_view (gcal); */
1492
1493 /* Timeout check to hide completed items */
1494 #if 0 /* KILL-BONOBO */
1495 priv->update_timeout = g_timeout_add_full (
1496 G_PRIORITY_LOW, 60000, (GSourceFunc)
1497 update_todo_view_cb, gcal, NULL);
1498 #endif
1499
1500 /* The Marcus Bains line */
1501 priv->update_marcus_bains_line_timeout = g_timeout_add_full (
1502 G_PRIORITY_LOW, 60000, (GSourceFunc)
1503 update_marcus_bains_line_cb, gcal, NULL);
1504
1505 /* update_memo_view (gcal); */
1506 }
1507
1508 /* Object initialization function for the gnome calendar */
1509 static void
1510 gnome_calendar_init (GnomeCalendar *gcal)
1511 {
1512 gcal->priv = GNOME_CALENDAR_GET_PRIVATE (gcal);
1513
1514 gcal->priv->todo_update_lock = g_mutex_new ();
1515 gcal->priv->dn_query_lock = g_mutex_new ();
1516
1517 gcal->priv->current_view_type = GNOME_CAL_WORK_WEEK_VIEW;
1518 gcal->priv->range_selected = FALSE;
1519 gcal->priv->lview_select_daten_range = TRUE;
1520
1521 setup_widgets (gcal);
1522
1523 gcal->priv->dn_queries = NULL;
1524 gcal->priv->sexp = g_strdup ("#t"); /* Match all */
1525 gcal->priv->todo_sexp = g_strdup ("#t");
1526 gcal->priv->memo_sexp = g_strdup ("#t");
1527
1528 gcal->priv->visible_start = -1;
1529 gcal->priv->visible_end = -1;
1530 gcal->priv->updating = FALSE;
1531
1532 gcal->priv->cancellable = g_cancellable_new ();
1533 }
1534
1535 static void
1536 gnome_calendar_do_dispose (GObject *object)
1537 {
1538 GnomeCalendarPrivate *priv;
1539 gint ii;
1540
1541 priv = GNOME_CALENDAR_GET_PRIVATE (object);
1542
1543 if (priv->registry != NULL) {
1544 g_object_unref (priv->registry);
1545 priv->registry = NULL;
1546 }
1547
1548 if (priv->model != NULL) {
1549 g_signal_handlers_disconnect_by_func (
1550 priv->model, view_progress_cb, object);
1551 g_signal_handlers_disconnect_by_func (
1552 priv->model, view_complete_cb, object);
1553 g_object_unref (priv->model);
1554 priv->model = NULL;
1555 }
1556
1557 for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
1558 if (priv->views[ii] != NULL) {
1559 g_object_unref (priv->views[ii]);
1560 priv->views[ii] = NULL;
1561 }
1562 }
1563
1564 free_dn_queries (GNOME_CALENDAR (object));
1565
1566 if (priv->sexp) {
1567 g_free (priv->sexp);
1568 priv->sexp = NULL;
1569 }
1570
1571 if (priv->update_timeout) {
1572 g_source_remove (priv->update_timeout);
1573 priv->update_timeout = 0;
1574 }
1575
1576 if (priv->update_marcus_bains_line_timeout) {
1577 g_source_remove (priv->update_marcus_bains_line_timeout);
1578 priv->update_marcus_bains_line_timeout = 0;
1579 }
1580
1581 if (priv->cancellable) {
1582 g_cancellable_cancel (priv->cancellable);
1583 g_object_unref (priv->cancellable);
1584 priv->cancellable = NULL;
1585 }
1586
1587 /* Chain up to parent's dispose() method. */
1588 G_OBJECT_CLASS (gnome_calendar_parent_class)->dispose (object);
1589 }
1590
1591 static void
1592 gnome_calendar_finalize (GObject *object)
1593 {
1594 GnomeCalendarPrivate *priv;
1595
1596 priv = GNOME_CALENDAR_GET_PRIVATE (object);
1597
1598 g_mutex_free (priv->todo_update_lock);
1599 g_mutex_free (priv->dn_query_lock);
1600
1601 /* Chain up to parent's finalize() method. */
1602 G_OBJECT_CLASS (gnome_calendar_parent_class)->finalize (object);
1603 }
1604
1605 static void
1606 notify_selected_time_changed (GnomeCalendar *gcal)
1607 {
1608 GnomeCalendarPrivate *priv;
1609 gint i;
1610
1611 priv = gcal->priv;
1612 for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) {
1613 g_signal_emit_by_name (priv->views[i], "selected_time_changed");
1614 }
1615 }
1616
1617 static void
1618 gnome_calendar_goto_date (GnomeCalendar *gcal,
1619 GnomeCalendarGotoDateType goto_date)
1620 {
1621 ECalModel *model;
1622 time_t new_time = 0;
1623 gint week_start_day;
1624 gboolean need_updating = FALSE;
1625 icaltimezone *timezone;
1626
1627 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1628
1629 model = gnome_calendar_get_model (gcal);
1630 week_start_day = e_cal_model_get_week_start_day (model);
1631 timezone = e_cal_model_get_timezone (model);
1632
1633 switch (goto_date) {
1634 /* GNOME_CAL_GOTO_TODAY and GNOME_CAL_GOTO_DATE are
1635 * currently not used
1636 */
1637 case GNOME_CAL_GOTO_TODAY:
1638 break;
1639 case GNOME_CAL_GOTO_DATE:
1640 break;
1641 case GNOME_CAL_GOTO_FIRST_DAY_OF_MONTH:
1642 new_time = time_month_begin_with_zone (
1643 gcal->priv->base_view_time, timezone);
1644 need_updating = TRUE;
1645 break;
1646 case GNOME_CAL_GOTO_LAST_DAY_OF_MONTH:
1647 new_time = time_add_month_with_zone (
1648 gcal->priv->base_view_time, 1, timezone);
1649 new_time = time_month_begin_with_zone (new_time, timezone);
1650 new_time = time_add_day_with_zone (new_time, -1, timezone);
1651 need_updating = TRUE;
1652 break;
1653 case GNOME_CAL_GOTO_FIRST_DAY_OF_WEEK:
1654 new_time = time_week_begin_with_zone (
1655 gcal->priv->base_view_time, week_start_day, timezone);
1656 need_updating = TRUE;
1657 break;
1658 case GNOME_CAL_GOTO_LAST_DAY_OF_WEEK:
1659 new_time = time_week_begin_with_zone (
1660 gcal->priv->base_view_time, week_start_day, timezone);
1661 if (gcal->priv->current_view_type == GNOME_CAL_DAY_VIEW ||
1662 gcal->priv->current_view_type == GNOME_CAL_WORK_WEEK_VIEW) {
1663 /* FIXME Shouldn't hard code work week end */
1664 /* goto Friday of this week */
1665 new_time = time_add_day_with_zone (new_time, 4, timezone);
1666 } else {
1667 /* goto Sunday of this week */
1668 /* FIXME Shouldn't hard code week end */
1669 new_time = time_add_day_with_zone (new_time, 6, timezone);
1670 }
1671 need_updating = TRUE;
1672 break;
1673 case GNOME_CAL_GOTO_SAME_DAY_OF_PREVIOUS_WEEK:
1674 new_time = time_add_week_with_zone (
1675 gcal->priv->base_view_time, -1, timezone);
1676 need_updating = TRUE;
1677 break;
1678 case GNOME_CAL_GOTO_SAME_DAY_OF_NEXT_WEEK:
1679 new_time = time_add_week_with_zone (
1680 gcal->priv->base_view_time, 1, timezone);
1681 need_updating = TRUE;
1682 break;
1683 default:
1684 break;
1685 }
1686
1687 if (need_updating) {
1688 gnome_calendar_set_selected_time_range (gcal, new_time);
1689 notify_selected_time_changed (gcal);
1690 }
1691 }
1692
1693 void
1694 gnome_calendar_goto (GnomeCalendar *gcal,
1695 time_t new_time)
1696 {
1697 GnomeCalendarPrivate *priv;
1698 gint i;
1699
1700 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1701 g_return_if_fail (new_time != -1);
1702
1703 priv = gcal->priv;
1704
1705 gnome_calendar_set_selected_time_range (gcal, new_time);
1706
1707 for (i = 0; i < GNOME_CAL_LAST_VIEW; i++)
1708 e_calendar_view_set_selected_time_range (
1709 priv->views[i], new_time, new_time);
1710 }
1711
1712 void
1713 gnome_calendar_update_view_times (GnomeCalendar *gcal,
1714 time_t start_time)
1715 {
1716 GnomeCalendarPrivate *priv;
1717 ECalModel *model;
1718 time_t real_start_time = start_time;
1719 time_t end_time, select_time = 0;
1720
1721 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1722
1723 priv = gcal->priv;
1724
1725 priv->base_view_time = start_time;
1726
1727 model = gnome_calendar_get_model (gcal);
1728
1729 get_times_for_views (
1730 gcal, priv->current_view_type,
1731 &real_start_time, &end_time, &select_time);
1732
1733 if (priv->current_view_type == GNOME_CAL_LIST_VIEW &&
1734 !priv->lview_select_daten_range)
1735 return;
1736
1737 e_cal_model_set_time_range (model, real_start_time, end_time);
(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)
1738
1739 if (select_time != 0 && select_time >= real_start_time && select_time <= end_time)
1740 e_calendar_view_set_selected_time_range (
1741 priv->views[priv->current_view_type],
1742 select_time, select_time);
1743 }
1744
1745 static void
1746 gnome_calendar_direction (GnomeCalendar *gcal,
1747 gint direction)
1748 {
1749 ECalModel *model;
1750 icaltimezone *timezone;
1751
1752 model = gnome_calendar_get_model (gcal);
1753 timezone = e_cal_model_get_timezone (model);
1754
1755 switch (gnome_calendar_get_view (gcal)) {
1756 case GNOME_CAL_DAY_VIEW:
1757 gcal->priv->base_view_time = time_add_day_with_zone (
1758 gcal->priv->base_view_time, direction, timezone);
1759 break;
1760 case GNOME_CAL_WORK_WEEK_VIEW:
1761 case GNOME_CAL_WEEK_VIEW:
1762 gcal->priv->base_view_time = time_add_week_with_zone (
1763 gcal->priv->base_view_time, direction, timezone);
1764 break;
1765 case GNOME_CAL_MONTH_VIEW:
1766 case GNOME_CAL_LIST_VIEW:
1767 gcal->priv->base_view_time = time_add_month_with_zone (
1768 gcal->priv->base_view_time, direction, timezone);
1769 break;
1770 default:
1771 g_return_if_reached ();
1772 }
1773
1774 gnome_calendar_set_selected_time_range (
1775 gcal, gcal->priv->base_view_time);
1776 }
1777
1778 void
1779 gnome_calendar_next (GnomeCalendar *gcal)
1780 {
1781 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1782
1783 gnome_calendar_direction (gcal, 1);
1784 }
1785
1786 void
1787 gnome_calendar_previous (GnomeCalendar *gcal)
1788 {
1789 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1790
1791 gnome_calendar_direction (gcal, -1);
1792 }
1793
1794 void
1795 gnome_calendar_dayjump (GnomeCalendar *gcal,
1796 time_t time)
1797 {
1798 ECalModel *model;
1799 icaltimezone *timezone;
1800
1801 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1802
1803 model = gnome_calendar_get_model (gcal);
1804 timezone = e_cal_model_get_timezone (model);
1805
1806 gcal->priv->base_view_time =
1807 time_day_begin_with_zone (time, timezone);
1808
1809 gnome_calendar_update_view_times (gcal, gcal->priv->base_view_time);
1810 gnome_calendar_set_view (gcal, GNOME_CAL_DAY_VIEW);
1811 }
1812
1813 void
1814 gnome_calendar_goto_today (GnomeCalendar *gcal)
1815 {
1816 GnomeCalendarViewType view_type;
1817 ECalendarView *view;
1818
1819 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1820
1821 view_type = gnome_calendar_get_view (gcal);
1822 view = gnome_calendar_get_calendar_view (gcal, view_type);
1823
1824 gnome_calendar_goto (gcal, time (NULL));
1825 gtk_widget_grab_focus (GTK_WIDGET (view));
1826 }
1827
1828 /**
1829 * gnome_calendar_get_view:
1830 * @gcal: A calendar.
1831 *
1832 * Queries the type of the view that is being shown in a calendar.
1833 *
1834 * Return value: Type of the view that is currently shown.
1835 **/
1836 GnomeCalendarViewType
1837 gnome_calendar_get_view (GnomeCalendar *gcal)
1838 {
1839 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), GNOME_CAL_DAY_VIEW);
1840
1841 return gcal->priv->current_view_type;
1842 }
1843
1844 /**
1845 * gnome_calendar_set_view:
1846 * @gcal: A calendar.
1847 * @view_type: Type of view to show.
1848 *
1849 * Sets the view that should be shown in a calendar. If @reset_range is true,
1850 * this function will automatically set the number of days or weeks shown in
1851 * the view; otherwise the last configuration will be kept.
1852 **/
1853 void
1854 gnome_calendar_set_view (GnomeCalendar *gcal,
1855 GnomeCalendarViewType view_type)
1856 {
1857 ECalendarView *calendar_view;
1858 gint ii;
1859
1860 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1861
1862 if (gcal->priv->current_view_type == view_type &&
1863 E_CALENDAR_VIEW (gcal->priv->views[view_type])->in_focus)
1864 return;
1865
1866 gcal->priv->current_view_type = view_type;
1867 gnome_calendar_set_range_selected (gcal, FALSE);
1868
1869 E_CALENDAR_VIEW (gcal->priv->views[view_type])->in_focus = TRUE;
1870 for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
1871 if (ii == view_type)
1872 continue;
1873 E_CALENDAR_VIEW (gcal->priv->views[ii])->in_focus = FALSE;
1874 }
1875
1876 calendar_view = gnome_calendar_get_calendar_view (gcal, view_type);
1877 gtk_widget_grab_focus (GTK_WIDGET (calendar_view));
1878
1879 g_object_notify (G_OBJECT (gcal), "view");
1880 }
1881
1882 void
1883 gnome_calendar_display_view (GnomeCalendar *gcal,
1884 GnomeCalendarViewType view_type)
1885 {
1886 ECalendarView *view;
1887 gboolean preserve_day;
1888 gboolean range_selected;
1889 time_t start_time;
1890
1891 view = gnome_calendar_get_calendar_view (gcal, view_type);
1892
1893 /* Set the view without changing the selection or updating the date
1894 * navigator. If a range of dates isn't selected, also reset the
1895 * number of days/weeks shown to the default (i.e. 1 day for the
1896 * day view or 6 weeks for the month view). */
1897
1898 preserve_day = FALSE;
1899
1900 switch (view_type) {
1901 case GNOME_CAL_DAY_VIEW:
1902 if (!gnome_calendar_get_range_selected (gcal))
1903 e_day_view_set_days_shown (E_DAY_VIEW (view), 1);
1904
1905 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator));
1906 break;
1907
1908 case GNOME_CAL_WORK_WEEK_VIEW:
1909 preserve_day = TRUE;
1910 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator));
1911 break;
1912
1913 case GNOME_CAL_WEEK_VIEW:
1914 preserve_day = TRUE;
1915 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator));
1916 break;
1917
1918 case GNOME_CAL_MONTH_VIEW:
1919 if (!gnome_calendar_get_range_selected (gcal))
1920 e_week_view_set_weeks_shown (E_WEEK_VIEW (view), 6);
1921
1922 preserve_day = TRUE;
1923 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator));
1924 break;
1925
1926 case GNOME_CAL_LIST_VIEW:
1927 if (!gcal->priv->lview_select_daten_range)
1928 gtk_widget_hide (GTK_WIDGET (gcal->priv->date_navigator));
1929 else
1930 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator));
1931 break;
1932
1933 default:
1934 g_return_if_reached ();
1935 }
1936
1937 range_selected = gnome_calendar_get_range_selected (gcal);
1938 gnome_calendar_set_view (gcal, view_type);
1939 gnome_calendar_set_range_selected (gcal, range_selected);
1940
1941 /* For the week & month views we want the selection in the date
1942 * navigator to be rounded to the nearest week when the arrow buttons
1943 * are pressed to move to the previous/next month. */
1944 g_object_set (
1945 gcal->priv->date_navigator->calitem,
1946 "preserve_day_when_moving", preserve_day, NULL);
1947
1948 /* keep week days selected as before for a work week view */
1949 g_object_set (
1950 gcal->priv->date_navigator->calitem,
1951 "keep_wdays_on_weeknum_click",
1952 view_type == GNOME_CAL_WORK_WEEK_VIEW,
1953 NULL);
1954
1955 if (!gcal->priv->base_view_time)
1956 start_time = time (NULL);
1957 else
1958 start_time = gcal->priv->base_view_time;
1959
1960 gnome_calendar_set_selected_time_range (gcal, start_time);
1961
1962 }
1963
1964 GtkWidget *
1965 gnome_calendar_new (ESourceRegistry *registry)
1966 {
1967 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
1968
1969 return g_object_new (
1970 GNOME_TYPE_CALENDAR,
1971 "registry", registry, NULL);
1972 }
1973
1974 ESourceRegistry *
1975 gnome_calendar_get_registry (GnomeCalendar *gcal)
1976 {
1977 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
1978
1979 return gcal->priv->registry;
1980 }
1981
1982 ECalendar *
1983 gnome_calendar_get_date_navigator (GnomeCalendar *gcal)
1984 {
1985 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
1986
1987 return gcal->priv->date_navigator;
1988 }
1989
1990 void
1991 gnome_calendar_set_date_navigator (GnomeCalendar *gcal,
1992 ECalendar *date_navigator)
1993 {
1994 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1995
1996 if (gcal->priv->date_navigator == date_navigator)
1997 return;
1998
1999 if (date_navigator != NULL) {
2000 g_return_if_fail (E_IS_CALENDAR (date_navigator));
2001 g_object_ref (date_navigator);
2002 }
2003
2004 if (gcal->priv->date_navigator != NULL)
2005 g_object_unref (gcal->priv->date_navigator);
2006
2007 gcal->priv->date_navigator = date_navigator;
2008
2009 /* Update the new date navigator */
2010 gnome_calendar_update_date_navigator (gcal);
2011
2012 g_object_notify (G_OBJECT (gcal), "date-navigator");
2013 }
2014
2015 GtkWidget *
2016 gnome_calendar_get_memo_table (GnomeCalendar *gcal)
2017 {
2018 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
2019
2020 return gcal->priv->memo_table;
2021 }
2022
2023 void
2024 gnome_calendar_set_memo_table (GnomeCalendar *gcal,
2025 GtkWidget *memo_table)
2026 {
2027 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
2028
2029 if (gcal->priv->memo_table == memo_table)
2030 return;
2031
2032 if (memo_table != NULL) {
2033 g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
2034 g_object_ref (memo_table);
2035 }
2036
2037 if (gcal->priv->memo_table != NULL)
2038 g_object_unref (gcal->priv->memo_table);
2039
2040 gcal->priv->memo_table = memo_table;
2041
2042 g_object_notify (G_OBJECT (gcal), "memo-table");
2043 }
2044
2045 GtkWidget *
2046 gnome_calendar_get_task_table (GnomeCalendar *gcal)
2047 {
2048 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
2049
2050 return gcal->priv->task_table;
2051 }
2052
2053 void
2054 gnome_calendar_set_task_table (GnomeCalendar *gcal,
2055 GtkWidget *task_table)
2056 {
2057 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
2058
2059 if (gcal->priv->task_table == task_table)
2060 return;
2061
2062 if (task_table != NULL) {
2063 g_return_if_fail (E_IS_TASK_TABLE (task_table));
2064 g_object_ref (task_table);
2065 }
2066
2067 if (gcal->priv->task_table != NULL)
2068 g_object_unref (gcal->priv->task_table);
2069
2070 gcal->priv->task_table = task_table;
2071
2072 g_object_notify (G_OBJECT (gcal), "task-table");
2073 }
2074
2075 /**
2076 * gnome_calendar_get_model:
2077 * @gcal: A calendar view.
2078 *
2079 * Queries the calendar model object that a calendar view is using.
2080 *
2081 * Return value: A calendar client interface object.
2082 **/
2083 ECalModel *
2084 gnome_calendar_get_model (GnomeCalendar *gcal)
2085 {
2086 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
2087
2088 return gcal->priv->model;
2089 }
2090
2091 gboolean
2092 gnome_calendar_get_range_selected (GnomeCalendar *gcal)
2093 {
2094 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), FALSE);
2095
2096 return gcal->priv->range_selected;
2097 }
2098
2099 void
2100 gnome_calendar_set_range_selected (GnomeCalendar *gcal,
2101 gboolean range_selected)
2102 {
2103 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
2104
2105 gcal->priv->range_selected = range_selected;
2106 }
2107
2108 void
2109 gnome_calendar_set_selected_time_range (GnomeCalendar *gcal,
2110 time_t start_time)
2111 {
2112 gnome_calendar_update_view_times (gcal, start_time);
2113 gnome_calendar_update_date_navigator (gcal);
2114 gnome_calendar_notify_dates_shown_changed (gcal);
2115 }
2116
2117 /**
2118 * gnome_calendar_new_task:
2119 * @gcal: An Evolution calendar.
2120 * @dtstart: Start time of the task, in same timezone as model.
2121 * @dtend: End time of the task, in same timezone as model.
2122 *
2123 * Opens a task editor dialog for a new task. dtstart or dtend can be NULL.
2124 **/
2125 #if 0 /* KILL-BONOBO */
2126 void
2127 gnome_calendar_new_task (GnomeCalendar *gcal,
2128 time_t *dtstart,
2129 time_t *dtend)
2130 {
2131 GnomeCalendarPrivate *priv;
2132 ECal *ecal;
2133 ECalModel *model;
2134 CompEditor *editor;
2135 ECalComponent *comp;
2136 icalcomponent *icalcomp;
2137 const gchar *category;
2138 guint32 flags = 0;
2139 ECalComponentDateTime dt;
2140 struct icaltimetype itt;
2141
2142 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
2143
2144 priv = gcal->priv;
2145 model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo));
2146 ecal = e_cal_model_get_default_client (model);
2147 if (!ecal)
2148 return;
2149
2150 flags |= COMP_EDITOR_NEW_ITEM;
2151 editor = task_editor_new (ecal, flags);
2152
2153 icalcomp = e_cal_model_create_component_with_defaults (model, FALSE);
2154 comp = e_cal_component_new ();
2155 e_cal_component_set_icalcomponent (comp, icalcomp);
2156
2157 dt.value = &itt;
2158 dt.tzid = icaltimezone_get_tzid (e_cal_model_get_timezone (model));
2159
2160 if (dtstart) {
2161 itt = icaltime_from_timet_with_zone (
2162 *dtstart, FALSE, e_cal_model_get_timezone (model));
2163 e_cal_component_set_dtstart (comp, &dt);
2164 }
2165
2166 if (dtend) {
2167 itt = icaltime_from_timet_with_zone (
2168 *dtend, FALSE, e_cal_model_get_timezone (model));
2169 e_cal_component_set_due (comp, &dt); /* task uses 'due' not 'dtend' */
2170 }
2171
2172 if (dtstart || dtend)
2173 e_cal_component_commit_sequence (comp);
2174
2175 comp_editor_edit_comp (editor, comp);
2176 g_object_unref (comp);
2177
2178 gtk_window_present (GTK_WINDOW (editor));
2179 }
2180 #endif
2181
2182 /* Returns the selected time range for the current view. Note that this may be
2183 * different from the fields in the GnomeCalendar, since the view may clip
2184 * this or choose a more appropriate time. */
2185 void
2186 gnome_calendar_get_current_time_range (GnomeCalendar *gcal,
2187 time_t *start_time,
2188 time_t *end_time)
2189 {
2190 GnomeCalendarViewType view_type;
2191 ECalendarView *view;
2192
2193 view_type = gnome_calendar_get_view (gcal);
2194 view = gnome_calendar_get_calendar_view (gcal, view_type);
2195
2196 e_calendar_view_get_selected_time_range (view, start_time, end_time);
2197 }
2198
2199 /* This updates the month shown and the days selected in the calendar, if
2200 * necessary. */
2201 static void
2202 gnome_calendar_update_date_navigator (GnomeCalendar *gcal)
2203 {
2204 GnomeCalendarPrivate *priv;
2205 ECalModel *model;
2206 time_t start, end;
2207 gint week_start_day;
2208 GDate start_date, end_date;
2209 icaltimezone *timezone;
2210
2211 priv = gcal->priv;
2212
2213 /* If the ECalendar is not yet set, we just return. */
2214 if (priv->date_navigator == NULL)
2215 return;
2216
2217 /* If the ECalendar isn't visible, we just return. */
2218 if (!gtk_widget_get_visible (GTK_WIDGET (priv->date_navigator)))
2219 return;
2220
2221 if (priv->current_view_type == GNOME_CAL_LIST_VIEW &&
2222 !priv->lview_select_daten_range)
2223 return;
2224
2225 model = gnome_calendar_get_model (gcal);
2226 timezone = e_cal_model_get_timezone (model);
2227 week_start_day = e_cal_model_get_week_start_day (model);
2228 e_cal_model_get_time_range (model, &start, &end);
2229
2230 time_to_gdate_with_zone (&start_date, start, timezone);
2231 if (priv->current_view_type == GNOME_CAL_MONTH_VIEW) {
2232 EWeekView *week_view = E_WEEK_VIEW (priv->views[priv->current_view_type]);
2233
2234 if (week_start_day == 0
2235 && (!week_view->multi_week_view || week_view->compress_weekend))
2236 g_date_add_days (&start_date, 1);
2237 }
2238 time_to_gdate_with_zone (&end_date, end, timezone);
2239 g_date_subtract_days (&end_date, 1);
2240
2241 e_calendar_item_set_selection (
2242 priv->date_navigator->calitem,
2243 &start_date, &end_date);
2244 }
2245
2246 void
2247 gnome_calendar_notify_dates_shown_changed (GnomeCalendar *gcal)
2248 {
2249 GnomeCalendarViewType view_type;
2250 ECalendarView *calendar_view;
2251 GnomeCalendarPrivate *priv;
2252 time_t start_time, end_time;
2253 gboolean has_time_range;
2254
2255 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
2256
2257 priv = gcal->priv;
2258
2259 view_type = gnome_calendar_get_view (gcal);
2260 calendar_view = gnome_calendar_get_calendar_view (gcal, view_type);
2261
2262 /* If no time range is set yet, just return. */
2263 has_time_range = e_calendar_view_get_visible_time_range (
2264 calendar_view, &start_time, &end_time);
2265 if (!has_time_range)
2266 return;
2267
2268 /* We check if the visible date range has changed, and only emit the
2269 * signal if it has. (This makes sure we only change the folder title
2270 * bar label in the shell when we need to.) */
2271 if (priv->visible_start != start_time
2272 || priv->visible_end != end_time) {
2273 priv->visible_start = start_time;
2274 priv->visible_end = end_time;
2275
2276 gtk_widget_queue_draw (GTK_WIDGET (calendar_view));
2277 g_signal_emit (gcal, signals[DATES_SHOWN_CHANGED], 0);
2278 }
2279 update_todo_view (gcal);
2280 }
2281
2282 /* Returns the number of selected events (0 or 1 at present). */
2283 gint
2284 gnome_calendar_get_num_events_selected (GnomeCalendar *gcal)
2285 {
2286 GnomeCalendarViewType view_type;
2287 ECalendarView *view;
2288 gint retval = 0;
2289
2290 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), 0);
2291
2292 view_type = gnome_calendar_get_view (gcal);
2293 view = gnome_calendar_get_calendar_view (gcal, view_type);
2294
2295 if (E_IS_DAY_VIEW (view))
2296 retval = e_day_view_get_num_events_selected (E_DAY_VIEW (view));
2297 else
2298 retval = e_week_view_get_num_events_selected (E_WEEK_VIEW (view));
2299
2300 return retval;
2301 }
2302
2303 struct purge_data {
2304 gboolean remove;
2305 time_t older_than;
2306 };
2307
2308 static gboolean
2309 check_instance_cb (ECalComponent *comp,
2310 time_t instance_start,
2311 time_t instance_end,
2312 gpointer data)
2313 {
2314 struct purge_data *pd = data;
2315
2316 if (instance_end >= pd->older_than)
2317 pd->remove = FALSE;
2318
2319 return pd->remove;
2320 }
2321
2322 void
2323 gnome_calendar_purge (GnomeCalendar *gcal,
2324 time_t older_than)
2325 {
2326 gchar *sexp, *start, *end;
2327 GList *clients, *l;
2328
2329 g_return_if_fail (GNOME_IS_CALENDAR (gcal));
2330
2331 start = isodate_from_time_t (0);
2332 end = isodate_from_time_t (older_than);
2333 sexp = g_strdup_printf (
2334 "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")",
2335 start, end, gcal_get_default_tzloc (gcal));
2336
2337 gcal_update_status_message (gcal, _("Purging"), -1);
2338
2339 /* FIXME Confirm expunge */
2340 clients = e_cal_model_get_client_list (gnome_calendar_get_model (gcal));
2341 for (l = clients; l != NULL; l = l->next) {
2342 ECalClient *client = l->data;
2343 GSList *objects, *m;
2344 GError *error = NULL;
2345
2346 if (e_client_is_readonly (E_CLIENT (client)))
2347 continue;
2348
2349 e_cal_client_get_object_list_sync (
2350 client, sexp, &objects, NULL, &error);
2351
2352 if (error != NULL) {
2353 g_warning (
2354 "%s: Could not get the objects: %s",
2355 G_STRFUNC, error->message);
2356 g_error_free (error);
2357 continue;
2358 }
2359
2360 for (m = objects; m; m = m->next) {
2361 gboolean remove = TRUE;
2362
2363 /* FIXME write occur-before and occur-after
2364 * sexp funcs so we don't have to use the max
2365 * gint */
2366 if (!e_cal_client_check_recurrences_no_master (client)) {
2367 struct purge_data pd;
2368
2369 pd.remove = TRUE;
2370 pd.older_than = older_than;
2371
2372 e_cal_client_generate_instances_for_object_sync (client, m->data,
2373 older_than, G_MAXINT32,
2374 check_instance_cb,
2375 &pd);
2376
2377 remove = pd.remove;
2378 }
2379
2380 /* FIXME Better error handling */
2381 if (remove) {
2382 const gchar *uid = icalcomponent_get_uid (m->data);
2383 GError *error = NULL;
2384
2385 if (e_cal_util_component_is_instance (m->data) ||
2386 e_cal_util_component_has_recurrences (m->data)) {
2387 gchar *rid = NULL;
2388 struct icaltimetype recur_id;
2389
2390 recur_id = icalcomponent_get_recurrenceid (m->data);
2391
2392 if (!icaltime_is_null_time (recur_id))
2393 rid = icaltime_as_ical_string_r (recur_id);
2394
2395 e_cal_client_remove_object_sync (
2396 client, uid, rid,
2397 CALOBJ_MOD_ALL, NULL, &error);
2398 g_free (rid);
2399 } else {
2400 e_cal_client_remove_object_sync (
2401 client, uid, NULL,
2402 CALOBJ_MOD_THIS, NULL, &error);
2403 }
2404
2405 if (error != NULL) {
2406 g_warning (
2407 "%s: Unable to purge events: %s",
2408 G_STRFUNC, error->message);
2409 g_error_free (error);
2410 }
2411 }
2412 }
2413
2414 g_slist_foreach (objects, (GFunc) icalcomponent_free, NULL);
2415 g_slist_free (objects);
2416 }
2417
2418 g_list_free (clients);
2419
2420 gcal_update_status_message (gcal, NULL, -1);
2421
2422 g_free (sexp);
2423 g_free (start);
2424 g_free (end);
2425
2426 }