No issues found
1 /*
2 *
3 * Evolution calendar - Utilities for tagging ECalendar widgets
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with the program; if not, see <http://www.gnu.org/licenses/>
17 *
18 *
19 * Authors:
20 * Damon Chaplin <damon@ximian.com>
21 * Federico Mena-Quintero <federico@ximian.com>
22 *
23 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
24 *
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include "shell/e-shell.h"
32 #include "shell/e-shell-settings.h"
33 #include "calendar-config.h"
34 #include "tag-calendar.h"
35
36 struct calendar_tag_closure {
37 ECalendarItem *calitem;
38 icaltimezone *zone;
39 time_t start_time;
40 time_t end_time;
41
42 gboolean skip_transparent_events;
43 gboolean recur_events_italic;
44 };
45
46 /* Clears all the tags in a calendar and fills a closure structure with the
47 * necessary information for iterating over occurrences. Returns FALSE if
48 * the calendar has no dates shown. */
49 static gboolean
50 prepare_tag (ECalendar *ecal,
51 struct calendar_tag_closure *closure,
52 icaltimezone *zone,
53 gboolean clear_first)
54 {
55 gint start_year, start_month, start_day;
56 gint end_year, end_month, end_day;
57 struct icaltimetype start_tt = icaltime_null_time ();
58 struct icaltimetype end_tt = icaltime_null_time ();
59
60 if (clear_first)
61 e_calendar_item_clear_marks (ecal->calitem);
62
63 if (!e_calendar_item_get_date_range (
64 ecal->calitem,
65 &start_year, &start_month, &start_day,
66 &end_year, &end_month, &end_day))
67 return FALSE;
68
69 start_tt.year = start_year;
70 start_tt.month = start_month + 1;
71 start_tt.day = start_day;
72
73 end_tt.year = end_year;
74 end_tt.month = end_month + 1;
75 end_tt.day = end_day;
76
77 icaltime_adjust (&end_tt, 1, 0, 0, 0);
78
79 closure->calitem = ecal->calitem;
80
81 if (zone != NULL)
82 closure->zone = zone;
83 else
84 closure->zone = calendar_config_get_icaltimezone ();
85
86 closure->start_time =
87 icaltime_as_timet_with_zone (start_tt, closure->zone);
88 closure->end_time =
89 icaltime_as_timet_with_zone (end_tt, closure->zone);
90
91 return TRUE;
92 }
93
94 /* Marks the specified range in an ECalendar;
95 * called from e_cal_generate_instances() */
96 static gboolean
97 tag_calendar_cb (ECalComponent *comp,
98 time_t istart,
99 time_t iend,
100 struct calendar_tag_closure *closure)
101 {
102 struct icaltimetype start_tt, end_tt;
103 ECalComponentTransparency transparency;
104 guint8 style = 0;
105
106 /* If we are skipping TRANSPARENT events, return if the event is
107 * transparent. */
108 e_cal_component_get_transparency (comp, &transparency);
109 if (transparency == E_CAL_COMPONENT_TRANSP_TRANSPARENT) {
110 if (closure->skip_transparent_events)
111 return TRUE;
112
113 style = E_CALENDAR_ITEM_MARK_ITALIC;
114 } else if (closure->recur_events_italic && e_cal_component_is_instance (comp)) {
115 style = E_CALENDAR_ITEM_MARK_ITALIC;
116 } else {
117 style = E_CALENDAR_ITEM_MARK_BOLD;
118 }
119
120 start_tt = icaltime_from_timet_with_zone (istart, FALSE, closure->zone);
121 end_tt = icaltime_from_timet_with_zone (iend - 1, FALSE, closure->zone);
122
123 e_calendar_item_mark_days (
124 closure->calitem,
125 start_tt.year, start_tt.month - 1, start_tt.day,
126 end_tt.year, end_tt.month - 1, end_tt.day,
127 style, TRUE);
128
129 return TRUE;
130 }
131
132 static gboolean
133 get_recur_events_italic (void)
134 {
135 EShell *shell;
136 EShellSettings *shell_settings;
137
138 shell = e_shell_get_default ();
139 shell_settings = e_shell_get_shell_settings (shell);
140
141 return e_shell_settings_get_boolean (
142 shell_settings, "cal-recur-events-italic");
143 }
144
145 /**
146 * tag_calendar_by_client:
147 * @ecal: Calendar widget to tag.
148 * @client: A calendar client object.
149 * @cancellable: A #GCancellable; can be %NULL
150 *
151 * Tags an #ECalendar widget with the events that occur in its current time
152 * range. The occurrences are extracted from the specified calendar @client.
153 **/
154 void
155 tag_calendar_by_client (ECalendar *ecal,
156 ECalClient *client,
157 GCancellable *cancellable)
158 {
159 struct calendar_tag_closure *closure;
160
161 g_return_if_fail (E_IS_CALENDAR (ecal));
162 g_return_if_fail (E_IS_CAL_CLIENT (client));
163
164 /* If the ECalendar isn't visible, we just return. */
165 if (!gtk_widget_get_visible (GTK_WIDGET (ecal)))
166 return;
167
168 if (!e_client_is_opened (E_CLIENT (client)))
169 return;
170
171 closure = g_new0 (struct calendar_tag_closure, 1);
172
173 if (!prepare_tag (ecal, closure, NULL, TRUE)) {
174 g_free (closure);
175 return;
176 }
177
178 closure->skip_transparent_events = TRUE;
179 closure->recur_events_italic = get_recur_events_italic ();
180
181 e_cal_client_generate_instances (
182 client, closure->start_time, closure->end_time, cancellable,
183 (ECalRecurInstanceFn) tag_calendar_cb,
184 closure, (GDestroyNotify) g_free);
185 }
186
187 /* Resolves TZIDs for the recurrence generator, for when the comp is not on
188 * the server. We need to try to use builtin timezones first, as they may not
189 * be added to the server yet. */
190 static icaltimezone *
191 resolve_tzid_cb (const gchar *tzid,
192 ECalClient *client)
193 {
194 icaltimezone *zone = NULL;
195
196 /* Try to find the builtin timezone first. */
197 zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
198
199 if (!zone && tzid) {
200 /* FIXME: Handle errors. */
201 GError *error = NULL;
202
203 e_cal_client_get_timezone_sync (
204 client, tzid, &zone, NULL, &error);
205
206 if (error != NULL) {
207 g_warning (
208 "%s: Failed to get timezone '%s': %s",
209 G_STRFUNC, tzid, error->message);
210 g_error_free (error);
211 }
212 }
213
214 return zone;
215 }
216
217 /**
218 * tag_calendar_by_comp:
219 * @ecal: Calendar widget to tag.
220 * @comp: A calendar component object.
221 * @clear_first: Whether the #ECalendar should be cleared of any marks first.
222 *
223 * Tags an #ECalendar widget with any occurrences of a specific calendar
224 * component that occur within the calendar's current time range.
225 * Note that TRANSPARENT events are also tagged here.
226 *
227 * If comp_is_on_server is FALSE, it will try to resolve TZIDs using builtin
228 * timezones first, before querying the server, since the timezones may not
229 * have been added to the calendar on the server yet.
230 **/
231 void
232 tag_calendar_by_comp (ECalendar *ecal,
233 ECalComponent *comp,
234 ECalClient *client,
235 icaltimezone *display_zone,
236 gboolean clear_first,
237 gboolean comp_is_on_server,
238 gboolean can_recur_events_italic,
239 GCancellable *cancellable)
240 {
241 struct calendar_tag_closure closure;
242
243 g_return_if_fail (E_IS_CALENDAR (ecal));
244 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
245
246 /* If the ECalendar isn't visible, we just return. */
247 if (!gtk_widget_get_visible (GTK_WIDGET (ecal)))
248 return;
249
250 if (!prepare_tag (ecal, &closure, display_zone, clear_first))
251 return;
252
253 closure.skip_transparent_events = FALSE;
254 closure.recur_events_italic =
255 can_recur_events_italic && get_recur_events_italic ();
256
257 if (comp_is_on_server) {
258 struct calendar_tag_closure *alloced_closure;
259
260 alloced_closure = g_new0 (struct calendar_tag_closure, 1);
261
262 *alloced_closure = closure;
263
264 e_cal_client_generate_instances_for_object (
265 client, e_cal_component_get_icalcomponent (comp),
266 closure.start_time, closure.end_time, cancellable,
267 (ECalRecurInstanceFn) tag_calendar_cb,
268 alloced_closure, (GDestroyNotify) g_free);
269 } else
270 e_cal_recur_generate_instances (
271 comp, closure.start_time, closure.end_time,
272 (ECalRecurInstanceFn) tag_calendar_cb,
273 &closure,
274 (ECalRecurResolveTimezoneFn) resolve_tzid_cb,
275 client, closure.zone);
276 }