evolution-3.6.4/calendar/gui/e-task-list-selector.c

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 }