nautilus-places-sidebar.c 70.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */

/*
 *  Nautilus
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License as
 *  published by the Free Software Foundation; either version 2 of the
 *  License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this library; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Author : Mr Jamie McCracken (jamiemcc at blueyonder dot co dot uk)
 *
 */
 
#include <config.h>

#include <eel/eel-debug.h>
#include <eel/eel-gtk-extensions.h>
#include <eel/eel-glib-extensions.h>
#include <eel/eel-preferences.h>
#include <eel/eel-string.h>
31
#include <eel/eel-stock-dialogs.h>
32
#include <gdk/gdkkeysyms.h>
33
#include <gtk/gtk.h>
34
#include <glib/gi18n.h>
Alexander Larsson's avatar
 
Alexander Larsson committed
35
#include <libnautilus-private/nautilus-debug-log.h>
36
#include <libnautilus-private/nautilus-dnd.h>
37 38 39 40
#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>
Alexander Larsson's avatar
Alexander Larsson committed
41
#include <libnautilus-private/nautilus-file.h>
42
#include <libnautilus-private/nautilus-file-utilities.h>
43
#include <libnautilus-private/nautilus-file-operations.h>
44
#include <libnautilus-private/nautilus-trash-monitor.h>
Luca Ferretti's avatar
Luca Ferretti committed
45
#include <libnautilus-private/nautilus-icon-names.h>
46
#include <libnautilus-private/nautilus-autorun.h>
47 48
#include <libnautilus-private/nautilus-window-info.h>
#include <libnautilus-private/nautilus-window-slot-info.h>
49
#include <gio/gio.h>
50 51 52

#include "nautilus-bookmark-list.h"
#include "nautilus-places-sidebar.h"
53
#include "nautilus-window.h"
54

55
#define EJECT_BUTTON_XPAD 5
56

57 58 59 60 61 62 63
#define NAUTILUS_PLACES_SIDEBAR_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_PLACES_SIDEBAR, NautilusPlacesSidebarClass))
#define NAUTILUS_IS_PLACES_SIDEBAR(obj)         (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_PLACES_SIDEBAR))
#define NAUTILUS_IS_PLACES_SIDEBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_PLACES_SIDEBAR))

typedef struct {
	GtkScrolledWindow  parent;
	GtkTreeView        *tree_view;
64 65
	GtkCellRenderer    *icon_cell_renderer;
	GtkCellRenderer    *eject_text_cell_renderer;
66 67
	char 	           *uri;
	GtkListStore       *store;
68
	GtkTreeModel       *filter_model;
69 70
	NautilusWindowInfo *window;
	NautilusBookmarkList *bookmarks;
Alexander Larsson's avatar
Alexander Larsson committed
71
	GVolumeMonitor *volume_monitor;
72

73 74 75
	/* DnD */
	GList     *drag_list;
	gboolean  drag_data_received;
76
	int       drag_data_info;
77 78
	gboolean  drop_occured;

79
	GtkWidget *popup_menu;
80
	GtkWidget *popup_menu_open_in_new_tab_item;
81 82
	GtkWidget *popup_menu_remove_item;
	GtkWidget *popup_menu_rename_item;
83 84 85 86
	GtkWidget *popup_menu_separator_item;
	GtkWidget *popup_menu_mount_item;
	GtkWidget *popup_menu_unmount_item;
	GtkWidget *popup_menu_eject_item;
87
	GtkWidget *popup_menu_rescan_item;
88
	GtkWidget *popup_menu_format_item;
89
	GtkWidget *popup_menu_empty_trash_item;
90 91 92 93 94

	/* volume mounting - delayed open process */
	gboolean mounting;
	NautilusWindowSlotInfo *go_to_after_mount_slot;
	NautilusWindowOpenFlags go_to_after_mount_flags;
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
} NautilusPlacesSidebar;

typedef struct {
	GtkScrolledWindowClass parent;
} NautilusPlacesSidebarClass;

typedef struct {
        GObject parent;
} NautilusPlacesSidebarProvider;

typedef struct {
        GObjectClass parent;
} NautilusPlacesSidebarProviderClass;

enum {
	PLACES_SIDEBAR_COLUMN_ROW_TYPE,
	PLACES_SIDEBAR_COLUMN_URI,
112
	PLACES_SIDEBAR_COLUMN_DRIVE,
113
	PLACES_SIDEBAR_COLUMN_VOLUME,
114
	PLACES_SIDEBAR_COLUMN_MOUNT,
115 116
	PLACES_SIDEBAR_COLUMN_NAME,
	PLACES_SIDEBAR_COLUMN_ICON,
117
	PLACES_SIDEBAR_COLUMN_INDEX,
118
	PLACES_SIDEBAR_COLUMN_EJECT,
119 120 121
	PLACES_SIDEBAR_COLUMN_NO_EJECT,
	PLACES_SIDEBAR_COLUMN_BOOKMARK,
	PLACES_SIDEBAR_COLUMN_NO_BOOKMARK,
122 123 124 125 126 127 128 129 130 131 132 133 134 135
	
	PLACES_SIDEBAR_COLUMN_COUNT
};

typedef enum {
	PLACES_BUILT_IN,
	PLACES_MOUNTED_VOLUME,
	PLACES_BOOKMARK,
	PLACES_SEPARATOR
} PlaceType;

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);
136 137 138
static void  open_selected_bookmark                    (NautilusPlacesSidebar        *sidebar,
							GtkTreeModel                 *model,
							GtkTreePath                  *path,
139
							NautilusWindowOpenFlags flags);
140 141
static void  nautilus_places_sidebar_style_set         (GtkWidget                    *widget,
							GtkStyle                     *previous_style);
142 143 144 145 146 147 148 149
static gboolean eject_or_unmount_bookmark              (NautilusPlacesSidebar *sidebar,
							GtkTreePath *path);
static gboolean eject_or_unmount_selection             (NautilusPlacesSidebar *sidebar);
static void  check_unmount_and_eject                   (GMount *mount,
							GVolume *volume,
							GDrive *drive,
							gboolean *show_unmount,
							gboolean *show_eject);
150

151 152
static void bookmarks_check_popup_sensitivity          (NautilusPlacesSidebar *sidebar);

153 154 155 156 157 158 159
/* Identifiers for target types */
enum {
  GTK_TREE_MODEL_ROW,
  TEXT_URI_LIST
};

/* Target types for dragging from the shortcuts list */
160
static const GtkTargetEntry nautilus_shortcuts_source_targets[] = {
161 162 163
	{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
};

164
/* Target types for dropping into the shortcuts list */
165
static const GtkTargetEntry nautilus_shortcuts_drop_targets [] = {
166 167
	{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW },
	{ "text/uri-list", 0, TEXT_URI_LIST }
168 169
};

170 171 172 173 174
/* Drag and drop interface declarations */
typedef struct {
  GtkTreeModelFilter parent;

  NautilusPlacesSidebar *sidebar;
175
} NautilusShortcutsModelFilter;
176 177 178

typedef struct {
  GtkTreeModelFilterClass parent_class;
179
} NautilusShortcutsModelFilterClass;
180

181 182
#define NAUTILUS_SHORTCUTS_MODEL_FILTER_TYPE (_nautilus_shortcuts_model_filter_get_type ())
#define NAUTILUS_SHORTCUTS_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_SHORTCUTS_MODEL_FILTER_TYPE, NautilusShortcutsModelFilter))
183

184 185
GType _nautilus_shortcuts_model_filter_get_type (void);
static void nautilus_shortcuts_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface);
186

187 188
G_DEFINE_TYPE_WITH_CODE (NautilusShortcutsModelFilter,
			 _nautilus_shortcuts_model_filter,
189 190
			 GTK_TYPE_TREE_MODEL_FILTER,
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
191
						nautilus_shortcuts_model_filter_drag_source_iface_init));
192

193 194 195
static GtkTreeModel *nautilus_shortcuts_model_filter_new (NautilusPlacesSidebar *sidebar,
							  GtkTreeModel          *child_model,
							  GtkTreePath           *root);
196

197 198 199 200 201 202 203 204 205
G_DEFINE_TYPE_WITH_CODE (NautilusPlacesSidebar, nautilus_places_sidebar, GTK_TYPE_SCROLLED_WINDOW,
			 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR,
						nautilus_places_sidebar_iface_init));

G_DEFINE_TYPE_WITH_CODE (NautilusPlacesSidebarProvider, nautilus_places_sidebar_provider, G_TYPE_OBJECT,
			 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR_PROVIDER,
						sidebar_provider_iface_init));

static GtkTreeIter
206
add_place (NautilusPlacesSidebar *sidebar,
207 208
	   PlaceType place_type,
	   const char *name,
Alexander Larsson's avatar
Alexander Larsson committed
209
	   GIcon *icon,
210
	   const char *uri,
Alexander Larsson's avatar
Alexander Larsson committed
211 212
	   GDrive *drive,
	   GVolume *volume,
213
	   GMount *mount,
214
	   const int index)
215 216
{
	GdkPixbuf            *pixbuf;
217
	GtkTreeIter           iter, child_iter;
Alexander Larsson's avatar
Alexander Larsson committed
218 219
	NautilusIconInfo *icon_info;
	int icon_size;
220
	gboolean show_eject, show_unmount;
221
	gboolean show_eject_button;
222

Alexander Larsson's avatar
Alexander Larsson committed
223 224 225 226 227
	icon_size = nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU);
	icon_info = nautilus_icon_info_lookup (icon, icon_size);

	pixbuf = nautilus_icon_info_get_pixbuf_at_size (icon_info, icon_size);
	g_object_unref (icon_info);
228 229 230 231 232 233
	check_unmount_and_eject (mount, volume, drive,
				 &show_unmount, &show_eject);

	if (show_unmount || show_eject) {
		g_assert (place_type != PLACES_BOOKMARK);
	}
234 235 236 237 238 239 240

	if (mount == NULL) {
		show_eject_button = FALSE;
	} else {
		show_eject_button = (show_unmount || show_eject);
	}

241 242
	gtk_list_store_append (sidebar->store, &iter);
	gtk_list_store_set (sidebar->store, &iter,
243 244 245
			    PLACES_SIDEBAR_COLUMN_ICON, pixbuf,
			    PLACES_SIDEBAR_COLUMN_NAME, name,
			    PLACES_SIDEBAR_COLUMN_URI, uri,
246
			    PLACES_SIDEBAR_COLUMN_DRIVE, drive,
247
			    PLACES_SIDEBAR_COLUMN_VOLUME, volume,
248
			    PLACES_SIDEBAR_COLUMN_MOUNT, mount,
249
			    PLACES_SIDEBAR_COLUMN_ROW_TYPE, place_type,
250
			    PLACES_SIDEBAR_COLUMN_INDEX, index,
251 252
			    PLACES_SIDEBAR_COLUMN_EJECT, show_eject_button,
			    PLACES_SIDEBAR_COLUMN_NO_EJECT, !show_eject_button,
253 254
			    PLACES_SIDEBAR_COLUMN_BOOKMARK, place_type != PLACES_BOOKMARK,
			    PLACES_SIDEBAR_COLUMN_NO_BOOKMARK, place_type == PLACES_BOOKMARK,
255
			    -1);
256

257 258 259
	if (pixbuf != NULL) {
		g_object_unref (pixbuf);
	}
260 261 262 263 264
	gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (sidebar->filter_model));
	gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (sidebar->filter_model),
							  &child_iter,
							  &iter);
	return child_iter;
265 266 267 268 269
}

static void
update_places (NautilusPlacesSidebar *sidebar)
{
Alexander Larsson's avatar
Alexander Larsson committed
270 271 272 273
	NautilusBookmark *bookmark;
	GtkTreeSelection *selection;
	GtkTreeIter iter, last_iter;
	GVolumeMonitor *volume_monitor;
274 275
	GList *mounts, *l, *ll;
	GMount *mount;
Alexander Larsson's avatar
Alexander Larsson committed
276 277
	GList *drives;
	GDrive *drive;
278 279
	GList *volumes;
	GVolume *volume;
Alexander Larsson's avatar
Alexander Larsson committed
280 281 282 283
	int bookmark_count, index;
	char *location, *mount_uri, *name, *desktop_path;
	GIcon *icon;
	GFile *root;
284 285
	NautilusWindowSlotInfo *slot;

286 287
	selection = gtk_tree_view_get_selection (sidebar->tree_view);
	gtk_list_store_clear (sidebar->store);
288 289 290

	slot = nautilus_window_info_get_active_slot (sidebar->window);
	location = nautilus_window_slot_info_get_current_location (slot);
291 292 293 294 295

	/* add built in bookmarks */
	desktop_path = nautilus_get_desktop_directory ();

	if (strcmp (g_get_home_dir(), desktop_path) != 0) {
Federico Mena Quintero's avatar
Federico Mena Quintero committed
296 297
		char *display_name;

298
		mount_uri = nautilus_get_home_directory_uri ();
Federico Mena Quintero's avatar
Federico Mena Quintero committed
299
		display_name = g_filename_display_basename (g_get_home_dir ());
Luca Ferretti's avatar
Luca Ferretti committed
300
		icon = g_themed_icon_new (NAUTILUS_ICON_HOME);
301
		last_iter = add_place (sidebar, PLACES_BUILT_IN,
Alexander Larsson's avatar
Alexander Larsson committed
302
				       display_name, icon,
303
				       mount_uri, NULL, NULL, NULL, 0);
Alexander Larsson's avatar
Alexander Larsson committed
304
		g_object_unref (icon);
Federico Mena Quintero's avatar
Federico Mena Quintero committed
305
		g_free (display_name);
306
		if (eel_strcmp (location, mount_uri) == 0) {
307 308 309 310 311
			gtk_tree_selection_select_iter (selection, &last_iter);
		}	
		g_free (mount_uri);
	}

Alexander Larsson's avatar
Alexander Larsson committed
312
	mount_uri = g_filename_to_uri (desktop_path, NULL, NULL);
Luca Ferretti's avatar
Luca Ferretti committed
313
	icon = g_themed_icon_new (NAUTILUS_ICON_DESKTOP);
314
	last_iter = add_place (sidebar, PLACES_BUILT_IN,
Alexander Larsson's avatar
Alexander Larsson committed
315
			       _("Desktop"), icon,
316
			       mount_uri, NULL, NULL, NULL, 0);
Alexander Larsson's avatar
Alexander Larsson committed
317
	g_object_unref (icon);
318
	if (eel_strcmp (location, mount_uri) == 0) {
319 320 321 322 323
		gtk_tree_selection_select_iter (selection, &last_iter);
	}	
	g_free (mount_uri);
	g_free (desktop_path);
	
324
 	mount_uri = "file:///"; /* No need to strdup */
Luca Ferretti's avatar
Luca Ferretti committed
325
	icon = g_themed_icon_new (NAUTILUS_ICON_FILESYSTEM);
326
	last_iter = add_place (sidebar, PLACES_BUILT_IN,
Alexander Larsson's avatar
Alexander Larsson committed
327
			       _("File System"), icon,
328
			       mount_uri, NULL, NULL, NULL, 0);
Alexander Larsson's avatar
Alexander Larsson committed
329
	g_object_unref (icon);
330
	if (eel_strcmp (location, mount_uri) == 0) {
331
		gtk_tree_selection_select_iter (selection, &last_iter);
332
	}
333

334 335 336 337 338 339 340 341 342 343
 	mount_uri = "network:///"; /* No need to strdup */
	icon = g_themed_icon_new (NAUTILUS_ICON_NETWORK);
	last_iter = add_place (sidebar, PLACES_BUILT_IN,
			       _("Network"), icon,
			       mount_uri, NULL, NULL, NULL, 0);
	g_object_unref (icon);
	if (strcmp (location, mount_uri) == 0) {
		gtk_tree_selection_select_iter (selection, &last_iter);
	}

Alexander Larsson's avatar
Alexander Larsson committed
344
	volume_monitor = sidebar->volume_monitor;
345 346

	/* first go through all connected drives */
Alexander Larsson's avatar
Alexander Larsson committed
347
	drives = g_volume_monitor_get_connected_drives (volume_monitor);
348 349
	for (l = drives; l != NULL; l = l->next) {
		drive = l->data;
350 351 352

		volumes = g_drive_get_volumes (drive);
		if (volumes != NULL) {
353 354
			for (ll = volumes; ll != NULL; ll = ll->next) {
				volume = ll->data;
355 356 357 358 359 360 361 362 363 364 365
				mount = g_volume_get_mount (volume);
				if (mount != NULL) {
					/* Show mounted volume in the sidebar */
					icon = g_mount_get_icon (mount);
					root = g_mount_get_root (mount);
					mount_uri = g_file_get_uri (root);
					g_object_unref (root);
					name = g_mount_get_name (mount);
					last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
							       name, icon, mount_uri,
							       drive, volume, mount, 0);
366
					if (eel_strcmp (location, mount_uri) == 0) {
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
						gtk_tree_selection_select_iter (selection, &last_iter);
					}
					g_object_unref (mount);
					g_object_unref (icon);
					g_free (name);
					g_free (mount_uri);
				} else {
					/* Do show the unmounted volumes in the sidebar;
					 * this is so the user can mount it (in case automounting
					 * is off).
					 *
					 * Also, even if automounting is enabled, this gives a visual
					 * cue that the user should remember to yank out the media if
					 * he just unmounted it.
					 */
					icon = g_volume_get_icon (volume);
					name = g_volume_get_name (volume);
					last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
							       name, icon, NULL,
							       drive, volume, NULL, 0);
					g_object_unref (icon);
					g_free (name);
389
				}
Alexander Larsson's avatar
Alexander Larsson committed
390
				g_object_unref (volume);
391
			}
392
			g_list_free (volumes);
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
		} else {
			if (g_drive_is_media_removable (drive) && !g_drive_is_media_check_automatic (drive)) {
				/* If the drive has no mountable volumes and we cannot detect media change.. we
				 * display the drive in the sidebar so the user can manually poll the drive by
				 * right clicking and selecting "Rescan..."
				 *
				 * This is mainly for drives like floppies where media detection doesn't
				 * work.. but it's also for human beings who like to turn off media detection
				 * in the OS to save battery juice.
				 */
				icon = g_drive_get_icon (drive);
				name = g_drive_get_name (drive);
				last_iter = add_place (sidebar, PLACES_BUILT_IN,
						       name, icon, NULL,
						       drive, NULL, NULL, 0);
Alexander Larsson's avatar
Alexander Larsson committed
408
				g_object_unref (icon);
409 410
				g_free (name);
			}
411
		}
Alexander Larsson's avatar
Alexander Larsson committed
412
		g_object_unref (drive);
413 414 415
	}
	g_list_free (drives);

416 417
	/* add all volumes that is not associated with a drive */
	volumes = g_volume_monitor_get_volumes (volume_monitor);
418 419
	for (l = volumes; l != NULL; l = l->next) {
		volume = l->data;
Alexander Larsson's avatar
Alexander Larsson committed
420 421
		drive = g_volume_get_drive (volume);
		if (drive != NULL) {
422 423 424 425 426 427 428 429 430 431 432 433 434 435
		    	g_object_unref (volume);
			g_object_unref (drive);
			continue;
		}
		mount = g_volume_get_mount (volume);
		if (mount != NULL) {
			icon = g_mount_get_icon (mount);
			root = g_mount_get_root (mount);
			mount_uri = g_file_get_uri (root);
			g_object_unref (root);
			name = g_mount_get_name (mount);
			last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
					       name, icon, mount_uri,
					       NULL, volume, mount, 0);
436
			if (eel_strcmp (location, mount_uri) == 0) {
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
				gtk_tree_selection_select_iter (selection, &last_iter);
			}
			g_object_unref (mount);
			g_object_unref (icon);
			g_free (name);
			g_free (mount_uri);
		} else {
			/* see comment above in why we add an icon for an unmounted mountable volume */
			icon = g_volume_get_icon (volume);
			name = g_volume_get_name (volume);
			last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
					       name, icon, NULL,
					       NULL, volume, NULL, 0);
			g_object_unref (icon);
			g_free (name);
		}
		g_object_unref (volume);
	}
	g_list_free (volumes);

	/* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
	mounts = g_volume_monitor_get_mounts (volume_monitor);
	for (l = mounts; l != NULL; l = l->next) {
		mount = l->data;
David Zeuthen's avatar
David Zeuthen committed
461 462 463 464
		if (g_mount_is_shadowed (mount)) {
			g_object_unref (mount);
			continue;
		}
465 466 467 468
		volume = g_mount_get_volume (mount);
		if (volume != NULL) {
		    	g_object_unref (volume);
			g_object_unref (mount);
469 470
			continue;
		}
471 472
		icon = g_mount_get_icon (mount);
		root = g_mount_get_root (mount);
Alexander Larsson's avatar
Alexander Larsson committed
473 474
		mount_uri = g_file_get_uri (root);
		g_object_unref (root);
475
		name = g_mount_get_name (mount);
476
		last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
477
				       name, icon, mount_uri,
478
				       NULL, NULL, mount, 0);
479
		if (eel_strcmp (location, mount_uri) == 0) {
480 481
			gtk_tree_selection_select_iter (selection, &last_iter);
		}
482
		g_object_unref (mount);
Alexander Larsson's avatar
Alexander Larsson committed
483
		g_object_unref (icon);
484 485 486
		g_free (name);
		g_free (mount_uri);
	}
487
	g_list_free (mounts);
488

489
	mount_uri = "trash:///"; /* No need to strdup */
Alexander Larsson's avatar
Alexander Larsson committed
490
	icon = nautilus_trash_monitor_get_icon ();
491 492
	last_iter = add_place (sidebar, PLACES_BUILT_IN,
			       _("Trash"), icon, mount_uri,
493
			       NULL, NULL, NULL, 0);
494
	if (eel_strcmp (location, mount_uri) == 0) {
495 496
		gtk_tree_selection_select_iter (selection, &last_iter);
	}
Alexander Larsson's avatar
Alexander Larsson committed
497
	g_object_unref (icon);
498

499 500 501 502 503 504 505 506 507 508 509 510 511
	/* add separator */

	gtk_list_store_append (sidebar->store, &iter);
	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);

512 513 514 515
		if (nautilus_bookmark_uri_known_not_to_exist (bookmark)) {
			continue;
		}

516 517 518
		name = nautilus_bookmark_get_name (bookmark);
		icon = nautilus_bookmark_get_icon (bookmark);
		mount_uri = nautilus_bookmark_get_uri (bookmark);
519
		last_iter = add_place (sidebar, PLACES_BOOKMARK,
520
				       name, icon, mount_uri,
521
				       NULL, NULL, NULL, index);
522
		if (eel_strcmp (location, mount_uri) == 0) {
523 524 525
			gtk_tree_selection_select_iter (selection, &last_iter);
		}
		g_free (name);
Alexander Larsson's avatar
Alexander Larsson committed
526
		g_object_unref (icon);
527 528 529 530 531 532
		g_free (mount_uri);
	}
	g_free (location);
}

static gboolean
533 534 535
nautilus_shortcuts_row_separator_func (GtkTreeModel *model,
				       GtkTreeIter  *iter,
				       gpointer      data)
536 537 538 539 540 541 542 543 544 545 546 547
{
	PlaceType	 	type; 

  	gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, -1);
  
  	if (type == PLACES_SEPARATOR) {
   		return TRUE;
	}

  	return FALSE;
}

548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
static void
mount_added_callback (GVolumeMonitor *volume_monitor,
		      GMount *mount,
		      NautilusPlacesSidebar *sidebar)
{
	update_places (sidebar);
}

static void
mount_removed_callback (GVolumeMonitor *volume_monitor,
			GMount *mount,
			NautilusPlacesSidebar *sidebar)
{
	update_places (sidebar);
}

static void
mount_changed_callback (GVolumeMonitor *volume_monitor,
			GMount *mount,
			NautilusPlacesSidebar *sidebar)
{
	update_places (sidebar);
}

static void
volume_added_callback (GVolumeMonitor *volume_monitor,
		       GVolume *volume,
		       NautilusPlacesSidebar *sidebar)
{
	update_places (sidebar);
}
579 580

static void
581
volume_removed_callback (GVolumeMonitor *volume_monitor,
Alexander Larsson's avatar
Alexander Larsson committed
582
			 GVolume *volume,
583 584 585 586 587 588
			 NautilusPlacesSidebar *sidebar)
{
	update_places (sidebar);
}

static void
589 590 591
volume_changed_callback (GVolumeMonitor *volume_monitor,
			 GVolume *volume,
			 NautilusPlacesSidebar *sidebar)
592
{
593
	update_places (sidebar);
594 595 596
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
597 598
drive_disconnected_callback (GVolumeMonitor *volume_monitor,
			     GDrive         *drive,
599 600 601 602 603 604
			     NautilusPlacesSidebar *sidebar)
{
	update_places (sidebar);
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
605 606
drive_connected_callback (GVolumeMonitor *volume_monitor,
			  GDrive         *drive,
607
			  NautilusPlacesSidebar *sidebar)
608 609 610 611
{
	update_places (sidebar);
}

612 613 614 615 616 617 618 619
static void
drive_changed_callback (GVolumeMonitor *volume_monitor,
			GDrive         *drive,
			NautilusPlacesSidebar *sidebar)
{
	update_places (sidebar);
}

620 621 622 623 624 625 626
static gboolean
clicked_eject_button (NautilusPlacesSidebar *sidebar,
		      GtkTreePath **path)
{
	GdkEvent *event = gtk_get_current_event ();
	GdkEventButton *button_event = (GdkEventButton *) event;
	GtkTreeViewColumn *column;
627 628 629
	GtkTextDirection direction;
	int width, total_width;
	int eject_button_size;
630 631 632 633 634 635

	*path = NULL;

	if (event->type == GDK_BUTTON_PRESS &&
	    gtk_tree_view_get_path_at_pos (sidebar->tree_view,
					   button_event->x, button_event->y,
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
					   path, &column, NULL, NULL)) {
		total_width = 0;

		gtk_widget_style_get (GTK_WIDGET (sidebar->tree_view),
				      "horizontal-separator", &width,
				      NULL);
		total_width += width / 2;

		direction = gtk_widget_get_direction (GTK_WIDGET (sidebar->tree_view));
		if (direction != GTK_TEXT_DIR_RTL) {
			gtk_tree_view_column_cell_get_position (column,
								sidebar->icon_cell_renderer,
								NULL, &width);
			total_width += width;

			gtk_tree_view_column_cell_get_position (column,
								sidebar->eject_text_cell_renderer,
								NULL, &width);
			total_width += width;
		}

		total_width += EJECT_BUTTON_XPAD;
658

659
		eject_button_size = nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU);
660

661 662
		if (button_event->x - total_width >= 0 &&
		    button_event->x - total_width <= eject_button_size) {
663 664
			return TRUE;
		}
665 666
	} else if (event->type == GDK_BUTTON_RELEASE) {
		g_object_set_data (G_OBJECT (sidebar->tree_view), "myrect", NULL);
667 668 669 670 671 672 673 674 675
	}

	if (*path != NULL) {
		gtk_tree_path_free (*path);
	}

	return FALSE;
}

676 677 678 679 680 681
static void
row_activated_callback (GtkTreeView *tree_view,
			GtkTreePath *path,
			GtkTreeViewColumn *column,
			gpointer user_data)
{
682 683 684
	open_selected_bookmark (NAUTILUS_PLACES_SIDEBAR (user_data),
				gtk_tree_view_get_model (tree_view),
				path,
685
				0);
686 687 688 689 690 691 692 693 694 695 696 697
}

static void
desktop_location_changed_callback (gpointer user_data)
{
	NautilusPlacesSidebar *sidebar;
	
	sidebar = NAUTILUS_PLACES_SIDEBAR (user_data);

	update_places (sidebar);
}

698 699 700 701 702 703 704 705 706 707
static void
enable_tabs_changed_callback (gpointer user_data)
{
	NautilusPlacesSidebar *sidebar;

	sidebar = NAUTILUS_PLACES_SIDEBAR (user_data);

	bookmarks_check_popup_sensitivity (sidebar);
}

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
static void
loading_uri_callback (NautilusWindowInfo *window,
		      char *location,
		      NautilusPlacesSidebar *sidebar)
{
	GtkTreeSelection *selection;
	GtkTreeIter 	 iter;
	gboolean 	 valid;
	char  		 *uri;

        if (strcmp (sidebar->uri, location) != 0) {
		g_free (sidebar->uri);
                sidebar->uri = g_strdup (location);
  
		/* set selection if any place matches location */
		selection = gtk_tree_view_get_selection (sidebar->tree_view);
		gtk_tree_selection_unselect_all (selection);
725
  		valid = gtk_tree_model_get_iter_first (sidebar->filter_model, &iter);
726 727

		while (valid) {
728
			gtk_tree_model_get (sidebar->filter_model, &iter, 
729 730 731 732 733 734 735 736 737 738
		 		       	    PLACES_SIDEBAR_COLUMN_URI, &uri,
					    -1);
			if (uri != NULL) {
				if (strcmp (uri, location) == 0) {
					g_free (uri);
					gtk_tree_selection_select_iter (selection, &iter);
					break;
				}
				g_free (uri);
			}
739
        	 	valid = gtk_tree_model_iter_next (sidebar->filter_model, &iter);
740 741 742 743 744
		}
    	}
}


745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
static unsigned int
get_bookmark_index (GtkTreeView *tree_view)
{
	GtkTreeModel *model;
	GtkTreePath *p;
	GtkTreeIter iter;
	PlaceType place_type;
	int bookmark_index;

	model = gtk_tree_view_get_model (tree_view);

	bookmark_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) {
			bookmark_index = *gtk_tree_path_get_indices (p) + 1;
			break;
		}

		gtk_tree_path_next (p);
	}
	gtk_tree_path_free (p);

	g_assert (bookmark_index >= 0);

	return bookmark_index;
}

/* Computes the appropriate row and position for dropping */
static void
compute_drop_position (GtkTreeView *tree_view,
				 int                      x,
				 int                      y,
				 GtkTreePath            **path,
				 GtkTreeViewDropPosition *pos,
				 NautilusPlacesSidebar *sidebar)
{
	int bookmarks_index;
790
	int num_rows;
791
	int row;
792 793 794
	
	bookmarks_index = get_bookmark_index (tree_view);
	
795
	num_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (sidebar->filter_model), NULL);
796 797 798 799 800 801

	if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
					   x,
					   y,
					   path,
					   pos)) {
802
		row = num_rows - 1;
803 804 805 806 807 808 809 810
		*path = gtk_tree_path_new_from_indices (row, -1);
		*pos = GTK_TREE_VIEW_DROP_AFTER;
		return;
	}
	
	row = *gtk_tree_path_get_indices (*path);
	gtk_tree_path_free (*path);
	
811 812 813 814
	if (row == bookmarks_index - 1) {
		/* Only allow to drop after separator */
		*pos = GTK_TREE_VIEW_DROP_AFTER;
	} else if (row < bookmarks_index) {
815 816
		/* Hardcoded shortcuts can only be dragged into */
		*pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
817 818 819 820 821 822 823
	} else if (row >= num_rows) {
		row = num_rows - 1;
		*pos = GTK_TREE_VIEW_DROP_AFTER;
	} else if (*pos != GTK_TREE_VIEW_DROP_BEFORE &&
		   sidebar->drag_data_received &&
		   sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
		/* bookmark rows are never dragged into other bookmark rows */
824 825
		*pos = GTK_TREE_VIEW_DROP_AFTER;
	}
826

827 828 829
	*path = gtk_tree_path_new_from_indices (row, -1);
}

830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856

static void
get_drag_data (GtkTreeView *tree_view,
	       GdkDragContext *context, 
	       unsigned int time)
{
	GdkAtom target;
	
	target = gtk_drag_dest_find_target (GTK_WIDGET (tree_view), 
					    context, 
					    NULL);

	gtk_drag_get_data (GTK_WIDGET (tree_view),
			   context, target, time);
}

static void
free_drag_data (NautilusPlacesSidebar *sidebar)
{
	sidebar->drag_data_received = FALSE;

	if (sidebar->drag_list) {
		nautilus_drag_destroy_selection_list (sidebar->drag_list);
		sidebar->drag_list = NULL;
	}
}

857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
static gboolean
can_accept_file_as_bookmark (NautilusFile *file)
{
	return nautilus_file_is_directory (file);
}

static gboolean
can_accept_items_as_bookmarks (const GList *items)
{
	int max;
	char *uri;
	NautilusFile *file;

	/* Iterate through selection checking if item will get accepted as a bookmark.
	 * If more than 100 items selected, return an over-optimistic result.
	 */
	for (max = 100; items != NULL && max >= 0; items = items->next, max--) {
		uri = ((NautilusDragSelectionItem *)items->data)->uri;
Alexander Larsson's avatar
Alexander Larsson committed
875
		file = nautilus_file_get_by_uri (uri);
876 877 878 879 880 881 882 883 884 885
		if (!can_accept_file_as_bookmark (file)) {
			nautilus_file_unref (file);
			return FALSE;
		}
		nautilus_file_unref (file);
	}
	
	return TRUE;
}

886 887 888 889 890 891 892 893
static void
drag_data_delete_callback (GtkWidget             *widget,
			   GdkDragContext        *context,
			   NautilusPlacesSidebar *sidebar)
{
	g_signal_stop_emission_by_name (widget, "drag-data-delete");
}

894 895 896 897 898 899 900 901 902 903
static gboolean
drag_motion_callback (GtkTreeView *tree_view,
		      GdkDragContext *context,
		      int x,
		      int y,
		      unsigned int time,
		      NautilusPlacesSidebar *sidebar)
{
	GtkTreePath *path;
	GtkTreeViewDropPosition pos;
904
	int action;
905
	GtkTreeIter iter, child_iter;
906 907 908 909
	char *uri;

	if (!sidebar->drag_data_received) {
		get_drag_data (tree_view, context, time);
910
	}
911 912 913 914

	compute_drop_position (tree_view, x, y, &path, &pos, sidebar);

	if (pos == GTK_TREE_VIEW_DROP_BEFORE ||
915
	    pos == GTK_TREE_VIEW_DROP_AFTER ) {
916 917 918 919
		if (sidebar->drag_data_received &&
		    sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
			action = GDK_ACTION_MOVE;
		} else if (can_accept_items_as_bookmarks (sidebar->drag_list)) {
920 921 922 923 924
			action = GDK_ACTION_COPY;
		} else {
			action = 0;
		}
	} else {
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
		if (sidebar->drag_list == NULL) {
			action = 0;
		} else {
			gtk_tree_model_get_iter (sidebar->filter_model,
						 &iter, path);
			gtk_tree_model_filter_convert_iter_to_child_iter (
				GTK_TREE_MODEL_FILTER (sidebar->filter_model),
				&child_iter, &iter);
			gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store),
					    &child_iter,
					    PLACES_SIDEBAR_COLUMN_URI, &uri,
					    -1);
			nautilus_drag_default_drop_action_for_icons (context, uri,
								     sidebar->drag_list,
								     &action);
			g_free (uri);
		}
942
	}
943

944 945 946
	gtk_tree_view_set_drag_dest_row (tree_view, path, pos);
	gtk_tree_path_free (path);
	g_signal_stop_emission_by_name (tree_view, "drag-motion");
947

948 949 950 951 952 953
	if (action != 0) {
		gdk_drag_status (context, action, time);
		return TRUE;
	} else {
		return FALSE;
	}
954 955 956 957 958 959 960 961
}

static void
drag_leave_callback (GtkTreeView *tree_view,
		     GdkDragContext *context,
		     unsigned int time,
		     NautilusPlacesSidebar *sidebar)
{
962
	free_drag_data (sidebar);
963 964 965 966 967 968 969
	gtk_tree_view_set_drag_dest_row (tree_view, NULL, GTK_TREE_VIEW_DROP_BEFORE);
	g_signal_stop_emission_by_name (tree_view, "drag-leave");
}

/* Parses a "text/uri-list" string and inserts its URIs as bookmarks */
static void
bookmarks_drop_uris (NautilusPlacesSidebar *sidebar,
970
		     GtkSelectionData      *selection_data,
971 972 973
		     int                    position)
{
	NautilusBookmark *bookmark;
974
	NautilusFile *file;
975
	char *uri, *name;
976
	char **uris;
977
	int i;
Alexander Larsson's avatar
Alexander Larsson committed
978 979
	GFile *location;
	GIcon *icon;
980
	
981 982 983
	uris = gtk_selection_data_get_uris (selection_data);
	if (!uris)
		return;
984 985 986
	
	for (i = 0; uris[i]; i++) {
		uri = uris[i];
Alexander Larsson's avatar
Alexander Larsson committed
987
		file = nautilus_file_get_by_uri (uri);
988 989 990 991 992 993

		if (!can_accept_file_as_bookmark (file)) {
			nautilus_file_unref (file);
			continue;
		}

994
		uri = nautilus_file_get_drop_target_uri (file);
Alexander Larsson's avatar
Alexander Larsson committed
995
		location = g_file_new_for_uri (uri);
996
		nautilus_file_unref (file);
997

Alexander Larsson's avatar
Alexander Larsson committed
998
		name = nautilus_compute_title_for_location (location);
999

Luca Ferretti's avatar
Luca Ferretti committed
1000
		icon = g_themed_icon_new (NAUTILUS_ICON_FOLDER);
Alexander Larsson's avatar
Alexander Larsson committed
1001 1002 1003
		bookmark = nautilus_bookmark_new_with_icon (location, name,
							    FALSE, icon);
		g_object_unref (icon);
1004 1005 1006 1007
		
		if (!nautilus_bookmark_list_contains (sidebar->bookmarks, bookmark)) {
			nautilus_bookmark_list_insert_item (sidebar->bookmarks, bookmark, position++);
		}
Martin Wehner's avatar
Martin Wehner committed
1008

Alexander Larsson's avatar
Alexander Larsson committed
1009
		g_object_unref (location);
Martin Wehner's avatar
Martin Wehner committed
1010 1011 1012
		g_object_unref (bookmark);
		g_free (name);
		g_free (uri);
1013 1014 1015 1016 1017
	}

	g_strfreev (uris);
}

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
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);
}

1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
static GList*
build_selection_list (const char *data)
{
	NautilusDragSelectionItem *item;
	GList *result;
	char **uris;
	char *uri;
	int i;

	uris = g_uri_list_extract_uris (data);

	result = NULL;
	for (i = 0; uris[i]; i++) {
		uri = uris[i];
		item = nautilus_drag_selection_item_new ();
		item->uri = g_strdup (uri);
		item->got_icon_position = FALSE;
		result = g_list_prepend (result, item);
	}

	g_strfreev (uris);

	return g_list_reverse (result);
}

1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
static gboolean
get_selected_iter (NautilusPlacesSidebar *sidebar,
		   GtkTreeIter *iter)
{
	GtkTreeSelection *selection;
	GtkTreeIter parent_iter;

	selection = gtk_tree_view_get_selection (sidebar->tree_view);
	if (!gtk_tree_selection_get_selected (selection, NULL, &parent_iter)) {
		return FALSE;
	}
	gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (sidebar->filter_model),
							  iter,
							  &parent_iter);
	return TRUE;
}

/* Reorders the selected bookmark to the specified position */
static void
reorder_bookmarks (NautilusPlacesSidebar *sidebar,
		   int                   new_position)
{
	GtkTreeIter iter;
	NautilusBookmark *bookmark;
1083
	PlaceType type; 
1084 1085 1086 1087 1088 1089 1090
	int old_position;

	/* Get the selected path */

	if (!get_selected_iter (sidebar, &iter))
		g_assert_not_reached ();

1091 1092 1093 1094
	gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
			    PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
			    PLACES_SIDEBAR_COLUMN_INDEX, &old_position,
			    -1);
1095

1096 1097 1098
	if (type != PLACES_BOOKMARK ||
	    old_position < 0 ||
	    old_position >= nautilus_bookmark_list_length (sidebar->bookmarks)) {
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
		return;
	}

	/* Remove the path from the old position and insert it in the new one */

	if (old_position == new_position) {
		return;
	}
	bookmark = nautilus_bookmark_list_item_at (sidebar->bookmarks, old_position);
	nautilus_bookmark_list_insert_item (sidebar->bookmarks, bookmark, new_position);
	if (old_position > new_position) {
		old_position++;
	}
	nautilus_bookmark_list_delete_item_at (sidebar->bookmarks, old_position);
}

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
static void
drag_data_received_callback (GtkWidget *widget,
			     GdkDragContext *context,
			     int x,
			     int y,
			     GtkSelectionData *selection_data,
			     unsigned int info,
			     unsigned int time,
			     NautilusPlacesSidebar *sidebar)
{
	GtkTreeView *tree_view;
	GtkTreePath *tree_path;
	GtkTreeViewDropPosition tree_pos;
1128
	GtkTreeIter iter;
1129
	int position;
1130 1131 1132
	GtkTreeModel *model;
	char *drop_uri;
	GList *selection_list, *uris;
1133
	PlaceType type; 
1134
	gboolean success;
1135 1136 1137

	tree_view = GTK_TREE_VIEW (widget);

1138
	if (!sidebar->drag_data_received) {
1139 1140
		if (selection_data->target != GDK_NONE &&
		    info == TEXT_URI_LIST) {
1141
			sidebar->drag_list = build_selection_list (selection_data->data);
1142 1143 1144 1145
		} else {
			sidebar->drag_list = NULL;
		}
		sidebar->drag_data_received = TRUE;
1146
		sidebar->drag_data_info = info;
1147
	}
1148

1149
	g_signal_stop_emission_by_name (widget, "drag-data-received");
1150

1151 1152
	if (!sidebar->drop_occured) {
		return;
1153 1154
	}

1155 1156 1157 1158
	/* Compute position */
	compute_drop_position (tree_view, x, y, &tree_path, &tree_pos, sidebar);

	success = FALSE;
1159

1160 1161
	if (tree_pos == GTK_TREE_VIEW_DROP_BEFORE ||
	    tree_pos == GTK_TREE_VIEW_DROP_AFTER) {
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
		model = gtk_tree_view_get_model (tree_view);

		if (!gtk_tree_model_get_iter (model, &iter, tree_path)) {
			goto out;
		}

		gtk_tree_model_get (model, &iter,
				    PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
				    PLACES_SIDEBAR_COLUMN_INDEX, &position,
				    -1);

		if (type != PLACES_SEPARATOR && type != PLACES_BOOKMARK) {
			goto out;
		}

		if (type == PLACES_BOOKMARK &&
		    tree_pos == GTK_TREE_VIEW_DROP_AFTER) {
1179 1180
			position++;
		}
1181

1182
		switch (info) {
1183
		case TEXT_URI_LIST:
1184
			bookmarks_drop_uris (sidebar, selection_data, position);
1185 1186
			success = TRUE;
			break;
1187 1188 1189 1190
		case GTK_TREE_MODEL_ROW:
			reorder_bookmarks (sidebar, position);
			success = TRUE;
			break;
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
		default:
			g_assert_not_reached ();
			break;
		}
	} else {
		/* file transfer requested */
		if (context->action == GDK_ACTION_ASK) {
			context->action =
				nautilus_drag_drop_action_ask (GTK_WIDGET (tree_view),
							       context->actions);
		}

		if (context->action > 0) {
			model = gtk_tree_view_get_model (tree_view);

			gtk_tree_model_get_iter (model, &iter, tree_path);
			gtk_tree_model_get (model, &iter,
					    PLACES_SIDEBAR_COLUMN_URI, &drop_uri,
					    -1);

			switch (info) {
1212