 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */

/*
 * Nautilus
 *
 * Copyright (C) 1999, 2000, 2001 Eazel, Inc.
 * Copyright (C) 2001 Red Hat, Inc.
 *
 * Nautilus 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.
 *
 * Nautilus 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Authors:  James Willcox  <jwillcox@gnome.org>
 *           Alexander Larsson <alexl@redhat.com>
 *
 * This is a sidebar displaying emblems which can be dragged onto files to
 * set/unset the chosen emblem.
 *
 */

#include <config.h>
#include "nautilus-emblem-sidebar.h"

#include <stdio.h>
#include <eel/eel-gtk-macros.h>
#include <eel/eel-glib-extensions.h>
#include <eel/eel-string.h>
#include <eel/eel-wrap-table.h>
#include <eel/eel-labeled-image.h>
#include <eel/eel-graphic-effects.h>
#include <eel/eel-gdk-pixbuf-extensions.h>
#include <eel/eel-stock-dialogs.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <gconf/gconf-client.h>
#include <libnautilus-private/nautilus-icon-dnd.h>
#include <libnautilus-private/nautilus-emblem-utils.h>
#include <libnautilus-private/nautilus-file-utilities.h>
#include <libnautilus-private/nautilus-sidebar-provider.h>
#include <libnautilus-private/nautilus-module.h>
#include <libnautilus-private/nautilus-signaller.h>

struct NautilusEmblemSidebarDetails {
	NautilusWindowInfo *window;
	GConfClient *client;
	GtkWidget *emblems_table;
	GtkWidget *popup;
	GtkWidget *popup_remove;
	GtkWidget *popup_rename;

	char *popup_emblem_keyword;
	char *popup_emblem_display_name;
	GdkPixbuf *popup_emblem_pixbuf;
};

#define ERASE_EMBLEM_KEYWORD			"erase"
#define STANDARD_EMBLEM_HEIGHT			52
#define EMBLEM_LABEL_SPACING			2

static void nautilus_emblem_sidebar_iface_init        (NautilusSidebarIface         *iface);
static void nautilus_emblem_sidebar_finalize          (GObject                      *object);
static void nautilus_emblem_sidebar_populate          (NautilusEmblemSidebar        *emblem_sidebar);
static void nautilus_emblem_sidebar_refresh           (NautilusEmblemSidebar        *emblem_sidebar);
static void nautilus_emblem_sidebar_iface_init        (NautilusSidebarIface         *iface);
static void sidebar_provider_iface_init               (NautilusSidebarProviderIface *iface);
static GType nautilus_emblem_sidebar_provider_get_type (void);

static const GtkTargetEntry drag_types[] = {
	{"property/keyword", 0, 0 }
};

enum {
	TARGET_URI_LIST,
	TARGET_URI,
	TARGET_NETSCAPE_URL
};

static const GtkTargetEntry dest_types[] = {
	{"text/uri-list", 0, TARGET_URI_LIST},
	{"text/plain", 0, TARGET_URI},
	{"_NETSCAPE_URL", 0, TARGET_NETSCAPE_URL}
};

typedef struct _Emblem {
	GdkPixbuf *pixbuf;
	char *uri;
	char *name;
	char *keyword;
} Emblem;

typedef struct {
        GObject parent;
} NautilusEmblemSidebarProvider;

typedef struct {
        GObjectClass parent;
} NautilusEmblemSidebarProviderClass;




G_DEFINE_TYPE_WITH_CODE (NautilusEmblemSidebar, nautilus_emblem_sidebar, GTK_TYPE_VBOX,
			 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR,
						nautilus_emblem_sidebar_iface_init));

G_DEFINE_TYPE_WITH_CODE (NautilusEmblemSidebarProvider, nautilus_emblem_sidebar_provider, G_TYPE_OBJECT,
			 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR_PROVIDER,
						sidebar_provider_iface_init));

static void
nautilus_emblem_sidebar_drag_data_get_cb (GtkWidget *widget,
					  GdkDragContext *context,
					  GtkSelectionData *data,
					  guint info,
					  guint time,
					  NautilusEmblemSidebar *emblem_sidebar)
{
	char *keyword;

	keyword = g_object_get_data (G_OBJECT (widget), "emblem-keyword");

	g_return_if_fail (keyword != NULL);

	gtk_selection_data_set (data, gtk_selection_data_get_target (data), 8,
				keyword,
				strlen (keyword));
}

static void
nautilus_emblem_sidebar_enter_notify_cb (GtkWidget *widget,
					 NautilusEmblemSidebar *emblem_sidebar)
{
	GdkPixbuf *pixbuf;
	EelLabeledImage *image;

	pixbuf = g_object_get_data (G_OBJECT (widget), "prelight-pixbuf");
	image = g_object_get_data (G_OBJECT (widget), "labeled-image");

	eel_labeled_image_set_pixbuf (EEL_LABELED_IMAGE (image), pixbuf);
}

static void
nautilus_emblem_sidebar_leave_notify_cb (GtkWidget *widget,
					 NautilusEmblemSidebar *emblem_sidebar)
{
	GdkPixbuf *pixbuf;
	EelLabeledImage *image;

	pixbuf = g_object_get_data (G_OBJECT (widget), "original-pixbuf");
	image = g_object_get_data (G_OBJECT (widget), "labeled-image");

	eel_labeled_image_set_pixbuf (EEL_LABELED_IMAGE (image), pixbuf);
}

static gboolean
nautilus_emblem_sidebar_button_press_cb (GtkWidget *widget,
					 GdkEventButton *event,
					 NautilusEmblemSidebar *emblem_sidebar)
{
	char *keyword, *name;
	GdkPixbuf *pixbuf;

	if (event->button == 3) {
		keyword = g_object_get_data (G_OBJECT (widget),
					     "emblem-keyword");
		name = g_object_get_data (G_OBJECT (widget),
					  "emblem-display-name");
		pixbuf = g_object_get_data (G_OBJECT (widget),
					    "original-pixbuf");

		emblem_sidebar->details->popup_emblem_keyword = keyword;
		emblem_sidebar->details->popup_emblem_display_name = name;
		emblem_sidebar->details->popup_emblem_pixbuf = pixbuf;

		gtk_widget_set_sensitive (emblem_sidebar->details->popup_remove,
				nautilus_emblem_can_remove_emblem (keyword));
		gtk_widget_set_sensitive (emblem_sidebar->details->popup_rename,
				nautilus_emblem_can_rename_emblem (keyword));


		gtk_menu_popup (GTK_MENU (emblem_sidebar->details->popup),
				NULL, NULL, NULL, NULL, event->button,
				event->time);
	}

	return TRUE;
}

static void
send_emblems_changed (void)
{
	g_signal_emit_by_name (nautilus_signaller_get_current (),
			       "emblems_changed");
}

static void
emblems_changed_callback (GObject *signaller,
			  NautilusEmblemSidebar *emblem_sidebar)
{
	nautilus_emblem_sidebar_refresh (emblem_sidebar);
}

static void
nautilus_emblem_sidebar_delete_cb (GtkWidget *menu_item,
				   NautilusEmblemSidebar *emblem_sidebar)
{
	char *error;

	if (nautilus_emblem_remove_emblem (emblem_sidebar->details->popup_emblem_keyword)) {
		send_emblems_changed ();
	} else {
		error = g_strdup_printf (_("Could not remove emblem with name '%s'."), emblem_sidebar->details->popup_emblem_display_name);
		eel_show_error_dialog (error, _("This is probably because the emblem is a permanent one, and not one that you added yourself."),
				       NULL);
		g_free (error);
	}
}

static void
rename_dialog_response_cb (GtkWidget *dialog, int response,
			   NautilusEmblemSidebar *emblem_sidebar)
{
	GtkWidget *entry;
	char *keyword, *name, *error;
	
	keyword = g_object_get_data (G_OBJECT (dialog), "emblem-keyword");

	if (response == GTK_RESPONSE_CANCEL) {
		g_free (keyword);
		gtk_widget_destroy (dialog);
		return;
	} else if (response == GTK_RESPONSE_HELP) {
		g_message ("Implement me!");
		return;
	}
	
	entry = g_object_get_data (G_OBJECT (dialog), "entry");

	name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));

	gtk_widget_destroy (dialog);

	if (nautilus_emblem_rename_emblem (keyword, name)) {
		send_emblems_changed ();
	} else {
		error = g_strdup_printf (_("Could not rename emblem with name '%s'."), name);
		eel_show_error_dialog (error, _("This is probably because the emblem is a permanent one, and not one that you added yourself."),
				       NULL);
		g_free (error);
	}

	g_free (keyword);
	g_free (name);
}

static GtkWidget *
create_rename_emblem_dialog (NautilusEmblemSidebar *emblem_sidebar,
			     const char *keyword, const char *orig_name,
			     GdkPixbuf *pixbuf)
{
	GtkWidget *dialog, *label, *image, *entry, *hbox;

	image = gtk_image_new_from_pixbuf (pixbuf);
	entry = gtk_entry_new ();

	dialog = gtk_dialog_new_with_buttons (_("Rename Emblem"),
					      NULL,
					      0,
					      GTK_STOCK_CANCEL,
					      GTK_RESPONSE_CANCEL,
					      GTK_STOCK_OK,
					      GTK_RESPONSE_OK,
					      GTK_STOCK_HELP,
					      GTK_RESPONSE_HELP,
					      NULL);

	gtk_dialog_set_default_response (GTK_DIALOG (dialog),
					 GTK_RESPONSE_OK);

	g_object_set_data (G_OBJECT (dialog), "emblem-keyword",
			   g_strdup (keyword));
	g_object_set_data (G_OBJECT (dialog), "entry",
			   entry);

	label = gtk_label_new (_("Enter a new name for the displayed emblem:"));
	gtk_widget_show (label);
	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), label,
			    FALSE, FALSE, 8);
	
	
	hbox = gtk_hbox_new (FALSE, 8);
	gtk_box_pack_start (GTK_BOX (hbox), image, TRUE, TRUE, 8);

	gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);

	gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 8);
	gtk_widget_show_all (hbox);

	/* it would be nice to have the text selected, ready to be overwritten
	 * by the user, but that doesn't seem possible.
	 */
	gtk_widget_grab_focus (entry);
	gtk_entry_set_text (GTK_ENTRY (entry), orig_name);

	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox,
			    TRUE, TRUE, 8);


	return dialog;
}

static void
nautilus_emblem_sidebar_rename_cb (GtkWidget *menu_item,
				   NautilusEmblemSidebar *emblem_sidebar)
{
	GtkWidget *dialog;

	dialog = create_rename_emblem_dialog (emblem_sidebar,
			emblem_sidebar->details->popup_emblem_keyword,
			emblem_sidebar->details->popup_emblem_display_name,
			emblem_sidebar->details->popup_emblem_pixbuf);
	g_signal_connect (dialog, "response",
			  G_CALLBACK (rename_dialog_response_cb),
			  emblem_sidebar);
	gtk_widget_show (dialog);
}

static void
create_popup_menu (NautilusEmblemSidebar *emblem_sidebar)
{
	GtkWidget *popup, *menu_item, *menu_image;

	popup = gtk_menu_new ();

	/* add the "rename" menu item */
	menu_image = gtk_image_new_from_stock (GTK_STOCK_PROPERTIES,
					       GTK_ICON_SIZE_MENU);
	gtk_widget_show (menu_image);
	menu_item = gtk_image_menu_item_new_with_label (_("Rename"));
	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
				       menu_image);

	g_signal_connect (menu_item, "activate",
			  G_CALLBACK (nautilus_emblem_sidebar_rename_cb),
			  emblem_sidebar);
	gtk_widget_show (menu_item);
	gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
	emblem_sidebar->details->popup_rename = menu_item;

	/* add "delete" menu item */
	menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE,
							NULL);
	g_signal_connect (menu_item, "activate",
			  G_CALLBACK (nautilus_emblem_sidebar_delete_cb),
			  emblem_sidebar);
	gtk_widget_show (menu_item);
	gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
	emblem_sidebar->details->popup_remove = menu_item;

	emblem_sidebar->details->popup = popup;
}

static GtkWidget *
create_emblem_widget_with_pixbuf (NautilusEmblemSidebar *emblem_sidebar,
				  const char *keyword,
				  const char *display_name,
				  GdkPixbuf *pixbuf)
{
	GtkWidget *image, *event_box;
	GdkPixbuf *prelight_pixbuf;


	image = eel_labeled_image_new (display_name, pixbuf);

	eel_labeled_image_set_fixed_image_height (EEL_LABELED_IMAGE (image),
						  STANDARD_EMBLEM_HEIGHT);
	eel_labeled_image_set_spacing (EEL_LABELED_IMAGE (image),
				       EMBLEM_LABEL_SPACING);
	event_box = gtk_event_box_new ();
	gtk_container_add (GTK_CONTAINER (event_box), image);

	prelight_pixbuf = eel_create_spotlight_pixbuf (pixbuf);
	

	gtk_drag_source_set (event_box, GDK_BUTTON1_MASK, drag_types,
			     G_N_ELEMENTS (drag_types),
			     GDK_ACTION_COPY | GDK_ACTION_MOVE);

	gtk_drag_source_set_icon_pixbuf (event_box, pixbuf);

	

	g_signal_connect (event_box, "button_press_event",
			  G_CALLBACK (nautilus_emblem_sidebar_button_press_cb),
			  emblem_sidebar);
	g_signal_connect (event_box, "drag-data-get",
			  G_CALLBACK (nautilus_emblem_sidebar_drag_data_get_cb),
			  emblem_sidebar);
	g_signal_connect (event_box, "enter-notify-event",
			  G_CALLBACK (nautilus_emblem_sidebar_enter_notify_cb),
			  emblem_sidebar);
	g_signal_connect (event_box, "leave-notify-event",
			  G_CALLBACK (nautilus_emblem_sidebar_leave_notify_cb),
			  emblem_sidebar);
	
	g_object_set_data_full (G_OBJECT (event_box),
				"emblem-keyword",
				g_strdup (keyword), g_free);
	g_object_set_data_full (G_OBJECT (event_box),
				"emblem-display-name",
				g_strdup (display_name), g_free);
	g_object_set_data_full (G_OBJECT (event_box),
				"original-pixbuf",
				pixbuf, g_object_unref);
	g_object_set_data_full (G_OBJECT (event_box),
				"prelight-pixbuf",
				prelight_pixbuf, g_object_unref);
	g_object_set_data (G_OBJECT (event_box),
			   "labeled-image", image);

	return event_box;

}

static GtkWidget *
create_emblem_widget (NautilusEmblemSidebar *emblem_sidebar,
		      const char *name)
{
	GtkWidget *ret;
	const char *display_name;
	char *keyword;
	GdkPixbuf *pixbuf;
	NautilusIconInfo *info;

	info = nautilus_icon_info_lookup_from_name (name, NAUTILUS_ICON_SIZE_STANDARD);

	pixbuf = nautilus_icon_info_get_pixbuf_at_size (info, NAUTILUS_ICON_SIZE_STANDARD);
	
	display_name = nautilus_icon_info_get_display_name (info);
	
	keyword = nautilus_emblem_get_keyword_from_icon_name (name);
	if (display_name == NULL) {
		display_name = keyword;
	}

	ret = create_emblem_widget_with_pixbuf (emblem_sidebar, keyword,
						display_name, pixbuf);
	g_free (keyword);
	g_object_unref (info);
	return ret;
}

static void
emblem_name_entry_changed_cb (GtkWidget *entry, Emblem *emblem)
{
	char *text;

	g_free (emblem->name);

	text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);

	emblem->name = g_strdup (text);
}


static void
destroy_emblem (Emblem *emblem, gpointer user_data)
{
	g_return_if_fail (emblem != NULL);


	if (emblem->pixbuf != NULL) {
		g_object_unref (emblem->pixbuf);
		emblem->pixbuf = NULL;
	}

	if (emblem->name != NULL) {
		g_free (emblem->name);
		emblem->name = NULL;
	}

	if (emblem->uri != NULL) {
		g_free (emblem->uri);
		emblem->uri = NULL;
	}

	if (emblem->keyword != NULL) {
		g_free (emblem->keyword);
		emblem->keyword = NULL;
	}
	
	g_free (emblem);
}

static void
destroy_emblem_list (GSList *list)
{
	g_slist_foreach (list, (GFunc)destroy_emblem, NULL);
	g_slist_free (list);
}

static GtkWidget *
create_add_emblems_dialog (NautilusEmblemSidebar *emblem_sidebar,
			   GSList *emblems)
{
	GtkWidget *dialog, *label, *table, *image;
	GtkWidget *first_entry, *entry, *scroller, *hbox;
	Emblem *emblem;
	GSList *list;
	int num_emblems;

	first_entry = NULL;
	
	dialog = gtk_dialog_new_with_buttons (_("Add Emblems..."),
					      NULL,
					      0,
					      GTK_STOCK_CANCEL,
					      GTK_RESPONSE_CANCEL,
					      GTK_STOCK_OK,
					      GTK_RESPONSE_OK,
					      GTK_STOCK_HELP,
					      GTK_RESPONSE_HELP,
					      NULL);

	gtk_dialog_set_default_response (GTK_DIALOG (dialog),
					 GTK_RESPONSE_OK);

	/* FIXME:  make a better message */
	if (g_slist_length (emblems) > 1) {
		label = gtk_label_new (_("Enter a descriptive name next to each emblem.  This name will be used in other places to identify the emblem."));
	} else {
		label = gtk_label_new (_("Enter a descriptive name next to the emblem.  This name will be used in other places to identify the emblem."));
	}
	
	gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
			    label, FALSE, FALSE, 8);
	gtk_widget_show (label);
	
	scroller = eel_scrolled_wrap_table_new (TRUE, GTK_SHADOW_NONE, &table);
	eel_wrap_table_set_x_spacing (EEL_WRAP_TABLE (table), 8);
	eel_wrap_table_set_y_spacing (EEL_WRAP_TABLE (table), 8);
	
	num_emblems=0;
	list = emblems;
	while (list != NULL) {
		/* walk through the list of emblems, and create an image
		 * and entry for each one
		 */

		emblem = (Emblem *)list->data;
		list = list->next;

		image = gtk_image_new_from_pixbuf (emblem->pixbuf);

		hbox = gtk_hbox_new (TRUE, 0);
		gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);

		entry = gtk_entry_new ();
		gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
		g_signal_connect (entry, "changed",
				  G_CALLBACK (emblem_name_entry_changed_cb),
				  emblem);

		gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
		gtk_container_add (GTK_CONTAINER (table), hbox);

		if (num_emblems == 0) {
			first_entry = entry;
		}

		num_emblems++;
	}

	gtk_container_set_border_width (GTK_CONTAINER (dialog), 8);
	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
			    scroller, TRUE, TRUE, 8);
	gtk_widget_show_all (scroller);

	gtk_widget_grab_focus (first_entry);

	/* we expand the window to hold up to about 4 emblems, but after that
	 * let the scroller do its thing.  Is there a better way to do this?
	 */
	gtk_window_set_default_size (GTK_WINDOW (dialog), 400,
				     MIN (120+(60*num_emblems), 350));

	g_object_set_data_full (G_OBJECT (dialog), "emblems-to-add",
				emblems, (GDestroyNotify)destroy_emblem_list);

	return dialog;
}

static void
remove_widget (GtkWidget *widget, GtkContainer *container)
{
	gtk_container_remove (container, widget);
}

static void
nautilus_emblem_sidebar_refresh (NautilusEmblemSidebar *emblem_sidebar)
{
	nautilus_emblem_refresh_list ();

	gtk_container_foreach (GTK_CONTAINER (emblem_sidebar->details->emblems_table),
			       (GtkCallback)remove_widget,
			       emblem_sidebar->details->emblems_table);
	
	nautilus_emblem_sidebar_populate (emblem_sidebar);
}

static void
add_emblems_dialog_response_cb (GtkWidget *dialog, int response,
				NautilusEmblemSidebar *emblem_sidebar)
{
	Emblem *emblem;
	GSList *emblems;
	GSList *l;

	switch (response) {
	case GTK_RESPONSE_CANCEL:
		gtk_widget_destroy (dialog);
		break;

	case GTK_RESPONSE_HELP:
		g_message ("Implement me!");
		break;

	case GTK_RESPONSE_OK:
		emblems = g_object_get_data (G_OBJECT (dialog),
					     "emblems-to-add");

		for (l = emblems; l; l = l->next) {
			char *keyword;

			emblem = (Emblem *)l->data;
			if (emblem->keyword != NULL) {
				/* this one has already been verified */
				continue;
			}

			keyword = nautilus_emblem_create_unique_keyword (emblem->name);
			if (!nautilus_emblem_verify_keyword
				(GTK_WINDOW (dialog), keyword, emblem->name)) {
				g_free (keyword);
				return;
			} else {
				emblem->keyword = keyword;
			}

		}

		for (l = emblems; l; l = l->next) {
			emblem = (Emblem *)l->data;

			nautilus_emblem_install_custom_emblem (emblem->pixbuf,
							       emblem->keyword,
							       emblem->name,
							       GTK_WINDOW (dialog));
		}

		gtk_widget_destroy (dialog);

		send_emblems_changed ();
		break;
	}
}

static void
show_add_emblems_dialog (NautilusEmblemSidebar *emblem_sidebar,
			 GSList *emblems)
{
	GtkWidget *dialog;
	
	g_return_if_fail (emblems != NULL);

	dialog = create_add_emblems_dialog (emblem_sidebar, emblems);

	if (dialog == NULL) {
		return;
	}

	g_signal_connect (dialog, "response",
			  G_CALLBACK (add_emblems_dialog_response_cb),
			  emblem_sidebar);

	gtk_window_present (GTK_WINDOW (dialog));
}

static void
nautilus_emblem_sidebar_drag_received_cb (GtkWidget *widget,
					  GdkDragContext *drag_context,
					  gint x,
					  gint y,
					  GtkSelectionData *data,
					  guint info,
					  guint time,
					  NautilusEmblemSidebar *emblem_sidebar)
{
	GSList *emblems;
	Emblem *emblem;
	GdkPixbuf *pixbuf;
	char *uri, *error, *uri_utf8;
	char **uris;
	GFile *f;
	int i;
	gboolean had_failure;
	gint data_format, data_length;
	const guchar *data_data;

	had_failure = FALSE;
	emblems = NULL;
	data_format = gtk_selection_data_get_format (data);
	data_length = gtk_selection_data_get_length (data);
	data_data = gtk_selection_data_get_data (data);

	switch (info) {
	case TARGET_URI_LIST:
		if (data_format != 8 ||
		    data_length == 0) {
			g_message ("URI list had wrong format (%d) or length (%d)\n",
				   data_format, data_length);
			return;
		}

		uris = g_uri_list_extract_uris (data_data);
		if (uris == NULL) {
			break;
		}

		for (i = 0; uris[i] != NULL; ++i) {
			f = g_file_new_for_uri (uris[i]);
			pixbuf = nautilus_emblem_load_pixbuf_for_emblem (f);

			if (pixbuf == NULL) {
				/* this one apparently isn't an image, or
				 * at least not one that we know how to read
				 */
				had_failure = TRUE;
				g_object_unref (f);
				continue;
			}

			emblem = g_new (Emblem, 1);
			emblem->uri = g_file_get_uri (f);
			emblem->name = NULL; /* created later on by the user */
			emblem->keyword = NULL;
			emblem->pixbuf = pixbuf;
			
			g_object_unref (f);

			emblems = g_slist_prepend (emblems, emblem);
		}

		g_strfreev (uris);

		if (had_failure && emblems != NULL) {
			eel_show_error_dialog (_("Some of the files could not be added as emblems."), _("The emblems do not appear to be valid images."), NULL);
		} else if (had_failure && emblems == NULL) {
			eel_show_error_dialog (_("None of the files could be added as emblems."), _("The emblems do not appear to be valid images."), NULL);

		}
 
		if (emblems != NULL) {
			show_add_emblems_dialog (emblem_sidebar, emblems);
		}

		break;
	
	case TARGET_URI:
		if (data_format != 8 ||
		    data_length == 0) {
			g_warning ("URI had wrong format (%d) or length (%d)\n",
				   data_format, data_length);
			return;
		}

		uri = g_strndup (data_data, data_length);

		f = g_file_new_for_uri (uri);
		pixbuf = nautilus_emblem_load_pixbuf_for_emblem (f);

		if (pixbuf != NULL) {
			emblem = g_new (Emblem, 1);
			emblem->uri = uri;
			emblem->name = NULL;
			emblem->keyword = NULL;
			emblem->pixbuf = pixbuf;

			emblems = g_slist_prepend (NULL, emblem);

			show_add_emblems_dialog (emblem_sidebar, emblems);
		} else {
			uri_utf8 = g_file_get_parse_name (f);

			if (uri_utf8) {
				error = g_strdup_printf (_("The file '%s' does not appear to be a valid image."), uri_utf8);
				g_free (uri_utf8);
			} else {
				error = g_strdup (_("The dragged file does not appear to be a valid image."));
			}
			eel_show_error_dialog (_("The emblem cannot be added."), error, NULL);
			g_free (error);
			g_free (uri_utf8);
		}

		g_object_unref (f);
		g_free (uri);
		
		break;	

	case TARGET_NETSCAPE_URL:
		if (data_format != 8 ||
		    data_length == 0) {
			g_message ("URI had wrong format (%d) or length (%d)\n",
				   data_format, data_length);
			return;
		}

		/* apparently, this is a URI/title pair?  or just a pair
		 * of identical URIs?  Regardless, this seems to work...
		 */

		uris = g_uri_list_extract_uris (data_data);
		if (uris == NULL) {
			break;
		}

		uri = uris[0];
		if (uri == NULL) {
			g_strfreev (uris);
			break;
		}

		f = g_file_new_for_uri (uri);
		pixbuf = nautilus_emblem_load_pixbuf_for_emblem (f);
		g_object_unref (f);

		if (pixbuf != NULL) {
			emblem = g_new (Emblem, 1);
			emblem->uri = g_strdup (uri);
			emblem->name = NULL;
			emblem->keyword = NULL;
			emblem->pixbuf = pixbuf;

			emblems = g_slist_prepend (NULL, emblem);

			show_add_emblems_dialog (emblem_sidebar, emblems);
		} else {
			g_warning ("Tried to load '%s', but failed.\n",
				   uri);
			error = g_strdup_printf (_("The file '%s' does not appear to be a valid image."), uri);
			eel_show_error_dialog (_("The emblem cannot be added."), error, NULL);
			g_free (error);
		}

		g_strfreev (uris);

		break;
	}
}

static GtkWidget *
nautilus_emblem_sidebar_create_container (NautilusEmblemSidebar *emblem_sidebar)
{
	GtkWidget *emblems_table, *scroller;

	/* The emblems wrapped table */
	scroller = eel_scrolled_wrap_table_new (TRUE, GTK_SHADOW_IN, &emblems_table);

	gtk_container_set_border_width (GTK_CONTAINER (emblems_table), 8);

	/* set up dnd for adding emblems */
	gtk_drag_dest_set (scroller,
			   GTK_DEST_DEFAULT_ALL,
			   dest_types, G_N_ELEMENTS (dest_types),
			   GDK_ACTION_COPY | GDK_ACTION_MOVE);

	g_signal_connect (scroller, "drag-data-received",
			  G_CALLBACK (nautilus_emblem_sidebar_drag_received_cb),
			  emblem_sidebar);
			
	gtk_widget_show (scroller);

	emblem_sidebar->details->emblems_table = emblems_table;

	return scroller;
}

static gint
emblem_widget_sort_func (gconstpointer a, gconstpointer b)
{
	GObject *obj_a, *obj_b;

	obj_a = G_OBJECT (a);
	obj_b = G_OBJECT (b);

	return strcmp (g_object_get_data (obj_a, "emblem-display-name"),
		       g_object_get_data (obj_b, "emblem-display-name"));
}

static void
nautilus_emblem_sidebar_populate (NautilusEmblemSidebar *emblem_sidebar)
{
	GList *icons, *l, *widgets;
	GtkWidget *emblem_widget;
	char *name;
	char *path;
	GdkPixbuf *erase_pixbuf;

	erase_pixbuf = NULL;

	path = nautilus_pixmap_file ("erase.png");
	if (path != NULL) {
		erase_pixbuf = gdk_pixbuf_new_from_file (path, NULL);
	}
	g_free (path);

	if (erase_pixbuf != NULL) {
		emblem_widget = create_emblem_widget_with_pixbuf (emblem_sidebar,
							ERASE_EMBLEM_KEYWORD,
							_("Erase"),
							erase_pixbuf);
		gtk_container_add (GTK_CONTAINER
				(emblem_sidebar->details->emblems_table),
				emblem_widget);
	}


	icons = nautilus_emblem_list_available ();

	l = icons;
	widgets = NULL;
	while (l != NULL) {
		name = (char *)l->data;
		l = l->next;

		if (!nautilus_emblem_should_show_in_list (name)) {
			continue;
		}

		emblem_widget = create_emblem_widget (emblem_sidebar, name);
		
		widgets = g_list_prepend (widgets, emblem_widget);
	}
	eel_g_list_free_deep (icons);

	/* sort the emblems by display name */
	widgets = g_list_sort (widgets, emblem_widget_sort_func);

	l = widgets;
	while (l != NULL) {
		gtk_container_add
			(GTK_CONTAINER (emblem_sidebar->details->emblems_table),
			 l->data);
		l = l->next;
	}
	g_list_free (widgets);

	gtk_widget_show_all (emblem_sidebar->details->emblems_table);
}

static void
nautilus_emblem_sidebar_init (NautilusEmblemSidebar *emblem_sidebar)
{
	GtkWidget *widget;
	
	emblem_sidebar->details = g_new0 (NautilusEmblemSidebarDetails, 1);

	emblem_sidebar->details->client = gconf_client_get_default ();

	create_popup_menu (emblem_sidebar);

	widget = nautilus_emblem_sidebar_create_container (emblem_sidebar);
	nautilus_emblem_sidebar_populate (emblem_sidebar);

	g_signal_connect_object (nautilus_signaller_get_current (),
				 "emblems_changed",
				 G_CALLBACK (emblems_changed_callback), emblem_sidebar, 0);
	
	gtk_box_pack_start (GTK_BOX (emblem_sidebar), widget,
			    TRUE, TRUE, 0);
}

static void
nautilus_emblem_sidebar_finalize (GObject *object)
{
	NautilusEmblemSidebar *emblem_sidebar;

	g_assert (NAUTILUS_IS_EMBLEM_SIDEBAR (object));
	emblem_sidebar = NAUTILUS_EMBLEM_SIDEBAR (object);

	if (emblem_sidebar->details != NULL) {
		if (emblem_sidebar->details->client != NULL) {
			g_object_unref (emblem_sidebar->details->client);
		}

		g_free (emblem_sidebar->details);
	}

	G_OBJECT_CLASS (nautilus_emblem_sidebar_parent_class)->finalize (object);
}

static void
nautilus_emblem_sidebar_class_init (NautilusEmblemSidebarClass *object_klass)
{
	GObjectClass *gobject_class;
	
	NautilusEmblemSidebarClass *klass;

	klass = NAUTILUS_EMBLEM_SIDEBAR_CLASS (object_klass);
	gobject_class = G_OBJECT_CLASS (object_klass);

	gobject_class->finalize = nautilus_emblem_sidebar_finalize;
}

static const char *
nautilus_emblem_sidebar_get_sidebar_id (NautilusSidebar *sidebar)
{
	return NAUTILUS_EMBLEM_SIDEBAR_ID;
}

static char *
nautilus_emblem_sidebar_get_tab_label (NautilusSidebar *sidebar)
{
	return g_strdup (_("Emblems"));
}

static char *
nautilus_emblem_sidebar_get_tab_tooltip (NautilusSidebar *sidebar)
{
	return g_strdup (_("Show Emblems"));
}

static GdkPixbuf *
nautilus_emblem_sidebar_get_tab_icon (NautilusSidebar *sidebar)
{
	return NULL;
}

static void
nautilus_emblem_sidebar_is_visible_changed (NautilusSidebar *sidebar,
					     gboolean         is_visible)
{
	/* Do nothing */
}

static void
nautilus_emblem_sidebar_iface_init (NautilusSidebarIface *iface)
{
	iface->get_sidebar_id = nautilus_emblem_sidebar_get_sidebar_id;
	iface->get_tab_label = nautilus_emblem_sidebar_get_tab_label;
	iface->get_tab_tooltip = nautilus_emblem_sidebar_get_tab_tooltip;
	iface->get_tab_icon = nautilus_emblem_sidebar_get_tab_icon;
	iface->is_visible_changed = nautilus_emblem_sidebar_is_visible_changed;
}

static void
nautilus_emblem_sidebar_set_parent_window (NautilusEmblemSidebar *sidebar,
					    NautilusWindowInfo *window)
{
	sidebar->details->window = window;
}

static NautilusSidebar *
nautilus_emblem_sidebar_create (NautilusSidebarProvider *provider,
				NautilusWindowInfo *window)
{
	NautilusEmblemSidebar *sidebar;
	
	sidebar = g_object_new (nautilus_emblem_sidebar_get_type (), NULL);
	nautilus_emblem_sidebar_set_parent_window (sidebar, window);
	g_object_ref_sink (sidebar);

	return NAUTILUS_SIDEBAR (sidebar);
}

static void 
sidebar_provider_iface_init (NautilusSidebarProviderIface *iface)
{
	iface->create = nautilus_emblem_sidebar_create;
}

static void
nautilus_emblem_sidebar_provider_init (NautilusEmblemSidebarProvider *sidebar)
{
}

static void
nautilus_emblem_sidebar_provider_class_init (NautilusEmblemSidebarProviderClass *class)
{
}

void
nautilus_emblem_sidebar_register (void)
{
        nautilus_module_add_type (nautilus_emblem_sidebar_provider_get_type ());
}

