nautilus-3.6.3/src/nautilus-view-dnd.c

No issues found

  1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
  2 
  3 /*
  4  * nautilus-view-dnd.c: DnD helpers for NautilusView
  5  *
  6  * Copyright (C) 1999, 2000  Free Software Foundaton
  7  * Copyright (C) 2000, 2001  Eazel, Inc.
  8  *
  9  * This program is free software; you can redistribute it and/or
 10  * modify it under the terms of the GNU General Public License as
 11  * published by the Free Software Foundation; either version 2 of the
 12  * License, or (at your option) any later version.
 13  *
 14  * This program is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17  * General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU General Public
 20  * License along with this program; if not, write to the
 21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 22  * Boston, MA 02111-1307, USA.
 23  *
 24  * Authors: Ettore Perazzoli
 25  * 	    Darin Adler <darin@bentspoon.com>
 26  * 	    John Sullivan <sullivan@eazel.com>
 27  *          Pavel Cisler <pavel@eazel.com>
 28  */
 29 
 30 #include <config.h>
 31 
 32 #include "nautilus-view-dnd.h"
 33 
 34 #include "nautilus-view.h"
 35 
 36 #include <eel/eel-stock-dialogs.h>
 37 #include <eel/eel-string.h>
 38 
 39 #include <glib/gi18n.h>
 40 
 41 #include <libnautilus-private/nautilus-clipboard.h>
 42 #include <libnautilus-private/nautilus-dnd.h>
 43 
 44 #define GET_ANCESTOR(obj) \
 45 	GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (obj), GTK_TYPE_WINDOW))
 46 
 47 static inline void
 48 view_widget_to_file_operation_position (NautilusView *view,
 49                                         GdkPoint *position)
 50 {
 51 	NautilusViewClass *class = NAUTILUS_VIEW_GET_CLASS (view);
 52 
 53 	if (class->widget_to_file_operation_position != NULL) {
 54 		class->widget_to_file_operation_position (view, position);
 55 	}
 56 }
 57 
 58 static void
 59 view_widget_to_file_operation_position_xy (NautilusView *view,
 60                                            int *x, int *y)
 61 {
 62 	GdkPoint position;
 63 
 64 	position.x = *x;
 65 	position.y = *y;
 66 	view_widget_to_file_operation_position (view, &position);
 67 	*x = position.x;
 68 	*y = position.y;
 69 }
 70 
 71 typedef struct {
 72 	NautilusView *view;
 73 	char *link_name;
 74 	char *target_uri;
 75 	char *url;
 76 	GdkPoint point;
 77 } NetscapeUrlDropLink;
 78 
 79 static void
 80 revert_slashes (char *string)
 81 {
 82 	while (*string != 0) {
 83 		if (*string == '/') {
 84 			*string = '\\';
 85 		}
 86 		string++;
 87 	}
 88 }
 89 
 90 static void
 91 handle_netscape_url_drop_link_cb (GObject *source_object,
 92 				  GAsyncResult *res,
 93 				  gpointer user_data)
 94 {
 95 	NetscapeUrlDropLink *data = user_data;
 96 	char *link_name = data->link_name;
 97 	char *link_display_name;
 98 	gint screen_num;
 99 	GFileInfo *info;
100 	char *icon_name = NULL;
101 	GdkScreen *screen;
102 
103 	info = g_file_query_info_finish (G_FILE (source_object),
104 					 res, NULL);
105 
106 	if (info != NULL) {
107 		GIcon *icon;
108 		const char * const *names;
109 
110 		icon = g_file_info_get_icon (info);
111 
112 		if (G_IS_THEMED_ICON (icon)) {
113 			names = g_themed_icon_get_names (G_THEMED_ICON (icon));
114 			icon_name = g_strdup (names[0]);
115 		}
116 	
117 		g_object_unref (info);
118 	}
119 
120 	if (icon_name == NULL) {
121 		icon_name = g_strdup ("text-html");
122 	}
123 
124 	link_display_name = g_strdup_printf (_("Link to %s"), link_name);
125 
126 	/* The filename can't contain slashes, strip em.
127 	   (the basename of http://foo/ is http://foo/) */
128 	revert_slashes (link_name);
129 
130 	screen = gtk_widget_get_screen (GTK_WIDGET (data->view));
131 	screen_num = gdk_screen_get_number (screen);
132 
133 	nautilus_link_local_create (data->target_uri,
134 				    link_name,
135 				    link_display_name,
136 				    icon_name,
137 				    data->url,
138 				    &data->point,
139 				    screen_num,
140 				    TRUE);
141 
142 	g_free (link_display_name);
143 	g_free (icon_name);
144 
145 	g_free (data->url);
146 	g_free (data->link_name);
147 	g_free (data->target_uri);
148 
149 	g_object_unref (data->view);
150 	g_slice_free (NetscapeUrlDropLink, data);
151 }
152 
153 void
154 nautilus_view_handle_netscape_url_drop (NautilusView  *view,
155                                         const char    *encoded_url,
156                                         const char    *target_uri,
157                                         GdkDragAction  action,
158                                         int            x,
159                                         int            y)
160 {
161 	char *url, *title;
162 	char *link_name;
163 	GArray *points;
164 	char **bits;
165 	GList *uri_list = NULL;
166 	GFile *f;
167 
168 	f = g_file_new_for_uri (target_uri);
169 
170 	if (!g_file_is_native (f)) {
171 		eel_show_warning_dialog (_("Drag and drop is not supported."),
172 					 _("Drag and drop is only supported on local file systems."),
173                                          GET_ANCESTOR (view));
174 		g_object_unref (f);
175 		return;
176 	}
177 
178 	g_object_unref (f);
179 
180 	/* _NETSCAPE_URL_ works like this: $URL\n$TITLE */
181 	bits = g_strsplit (encoded_url, "\n", 0);
182 	switch (g_strv_length (bits)) {
183 	case 0:
184 		g_strfreev (bits);
185 		return;
186 	case 1:
187 		url = bits[0];
188 		title = NULL;
189 		break;
190 	default:
191 		url = bits[0];
192 		title = bits[1];
193 	}
194 
195 	f = g_file_new_for_uri (url);
196 
197 	view_widget_to_file_operation_position_xy (view, &x, &y);
198 
199 	/* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE
200 	 * and we don't support combinations either. */
201 	if ((action != GDK_ACTION_DEFAULT) &&
202 	    (action != GDK_ACTION_COPY) &&
203 	    (action != GDK_ACTION_MOVE) &&
204 	    (action != GDK_ACTION_LINK)) {
205 		eel_show_warning_dialog (_("Drag and drop is not supported."),
206 					 _("An invalid drag type was used."),
207                                          GET_ANCESTOR (view));
208 		return;
209 	}
210 
211 	if (action == GDK_ACTION_LINK) {
212 		if (g_strcmp0 (title, NULL) == 0) {
213 			link_name = g_file_get_basename (f);
214 		} else {
215 			link_name = g_strdup (title);
216 		}
217 
218 		if (g_strcmp0 (link_name, NULL) != 0) {
219 			NetscapeUrlDropLink *data;
220 
221 			data = g_slice_new0 (NetscapeUrlDropLink);
222 			data->link_name = link_name;
223 			data->point.x = x;
224 			data->point.y = y;
225 			data->view = g_object_ref (view);
226 			data->target_uri = g_strdup (target_uri);
227 			data->url = g_strdup (url);
228 
229 			g_file_query_info_async (f,
230 						 G_FILE_ATTRIBUTE_STANDARD_ICON,
231 						 0, 0, NULL,
232 						 handle_netscape_url_drop_link_cb,
233 						 data);
234 		}
235 	} else {
236 		GdkPoint tmp_point = { 0, 0 };
237 
238 		/* pass in a 1-item array of icon positions, relative to x, y */
239 		points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
240 		g_array_append_val (points, tmp_point);
241 
242 		uri_list = g_list_append (uri_list, url);
243 
244 		nautilus_view_move_copy_items (view, uri_list, points,
245                                                target_uri,
246                                                action, x, y);
247 
248 		g_list_free (uri_list);
249 		g_array_free (points, TRUE);
250 	}
251 
252 	g_object_unref (f);
253 	g_strfreev (bits);
254 }
255 
256 void
257 nautilus_view_handle_uri_list_drop (NautilusView  *view,
258                                     const char    *item_uris,
259                                     const char    *target_uri,
260                                     GdkDragAction  action,
261                                     int            x,
262                                     int            y)
263 {
264 	gchar **uri_list;
265 	GList *real_uri_list = NULL;
266 	char *container_uri;
267 	int n_uris, i;
268 	GArray *points;
269 
270 	if (item_uris == NULL) {
271 		return;
272 	}
273 
274 	container_uri = NULL;
275 	if (target_uri == NULL) {
276 		container_uri = nautilus_view_get_backing_uri (view);
277 		g_assert (container_uri != NULL);
278 	}
279 
280 	if (action == GDK_ACTION_ASK) {
281 		action = nautilus_drag_drop_action_ask
282 			(GTK_WIDGET (view),
283 			 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
284 		if (action == 0) {
285 			g_free (container_uri);
286 			return;
287 		}
288 	}
289 
290 	/* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE
291 	 * and we don't support combinations either. */
292 	if ((action != GDK_ACTION_DEFAULT) &&
293 	    (action != GDK_ACTION_COPY) &&
294 	    (action != GDK_ACTION_MOVE) &&
295 	    (action != GDK_ACTION_LINK)) {
296 		eel_show_warning_dialog (_("Drag and drop is not supported."),
297 					 _("An invalid drag type was used."),
298                                          GET_ANCESTOR (view));
299 		g_free (container_uri);
300 		return;
301 	}
302 
303 	n_uris = 0;
304 	uri_list = g_uri_list_extract_uris (item_uris);
305 	for (i = 0; uri_list[i] != NULL; i++) {
306 		real_uri_list = g_list_append (real_uri_list, uri_list[i]);
307 		n_uris++;
308 	}
309 	g_free (uri_list);
310 
311 	/* do nothing if no real uris are left */
312 	if (n_uris == 0) {
313 		g_free (container_uri);
314 		return;
315 	}
316 
317 	if (n_uris == 1) {
318 		GdkPoint tmp_point = { 0, 0 };
319 
320 		/* pass in a 1-item array of icon positions, relative to x, y */
321 		points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
322 		g_array_append_val (points, tmp_point);
323 	} else {
324 		points = NULL;
325 	}
326 
327 	view_widget_to_file_operation_position_xy (view, &x, &y);
328 
329 	nautilus_view_move_copy_items (view, real_uri_list, points,
330 				       target_uri != NULL ? target_uri : container_uri,
331 				       action, x, y);
332 
333 	g_list_free_full (real_uri_list, g_free);
334 
335 	if (points != NULL)
336 		g_array_free (points, TRUE);
337 
338 	g_free (container_uri);
339 }
340 
341 #define MAX_LEN_FILENAME 128
342 #define MIN_LEN_FILENAME 10
343 
344 static char *
345 get_drop_filename (const char *text)
346 {
347 	char *filename;
348 	char trimmed[MAX_LEN_FILENAME];
349 	int i;
350 	int last_word = -1;
351 	int last_sentence = -1;
352 	int last_nonspace = -1;
353 	int num_attrs;
354 	PangoLogAttr *attrs;
355 
356 	num_attrs = MIN (g_utf8_strlen (text, -1) + 1, MAX_LEN_FILENAME);
357 	attrs = g_new (PangoLogAttr, num_attrs);
358 	g_utf8_strncpy (trimmed, text, num_attrs);
359 	pango_get_log_attrs (trimmed, -1, -1, pango_language_get_default (), attrs, num_attrs);
360 
361 	/* since the end of the text will always match a word boundary don't include it */
362 	for (i = 0; (i < num_attrs - 1); i++) {
363 		if (!attrs[i].is_white)
364 			last_nonspace = i;
365 		if (attrs[i].is_sentence_end)
366 			last_sentence = last_nonspace;
367 		if (attrs[i].is_word_boundary)
368 			last_word = last_nonspace;
369 	}
370 	g_free (attrs);
371 
372 	if (last_sentence > 0)
373 		i = last_sentence;
374 	else
375 		i = last_word;
376 
377 	if (i > MIN_LEN_FILENAME) {
378 		char basename[MAX_LEN_FILENAME];
379 		g_utf8_strncpy (basename, trimmed, i);
380 		filename = g_strdup_printf ("%s.txt", basename);
381 	} else {
382 		/* Translator: This is the filename used for when you dnd text to a directory */
383 		filename = g_strdup (_("Dropped Text.txt"));
384 	}
385 
386 	return filename;
387 }
388 
389 void
390 nautilus_view_handle_text_drop (NautilusView  *view,
391                                 const char    *text,
392                                 const char    *target_uri,
393                                 GdkDragAction  action,
394                                 int            x,
395                                 int            y)
396 {
397 	int length;
398 	char *container_uri;
399 	GdkPoint pos;
400 	char *filename;
401 
402 	if (text == NULL) {
403 		return;
404 	}
405 
406 	g_return_if_fail (action == GDK_ACTION_COPY);
407 
408 	container_uri = NULL;
409 	if (target_uri == NULL) {
410 		container_uri = nautilus_view_get_backing_uri (view);
411 		g_assert (container_uri != NULL);
412 	}
413 
414 	length = strlen (text);
415 
416 	pos.x = x;
417 	pos.y = y;
418 	view_widget_to_file_operation_position (view, &pos);
419 
420 	/* try to get text to use as a filename */
421 	filename = get_drop_filename (text);
422 
423 	nautilus_view_new_file_with_initial_contents (view,
424 						      target_uri != NULL ? target_uri : container_uri,
425 						      filename,
426 						      text,
427 						      length,
428 						      &pos);
429 	g_free (filename);
430 	g_free (container_uri);
431 }
432 
433 void
434 nautilus_view_handle_raw_drop (NautilusView *view,
435                                const char   *raw_data,
436                                int           length,
437                                const char   *target_uri,
438                                const char   *direct_save_uri,
439                                GdkDragAction action,
440                                int           x,
441                                int           y)
442 {
443 	char *container_uri, *filename;
444 	GFile *direct_save_full;
445 	GdkPoint pos;
446 
447 	if (raw_data == NULL) {
448 		return;
449 	}
450 
451 	g_return_if_fail (action == GDK_ACTION_COPY);
452 
453 	container_uri = NULL;
454 	if (target_uri == NULL) {
455 		container_uri = nautilus_view_get_backing_uri (view);
456 		g_assert (container_uri != NULL);
457 	}
458 
459 	pos.x = x;
460 	pos.y = y;
461 	view_widget_to_file_operation_position (view, &pos);
462 
463 	filename = NULL;
464 	if (direct_save_uri != NULL) {
465 		direct_save_full = g_file_new_for_uri (direct_save_uri);
466 		filename = g_file_get_basename (direct_save_full);
467 	}
468 	if (filename == NULL) {
469 		/* Translator: This is the filename used for when you dnd raw
470 		 * data to a directory, if the source didn't supply a name.
471 		 */
472 		filename = g_strdup (_("dropped data"));
473 	}
474 
475 	nautilus_view_new_file_with_initial_contents (
476 		view, target_uri != NULL ? target_uri : container_uri,
477 		filename, raw_data, length, &pos);
478 
479 	g_free (container_uri);
480 	g_free (filename);
481 }
482 
483 void 
484 nautilus_view_drop_proxy_received_uris (NautilusView *view,
485 					const GList *source_uri_list,
486 					const char *target_uri,
487 					GdkDragAction action)
488 {
489 	char *container_uri;
490 
491 	container_uri = NULL;
492 	if (target_uri == NULL) {
493 		container_uri = nautilus_view_get_backing_uri (view);
494 		g_assert (container_uri != NULL);
495 	}
496 
497 	if (action == GDK_ACTION_ASK) {
498 		action = nautilus_drag_drop_action_ask
499 			(GTK_WIDGET (view),
500 			 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
501 		if (action == 0) {
502 			return;
503 		}
504 	}
505 
506 	nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
507 						    source_uri_list,
508 						    nautilus_view_get_copied_files_atom (view));
509 
510 	nautilus_view_move_copy_items (view, source_uri_list, NULL,
511 				       target_uri != NULL ? target_uri : container_uri,
512 				       action, 0, 0);
513 
514 	g_free (container_uri);
515 }