Re: [PATCH] - Add drag drop of bookmarks to places sidebar



Jamie McCracken wrote:
Attached is patch to allow drag drop of folder uris to blank rows in the places sidebar.

Also added some ints to sidebar for later use.



Updated this to include :

- highlights row when dragging
- copies files when dropped onto exisitng place
- added volume/bookmark pointer to list store for forthcoming popup menu

--
Mr Jamie McCracken
http://www.advogato.org/person/jamiemcc/
Index: src/nautilus-places-sidebar.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-places-sidebar.c,v
retrieving revision 1.1
diff -u -r1.1 nautilus-places-sidebar.c
--- src/nautilus-places-sidebar.c	1 Jul 2005 14:13:49 -0000	1.1
+++ src/nautilus-places-sidebar.c	11 Jul 2005 00:55:24 -0000
@@ -28,12 +28,14 @@
 #include <eel/eel-glib-extensions.h>
 #include <eel/eel-preferences.h>
 #include <eel/eel-string.h>
+#include <eel/eel-stock-dialogs.h>
 #include <gtk/gtkalignment.h>
 #include <gtk/gtkbutton.h>
 #include <gtk/gtkvbox.h>
 #include <gtk/gtkcellrendererpixbuf.h>
 #include <gtk/gtkcellrenderertext.h>
 #include <gtk/gtkliststore.h>
+#include <gtk/gtkmessagedialog.h>
 #include <gtk/gtksizegroup.h>
 #include <gtk/gtkstock.h>
 #include <gtk/gtktreemodel.h>
@@ -45,6 +47,7 @@
 #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>
 
@@ -81,7 +84,7 @@
 	PLACES_SIDEBAR_COLUMN_URI,
 	PLACES_SIDEBAR_COLUMN_NAME,
 	PLACES_SIDEBAR_COLUMN_ICON,
-	
+	PLACES_SIDEBAR_COLUMN_USER_DATA,
 	PLACES_SIDEBAR_COLUMN_COUNT
 };
 
@@ -92,6 +95,12 @@
 	PLACES_SEPARATOR
 } PlaceType;
 
+static const GtkTargetEntry dest_targets[] = {
+  { "text/uri-list", 0, 0}
+};
+
+#define MAX_BOOKMARK_LENGTH 80
+
 static void  nautilus_places_sidebar_iface_init        (NautilusSidebarIface         *iface);
 static void  sidebar_provider_iface_init               (NautilusSidebarProviderIface *iface);
 static GType nautilus_places_sidebar_provider_get_type (void);
@@ -104,10 +113,9 @@
 			 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR_PROVIDER,
 						sidebar_provider_iface_init));
 
-
 static GtkTreeIter
 add_place (GtkListStore *store, PlaceType place_type,
-	   const char *name, const char *icon, const char *uri)
+	   const char *name, const char *icon, const char *uri, gpointer user_data)
 {
 	GdkPixbuf            *pixbuf;
 	GtkTreeIter           iter;
@@ -119,6 +127,7 @@
 			    PLACES_SIDEBAR_COLUMN_NAME, name,
 			    PLACES_SIDEBAR_COLUMN_URI, uri,
 			    PLACES_SIDEBAR_COLUMN_ROW_TYPE, place_type,
+			    PLACES_SIDEBAR_COLUMN_USER_DATA, user_data,
 			    -1);
 	if (pixbuf != NULL) {
 		g_object_unref (pixbuf);
@@ -126,6 +135,35 @@
 	return iter;
 }
 
+
+static void
+unref_volumes (NautilusPlacesSidebar *sidebar)
+{
+	GtkTreeIter 	 iter;
+	gboolean 	 valid;
+	gpointer 	 ptr;
+	GnomeVFSVolume 	 *volume;
+	PlaceType 	 place_type;
+
+	valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store), &iter);
+
+	while (valid) {
+		gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 
+	 		       	    PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+				    PLACES_SIDEBAR_COLUMN_USER_DATA, &ptr,
+				    -1);
+		if (place_type == PLACES_MOUNTED_VOLUME) {
+			volume = GNOME_VFS_VOLUME (ptr);
+			if (volume) {
+				gnome_vfs_volume_unref (volume);
+			}
+		}
+         	valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (sidebar->store), &iter);
+	}
+}
+
+
+
 static void
 update_places (NautilusPlacesSidebar *sidebar)
 {
@@ -135,10 +173,14 @@
 	GnomeVFSVolumeMonitor *volume_monitor;
 	GList 		      *volumes, *l;
 	GnomeVFSVolume 	      *volume;
-	int 		      bookmark_count, index;
+	int 		       index, bookmark_count;
 	char 		      *location, *icon, *mount_uri, *name, *desktop_path;
 		
 	selection = gtk_tree_view_get_selection (sidebar->tree_view);
+
+	/* unref existing volumes before clearing */
+	unref_volumes (sidebar);
+
 	gtk_list_store_clear (sidebar->store);
 	location = nautilus_window_info_get_current_location (sidebar->window);
 
@@ -149,7 +191,7 @@
 	if (strcmp (g_get_home_dir(), desktop_path) != 0) {
 		mount_uri = gnome_vfs_get_uri_from_local_path (g_get_home_dir ());
 		last_iter = add_place (sidebar->store, PLACES_BUILT_IN,
-				       _("Home"), "gnome-fs-home", mount_uri);
+				       _("Home"), "gnome-fs-home", mount_uri, NULL);
 		if (strcmp (location, mount_uri) == 0) {
 			gtk_tree_selection_select_iter (selection, &last_iter);
 		}	
@@ -158,7 +200,7 @@
 
 	mount_uri = gnome_vfs_get_uri_from_local_path (desktop_path);
 	last_iter = add_place (sidebar->store, PLACES_BUILT_IN,
-			       _("Desktop"), "gnome-fs-desktop", mount_uri);
+			       _("Desktop"), "gnome-fs-desktop", mount_uri, NULL);
 	if (strcmp (location, mount_uri) == 0) {
 		gtk_tree_selection_select_iter (selection, &last_iter);
 	}	
@@ -167,7 +209,7 @@
 	
  	mount_uri = "file:///"; // No need to strdup
 	last_iter = add_place (sidebar->store, PLACES_BUILT_IN,
-			       _("Filesystem"), "gnome-fs-blockdev", mount_uri);
+			       _("Filesystem"), "gnome-fs-blockdev", mount_uri, NULL);
 	if (strcmp (location, mount_uri) == 0) {
 		gtk_tree_selection_select_iter (selection, &last_iter);
 	}	
@@ -187,11 +229,10 @@
 		mount_uri = gnome_vfs_volume_get_activation_uri (volume);
 		name = gnome_vfs_volume_get_display_name (volume);
 		last_iter = add_place (sidebar->store, PLACES_MOUNTED_VOLUME,
-				       name, icon, mount_uri);
+				       name, icon, mount_uri, volume);
 		if (strcmp (location, mount_uri) == 0) {
 			gtk_tree_selection_select_iter (selection, &last_iter);
 		}
-		gnome_vfs_volume_unref (volume);
 		g_free (icon);
 		g_free (name);
 		g_free (mount_uri);
@@ -206,9 +247,8 @@
 	gtk_list_store_set (sidebar->store, &iter,
 			    PLACES_SIDEBAR_COLUMN_ROW_TYPE, PLACES_SEPARATOR,
 			    -1);
-
+	
 	/* add bookmarks */
-
 	bookmark_count = nautilus_bookmark_list_length (sidebar->bookmarks);
 	for (index = 0; index < bookmark_count; ++index) {
 		bookmark = nautilus_bookmark_list_item_at (sidebar->bookmarks, index);
@@ -217,7 +257,7 @@
 		icon = nautilus_bookmark_get_icon (bookmark);
 		mount_uri = nautilus_bookmark_get_uri (bookmark);
 		last_iter = add_place (sidebar->store, PLACES_BOOKMARK,
-				       name, icon, mount_uri);
+				       name, icon, mount_uri, bookmark);
 		if (strcmp (location, mount_uri) == 0) {
 			gtk_tree_selection_select_iter (selection, &last_iter);
 		}
@@ -225,9 +265,9 @@
 		g_free (icon);
 		g_free (mount_uri);
 	}
-
-	g_free (location);
 	
+	g_free (location);
+
 }
 
 static gboolean
@@ -361,6 +401,168 @@
 }
 
 
+static gboolean
+is_uri_directory (const char *uri)
+{
+	gboolean result;
+	NautilusFile *file;
+
+	file = nautilus_file_get (uri);
+	if (!file) {
+		return FALSE;
+	}
+	result = nautilus_file_is_directory (file);
+	nautilus_file_unref (file);
+	return result;
+}
+
+static gboolean
+drag_motion_callback (GtkWidget *widget,
+		      GdkDragContext *context,
+		      int x,
+		      int y,
+		      guint32 time,
+		      gpointer data)
+{
+	NautilusPlacesSidebar *sidebar;
+	GtkTreePath *path;
+	GtkTreeViewDropPosition pos;
+
+	sidebar = NAUTILUS_PLACES_SIDEBAR (data);
+
+	gtk_tree_view_get_dest_row_at_pos (sidebar->tree_view,
+					   x, y, &path, &pos);
+
+	if (path) {
+		gtk_tree_view_set_drag_dest_row
+			(sidebar->tree_view,
+			 path,
+			 GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
+		gtk_tree_path_free (path);
+	} else {
+		gtk_tree_view_set_drag_dest_row (sidebar->tree_view, 
+						 NULL, 
+						 0);
+	}
+	return TRUE;
+}
+
+static void
+drag_leave_callback (GtkWidget *widget,
+		     GdkDragContext *context,
+		     guint32 time,
+		     gpointer data)
+{
+	NautilusPlacesSidebar *sidebar;
+
+	sidebar = NAUTILUS_PLACES_SIDEBAR (data);
+
+	gtk_tree_view_set_drag_dest_row (sidebar->tree_view, 
+					 NULL, 
+					 0);
+}
+
+
+static void
+drag_data_received_callback (GtkWidget          *widget,
+			     GdkDragContext     *context,
+			     gint                x,
+			     gint                y,
+			     GtkSelectionData   *selection_data,
+			     guint               info,
+			     guint               time_,
+			     gpointer            user_data)
+{
+	NautilusPlacesSidebar *sidebar;
+	GtkListStore	      *store;
+	gboolean 	       abort_drag_drop;
+	GtkTreePath 	      *path;
+	GtkTreeModel 	      *model;
+	GtkTreeIter 	       iter;
+	GList 		      *item_uris;
+	char 		      *uri;
+
+  	sidebar = NAUTILUS_PLACES_SIDEBAR (user_data);
+	store = GTK_LIST_STORE (gtk_tree_view_get_model (sidebar->tree_view));
+	model = gtk_tree_view_get_model (sidebar->tree_view);
+	abort_drag_drop = FALSE;
+	item_uris = NULL;
+
+  	if (!gtk_tree_view_get_path_at_pos (sidebar->tree_view, x, y, &path, NULL, NULL, NULL)) {
+		/* add dragged folders to bookmarks */
+		gtk_tree_path_free (path);
+		if (selection_data->target == gdk_atom_intern ("text/uri-list", FALSE)) {
+
+			char **uris;
+			int i;
+			
+			uris = g_uri_list_extract_uris (selection_data->data);
+			for (i = 0; uris[i]; i++) {
+      				char *name;
+				NautilusBookmark *bookmark;
+
+				if (!is_uri_directory (uris[i])) {
+					abort_drag_drop = TRUE;
+					break;
+				}
+				name = nautilus_compute_title_for_uri (uris[i]);
+				name = eel_str_middle_truncate (name, MAX_BOOKMARK_LENGTH);	
+				bookmark = nautilus_bookmark_new (uris[i], name);
+				g_free (name);
+				if (!nautilus_bookmark_list_contains (sidebar->bookmarks, bookmark)) {
+					nautilus_bookmark_list_append (sidebar->bookmarks, bookmark);
+				} else {
+					g_object_unref (bookmark);
+				}
+			}
+			g_strfreev (uris);
+			if (abort_drag_drop) {
+				eel_run_simple_dialog (
+					GTK_WIDGET (sidebar), 
+				 	FALSE,
+				 	GTK_MESSAGE_ERROR,
+				 	_("Only folders can be set as bookmarks"),
+					_("You have attempted to add a non-folder as a bookmark"),
+					_("Bookmark Error"),
+					GTK_STOCK_OK, NULL);
+			}
+		}
+	  	return;
+	}
+
+	/* copy dragged files to dropped on uri */
+	if (!gtk_tree_model_get_iter (model, &iter, path)) {
+		gtk_tree_path_free (path);
+		return;
+	}
+	gtk_tree_path_free (path);
+	gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1);
+	
+	if (uri != NULL) {
+		if (selection_data->target == gdk_atom_intern ("text/uri-list", FALSE)) {
+			char **uris;
+			int i;
+			
+			uris = g_uri_list_extract_uris (selection_data->data);
+
+			for (i = 0; uris[i]; i++) {
+				item_uris = g_list_prepend (item_uris, g_strdup (uris[i]));
+			}
+			g_strfreev (uris);
+
+			item_uris = g_list_reverse (item_uris);
+
+			nautilus_file_operations_copy_move (item_uris, NULL, uri,
+				  			    GDK_ACTION_COPY,
+			 				    GTK_WIDGET (sidebar->tree_view),
+			 				    NULL, NULL);
+		}
+		g_free (uri);
+	}
+	
+	g_signal_stop_emission_by_name (widget, "drag-data-received");
+}
+
 static void
 nautilus_places_sidebar_init (NautilusPlacesSidebar *sidebar)
 {
@@ -414,7 +616,8 @@
 					     G_TYPE_INT, 
 					     G_TYPE_STRING,
 					     G_TYPE_STRING,
-					     GDK_TYPE_PIXBUF
+					     GDK_TYPE_PIXBUF,
+					     G_TYPE_POINTER
 					     );
 
 	gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (sidebar->store));
@@ -433,10 +636,28 @@
 	selection = gtk_tree_view_get_selection (tree_view);
 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
 
+   	gtk_drag_dest_set (GTK_WIDGET (tree_view),
+		     	   GTK_DEST_DEFAULT_ALL,
+		     	   dest_targets,
+		     	   1,
+		     	   GDK_ACTION_COPY);
+
 	g_signal_connect_object
 		(tree_view, "row_activated", 
 		 G_CALLBACK (row_activated_callback), sidebar, 0);
 
+	g_signal_connect_object (tree_view,
+				 "drag_motion",
+				 G_CALLBACK (drag_motion_callback),
+				 sidebar, 0);
+	g_signal_connect_object (tree_view,
+				 "drag_leave",
+				 G_CALLBACK (drag_leave_callback),
+				 sidebar, 0);
+
+	g_signal_connect (tree_view, "drag-data-received",
+		G_CALLBACK (drag_data_received_callback), sidebar);
+
 	eel_preferences_add_callback (NAUTILUS_PREFERENCES_CLICK_POLICY,
 				      click_policy_changed_callback,
 				      sidebar);
@@ -458,6 +679,8 @@
 	g_free (sidebar->uri);
 	sidebar->uri = NULL;
 
+	unref_volumes (sidebar);
+
 	if (sidebar->store != NULL) {
 		g_object_unref (sidebar->store);
 		sidebar->store = NULL;


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