Re: [PATCH] Fixed drag and drop between Nautilus and Mozilla



Hi,

Thanks for your comments. On the basis of them I have rewritten the
patch - attached.

It is a lot cleaner now, and it works exactly as you described in that
mail. With one exception:

The default mozilla drag action is GDK_ACTION_COPY, and the code opens
the link-or-download dialog on that. We can't distinguish it from a
ctrl-drag, where the dialog will also popup. 

I removed the (crappy and broken) custom linking code, as I get the
feeling it either belongs somewhere else in a more generic place within
nautilus, or in gnome-vfs. In a WebDAV window right click->"make link"
doesn't work either ..

Then there still is the remaining issue that the .desktop file
generation code doesn't do an overwrite check. 

Cheers,

Jorn

On Wed, 2005-01-12 at 15:34 +0100, Alexander Larsson wrote:
> On Sun, 2005-01-09 at 21:27 +0100, Jorn Baayen wrote:
> > Hi,
> > 
> > Not entirely unmotivated by the bounty I have been working on #127553,
> > "Drag and Drop between Gnome and Mozilla". I got the thing mostly
> > solved, but the code could use some reviewing, and I need some
> > directions for solving the last remaining issue:
> > 
> > nautilus_link_local_create just overwrites any file without asking. So,
> > we need an overwrite confirmation dialog. However, the standard one is
> > nested in nautilus-file-operations.c:handle_transfer_overwrite. I could
> > move it into its own function, which could then be used in
> > nautilus_link_local_create as well. Another option would be
> > link_local_creating the links in tmp files, and then using
> > fm_directory_view_move_copy_items to move them to the right place.
> > 
> > I'll attach the patch to this mail as well for increased reviewing
> > convenience.
> 
> Thanks. Btw. I once wrote up how i wanted this to work for another
> bounty seeker:
> http://mail.gnome.org/archives/nautilus-list/2004-February/msg00074.html
> Did you read that?
> 
> Anyway, back to the patch:
> 
> +if (eel_is_remote_uri (uri)) {
> +/* Create a list of remote uris, so that we only
> + * once have to ask what to do
> + */
> 
> This isn't right. eel_is_remote_uri uses gnome_vfs_uri_is_local() which
> does some magic to check the "localness" of the file, such that e.g.
> files on NFS partitions are not local. Use 
> eel_vfs_has_capability (uri, EEL_VFS_CAPABILITY_IS_REMOTE_AND_SLOW)
> instead to match the rest of the function. (although the capabilities
> stuff was never really finished well it should work for this.)
> 
> nautilus_link_local_create_from_gnome_entry (entry, container_uri, 
> -                                             (n_links > 0) ? NULL: &point, screen_num);
> +                                             &point, screen_num);
> 
> Why this change? Doesn't that mean all the icons will be placed in the
> same position? Maybe we should just use &point for the first item in the
> list?
> 
> +if (n_symlink_uris > 0) {
> +fm_directory_view_move_copy_items (symlink_uri_list, points,
> +   container_uri,
> +   GDK_ACTION_LINK, x, y, FM_DIRECTORY_VIEW (view));
> +g_list_free (symlink_uri_list);
> +}
> 
> Why use GDK_ACTION_LINK here? Shouldn't you use "action" as specified by
> the user? (or as returned by nautilus_drag_drop_action_ask earlier in
> the function).
> 
> + if (strcmp (scheme, "http") == 0) {
> +  if (n_uris > 1) {
> +   prompt = _("Download the links?");
> +   detail = _("You can download the links or create bookmarks.");
> +  } else {
> +   prompt = _("Download the link?");
> +   detail = _("You can download the link or create a bookmark.");
> +  }
> +
> +  link_action = _("_Bookmark");
> +  copy_action = _("_Download");
> 
> I'm not sure bookmark is the best term here. It has a very specific
> meaning in the context of web browsers, and making a deskop file link is
> not it.
> 
> Also, the general handling of dnd modifiers seems wrong to me. If you
> hold down ctrl-shift to force a link, or ctrl to force a copy you should
> never ask the user what they want, since they explicitly requested a
> specific operation. I'm not sure if mozilla supports the ASK action, but
> if ASK is used and specified by the user, it looks like this code will
> ask twice, which strikes me as strange.
> 
> While I was looking at this i took the opportunity to remove the old
> "historic" links support and remove some unused nautilus-link stuff. The
> changes conflict (very slightly) with your patch (one argument removed
> from nautilus_link_local_create).
> 
> =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>  Alexander Larsson                                            Red Hat, Inc 
>                    alexl redhat com    alla lysator liu se 
> He's a globe-trotting Jewish jungle king on the hunt for the last specimen of 
> a great and near-mythical creature. She's a provocative motormouth snake 
> charmer with the power to see death. They fight crime! 
> 
Index: libnautilus-private/nautilus-icon-container.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.c,v
retrieving revision 1.381
diff -u -r1.381 nautilus-icon-container.c
--- libnautilus-private/nautilus-icon-container.c	15 Dec 2004 11:20:41 -0000	1.381
+++ libnautilus-private/nautilus-icon-container.c	12 Jan 2005 19:40:17 -0000
@@ -227,6 +227,7 @@
 	RENAMING_ICON,
 	LAYOUT_CHANGED,
 	MOVE_COPY_ITEMS,
+	HANDLE_URL,
 	HANDLE_URI_LIST,
 	PREVIEW,
 	SELECTION_CHANGED,
@@ -4105,6 +4106,19 @@
 				G_TYPE_INT,
 				G_TYPE_INT,
 				G_TYPE_INT);
+	signals[HANDLE_URL]
+		= g_signal_new ("handle_url",
+		                G_TYPE_FROM_CLASS (class),
+		                G_SIGNAL_RUN_LAST,
+		                G_STRUCT_OFFSET (NautilusIconContainerClass, 
+						     handle_url),
+		                NULL, NULL,
+		                nautilus_marshal_VOID__STRING_INT_INT_INT,
+		                G_TYPE_NONE, 4,
+				G_TYPE_STRING,
+				G_TYPE_INT,
+				G_TYPE_INT,
+				G_TYPE_INT);
 	signals[HANDLE_URI_LIST] 
 		= g_signal_new ("handle_uri_list",
 		                G_TYPE_FROM_CLASS (class),
@@ -4112,9 +4126,9 @@
 		                G_STRUCT_OFFSET (NautilusIconContainerClass, 
 						     handle_uri_list),
 		                NULL, NULL,
-		                nautilus_marshal_VOID__POINTER_INT_INT_INT,
+		                nautilus_marshal_VOID__STRING_INT_INT_INT,
 		                G_TYPE_NONE, 4,
-				G_TYPE_POINTER,
+				G_TYPE_STRING,
 				G_TYPE_INT,
 				G_TYPE_INT,
 				G_TYPE_INT);
Index: libnautilus-private/nautilus-icon-container.h
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.h,v
retrieving revision 1.84
diff -u -r1.84 nautilus-icon-container.h
--- libnautilus-private/nautilus-icon-container.h	10 Jan 2004 20:58:06 -0000	1.84
+++ libnautilus-private/nautilus-icon-container.h	12 Jan 2005 19:40:17 -0000
@@ -100,8 +100,12 @@
 						   int copy_action,
 						   int x,
 						   int y);
+	void	     (* handle_url)		  (NautilusIconContainer *container,
+						   char *url,
+						   int x,
+						   int y);
 	void	     (* handle_uri_list)    	  (NautilusIconContainer *container,
-						   GList *item_uris,
+						   char *uri_list,
 						   int x,
 						   int y);
 
Index: libnautilus-private/nautilus-icon-dnd.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-dnd.c,v
retrieving revision 1.140
diff -u -r1.140 nautilus-icon-dnd.c
--- libnautilus-private/nautilus-icon-dnd.c	22 Oct 2004 15:44:16 -0000	1.140
+++ libnautilus-private/nautilus-icon-dnd.c	12 Jan 2005 19:40:17 -0000
@@ -615,6 +615,20 @@
 	nautilus_icon_container_update_icon (container, drop_target_icon);
 }
 
+/* handle dropped url */
+static void
+receive_dropped_url (NautilusIconContainer *container, const char *encoded_url, GdkDragAction action, int x, int y)
+{
+	if (encoded_url == NULL) {
+		return;
+	}
+
+	g_signal_emit_by_name (container, "handle_url",
+			       encoded_url,
+			       action,
+			       x, y);
+}
+
 /* handle dropped uri list */
 static void
 receive_dropped_uri_list (NautilusIconContainer *container, const char *uri_list, GdkDragAction action, int x, int y)
@@ -1590,8 +1604,13 @@
 				(NAUTILUS_ICON_CONTAINER (widget),
 				 (char *) data->data, x, y);
 			break;
-		case NAUTILUS_ICON_DND_URI_LIST:
 		case NAUTILUS_ICON_DND_URL:
+			receive_dropped_url
+				(NAUTILUS_ICON_CONTAINER (widget),
+				 (char *) data->data, context->action, x, y);
+			success = TRUE;
+			break;
+		case NAUTILUS_ICON_DND_URI_LIST:
 			receive_dropped_uri_list
 				(NAUTILUS_ICON_CONTAINER (widget),
 				 (char *) data->data, context->action, x, y);
Index: libnautilus-private/nautilus-marshal.list
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-marshal.list,v
retrieving revision 1.7
diff -u -r1.7 nautilus-marshal.list
--- libnautilus-private/nautilus-marshal.list	11 Jan 2004 20:34:32 -0000	1.7
+++ libnautilus-private/nautilus-marshal.list	12 Jan 2005 19:40:17 -0000
@@ -6,7 +6,7 @@
 INT:POINTER,POINTER
 POINTER:VOID
 VOID:DOUBLE
-VOID:POINTER,INT,INT,INT
+VOID:STRING,INT,INT,INT
 VOID:POINTER,POINTER
 VOID:POINTER,POINTER
 VOID:POINTER,STRING
Index: src/file-manager/fm-icon-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-icon-view.c,v
retrieving revision 1.303
diff -u -r1.303 fm-icon-view.c
--- src/file-manager/fm-icon-view.c	12 Jan 2005 14:36:42 -0000	1.303
+++ src/file-manager/fm-icon-view.c	12 Jan 2005 19:40:18 -0000
@@ -46,6 +46,7 @@
 #include <gtk/gtkradioaction.h>
 #include <gtk/gtksignal.h>
 #include <gtk/gtkwindow.h>
+#include <gtk/gtkstock.h>
 #include <libgnome/gnome-i18n.h>
 #include <libgnome/gnome-config.h>
 #include <libgnome/gnome-desktop-item.h>
@@ -187,7 +188,7 @@
 								       NautilusFile         *file,
 								       gboolean              start_flag);
 static void                 update_layout_menus                       (FMIconView           *view);
-
+static GdkDragAction        ask_link_action                           (FMIconView           *view);
 
 static void fm_icon_view_iface_init (NautilusViewIface *iface);
 
@@ -2458,27 +2459,140 @@
 	gtk_widget_show (GTK_WIDGET (icon_container));
 }
 
+/* Handles an URL received from Mozilla */
+static void
+icon_view_handle_url (NautilusIconContainer *container, const char *encoded_url,
+		      GdkDragAction action, int x, int y, FMIconView *view)
+{
+	GdkPoint point;
+	GdkScreen *screen;
+	int screen_num;
+	char *url, *title;
+	char *link_name, *link_file_name, *link_display_name;
+	char *container_uri;
+	GArray *points;
+	char **bits;
+	GList *uri_list = NULL;
+
+	if (encoded_url == NULL) {
+		return;
+	}
+
+	container_uri = fm_directory_view_get_backing_uri (FM_DIRECTORY_VIEW (view));
+	g_return_if_fail (container_uri != NULL);
+
+	if (eel_vfs_has_capability (container_uri,
+				    EEL_VFS_CAPABILITY_IS_REMOTE_AND_SLOW)) {
+		eel_show_warning_dialog (_("Drag and drop is not supported."),
+					 _("Drag and drop is only supported on local file systems."),
+					 _("Drag and Drop Error"),
+					 fm_directory_view_get_containing_window (FM_DIRECTORY_VIEW (view)));
+		g_free (container_uri);
+		return;
+	}
+
+	/* GDK_ACTION_COPY is Mozilla's default drag action:
+	 * On a standard drag from mozilla we ask the user
+	 * whether he wants to copy or link the link. */
+	if (action == GDK_ACTION_COPY || action == GDK_ACTION_ASK) {
+		action = ask_link_action (view);
+		if (action == 0) {
+			g_free (container_uri);
+			return;
+		}
+	}
+
+	/* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE
+	 * and we don't support combinations either. */
+	if ((action != GDK_ACTION_DEFAULT) &&
+	    (action != GDK_ACTION_COPY) &&
+	    (action != GDK_ACTION_MOVE) &&
+	    (action != GDK_ACTION_LINK)) {
+		eel_show_warning_dialog (_("Drag and drop is not supported."),
+					 _("An invalid drag type was used."),
+					 _("Drag and Drop Error"),
+					 fm_directory_view_get_containing_window (FM_DIRECTORY_VIEW (view)));
+		g_free (container_uri);
+		return;
+	}
+
+	/* _NETSCAPE_URL_ works like this: $URL\n$TITLE */
+	bits = g_strsplit (encoded_url, "\n", 0);
+	switch (g_strv_length (bits)) {
+	case 0:
+		g_strfreev (bits);
+		g_free (container_uri);
+		return;
+	case 1:
+		url = bits[0];
+		title = NULL;
+		break;
+	default:
+		url = bits[0];
+		title = bits[1];
+	}
+
+	if (action == GDK_ACTION_LINK) {
+		if (eel_str_is_empty (title)) {
+			link_name = eel_uri_get_basename (url);
+		} else {
+			link_name = g_strdup (title);
+		}
+
+		if (!eel_str_is_empty (link_name)) {
+			/* FIXME: Handle name conflicts? */
+			link_file_name = g_strconcat (link_name, ".desktop", NULL);
+			link_display_name = g_strdup_printf (_("link to %s"), link_name);
+
+			point.x = x;
+			point.y = y;
+
+			screen = gtk_widget_get_screen (GTK_WIDGET (view));
+			screen_num = gdk_screen_get_number (screen);
+
+			nautilus_link_local_create (container_uri,
+						    link_file_name,
+						    link_display_name,
+						    "gnome-fs-bookmark",
+						    url,
+						    &point,
+						    screen_num);
+
+			g_free (link_file_name);
+			g_free (link_display_name);
+		}
+		g_free (link_name);
+	} else {
+		GdkPoint tmp_point = { 0, 0 };
+
+		/* pass in a 1-item array of icon positions, relative to x, y */
+		points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
+		g_array_append_val (points, tmp_point);
+
+		uri_list = g_list_append (uri_list, url);
+
+		fm_directory_view_move_copy_items (uri_list, points,
+						   container_uri,
+						   action, x, y, FM_DIRECTORY_VIEW (view));
+
+		g_list_free (uri_list);
+		g_array_free (points, TRUE);
+	}
+
+	g_strfreev (bits);
+
+	g_free (container_uri);
+}
+
 static void
 icon_view_handle_uri_list (NautilusIconContainer *container, const char *item_uris,
 			   GdkDragAction action, int x, int y, FMIconView *view)
 {
-
 	GList *uri_list;
 	GList *node, *real_uri_list = NULL;
-	GnomeDesktopItem *entry;
-	GdkPoint point;
-	char *uri;
-	char *path;
-	char *stripped_uri;
 	char *container_uri;
-	char *mime_type;
-	const char *last_slash, *link_name;
-	char *link_file_name;
-	int n_uris, n_links;
-	gboolean all_local;
+	int n_uris;
 	GArray *points;
-	GdkScreen *screen;
-	int screen_num;
 
 	if (item_uris == NULL) {
 		return;
@@ -2498,7 +2612,7 @@
 	}
 
 	if (action == GDK_ACTION_ASK) {
-		action = nautilus_drag_drop_action_ask 
+		action = nautilus_drag_drop_action_ask
 			(GTK_WIDGET (container),
 			 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
 		if (action == 0) {
@@ -2506,7 +2620,7 @@
 			return;
 		}
 	}
-	
+
 	/* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE
 	 * and we don't support combinations either. */
 	if ((action != GDK_ACTION_DEFAULT) &&
@@ -2521,128 +2635,43 @@
 		return;
 	}
 
-	point.x = x;
-	point.y = y;
-
-	screen = gtk_widget_get_screen (GTK_WIDGET (view));
-	screen_num = gdk_screen_get_number (screen);
-		
 	/* Most of what comes in here is not really URIs, but rather paths that
 	 * have a file: prefix in them.  We try to sanitize the uri list as a
-	 * result.  Additionally, if they are all local files, then we can copy
-	 * them.  Otherwise, we just make links.
+	 * result.
 	 */
-	all_local = TRUE;
 	n_uris = 0;
 	uri_list = nautilus_icon_dnd_uri_list_extract_uris (item_uris);
 	for (node = uri_list; node != NULL; node = node->next) {
-		gchar *sanitized_uri;
+		char *sanitized_uri;
 
 		sanitized_uri = eel_make_uri_from_half_baked_uri (node->data);
 		if (sanitized_uri == NULL)
 			continue;
 		real_uri_list = g_list_append (real_uri_list, sanitized_uri);
-		if (eel_vfs_has_capability (sanitized_uri,
-					    EEL_VFS_CAPABILITY_IS_REMOTE_AND_SLOW)) {
-			all_local = FALSE;
-		}
 		n_uris++;
 	}
 	nautilus_icon_dnd_uri_list_free_strings (uri_list);
 
-	if (all_local == TRUE &&
-	    (action == GDK_ACTION_COPY ||
-	     action == GDK_ACTION_MOVE)) {
-		/* Copying files */
-		if (n_uris == 1) {
-			GdkPoint tmp_point = { 0, 0 };
-
-			/* pass in a 1-item array of icon positions, relative to x, y */
-			points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
-			g_array_append_val (points, tmp_point);
-		} else {
-			points = NULL;
-		}
-		fm_directory_view_move_copy_items (real_uri_list, points,
-						   container_uri,
-						   action, x, y, FM_DIRECTORY_VIEW (view));
-		
-		if (points)
-			g_array_free (points, TRUE);
-	} else {
-		n_links = 0;
-		for (node = real_uri_list; node != NULL; node = node->next) {
-			/* Make a link using the desktop file contents? */
-			uri = node->data;
-			path = gnome_vfs_get_local_path_from_uri (uri);
-
-			if (path != NULL) {
-				mime_type = gnome_vfs_get_mime_type (uri);
-
-				if (mime_type != NULL &&
-				    (strcmp (mime_type, "application/x-gnome-app-info") == 0 ||
-				     strcmp (mime_type, "application/x-desktop") == 0)) {
-					entry = gnome_desktop_item_new_from_file (path,
-										  0,
-										  NULL);
-				} else {
-					entry = NULL;
-				}
-
-				g_free (mime_type);
-				g_free (path);
-			} else {
-				entry = NULL;
-			}
+	if (n_uris == 1) {
+		GdkPoint tmp_point = { 0, 0 };
 
-			if (entry != NULL) {
-				/* FIXME: Handle name conflicts? */
-				nautilus_link_local_create_from_gnome_entry (entry, container_uri, 
-				                                             (n_links > 0) ? NULL: &point, screen_num);
+		/* pass in a 1-item array of icon positions, relative to x, y */
+		points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
+		g_array_append_val (points, tmp_point);
+	} else {
+		points = NULL;
+	}
 
-				gnome_desktop_item_unref (entry);
-				continue;
-			}
+	fm_directory_view_move_copy_items (real_uri_list, points,
+					   container_uri,
+					   action, x, y, FM_DIRECTORY_VIEW (view));
 
-			/* Make a link from the URI alone. Generate the file
-			 * name by extracting the basename of the URI.
-			 */
-			/* FIXME: This should be using eel_uri_get_basename
-			 * instead of a "roll our own" solution.
-			 */
-			stripped_uri = eel_str_strip_trailing_chr (uri, '/');
-			last_slash = strrchr (stripped_uri, '/');
-			link_name = last_slash == NULL ? NULL : last_slash + 1;
-			
-			if (!eel_str_is_empty (link_name)) {
-				link_file_name = g_strconcat (link_name, ".desktop", NULL);
-				/* FIXME: Handle name conflicts? */
-				nautilus_link_local_create (container_uri,
-							    link_file_name,
-							    link_name,
-							    NULL, uri,
-							    (n_links > 0) ? NULL: &point, 
-							    screen_num);
-				g_free (link_file_name);
-			}
-			
-			n_links++;
-			g_free (stripped_uri);
-			
-			/* The following break statement handles mozilla urls.  
-			 * Do not remove it; otherwise, nautilus will create two 
-			 * links when the url is dropped on the desktop.
-			 */
-			if (path == NULL) {
-				break;
-			}
-		}
-	}
-	
 	nautilus_icon_dnd_uri_list_free_strings (real_uri_list);
 
+	if (points != NULL)
+		g_array_free (points, TRUE);
+
 	g_free (container_uri);
-	
 }
 
 static char *
@@ -2681,6 +2710,42 @@
 	}
 }
 
+static GdkDragAction
+ask_link_action (FMIconView *view)
+{
+	int button_pressed;
+	GdkDragAction result;
+
+	button_pressed = eel_run_simple_dialog (GTK_WIDGET (fm_directory_view_get_containing_window (FM_DIRECTORY_VIEW (view))),
+			                        TRUE,
+			                        GTK_MESSAGE_QUESTION,
+                                                _("Download the link?"),
+                                                _("You can download it or copy is as link."),
+                                                NULL, /* as per HIG */
+                                                _("Copy as _Link"),
+                                                GTK_STOCK_CANCEL,
+                                                _("_Download"),
+                                                NULL);
+
+	switch (button_pressed) {
+	case 0:
+		result = GDK_ACTION_LINK;
+		break;
+	case 1:
+	case GTK_RESPONSE_DELETE_EVENT:
+		result = 0;
+		break;
+	case 2:
+		result = GDK_ACTION_COPY;
+		break;
+	default:
+		g_assert_not_reached ();
+		result = 0;
+	}
+
+	return result;
+}
+
 static void
 fm_icon_view_class_init (FMIconViewClass *klass)
 {
@@ -2805,6 +2870,8 @@
 						  labels_beside_icons_changed_callback,
 						  icon_view, G_OBJECT (icon_view));
 
+	g_signal_connect_object (get_icon_container (icon_view), "handle_url",
+				 G_CALLBACK (icon_view_handle_url), icon_view, 0);
 	g_signal_connect_object (get_icon_container (icon_view), "handle_uri_list",
 				 G_CALLBACK (icon_view_handle_uri_list), icon_view, 0);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]