[PATCH] Nautilus Places sidebar URI dropping



The attached patch was in bugzilla [1] but unfortunetely not reviewed
for some time:
"The attached patch allows users to drop files to the sidebar, either
for copying/moving them to the folders in the sidebar, or for adding
them to it. If you hover builtin bookmarks and volumes (above sep.),
only copying/moving is allowed. This patch also implements middle-click
dragging."

[1] http://bugzilla.gnome.org/show_bug.cgi?id=43311

-- 
Christian Neumair <chris gnome-de org>
Index: src/nautilus-places-sidebar.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-places-sidebar.c,v
retrieving revision 1.5
diff -u -p -r1.5 nautilus-places-sidebar.c
--- src/nautilus-places-sidebar.c	11 Jul 2005 10:12:46 -0000	1.5
+++ src/nautilus-places-sidebar.c	3 Sep 2005 09:54:28 -0000
@@ -34,17 +34,20 @@
 #include <gtk/gtkcellrendererpixbuf.h>
 #include <gtk/gtkcellrenderertext.h>
 #include <gtk/gtkliststore.h>
+#include <gtk/gtkmain.h>
 #include <gtk/gtksizegroup.h>
 #include <gtk/gtkstock.h>
 #include <gtk/gtktreemodel.h>
 #include <gtk/gtktreeselection.h>
 #include <libgnome/gnome-macros.h>
 #include <libgnome/gnome-i18n.h>
+#include <libnautilus-private/nautilus-dnd.h>
 #include <libnautilus-private/nautilus-bookmark.h>
 #include <libnautilus-private/nautilus-global-preferences.h>
 #include <libnautilus-private/nautilus-sidebar-provider.h>
 #include <libnautilus-private/nautilus-module.h>
 #include <libnautilus-private/nautilus-file-utilities.h>
+#include <libnautilus-private/nautilus-file-operations.h>
 #include <libgnomevfs/gnome-vfs-utils.h>
 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
 
@@ -62,6 +65,10 @@ typedef struct {
 	GtkListStore       *store;
 	NautilusWindowInfo *window;
 	NautilusBookmarkList *bookmarks;
+
+	/* DnD */
+	GList    *drag_data;
+	gboolean  drag_data_received;
 } NautilusPlacesSidebar;
 
 typedef struct {
@@ -96,6 +103,10 @@ static void  nautilus_places_sidebar_ifa
 static void  sidebar_provider_iface_init               (NautilusSidebarProviderIface *iface);
 static GType nautilus_places_sidebar_provider_get_type (void);
 
+static const GtkTargetEntry drop_targets [] = {
+	{ NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST }
+};
+
 G_DEFINE_TYPE_WITH_CODE (NautilusPlacesSidebar, nautilus_places_sidebar, GTK_TYPE_SCROLLED_WINDOW,
 			 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR,
 						nautilus_places_sidebar_iface_init));
@@ -360,6 +371,248 @@ loading_uri_callback (NautilusWindowInfo
     	}
 }
 
+static void
+drag_motion_callback (GtkTreeView *tree_view,
+		      GdkDragContext *context,
+		      int x,
+		      int y,
+		      unsigned int time,
+		      NautilusPlacesSidebar *sidebar)
+{
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	GtkTreeViewDropPosition pos;
+	GdkAtom target;
+	PlaceType place_type;
+	char *uri;
+	unsigned int action;
+
+	if (!sidebar->drag_data_received) {
+		target = gtk_drag_dest_find_target (GTK_WIDGET (tree_view), context, NULL);
+		gtk_drag_get_data (GTK_WIDGET (tree_view), context, target, time);
+	}
+
+	model = gtk_tree_view_get_model (tree_view);
+
+	gtk_tree_view_get_dest_row_at_pos (tree_view, x, y, &path, &pos);
+	if (path != NULL) {
+		gtk_tree_model_get_iter (model, &iter, path);
+		gtk_tree_model_get (model, &iter,
+				    PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+				    PLACES_SIDEBAR_COLUMN_URI, &uri,
+				    -1);
+
+		if (place_type == PLACES_SEPARATOR) {
+			gtk_tree_path_free (path);
+			path = NULL;
+			action = 0;
+		} else {
+			nautilus_drag_default_drop_action_for_icons (context, uri,
+								     sidebar->drag_data,
+								     &action);
+
+			if (action == GDK_ACTION_ASK
+			    || place_type != PLACES_BOOKMARK) {
+				pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
+			}
+		}
+
+		g_free (uri);
+	}
+
+	gtk_tree_view_set_drag_dest_row (tree_view, path, pos);
+	gdk_drag_status (context, action, time);
+}
+
+static void
+drag_leave_callback (GtkTreeView *tree_view,
+		     GdkDragContext *context,
+		     unsigned int time,
+		     NautilusPlacesSidebar *sidebar)
+{
+	GdkEvent *current_event;
+	gtk_tree_view_set_drag_dest_row (tree_view, NULL, GTK_TREE_VIEW_DROP_BEFORE);
+
+	current_event = gtk_get_current_event ();
+	if (current_event == NULL || current_event->type != GDK_DROP_START) {
+		/* this is not reached if the drop succeds. In that case, the
+		 * drag data is cleared in the "drag-drop" handler */
+		nautilus_drag_destroy_selection_list (sidebar->drag_data);
+		sidebar->drag_data_received = FALSE;
+	}
+}
+
+static void
+drag_data_received_callback (GtkWidget *widget,
+			     GdkDragContext *context,
+			     int x,
+			     int y,
+			     GtkSelectionData *data,
+			     unsigned int info,
+			     unsigned int time,
+			     NautilusPlacesSidebar *sidebar)
+{
+	if (data->target != GDK_NONE) {
+		sidebar->drag_data = nautilus_drag_build_selection_list (data);
+	} else {
+		sidebar->drag_data = NULL;
+	}
+
+	sidebar->drag_data_received = TRUE;
+}
+
+static unsigned int
+get_bookmark_index_at_path (GtkTreeView *tree_view,
+			    GtkTreePath *bookmark_path)
+{
+	GtkTreeModel *model;
+	GtkTreePath *p;
+	GtkTreeIter iter;
+	PlaceType place_type;
+	int separator_index, bookmark_index;
+
+	model = gtk_tree_view_get_model (tree_view);
+
+	bookmark_index = *gtk_tree_path_get_indices (bookmark_path);
+	separator_index = -1;
+
+	/* find separator */
+	p = gtk_tree_path_new_first ();
+	while (p != NULL) {
+		gtk_tree_model_get_iter (model, &iter, p);
+		gtk_tree_model_get (model, &iter,
+				    PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+				    -1);
+
+		if (place_type == PLACES_SEPARATOR) {
+			separator_index = *gtk_tree_path_get_indices (p);
+			break;
+		}
+
+		gtk_tree_path_next (p);
+	}
+	gtk_tree_path_free (p);
+
+	g_assert (separator_index >= 0);
+
+	return bookmark_index - separator_index - 1;
+}
+
+static GList *
+uri_list_from_selection (GList *selection)
+{
+	NautilusDragSelectionItem *item;
+	GList *ret;
+	GList *l;
+
+	ret = NULL;
+	for (l = selection; l != NULL; l = l->next) {
+		item = l->data;
+		ret = g_list_prepend (ret, item->uri);
+	}
+
+	return g_list_reverse (ret);
+}
+
+static gboolean
+drag_drop_callback (GtkTreeView *tree_view,
+		    GdkDragContext *context,
+		    int x,
+		    int y,
+		    unsigned int time,
+		    NautilusPlacesSidebar *sidebar)
+{
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	NautilusDragSelectionItem *item;
+	PlaceType place_type;
+	GtkTreeViewDropPosition pos;
+	NautilusBookmark *bookmark;
+	GnomeVFSURI *uri;
+	char *drop_uri;
+	char *bookmark_name;
+	unsigned int bookmark_index;
+	GList *uris;
+	GList *l;
+
+	if (context->action == 0) {
+		nautilus_drag_destroy_selection_list (sidebar->drag_data);
+		sidebar->drag_data_received = FALSE;
+
+		return FALSE;
+	}
+
+	model = gtk_tree_view_get_model (tree_view);
+
+	gtk_tree_view_get_dest_row_at_pos (tree_view, x, y, &path, &pos);
+	if (path == NULL) {
+		nautilus_drag_destroy_selection_list (sidebar->drag_data);
+		sidebar->drag_data_received = FALSE;
+
+		return FALSE;
+	}
+
+	if (context->action == GDK_ACTION_ASK) {
+		context->action =
+			nautilus_drag_drop_action_ask (GTK_WIDGET (tree_view),
+						       context->actions);
+		pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
+	}
+
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_model_get (model, &iter,
+			    PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+			    PLACES_SIDEBAR_COLUMN_URI, &drop_uri,
+			    -1);
+
+	if (place_type != PLACES_BOOKMARK) {
+		pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
+	}
+
+	if (pos == GTK_TREE_VIEW_DROP_BEFORE
+	    || pos == GTK_TREE_VIEW_DROP_AFTER) {
+		/* bookmark addition requested */
+
+		bookmark_index = get_bookmark_index_at_path (tree_view, path);
+		if (pos == GTK_TREE_VIEW_DROP_AFTER) {
+			bookmark_index++;
+		}
+
+		for (l = sidebar->drag_data; l != NULL; l = l->next) {
+			item = l->data;
+
+			uri = gnome_vfs_uri_new (item->uri);
+			bookmark_name = gnome_vfs_uri_extract_short_name (uri);
+
+			bookmark = nautilus_bookmark_new (item->uri, bookmark_name);
+
+			g_free (bookmark_name);
+			gnome_vfs_uri_unref (uri);
+
+			if (!nautilus_bookmark_list_contains (sidebar->bookmarks, bookmark)) {
+				nautilus_bookmark_list_insert_item (sidebar->bookmarks, bookmark, bookmark_index);
+			}
+		}
+	} else {
+		/* file transfer requested */
+		uris = uri_list_from_selection (sidebar->drag_data);
+		nautilus_file_operations_copy_move (uris, NULL, drop_uri,
+						    context->action, GTK_WIDGET (tree_view),
+						    NULL, NULL);
+		g_list_free (uris);
+	}
+
+	nautilus_drag_destroy_selection_list (sidebar->drag_data);
+	sidebar->drag_data_received = FALSE;
+
+	gtk_drag_finish (context, TRUE, FALSE, time);
+
+	g_free (drop_uri);
+	gtk_tree_path_free (path);
+	return TRUE;
+}
 
 static void
 nautilus_places_sidebar_init (NautilusPlacesSidebar *sidebar)
@@ -422,6 +675,19 @@ nautilus_places_sidebar_init (NautilusPl
 	g_signal_connect_object
 		(tree_view, "row_activated", 
 		 G_CALLBACK (row_activated_callback), sidebar, 0);
+
+	/* DnD */
+	gtk_drag_dest_set (GTK_WIDGET (tree_view), 0,
+			   drop_targets, G_N_ELEMENTS (drop_targets),
+			   GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+	g_signal_connect (tree_view, "drag-motion",
+			  G_CALLBACK (drag_motion_callback), sidebar);
+	g_signal_connect (tree_view, "drag-leave",
+			  G_CALLBACK (drag_leave_callback), sidebar);
+	g_signal_connect (tree_view, "drag-data-received",
+			  G_CALLBACK (drag_data_received_callback), sidebar);
+	g_signal_connect (tree_view, "drag-drop",
+			  G_CALLBACK (drag_drop_callback), sidebar);
 
 	eel_preferences_add_callback (NAUTILUS_PREFERENCES_CLICK_POLICY,
 				      click_policy_changed_callback,

Attachment: signature.asc
Description: This is a digitally signed message part



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