No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* e-task-list-selector.c
3 *
4 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
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 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include <config.h>
22
23 #include "e-task-list-selector.h"
24
25 #include <string.h>
26 #include <libecal/libecal.h>
27
28 #include "e-util/e-selection.h"
29 #include "calendar/gui/comp-util.h"
30
31 #define E_TASK_LIST_SELECTOR_GET_PRIVATE(obj) \
32 (G_TYPE_INSTANCE_GET_PRIVATE \
33 ((obj), E_TYPE_TASK_LIST_SELECTOR, ETaskListSelectorPrivate))
34
35 struct _ETaskListSelectorPrivate {
36 gint dummy_value;
37 };
38
39 G_DEFINE_TYPE (
40 ETaskListSelector,
41 e_task_list_selector,
42 E_TYPE_SOURCE_SELECTOR)
43
44 static gboolean
45 task_list_selector_update_single_object (ECalClient *client,
46 icalcomponent *icalcomp)
47 {
48 gchar *uid = NULL;
49 icalcomponent *tmp_icalcomp;
50
51 uid = (gchar *) icalcomponent_get_uid (icalcomp);
52
53 if (e_cal_client_get_object_sync (client, uid, NULL, &tmp_icalcomp, NULL, NULL)) {
54 icalcomponent_free (tmp_icalcomp);
55
56 return e_cal_client_modify_object_sync (
57 client, icalcomp, CALOBJ_MOD_ALL, NULL, NULL);
58 }
59
60 if (!e_cal_client_create_object_sync (client, icalcomp, &uid, NULL, NULL))
61 return FALSE;
62
63 if (uid)
64 icalcomponent_set_uid (icalcomp, uid);
65
66 g_free (uid);
67
68 return TRUE;
69 }
70
71 static gboolean
72 task_list_selector_update_objects (ECalClient *client,
73 icalcomponent *icalcomp)
74 {
75 icalcomponent *subcomp;
76 icalcomponent_kind kind;
77
78 kind = icalcomponent_isa (icalcomp);
79 if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT)
80 return task_list_selector_update_single_object (
81 client, icalcomp);
82 else if (kind != ICAL_VCALENDAR_COMPONENT)
83 return FALSE;
84
85 subcomp = icalcomponent_get_first_component (
86 icalcomp, ICAL_ANY_COMPONENT);
87 while (subcomp != NULL) {
88 gboolean success;
89
90 kind = icalcomponent_isa (subcomp);
91 if (kind == ICAL_VTIMEZONE_COMPONENT) {
92 icaltimezone *zone;
93 GError *error = NULL;
94
95 zone = icaltimezone_new ();
96 icaltimezone_set_component (zone, subcomp);
97
98 e_cal_client_add_timezone_sync (client, zone, NULL, &error);
99 icaltimezone_free (zone, 1);
100 if (error != NULL) {
101 g_warning (
102 "%s: Failed to add timezone: %s",
103 G_STRFUNC, error->message);
104 g_error_free (error);
105 return FALSE;
106 }
107 } else if (kind == ICAL_VTODO_COMPONENT ||
108 kind == ICAL_VEVENT_COMPONENT) {
109 success = task_list_selector_update_single_object (
110 client, subcomp);
111 if (!success)
112 return FALSE;
113 }
114
115 subcomp = icalcomponent_get_next_component (
116 icalcomp, ICAL_ANY_COMPONENT);
117 }
118
119 return TRUE;
120 }
121
122 static void
123 client_opened_cb (GObject *source_object,
124 GAsyncResult *result,
125 gpointer user_data)
126 {
127 ESource *source = E_SOURCE (source_object);
128 EClient *client = NULL;
129 gchar *uid = user_data;
130 GError *error = NULL;
131
132 g_return_if_fail (uid != NULL);
133
134 e_client_utils_open_new_finish (source, result, &client, &error);
135
136 if (error != NULL) {
137 g_warn_if_fail (client == NULL);
138 g_warning (
139 "%s: Failed to open task list: %s",
140 G_STRFUNC, error->message);
141 g_error_free (error);
142 goto exit;
143 }
144
145 g_return_if_fail (E_IS_CLIENT (client));
146
147 if (!e_client_is_readonly (client))
148 e_cal_client_remove_object_sync (
149 E_CAL_CLIENT (client), uid, NULL,
150 CALOBJ_MOD_THIS, NULL, NULL);
151
152 g_object_unref (client);
153
154 exit:
155 g_free (uid);
156 }
157
158 static gboolean
159 task_list_selector_process_data (ESourceSelector *selector,
160 ECalClient *client,
161 const gchar *source_uid,
162 icalcomponent *icalcomp,
163 GdkDragAction action)
164 {
165 ESource *source;
166 ESourceRegistry *registry;
167 icalcomponent *tmp_icalcomp = NULL;
168 const gchar *uid;
169 gchar *old_uid = NULL;
170 gboolean success = FALSE;
171 GError *error = NULL;
172
173 /* FIXME Deal with GDK_ACTION_ASK. */
174 if (action == GDK_ACTION_COPY) {
175 old_uid = g_strdup (icalcomponent_get_uid (icalcomp));
176 uid = e_cal_component_gen_uid ();
177 icalcomponent_set_uid (icalcomp, uid);
178 }
179
180 uid = icalcomponent_get_uid (icalcomp);
181 if (old_uid == NULL)
182 old_uid = g_strdup (uid);
183
184 if (e_cal_client_get_object_sync (client, uid, NULL, &tmp_icalcomp, NULL, &error)) {
185 icalcomponent_free (tmp_icalcomp);
186 success = TRUE;
187 goto exit;
188 }
189
190 if (error != NULL && !g_error_matches (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND)) {
191 g_message (
192 "Failed to search the object in destination "
193 "task list: %s", error->message);
194 g_error_free (error);
195 goto exit;
196 }
197
198 if (error)
199 g_error_free (error);
200 error = NULL;
201
202 success = task_list_selector_update_objects (client, icalcomp);
203
204 if (!success || action != GDK_ACTION_MOVE)
205 goto exit;
206
207 registry = e_source_selector_get_registry (selector);
208 source = e_source_registry_ref_source (registry, source_uid);
209
210 if (source != NULL) {
211 e_client_utils_open_new (
212 source, E_CLIENT_SOURCE_TYPE_MEMOS, TRUE, NULL,
213 client_opened_cb, g_strdup (old_uid));
214 g_object_unref (source);
215 }
216
217 exit:
218 g_free (old_uid);
219
220 return success;
221 }
222
223 struct DropData
224 {
225 ESourceSelector *selector;
226 GdkDragAction action;
227 GSList *list;
228 };
229
230 static void
231 client_opened_for_drop_cb (GObject *source_object,
232 GAsyncResult *result,
233 gpointer user_data)
234 {
235 ESource *source = E_SOURCE (source_object);
236 struct DropData *dd = user_data;
237 EClient *client = NULL;
238 ECalClient *cal_client;
239 GSList *iter;
240 GError *error = NULL;
241
242 g_return_if_fail (dd != NULL);
243
244 e_client_utils_open_new_finish (source, result, &client, &error);
245
246 if (error != NULL) {
247 g_warn_if_fail (client == NULL);
248 g_warning (
249 "%s: Failed to open task list: %s",
250 G_STRFUNC, error->message);
251 g_error_free (error);
252 goto exit;
253 }
254
255 g_return_if_fail (E_IS_CLIENT (client));
256
257 cal_client = E_CAL_CLIENT (client);
258
259 for (iter = dd->list; iter != NULL; iter = iter->next) {
260 gchar *source_uid = iter->data;
261 icalcomponent *icalcomp;
262 gchar *component_string;
263
264 /* Each string is "source_uid\ncomponent_string". */
265 component_string = strchr (source_uid, '\n');
266 if (component_string == NULL)
267 continue;
268
269 *component_string++ = '\0';
270 icalcomp = icalparser_parse_string (component_string);
271 if (icalcomp == NULL)
272 continue;
273
274 task_list_selector_process_data (
275 dd->selector, cal_client, source_uid,
276 icalcomp, dd->action);
277
278 icalcomponent_free (icalcomp);
279 }
280
281 g_object_unref (client);
282
283 exit:
284 g_slist_foreach (dd->list, (GFunc) g_free, NULL);
285 g_slist_free (dd->list);
286 g_object_unref (dd->selector);
287 g_free (dd);
288 }
289
290 static void
291 task_list_selector_constructed (GObject *object)
292 {
293 ESourceSelector *selector;
294 ESourceRegistry *registry;
295 ESource *source;
296
297 selector = E_SOURCE_SELECTOR (object);
298 registry = e_source_selector_get_registry (selector);
299 source = e_source_registry_ref_default_task_list (registry);
300 e_source_selector_set_primary_selection (selector, source);
301 g_object_unref (source);
302
303 /* Chain up to parent's constructed() method. */
304 G_OBJECT_CLASS (e_task_list_selector_parent_class)->
305 constructed (object);
306 }
307
308 static gboolean
309 task_list_selector_data_dropped (ESourceSelector *selector,
310 GtkSelectionData *selection_data,
311 ESource *destination,
312 GdkDragAction action,
313 guint info)
314 {
315 struct DropData *dd;
316
317 dd = g_new0 (struct DropData, 1);
318 dd->selector = g_object_ref (selector);
319 dd->action = action;
320 dd->list = cal_comp_selection_get_string_list (selection_data);
321
322 e_client_utils_open_new (
323 destination, E_CLIENT_SOURCE_TYPE_TASKS, TRUE, NULL,
324 client_opened_for_drop_cb, dd);
325
326 return TRUE;
327 }
328
329 static void
330 e_task_list_selector_class_init (ETaskListSelectorClass *class)
331 {
332 GObjectClass *object_class;
333 ESourceSelectorClass *source_selector_class;
334
335 g_type_class_add_private (class, sizeof (ETaskListSelectorPrivate));
336
337 object_class = G_OBJECT_CLASS (class);
338 object_class->constructed = task_list_selector_constructed;
339
340 source_selector_class = E_SOURCE_SELECTOR_CLASS (class);
341 source_selector_class->data_dropped = task_list_selector_data_dropped;
342 }
343
344 static void
345 e_task_list_selector_init (ETaskListSelector *selector)
346 {
347 selector->priv = E_TASK_LIST_SELECTOR_GET_PRIVATE (selector);
348
349 gtk_drag_dest_set (
350 GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL,
351 NULL, 0, GDK_ACTION_COPY | GDK_ACTION_MOVE);
352
353 e_drag_dest_add_calendar_targets (GTK_WIDGET (selector));
354 }
355
356 GtkWidget *
357 e_task_list_selector_new (ESourceRegistry *registry)
358 {
359 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
360
361 return g_object_new (
362 E_TYPE_TASK_LIST_SELECTOR,
363 "extension-name", E_SOURCE_EXTENSION_TASK_LIST,
364 "registry", registry, NULL);
365 }